Commit a5b8bd47 authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo

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: default avatarWang Nan <wangnan0@huawei.com>
Acked-by: default avatarAlexei 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent bec7d68c
...@@ -78,12 +78,27 @@ void libbpf_set_print(libbpf_print_fn_t warn, ...@@ -78,12 +78,27 @@ void libbpf_set_print(libbpf_print_fn_t warn,
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
#endif #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 { struct bpf_object {
char license[64]; char license[64];
u32 kern_version; u32 kern_version;
void *maps_buf; void *maps_buf;
size_t maps_buf_sz; size_t maps_buf_sz;
struct bpf_program *programs;
size_t nr_programs;
/* /*
* Information when doing elf related work. Only valid if fd * Information when doing elf related work. Only valid if fd
* is valid. * is valid.
...@@ -100,6 +115,85 @@ struct bpf_object { ...@@ -100,6 +115,85 @@ struct bpf_object {
}; };
#define obj_elf_valid(o) ((o)->efile.elf) #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, static struct bpf_object *bpf_object__new(const char *path,
void *obj_buf, void *obj_buf,
size_t obj_buf_sz) size_t obj_buf_sz)
...@@ -342,6 +436,17 @@ static int bpf_object__elf_collect(struct bpf_object *obj) ...@@ -342,6 +436,17 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
err = -EEXIST; err = -EEXIST;
} else } else
obj->efile.symbols = data; 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) if (err)
goto out; goto out;
...@@ -415,11 +520,20 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf, ...@@ -415,11 +520,20 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
void bpf_object__close(struct bpf_object *obj) void bpf_object__close(struct bpf_object *obj)
{ {
size_t i;
if (!obj) if (!obj)
return; return;
bpf_object__elf_finish(obj); bpf_object__elf_finish(obj);
zfree(&obj->maps_buf); 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); free(obj);
} }
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