Adding support to load and attach ftrace probe.

Adding new section type 'fentry.ftrace', that identifies
ftrace probe and assigns BPF_TRACE_FTRACE_ENTRY to prog's
expected_attach_type.

The attach function creates bpf_functions object and
makes an ftrace link with the program.

Signed-off-by: Jiri Olsa <jo...@kernel.org>
---
 tools/lib/bpf/bpf.c      | 12 +++++++
 tools/lib/bpf/bpf.h      |  5 ++-
 tools/lib/bpf/libbpf.c   | 74 ++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.map |  1 +
 4 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index bba48ff4c5c0..b3195ac3e32e 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -643,6 +643,7 @@ int bpf_link_create(int prog_fd, int target_fd,
        attr.link_create.target_fd = target_fd;
        attr.link_create.attach_type = attach_type;
        attr.link_create.flags = OPTS_GET(opts, flags, 0);
+       attr.link_create.funcs_fd = OPTS_GET(opts, funcs_fd, 0);
 
        if (iter_info_len) {
                attr.link_create.iter_info =
@@ -971,3 +972,14 @@ int bpf_prog_bind_map(int prog_fd, int map_fd,
 
        return sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr));
 }
+
+int bpf_functions_add(int fd, int btf_id)
+{
+       union bpf_attr attr;
+
+       memset(&attr, 0, sizeof(attr));
+       attr.functions_add.fd = fd;
+       attr.functions_add.btf_id = btf_id;
+
+       return sys_bpf(BPF_FUNCTIONS_ADD, &attr, sizeof(attr));
+}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 875dde20d56e..f677fe06262b 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -175,8 +175,9 @@ struct bpf_link_create_opts {
        union bpf_iter_link_info *iter_info;
        __u32 iter_info_len;
        __u32 target_btf_id;
+       __u32 funcs_fd;
 };
-#define bpf_link_create_opts__last_field target_btf_id
+#define bpf_link_create_opts__last_field funcs_fd
 
 LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
                               enum bpf_attach_type attach_type,
@@ -278,6 +279,8 @@ struct bpf_test_run_opts {
 LIBBPF_API int bpf_prog_test_run_opts(int prog_fd,
                                      struct bpf_test_run_opts *opts);
 
+LIBBPF_API int bpf_functions_add(int fd, int btf_id);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index ed5586cce227..b3cb43990524 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -8838,6 +8838,10 @@ static const struct bpf_sec_def section_defs[] = {
                .expected_attach_type = BPF_TRACE_ITER,
                .is_attach_btf = true,
                .attach_fn = attach_iter),
+       SEC_DEF("fentry.ftrace/", TRACING,
+               .expected_attach_type = BPF_TRACE_FTRACE_ENTRY,
+               .is_attach_btf = true,
+               .attach_fn = attach_trace),
        BPF_EAPROG_SEC("xdp_devmap/",           BPF_PROG_TYPE_XDP,
                                                BPF_XDP_DEVMAP),
        BPF_EAPROG_SEC("xdp_cpumap/",           BPF_PROG_TYPE_XDP,
@@ -9125,6 +9129,7 @@ static int bpf_object__collect_st_ops_relos(struct 
bpf_object *obj,
 #define BTF_TRACE_PREFIX "btf_trace_"
 #define BTF_LSM_PREFIX "bpf_lsm_"
 #define BTF_ITER_PREFIX "bpf_iter_"
+#define BTF_FTRACE_PROBE "bpf_ftrace_probe"
 #define BTF_MAX_NAME_SIZE 128
 
 static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
@@ -9158,6 +9163,9 @@ static inline int find_attach_btf_id(struct btf *btf, 
const char *name,
        else if (attach_type == BPF_TRACE_ITER)
                err = find_btf_by_prefix_kind(btf, BTF_ITER_PREFIX, name,
                                              BTF_KIND_FUNC);
+       else if (attach_type == BPF_TRACE_FTRACE_ENTRY)
+               err = btf__find_by_name_kind(btf, BTF_FTRACE_PROBE,
+                                            BTF_KIND_FUNC);
        else
                err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
 
@@ -10191,8 +10199,74 @@ static struct bpf_link 
*bpf_program__attach_btf_id(struct bpf_program *prog)
        return (struct bpf_link *)link;
 }
 
+static struct bpf_link *bpf_program__attach_ftrace(struct bpf_program *prog)
+{
+       char *pattern = prog->sec_name + prog->sec_def->len;
+       DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
+       int prog_fd, link_fd, cnt, err, i;
+       enum bpf_attach_type attach_type;
+       struct bpf_link *link = NULL;
+       __s32 *ids = NULL;
+       int funcs_fd = -1;
+
+       prog_fd = bpf_program__fd(prog);
+       if (prog_fd < 0) {
+               pr_warn("prog '%s': can't attach before loaded\n", prog->name);
+               return ERR_PTR(-EINVAL);
+       }
+
+       err = bpf_object__load_vmlinux_btf(prog->obj, true);
+       if (err)
+               return ERR_PTR(err);
+
+       cnt = btf__find_by_pattern_kind(prog->obj->btf_vmlinux, pattern,
+                                       BTF_KIND_FUNC, &ids);
+       if (cnt <= 0)
+               return ERR_PTR(-EINVAL);
+
+       for (i = 0; i < cnt; i++) {
+               err = bpf_functions_add(funcs_fd, ids[i]);
+               if (err < 0) {
+                       pr_warn("prog '%s': can't attach function BTF ID %d\n",
+                               prog->name, ids[i]);
+                       goto out_err;
+               }
+               if (funcs_fd == -1)
+                       funcs_fd = err;
+       }
+
+       link = calloc(1, sizeof(*link));
+       if (!link) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+       link->detach = &bpf_link__detach_fd;
+
+       opts.funcs_fd = funcs_fd;
+
+       attach_type = bpf_program__get_expected_attach_type(prog);
+       link_fd = bpf_link_create(prog_fd, 0, attach_type, &opts);
+       if (link_fd < 0) {
+               err = -errno;
+               goto out_err;
+       }
+       link->fd = link_fd;
+       free(ids);
+       return link;
+
+out_err:
+       if (funcs_fd != -1)
+               close(funcs_fd);
+       free(link);
+       free(ids);
+       return ERR_PTR(err);
+}
+
 struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
 {
+       if (prog->expected_attach_type == BPF_TRACE_FTRACE_ENTRY)
+               return bpf_program__attach_ftrace(prog);
+
        return bpf_program__attach_btf_id(prog);
 }
 
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index b9b29baf1df8..69cbe54125e3 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -355,6 +355,7 @@ LIBBPF_0.4.0 {
        global:
                btf__add_float;
                btf__add_type;
+               bpf_functions_add;
                bpf_linker__add_file;
                bpf_linker__finalize;
                bpf_linker__free;
-- 
2.30.2

Reply via email to