summaryrefslogtreecommitdiff
path: root/tools/bpf/bpftool/btf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bpf/bpftool/btf.c')
-rw-r--r--tools/bpf/bpftool/btf.c166
1 files changed, 68 insertions, 98 deletions
diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 58a2cd002a4b..1b8ec91899e6 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -8,8 +8,8 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <gelf.h>
#include <bpf.h>
+#include <libbpf.h>
#include <linux/btf.h>
#include "btf.h"
@@ -208,8 +208,8 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
break;
}
case BTF_KIND_FWD: {
- const char *fwd_kind = BTF_INFO_KIND(t->info) ? "union"
- : "struct";
+ const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
+ : "struct";
if (json_output)
jsonw_string_field(w, "fwd_kind", fwd_kind);
@@ -340,109 +340,40 @@ static int dump_btf_raw(const struct btf *btf,
return 0;
}
-static bool check_btf_endianness(GElf_Ehdr *ehdr)
+static void __printf(2, 0) btf_dump_printf(void *ctx,
+ const char *fmt, va_list args)
{
- static unsigned int const endian = 1;
-
- switch (ehdr->e_ident[EI_DATA]) {
- case ELFDATA2LSB:
- return *(unsigned char const *)&endian == 1;
- case ELFDATA2MSB:
- return *(unsigned char const *)&endian == 0;
- default:
- return 0;
- }
+ vfprintf(stdout, fmt, args);
}
-static int btf_load_from_elf(const char *path, struct btf **btf)
+static int dump_btf_c(const struct btf *btf,
+ __u32 *root_type_ids, int root_type_cnt)
{
- int err = -1, fd = -1, idx = 0;
- Elf_Data *btf_data = NULL;
- Elf_Scn *scn = NULL;
- Elf *elf = NULL;
- GElf_Ehdr ehdr;
-
- if (elf_version(EV_CURRENT) == EV_NONE) {
- p_err("failed to init libelf for %s", path);
- return -1;
- }
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- p_err("failed to open %s: %s", path, strerror(errno));
- return -1;
- }
-
- elf = elf_begin(fd, ELF_C_READ, NULL);
- if (!elf) {
- p_err("failed to open %s as ELF file", path);
- goto done;
- }
- if (!gelf_getehdr(elf, &ehdr)) {
- p_err("failed to get EHDR from %s", path);
- goto done;
- }
- if (!check_btf_endianness(&ehdr)) {
- p_err("non-native ELF endianness is not supported");
- goto done;
- }
- if (!elf_rawdata(elf_getscn(elf, ehdr.e_shstrndx), NULL)) {
- p_err("failed to get e_shstrndx from %s\n", path);
- goto done;
- }
+ struct btf_dump *d;
+ int err = 0, i;
- while ((scn = elf_nextscn(elf, scn)) != NULL) {
- GElf_Shdr sh;
- char *name;
+ d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
- idx++;
- if (gelf_getshdr(scn, &sh) != &sh) {
- p_err("failed to get section(%d) header from %s",
- idx, path);
- goto done;
- }
- name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
- if (!name) {
- p_err("failed to get section(%d) name from %s",
- idx, path);
- goto done;
- }
- if (strcmp(name, BTF_ELF_SEC) == 0) {
- btf_data = elf_getdata(scn, 0);
- if (!btf_data) {
- p_err("failed to get section(%d, %s) data from %s",
- idx, name, path);
+ if (root_type_cnt) {
+ for (i = 0; i < root_type_cnt; i++) {
+ err = btf_dump__dump_type(d, root_type_ids[i]);
+ if (err)
goto done;
- }
- break;
}
- }
-
- if (!btf_data) {
- p_err("%s ELF section not found in %s", BTF_ELF_SEC, path);
- goto done;
- }
+ } else {
+ int cnt = btf__get_nr_types(btf);
- *btf = btf__new(btf_data->d_buf, btf_data->d_size);
- if (IS_ERR(*btf)) {
- err = PTR_ERR(*btf);
- *btf = NULL;
- p_err("failed to load BTF data from %s: %s",
- path, strerror(err));
- goto done;
+ for (i = 1; i <= cnt; i++) {
+ err = btf_dump__dump_type(d, i);
+ if (err)
+ goto done;
+ }
}
- err = 0;
done:
- if (err) {
- if (*btf) {
- btf__free(*btf);
- *btf = NULL;
- }
- }
- if (elf)
- elf_end(elf);
- close(fd);
+ btf_dump__free(d);
return err;
}
@@ -451,6 +382,7 @@ static int do_dump(int argc, char **argv)
struct btf *btf = NULL;
__u32 root_type_ids[2];
int root_type_cnt = 0;
+ bool dump_c = false;
__u32 btf_id = -1;
const char *src;
int fd = -1;
@@ -522,9 +454,14 @@ static int do_dump(int argc, char **argv)
}
NEXT_ARG();
} else if (is_prefix(src, "file")) {
- err = btf_load_from_elf(*argv, &btf);
- if (err)
+ btf = btf__parse_elf(*argv, NULL);
+ if (IS_ERR(btf)) {
+ err = PTR_ERR(btf);
+ btf = NULL;
+ p_err("failed to load BTF from %s: %s",
+ *argv, strerror(err));
goto done;
+ }
NEXT_ARG();
} else {
err = -1;
@@ -532,6 +469,29 @@ static int do_dump(int argc, char **argv)
goto done;
}
+ while (argc) {
+ if (is_prefix(*argv, "format")) {
+ NEXT_ARG();
+ if (argc < 1) {
+ p_err("expecting value for 'format' option\n");
+ goto done;
+ }
+ if (strcmp(*argv, "c") == 0) {
+ dump_c = true;
+ } else if (strcmp(*argv, "raw") == 0) {
+ dump_c = false;
+ } else {
+ p_err("unrecognized format specifier: '%s', possible values: raw, c",
+ *argv);
+ goto done;
+ }
+ NEXT_ARG();
+ } else {
+ p_err("unrecognized option: '%s'", *argv);
+ goto done;
+ }
+ }
+
if (!btf) {
err = btf__get_from_id(btf_id, &btf);
if (err) {
@@ -545,7 +505,16 @@ static int do_dump(int argc, char **argv)
}
}
- dump_btf_raw(btf, root_type_ids, root_type_cnt);
+ if (dump_c) {
+ if (json_output) {
+ p_err("JSON output for C-syntax dump is not supported");
+ err = -ENOTSUP;
+ goto done;
+ }
+ err = dump_btf_c(btf, root_type_ids, root_type_cnt);
+ } else {
+ err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
+ }
done:
close(fd);
@@ -561,10 +530,11 @@ static int do_help(int argc, char **argv)
}
fprintf(stderr,
- "Usage: %s btf dump BTF_SRC\n"
+ "Usage: %s btf dump BTF_SRC [format FORMAT]\n"
" %s btf help\n"
"\n"
" BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
+ " FORMAT := { raw | c }\n"
" " HELP_SPEC_MAP "\n"
" " HELP_SPEC_PROGRAM "\n"
" " HELP_SPEC_OPTIONS "\n"