Options cover existing parsing scenarios (ELF, raw, retrieving .BTF.ext) and also allow specification of the ELF section name containing BTF. This will allow consumers to retrieve BTF from .BTF.base_ref sections (BTF_BASE_REF_ELF_SEC) also. Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> --- tools/lib/bpf/btf.c | 24 ++++++++++++++++++------ tools/lib/bpf/btf.h | 32 ++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.map | 1 + 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index f02477af3d79..d43c3eba27e0 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1084,7 +1084,7 @@ struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf) return libbpf_ptr(btf_new(data, size, base_btf)); } -static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, +static struct btf *btf_parse_elf(const char *path, const char *btf_sec, struct btf *base_btf, struct btf_ext **btf_ext) { Elf_Data *btf_data = NULL, *btf_ext_data = NULL; @@ -1146,7 +1146,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, idx, path); goto done; } - if (strcmp(name, BTF_ELF_SEC) == 0) { + if (strcmp(name, btf_sec) == 0) { btf_data = elf_getdata(scn, 0); if (!btf_data) { pr_warn("failed to get section(%d, %s) data from %s\n", @@ -1166,7 +1166,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, } if (!btf_data) { - pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path); + pr_warn("failed to find '%s' ELF section in %s\n", btf_sec, path); err = -ENODATA; goto done; } @@ -1212,12 +1212,12 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext) { - return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext)); + return libbpf_ptr(btf_parse_elf(path, BTF_ELF_SEC, NULL, btf_ext)); } struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf) { - return libbpf_ptr(btf_parse_elf(path, base_btf, NULL)); + return libbpf_ptr(btf_parse_elf(path, BTF_ELF_SEC, base_btf, NULL)); } static struct btf *btf_parse_raw(const char *path, struct btf *base_btf) @@ -1293,6 +1293,18 @@ struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf) return libbpf_ptr(btf_parse_raw(path, base_btf)); } +struct btf *btf__parse_opts(const char *path, struct btf_parse_opts *opts) +{ + if (!OPTS_VALID(opts, btf_parse_opts)) + return libbpf_err_ptr(-EINVAL); + if (opts && !opts->btf_sec) + return btf__parse_raw_split(path, opts ? opts->base_btf : NULL); + return libbpf_ptr(btf_parse_elf(path, + opts ? opts->btf_sec : BTF_ELF_SEC, + opts ? opts->base_btf : NULL, + opts ? &opts->btf_ext : NULL)); +} + static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext) { struct btf *btf; @@ -1307,7 +1319,7 @@ static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ return btf; if (err != -EPROTO) return ERR_PTR(err); - return btf_parse_elf(path, base_btf, btf_ext); + return btf_parse_elf(path, BTF_ELF_SEC, base_btf, btf_ext); } struct btf *btf__parse(const char *path, struct btf_ext **btf_ext) diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index f2a853d6fa55..c63043520149 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -18,6 +18,7 @@ extern "C" { #define BTF_ELF_SEC ".BTF" #define BTF_EXT_ELF_SEC ".BTF.ext" +#define BTF_BASE_REF_ELF_SEC ".BTF.base_ref" #define MAPS_ELF_SEC ".maps" struct btf; @@ -129,6 +130,37 @@ LIBBPF_API struct btf *btf__parse_elf_split(const char *path, struct btf *base_b LIBBPF_API struct btf *btf__parse_raw(const char *path); LIBBPF_API struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf); +struct btf_parse_opts { + size_t sz; + /* use base BTF to parse split BTF */ + struct btf *base_btf; + /* retrieve optional .BTF.ext info */ + struct btf_ext *btf_ext; + /* BTF section name */ + const char *btf_sec; + size_t:0; +}; + +#define btf_parse_opts__last_field btf_sec + +/* @brief **btf__parse_opts()** parses BTF information from either a + * raw BTF file (*btf_sec* is NULL) or from the specified BTF section, + * also retrieving .BTF.ext info if *btf_ext* is non-NULL. If + * *base_btf* is specified, use it to parse split BTF from the + * specified location. + * + * @return new BTF object instance which has to be eventually freed with + * **btf__free()** + * + * On error, error-code-encoded-as-pointer is returned, not a NULL. To extract + * error code from such a pointer `libbpf_get_error()` should be used. If + * `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is + * returned on error instead. In both cases thread-local `errno` variable is + * always set to error code as well. + */ + +LIBBPF_API struct btf *btf__parse_opts(const char *path, struct btf_parse_opts *opts); + LIBBPF_API struct btf *btf__load_vmlinux_btf(void); LIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 3d53b1781af1..e9a7cb9c3c5b 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -415,5 +415,6 @@ LIBBPF_1.4.0 { bpf_token_create; btf__new_split; btf__new_split_base_ref; + btf__parse_opts; btf_ext__raw_data; } LIBBPF_1.3.0; -- 2.39.3