mirror of
https://github.com/netdata/libbpf.git
synced 2026-04-04 15:49:06 +08:00
libbpf: Avoid joining .BTF.ext data with BPF programs by section name
Instead of using ELF section names as a joining key between .BTF.ext and
corresponding BPF programs, pre-build .BTF.ext section number to ELF
section index mapping during bpf_object__open() and use it later for
matching .BTF.ext information (func/line info or CO-RE relocations) to
their respective BPF programs and subprograms.
This simplifies corresponding joining logic and let's libbpf do
manipulations with BPF program's ELF sections like dropping leading '?'
character for non-autoloaded programs. Original joining logic in
bpf_object__relocate_core() (see relevant comment that's now removed)
was never elegant, so it's a good improvement regardless. But it also
avoids unnecessary internal assumptions about preserving original ELF
section name as BPF program's section name (which was broken when
SEC("?abc") support was added).
Fixes: a3820c481112 ("libbpf: Support opting out from autoloading BPF programs declaratively")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20220426004511.2691730-5-andrii@kernel.org
This commit is contained in:
committed by
Andrii Nakryiko
parent
eb22de1f7d
commit
f2e994e0b7
@@ -2626,6 +2626,7 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
|
|||||||
const struct btf_ext_info_sec *sinfo;
|
const struct btf_ext_info_sec *sinfo;
|
||||||
struct btf_ext_info *ext_info;
|
struct btf_ext_info *ext_info;
|
||||||
__u32 info_left, record_size;
|
__u32 info_left, record_size;
|
||||||
|
size_t sec_cnt = 0;
|
||||||
/* The start of the info sec (including the __u32 record_size). */
|
/* The start of the info sec (including the __u32 record_size). */
|
||||||
void *info;
|
void *info;
|
||||||
|
|
||||||
@@ -2689,8 +2690,7 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_record_size = sec_hdrlen +
|
total_record_size = sec_hdrlen + (__u64)num_records * record_size;
|
||||||
(__u64)num_records * record_size;
|
|
||||||
if (info_left < total_record_size) {
|
if (info_left < total_record_size) {
|
||||||
pr_debug("%s section has incorrect num_records in .BTF.ext\n",
|
pr_debug("%s section has incorrect num_records in .BTF.ext\n",
|
||||||
ext_sec->desc);
|
ext_sec->desc);
|
||||||
@@ -2699,12 +2699,14 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
|
|||||||
|
|
||||||
info_left -= total_record_size;
|
info_left -= total_record_size;
|
||||||
sinfo = (void *)sinfo + total_record_size;
|
sinfo = (void *)sinfo + total_record_size;
|
||||||
|
sec_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ext_info = ext_sec->ext_info;
|
ext_info = ext_sec->ext_info;
|
||||||
ext_info->len = ext_sec->len - sizeof(__u32);
|
ext_info->len = ext_sec->len - sizeof(__u32);
|
||||||
ext_info->rec_size = record_size;
|
ext_info->rec_size = record_size;
|
||||||
ext_info->info = info + sizeof(__u32);
|
ext_info->info = info + sizeof(__u32);
|
||||||
|
ext_info->sec_cnt = sec_cnt;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2788,6 +2790,9 @@ void btf_ext__free(struct btf_ext *btf_ext)
|
|||||||
{
|
{
|
||||||
if (IS_ERR_OR_NULL(btf_ext))
|
if (IS_ERR_OR_NULL(btf_ext))
|
||||||
return;
|
return;
|
||||||
|
free(btf_ext->func_info.sec_idxs);
|
||||||
|
free(btf_ext->line_info.sec_idxs);
|
||||||
|
free(btf_ext->core_relo_info.sec_idxs);
|
||||||
free(btf_ext->data);
|
free(btf_ext->data);
|
||||||
free(btf_ext);
|
free(btf_ext);
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/libbpf.c
78
src/libbpf.c
@@ -2765,6 +2765,9 @@ static int bpf_object__init_btf(struct bpf_object *obj,
|
|||||||
btf__set_pointer_size(obj->btf, 8);
|
btf__set_pointer_size(obj->btf, 8);
|
||||||
}
|
}
|
||||||
if (btf_ext_data) {
|
if (btf_ext_data) {
|
||||||
|
struct btf_ext_info *ext_segs[3];
|
||||||
|
int seg_num, sec_num;
|
||||||
|
|
||||||
if (!obj->btf) {
|
if (!obj->btf) {
|
||||||
pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n",
|
pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n",
|
||||||
BTF_EXT_ELF_SEC, BTF_ELF_SEC);
|
BTF_EXT_ELF_SEC, BTF_ELF_SEC);
|
||||||
@@ -2778,6 +2781,43 @@ static int bpf_object__init_btf(struct bpf_object *obj,
|
|||||||
obj->btf_ext = NULL;
|
obj->btf_ext = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* setup .BTF.ext to ELF section mapping */
|
||||||
|
ext_segs[0] = &obj->btf_ext->func_info;
|
||||||
|
ext_segs[1] = &obj->btf_ext->line_info;
|
||||||
|
ext_segs[2] = &obj->btf_ext->core_relo_info;
|
||||||
|
for (seg_num = 0; seg_num < ARRAY_SIZE(ext_segs); seg_num++) {
|
||||||
|
struct btf_ext_info *seg = ext_segs[seg_num];
|
||||||
|
const struct btf_ext_info_sec *sec;
|
||||||
|
const char *sec_name;
|
||||||
|
Elf_Scn *scn;
|
||||||
|
|
||||||
|
if (seg->sec_cnt == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
seg->sec_idxs = calloc(seg->sec_cnt, sizeof(*seg->sec_idxs));
|
||||||
|
if (!seg->sec_idxs) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec_num = 0;
|
||||||
|
for_each_btf_ext_sec(seg, sec) {
|
||||||
|
/* preventively increment index to avoid doing
|
||||||
|
* this before every continue below
|
||||||
|
*/
|
||||||
|
sec_num++;
|
||||||
|
|
||||||
|
sec_name = btf__name_by_offset(obj->btf, sec->sec_name_off);
|
||||||
|
if (str_is_empty(sec_name))
|
||||||
|
continue;
|
||||||
|
scn = elf_sec_by_name(obj, sec_name);
|
||||||
|
if (!scn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
seg->sec_idxs[sec_num - 1] = elf_ndxscn(scn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
if (err && libbpf_needs_btf(obj)) {
|
if (err && libbpf_needs_btf(obj)) {
|
||||||
@@ -5642,7 +5682,7 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path)
|
|||||||
struct bpf_program *prog;
|
struct bpf_program *prog;
|
||||||
struct bpf_insn *insn;
|
struct bpf_insn *insn;
|
||||||
const char *sec_name;
|
const char *sec_name;
|
||||||
int i, err = 0, insn_idx, sec_idx;
|
int i, err = 0, insn_idx, sec_idx, sec_num;
|
||||||
|
|
||||||
if (obj->btf_ext->core_relo_info.len == 0)
|
if (obj->btf_ext->core_relo_info.len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5663,33 +5703,18 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg = &obj->btf_ext->core_relo_info;
|
seg = &obj->btf_ext->core_relo_info;
|
||||||
|
sec_num = 0;
|
||||||
for_each_btf_ext_sec(seg, sec) {
|
for_each_btf_ext_sec(seg, sec) {
|
||||||
|
sec_idx = seg->sec_idxs[sec_num];
|
||||||
|
sec_num++;
|
||||||
|
|
||||||
sec_name = btf__name_by_offset(obj->btf, sec->sec_name_off);
|
sec_name = btf__name_by_offset(obj->btf, sec->sec_name_off);
|
||||||
if (str_is_empty(sec_name)) {
|
if (str_is_empty(sec_name)) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/* bpf_object's ELF is gone by now so it's not easy to find
|
|
||||||
* section index by section name, but we can find *any*
|
|
||||||
* bpf_program within desired section name and use it's
|
|
||||||
* prog->sec_idx to do a proper search by section index and
|
|
||||||
* instruction offset
|
|
||||||
*/
|
|
||||||
prog = NULL;
|
|
||||||
for (i = 0; i < obj->nr_programs; i++) {
|
|
||||||
if (strcmp(obj->programs[i].sec_name, sec_name) == 0) {
|
|
||||||
prog = &obj->programs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!prog) {
|
|
||||||
pr_warn("sec '%s': failed to find a BPF program\n", sec_name);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
sec_idx = prog->sec_idx;
|
|
||||||
|
|
||||||
pr_debug("sec '%s': found %d CO-RE relocations\n",
|
pr_debug("sec '%s': found %d CO-RE relocations\n", sec_name, sec->num_info);
|
||||||
sec_name, sec->num_info);
|
|
||||||
|
|
||||||
for_each_btf_ext_rec(seg, sec, i, rec) {
|
for_each_btf_ext_rec(seg, sec, i, rec) {
|
||||||
if (rec->insn_off % BPF_INSN_SZ)
|
if (rec->insn_off % BPF_INSN_SZ)
|
||||||
@@ -5873,14 +5898,13 @@ static int adjust_prog_btf_ext_info(const struct bpf_object *obj,
|
|||||||
void *rec, *rec_end, *new_prog_info;
|
void *rec, *rec_end, *new_prog_info;
|
||||||
const struct btf_ext_info_sec *sec;
|
const struct btf_ext_info_sec *sec;
|
||||||
size_t old_sz, new_sz;
|
size_t old_sz, new_sz;
|
||||||
const char *sec_name;
|
int i, sec_num, sec_idx, off_adj;
|
||||||
int i, off_adj;
|
|
||||||
|
|
||||||
|
sec_num = 0;
|
||||||
for_each_btf_ext_sec(ext_info, sec) {
|
for_each_btf_ext_sec(ext_info, sec) {
|
||||||
sec_name = btf__name_by_offset(obj->btf, sec->sec_name_off);
|
sec_idx = ext_info->sec_idxs[sec_num];
|
||||||
if (!sec_name)
|
sec_num++;
|
||||||
return -EINVAL;
|
if (prog->sec_idx != sec_idx)
|
||||||
if (strcmp(sec_name, prog->sec_name) != 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for_each_btf_ext_rec(ext_info, sec, i, rec) {
|
for_each_btf_ext_rec(ext_info, sec, i, rec) {
|
||||||
|
|||||||
@@ -376,6 +376,13 @@ struct btf_ext_info {
|
|||||||
void *info;
|
void *info;
|
||||||
__u32 rec_size;
|
__u32 rec_size;
|
||||||
__u32 len;
|
__u32 len;
|
||||||
|
/* optional (maintained internally by libbpf) mapping between .BTF.ext
|
||||||
|
* section and corresponding ELF section. This is used to join
|
||||||
|
* information like CO-RE relocation records with corresponding BPF
|
||||||
|
* programs defined in ELF sections
|
||||||
|
*/
|
||||||
|
__u32 *sec_idxs;
|
||||||
|
int sec_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define for_each_btf_ext_sec(seg, sec) \
|
#define for_each_btf_ext_sec(seg, sec) \
|
||||||
|
|||||||
Reference in New Issue
Block a user