This patch collects all programs in an object file into an array of 'struct bpf_program' for further processing. That structure is 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_program' to prevent possible confusion.
Signed-off-by: Wang Nan <wangn...@huawei.com> --- tools/lib/bpf/libbpf.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 2068f0b..18b221f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -77,6 +77,18 @@ void libbpf_set_print(int (*warn)(const char *format, ...), # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ #endif +/* + * bpf_prog should be a better name but it has been used in + * linux/filter.h. + */ +struct bpf_program { + /* Index in elf obj file, for relocation use. */ + int idx; + char *section_name; + struct bpf_insn *insns; + size_t insns_cnt; +}; + struct bpf_object { char *path; bool needs_swap; @@ -86,6 +98,9 @@ struct bpf_object { size_t maps_buf_sz; char *config_str; + struct bpf_program *programs; + size_t nr_programs; + /* * Information when doing elf related work. Only valid if fd * is valid. @@ -99,6 +114,79 @@ struct bpf_object { }; #define obj_elf_valid(o) ((o)->elf.fd >= 0) +static void bpf_clear_program(struct bpf_program *prog) +{ + if (!prog) + return; + if (prog->section_name) { + free(prog->section_name); + prog->section_name = NULL; + } + if (prog->insns) { + free(prog->insns); + prog->insns = NULL; + } + prog->insns_cnt = 0; + prog->idx = -1; +} + +static struct bpf_program * +bpf_program_alloc(struct bpf_object *obj, void *data, size_t size, + char *name, int idx) +{ + struct bpf_program *prog, *progs; + int nr_progs; + + if (size < sizeof(struct bpf_insn)) { + pr_warning("corrupted section '%s'\n", name); + return NULL; + } + + progs = obj->programs; + nr_progs = obj->nr_programs; + + progs = realloc(progs, sizeof(*prog) * (nr_progs + 1)); + if (!progs) { + /* + * In this case the original obj->programs + * is still valid, so don't need special treat for + * bpf_close_object(). + */ + pr_warning("failed to alloc a new program '%s'\n", + name); + return NULL; + } + + obj->programs = progs; + + prog = &progs[nr_progs]; + bzero(prog, sizeof(*prog)); + + obj->nr_programs = nr_progs + 1; + + prog->section_name = strdup(name); + if (!prog->section_name) { + pr_warning("failed to alloc name for prog %s\n", + name); + goto out; + } + + prog->insns = malloc(size); + if (!prog->insns) { + pr_warning("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_clear_program(prog); + return NULL; +} + static struct bpf_object *__bpf_obj_alloc(const char *path) { struct bpf_object *obj; @@ -380,6 +468,22 @@ static int bpf_obj_elf_collect(struct bpf_object *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_program *prog; + + prog = bpf_program_alloc(obj, data->d_buf, + data->d_size, name, + idx); + if (!prog) { + pr_warning("failed to alloc " + "program %s (%s)", name, + obj->path); + err = -ENOMEM; + } else + pr_debug("found program %s\n", + prog->section_name); } if (err) goto out; @@ -446,5 +550,12 @@ void bpf_close_object(struct bpf_object *obj) free(obj->maps_buf); if (obj->config_str) free(obj->config_str); + if (obj->programs) { + size_t i; + + for (i = 0; i < obj->nr_programs; i++) + bpf_clear_program(&obj->programs[i]); + free(obj->programs); + } free(obj); } -- 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/