bpf tools: Collect eBPF programs from their own sections
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. bpf_object__add_program() creates a new 'struct bpf_program' object. It first init a variable in stack using bpf_program__init(), then if success, enlarges obj->programs array and copy the new object in. Signed-off-by: Wang Nan <wangnan0@huawei.com> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: David Ahern <dsahern@gmail.com> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kaixu Xia <xiakaixu@huawei.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1435716878-189507-13-git-send-email-wangnan0@huawei.com [ Made bpf_object__add_program() propagate the error (-EINVAL or -ENOMEM) ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
bec7d68cb5
commit
a5b8bd47dc
|
@ -78,12 +78,27 @@ void libbpf_set_print(libbpf_print_fn_t warn,
|
|||
# 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 license[64];
|
||||
u32 kern_version;
|
||||
void *maps_buf;
|
||||
size_t maps_buf_sz;
|
||||
|
||||
struct bpf_program *programs;
|
||||
size_t nr_programs;
|
||||
|
||||
/*
|
||||
* Information when doing elf related work. Only valid if fd
|
||||
* is valid.
|
||||
|
@ -100,6 +115,85 @@ struct bpf_object {
|
|||
};
|
||||
#define obj_elf_valid(o) ((o)->efile.elf)
|
||||
|
||||
static void bpf_program__exit(struct bpf_program *prog)
|
||||
{
|
||||
if (!prog)
|
||||
return;
|
||||
|
||||
zfree(&prog->section_name);
|
||||
zfree(&prog->insns);
|
||||
prog->insns_cnt = 0;
|
||||
prog->idx = -1;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_program__init(void *data, size_t size, char *name, int idx,
|
||||
struct bpf_program *prog)
|
||||
{
|
||||
if (size < sizeof(struct bpf_insn)) {
|
||||
pr_warning("corrupted section '%s'\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bzero(prog, sizeof(*prog));
|
||||
|
||||
prog->section_name = strdup(name);
|
||||
if (!prog->section_name) {
|
||||
pr_warning("failed to alloc name for prog %s\n",
|
||||
name);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->insns = malloc(size);
|
||||
if (!prog->insns) {
|
||||
pr_warning("failed to alloc insns for %s\n", name);
|
||||
goto errout;
|
||||
}
|
||||
prog->insns_cnt = size / sizeof(struct bpf_insn);
|
||||
memcpy(prog->insns, data,
|
||||
prog->insns_cnt * sizeof(struct bpf_insn));
|
||||
prog->idx = idx;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
bpf_program__exit(prog);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
|
||||
char *name, int idx)
|
||||
{
|
||||
struct bpf_program prog, *progs;
|
||||
int nr_progs, err;
|
||||
|
||||
err = bpf_program__init(data, size, name, idx, &prog);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
progs = obj->programs;
|
||||
nr_progs = obj->nr_programs;
|
||||
|
||||
progs = realloc(progs, sizeof(progs[0]) * (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);
|
||||
bpf_program__exit(&prog);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pr_debug("found program %s\n", prog.section_name);
|
||||
obj->programs = progs;
|
||||
obj->nr_programs = nr_progs + 1;
|
||||
progs[nr_progs] = prog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_object *bpf_object__new(const char *path,
|
||||
void *obj_buf,
|
||||
size_t obj_buf_sz)
|
||||
|
@ -342,6 +436,17 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|||
err = -EEXIST;
|
||||
} else
|
||||
obj->efile.symbols = data;
|
||||
} else if ((sh.sh_type == SHT_PROGBITS) &&
|
||||
(sh.sh_flags & SHF_EXECINSTR) &&
|
||||
(data->d_size > 0)) {
|
||||
err = bpf_object__add_program(obj, data->d_buf,
|
||||
data->d_size, name, idx);
|
||||
if (err) {
|
||||
char errmsg[128];
|
||||
strerror_r(-err, errmsg, sizeof(errmsg));
|
||||
pr_warning("failed to alloc program %s (%s): %s",
|
||||
name, obj->path, errmsg);
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -415,11 +520,20 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
|||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
bpf_object__elf_finish(obj);
|
||||
|
||||
zfree(&obj->maps_buf);
|
||||
|
||||
if (obj->programs && obj->nr_programs) {
|
||||
for (i = 0; i < obj->nr_programs; i++)
|
||||
bpf_program__exit(&obj->programs[i]);
|
||||
}
|
||||
zfree(&obj->programs);
|
||||
|
||||
free(obj);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue