This patch collects all programs in an object file and links them into
a list for further processing. 'struct bpf_perf_prog' is used for
representing each eBPF program. 'bpf_prog' should be a better name, but
it has been used by linux/filter.h. Although it is a kernel space name,
I still prefer to call it 'bpf_perf_prog' to prevent possible
confusion.

Signed-off-by: Wang Nan <wangn...@huawei.com>
---
 tools/perf/util/bpf-loader.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h | 14 +++++++
 2 files changed, 105 insertions(+)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index b9c701a..bbebaf1 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -59,11 +59,20 @@ static void bpf_obj_clear_elf(struct bpf_obj *obj)
        }
 }
 
+static void bpf_perf_prog_free(struct bpf_perf_prog *prog);
+
 static void bpf_obj_close(struct bpf_obj *obj)
 {
+       struct bpf_perf_prog *prog, *tmp;
+
        if (!obj)
                return;
 
+       list_for_each_entry_safe(prog, tmp, &obj->progs_list, list) {
+               list_del(&prog->list);
+               bpf_perf_prog_free(prog);
+       }
+
        bpf_obj_clear_elf(obj);
 
        if (obj->path)
@@ -85,6 +94,7 @@ static struct bpf_obj *bpf_obj_alloc(const char *path)
 
        obj->needs_swap = false;
        obj->elf.fd = -1;
+       INIT_LIST_HEAD(&obj->progs_list);
        return obj;
 out:
        bpf_obj_close(obj);
@@ -255,6 +265,70 @@ static int bpf_obj_config_init(struct bpf_obj *obj, void 
*data,
        return 0;
 }
 
+static void
+bpf_perf_prog_free(struct bpf_perf_prog *prog)
+{
+       if (!prog)
+               return;
+
+       if (prog->name)
+               free(prog->name);
+       if (prog->insns)
+               free(prog->insns);
+       free(prog);
+}
+
+static struct bpf_perf_prog *
+bpf_perf_prog_alloc(struct bpf_obj *obj __maybe_unused,
+                   void *data, size_t size,
+                   char *name, int idx)
+{
+       struct bpf_perf_prog *prog;
+
+       if (size < sizeof(struct bpf_insn)) {
+               pr_err("bpf: corrupted section %s\n", name);
+               return NULL;
+       }
+       
+       prog = calloc(1, sizeof(struct bpf_perf_prog));
+       if (!prog) {
+               pr_err("bpf: failed to alloc prog\n");
+               return NULL;
+       }
+
+       /*
+        * Name of a program could be:
+        * "k(ret)probe/[a-zA-Z_][a-zA-Z_0-9]"
+        *
+        * or
+        *
+        * "[a-zA-Z_][a-zA-Z_0-9]"
+        *
+        * Will be parsed in other function. This function only saves
+        * the name.
+        */
+       prog->name = strdup(name);
+       if (!prog->name) {
+               pr_err("bpf: failed to alloc name for prog %s\n",
+                       name);
+               goto out;
+       }
+
+       prog->insns = malloc(size);
+       if (!prog->insns) {
+               pr_err("bpf: failed to alloc insns for %s\n", name);
+               goto out;
+       }
+       prog->insns_cnt = size / sizeof(struct bpf_insn);
+       memcpy(prog->insns, data,
+               prog->insns_cnt * sizeof(struct bpf_insn));
+       prog->idx = idx;
+       return prog;
+out:
+       bpf_perf_prog_free(prog);
+       return NULL;
+}
+
 static int bpf_obj_elf_collect(struct bpf_obj *obj)
 {
        Elf *elf = obj->elf.elf;
@@ -322,6 +396,23 @@ static int bpf_obj_elf_collect(struct bpf_obj *obj)
                                err = -EEXIST;
                        } else
                                obj->elf.symbols = data;
+               } else if ((sh.sh_type == SHT_PROGBITS) &&
+                          (sh.sh_flags & SHF_EXECINSTR) &&
+                          (data->d_size > 0)) {
+                       struct bpf_perf_prog *prog;
+
+                       prog = bpf_perf_prog_alloc(obj, data->d_buf,
+                                                  data->d_size, name,
+                                                  idx);
+                       if (!prog) {
+                               pr_err("bpf: failed to alloc "
+                                      "program %s (%s)", name, obj->path);
+                               err = -ENOMEM;
+                       } else {
+                               pr_debug("bpf: found program %s\n",
+                                               prog->name);
+                               list_add(&prog->list, &obj->progs_list);
+                       }
                }
                if (err)
                        goto out;
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index f0b573c..f9cb46b 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -19,9 +19,23 @@
 int bpf__load(const char *path);
 int bpf__run(void);
 
+struct bpf_perf_prog {
+       struct list_head list;
+
+       /* Index in elf obj file, for relocation use. */
+       int idx;
+       char *name;
+       struct bpf_insn *insns;
+       size_t insns_cnt;
+};
+
 struct bpf_obj {
        /* All bpf objs should be linked together. */
        struct list_head list;
+
+       /* All eBPF programs are linked at this list */
+       struct list_head progs_list;
+
        char *path;
        bool needs_swap;
        char license[64];
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to