Commit f75a697e authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Daniel Borkmann

libbpf: Auto-detect btf_id of BTF-based raw_tracepoints

It's a responsiblity of bpf program author to annotate the program
with SEC("tp_btf/name") where "name" is a valid raw tracepoint.
The libbpf will try to find "name" in vmlinux BTF and error out
in case vmlinux BTF is not available or "name" is not found.
If "name" is indeed a valid raw tracepoint then in-kernel BTF
will have "btf_trace_##name" typedef that points to function
prototype of that raw tracepoint. BTF description captures
exact argument the kernel C code is passing into raw tracepoint.
The kernel verifier will check the types while loading bpf program.

libbpf keeps BTF type id in expected_attach_type, but since
kernel ignores this attribute for tracing programs copy it
into attach_btf_id attribute before loading.

Later the kernel will use prog->attach_btf_id to select raw tracepoint
during bpf_raw_tracepoint_open syscall command.
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAndrii Nakryiko <andriin@fb.com>
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20191016032505.2089704-6-ast@kernel.org
parent ccfe29eb
...@@ -228,6 +228,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, ...@@ -228,6 +228,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
attr.prog_type = load_attr->prog_type; attr.prog_type = load_attr->prog_type;
attr.expected_attach_type = load_attr->expected_attach_type; attr.expected_attach_type = load_attr->expected_attach_type;
if (attr.prog_type == BPF_PROG_TYPE_RAW_TRACEPOINT)
/* expected_attach_type is ignored for tracing progs */
attr.attach_btf_id = attr.expected_attach_type;
attr.insn_cnt = (__u32)load_attr->insns_cnt; attr.insn_cnt = (__u32)load_attr->insns_cnt;
attr.insns = ptr_to_u64(load_attr->insns); attr.insns = ptr_to_u64(load_attr->insns);
attr.license = ptr_to_u64(load_attr->license); attr.license = ptr_to_u64(load_attr->license);
......
...@@ -4489,19 +4489,22 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog, ...@@ -4489,19 +4489,22 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
prog->expected_attach_type = type; prog->expected_attach_type = type;
} }
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, atype) \ #define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, btf, atype) \
{ string, sizeof(string) - 1, ptype, eatype, is_attachable, atype } { string, sizeof(string) - 1, ptype, eatype, is_attachable, btf, atype }
/* Programs that can NOT be attached. */ /* Programs that can NOT be attached. */
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0) #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0, 0)
/* Programs that can be attached. */ /* Programs that can be attached. */
#define BPF_APROG_SEC(string, ptype, atype) \ #define BPF_APROG_SEC(string, ptype, atype) \
BPF_PROG_SEC_IMPL(string, ptype, 0, 1, atype) BPF_PROG_SEC_IMPL(string, ptype, 0, 1, 0, atype)
/* Programs that must specify expected attach type at load time. */ /* Programs that must specify expected attach type at load time. */
#define BPF_EAPROG_SEC(string, ptype, eatype) \ #define BPF_EAPROG_SEC(string, ptype, eatype) \
BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, eatype) BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, 0, eatype)
/* Programs that use BTF to identify attach point */
#define BPF_PROG_BTF(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 1, 0)
/* Programs that can be attached but attach type can't be identified by section /* Programs that can be attached but attach type can't be identified by section
* name. Kept for backward compatibility. * name. Kept for backward compatibility.
...@@ -4513,7 +4516,8 @@ static const struct { ...@@ -4513,7 +4516,8 @@ static const struct {
size_t len; size_t len;
enum bpf_prog_type prog_type; enum bpf_prog_type prog_type;
enum bpf_attach_type expected_attach_type; enum bpf_attach_type expected_attach_type;
int is_attachable; bool is_attachable;
bool is_attach_btf;
enum bpf_attach_type attach_type; enum bpf_attach_type attach_type;
} section_names[] = { } section_names[] = {
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER), BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
...@@ -4523,6 +4527,7 @@ static const struct { ...@@ -4523,6 +4527,7 @@ static const struct {
BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT), BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT),
BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT), BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT),
BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT), BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT),
BPF_PROG_BTF("tp_btf/", BPF_PROG_TYPE_RAW_TRACEPOINT),
BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP),
BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT),
BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN),
...@@ -4627,6 +4632,27 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, ...@@ -4627,6 +4632,27 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
continue; continue;
*prog_type = section_names[i].prog_type; *prog_type = section_names[i].prog_type;
*expected_attach_type = section_names[i].expected_attach_type; *expected_attach_type = section_names[i].expected_attach_type;
if (section_names[i].is_attach_btf) {
struct btf *btf = bpf_core_find_kernel_btf();
char raw_tp_btf_name[128] = "btf_trace_";
char *dst = raw_tp_btf_name + sizeof("btf_trace_") - 1;
int ret;
if (IS_ERR(btf)) {
pr_warning("vmlinux BTF is not found\n");
return -EINVAL;
}
/* prepend "btf_trace_" prefix per kernel convention */
strncat(dst, name + section_names[i].len,
sizeof(raw_tp_btf_name) - (dst - raw_tp_btf_name));
ret = btf__find_by_name(btf, raw_tp_btf_name);
btf__free(btf);
if (ret <= 0) {
pr_warning("%s is not found in vmlinux BTF\n", dst);
return -EINVAL;
}
*expected_attach_type = ret;
}
return 0; return 0;
} }
pr_warning("failed to guess program type based on ELF section name '%s'\n", name); pr_warning("failed to guess program type based on ELF section name '%s'\n", name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment