This patch adds BPF debug mode. When a bpf program is in debug mode, all calls to kfuncs and helpers are traced and output to the trace ring buffer, including arguments and return values, in a strace-like format. Signed-off-by: Juntong Deng <juntong.deng@xxxxxxxxxxx> --- include/linux/bpf.h | 3 ++- include/uapi/linux/bpf.h | 1 + kernel/bpf/syscall.c | 4 +++- tools/include/uapi/linux/bpf.h | 2 ++ tools/lib/bpf/libbpf.c | 6 ++++++ tools/lib/bpf/libbpf.h | 2 ++ 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1bc90d805872..c8585b436d0b 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1614,7 +1614,8 @@ struct bpf_prog { call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ call_get_func_ip:1, /* Do we call get_func_ip() */ tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ - sleepable:1; /* BPF program is sleepable */ + sleepable:1, /* BPF program is sleepable */ + debug_mode:1; enum bpf_prog_type type; /* Type of BPF program */ enum bpf_attach_type expected_attach_type; /* For some prog types */ u32 len; /* Number of filter blocks */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index fff6cdb8d11a..6c68a16a5549 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1272,6 +1272,7 @@ enum bpf_perf_event_type { /* The verifier internal test flag. Behavior is undefined */ #define BPF_F_TEST_REG_INVARIANTS (1U << 7) +#define BPF_F_DEBUG_MODE (1U << 8) /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c420edbfb7c8..1261315c2410 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2757,7 +2757,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_XDP_HAS_FRAGS | BPF_F_XDP_DEV_BOUND_ONLY | BPF_F_TEST_REG_INVARIANTS | - BPF_F_TOKEN_FD)) + BPF_F_TOKEN_FD | + BPF_F_DEBUG_MODE)) return -EINVAL; bpf_prog_load_fixup_attach_type(attr); @@ -2870,6 +2871,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->expected_attach_type = attr->expected_attach_type; prog->sleepable = !!(attr->prog_flags & BPF_F_SLEEPABLE); + prog->debug_mode = !!(attr->prog_flags & BPF_F_DEBUG_MODE); prog->aux->attach_btf = attach_btf; prog->aux->attach_btf_id = attr->attach_btf_id; prog->aux->dst_prog = dst_prog; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index fff6cdb8d11a..3b700cb86836 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1272,6 +1272,8 @@ enum bpf_perf_event_type { /* The verifier internal test flag. Behavior is undefined */ #define BPF_F_TEST_REG_INVARIANTS (1U << 7) +#define BPF_F_DEBUG_MODE (1U << 8) + /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 194809da5172..2ff3f2a597b3 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -689,6 +689,7 @@ struct bpf_object { bool loaded; bool has_subcalls; bool has_rodata; + bool debug_mode; struct bpf_gen *gen_loader; @@ -7520,6 +7521,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog load_attr.log_level = log_level; load_attr.prog_flags = prog->prog_flags; load_attr.fd_array = obj->fd_array; + if (obj->debug_mode) + load_attr.prog_flags |= BPF_F_DEBUG_MODE; load_attr.token_fd = obj->token_fd; if (obj->token_fd) @@ -7972,6 +7975,7 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, char *log_buf; size_t log_size; __u32 log_level; + bool debug_mode; if (obj_buf && !obj_name) return ERR_PTR(-EINVAL); @@ -7996,6 +8000,7 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, log_buf = OPTS_GET(opts, kernel_log_buf, NULL); log_size = OPTS_GET(opts, kernel_log_size, 0); log_level = OPTS_GET(opts, kernel_log_level, 0); + debug_mode = OPTS_GET(opts, debug_mode, false); if (log_size > UINT_MAX) return ERR_PTR(-EINVAL); if (log_size && !log_buf) @@ -8018,6 +8023,7 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, obj->log_buf = log_buf; obj->log_size = log_size; obj->log_level = log_level; + obj->debug_mode = debug_mode; if (token_path) { obj->token_path = strdup(token_path); diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 3020ee45303a..191547045b7e 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -123,6 +123,8 @@ struct bpf_object_open_opts { */ const char *object_name; /* parse map definitions non-strictly, allowing extra attributes/data */ + bool debug_mode; + /* open debug mode */ bool relaxed_maps; /* maps that set the 'pinning' attribute in their definition will have * their pin_path attribute set to a file in this directory, and be -- 2.39.5