[PATCH v9 bpf-next 08/10] bpftool: add BTF dump "format meta" to dump header/metadata

Alan Maguire <[email protected]>
Newsgroups org.kernel.vger.dwarves,org.kernel.vger.bpf
Message-ID <[email protected]>
Provide a way to dump BTF metadata info via bpftool; this
consists of BTF size, header fields and layout info
(if available); for example

$ bpftool btf dump file vmlinux format meta
size 6516862
magic 0xeb9f
version 1
flags 0x0
hdr_len 32
type_len 3929096
type_off 0
str_len 2587654
str_off 3929176
layout_len 80
layout_off 3929096
kind 0    UNKNOWN    info_sz 0    elem_sz 0    flags 0
kind 1    INT        info_sz 4    elem_sz 0    flags 0
kind 2    PTR        info_sz 0    elem_sz 0    flags 0
kind 3    ARRAY      info_sz 12   elem_sz 0    flags 0
kind 4    STRUCT     info_sz 0    elem_sz 12   flags 0
kind 5    UNION      info_sz 0    elem_sz 12   flags 0
kind 6    ENUM       info_sz 0    elem_sz 8    flags 0
kind 7    FWD        info_sz 0    elem_sz 0    flags 0
kind 8    TYPEDEF    info_sz 0    elem_sz 0    flags 0
kind 9    VOLATILE   info_sz 0    elem_sz 0    flags 0
kind 10   CONST      info_sz 0    elem_sz 0    flags 0
kind 11   RESTRICT   info_sz 0    elem_sz 0    flags 0
kind 12   FUNC       info_sz 0    elem_sz 0    flags 0
kind 13   FUNC_PROTO info_sz 0    elem_sz 8    flags 0
kind 14   VAR        info_sz 4    elem_sz 0    flags 0
kind 15   DATASEC    info_sz 0    elem_sz 12   flags 0
kind 16   FLOAT      info_sz 0    elem_sz 0    flags 0
kind 17   DECL_TAG   info_sz 4    elem_sz 0    flags 0
kind 18   TYPE_TAG   info_sz 0    elem_sz 0    flags 0
kind 19   ENUM64     info_sz 0    elem_sz 12   flags 0

JSON output is also supported:

$ bpftool -p btf dump file /var/tmp/vmlinux.kind_layout format meta
{
    "size": 6516862,
    "header": {
        "magic": 60319,
        "version": 1,
        "flags": 0,
        "hdr_len": 32,
        "type_len": 3929096,
        "type_off": 0,
        "str_len": 2587654,
        "str_off": 3929176,
        "layout_len": 80,
        "layout_offset": 3929096
    },
    "layouts": [{
            "kind": 0,
            "name": "UNKNOWN",
            "info_sz": 0,
            "elem_sz": 0,
            "flags": 0
        },{
            "kind": 1,
            "name": "INT",
            "info_sz": 4,
            "elem_sz": 0,
            "flags": 0
        },{
            "kind": 2,
            "name": "PTR",
            "info_sz": 0,
            "elem_sz": 0,
            "flags": 0
        },{
...

Signed-off-by: Alan Maguire <[email protected]>
---
 tools/bpf/bpftool/bash-completion/bpftool |  2 +-
 tools/bpf/bpftool/btf.c                   | 94 ++++++++++++++++++++++-
 2 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index a28f0cc522e4..d49d6a70cb74 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -950,7 +950,7 @@ _bpftool()
                             return 0
                             ;;
                         format)
-                            COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
+                            COMPREPLY=( $( compgen -W "c raw meta" -- "$cur" ) )
                             ;;
                         root_id)
                             return 0;
diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 946612029dee..02f6ca4b3a51 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -835,6 +835,90 @@ static int dump_btf_c(const struct btf *btf,
 	return err;
 }
 
+static int dump_btf_meta(const struct btf *btf)
+{
+	__u32 data_sz, i, nr_kinds = 0;
+	const struct btf_header *hdr;
+	const struct btf_layout *l;
+	const void *data;
+
+	data = btf__raw_data(btf, &data_sz);
+	if (!data)
+		return -ENOMEM;
+	hdr = data;
+	if (json_output) {
+		jsonw_start_object(json_wtr);		/* metadata object */
+		jsonw_uint_field(json_wtr, "size", data_sz);
+		jsonw_name(json_wtr, "header");
+		jsonw_start_object(json_wtr);		/* header object */
+		jsonw_uint_field(json_wtr, "magic", hdr->magic);
+		jsonw_uint_field(json_wtr, "version", hdr->version);
+		jsonw_uint_field(json_wtr, "flags", hdr->flags);
+		jsonw_uint_field(json_wtr, "hdr_len", hdr->hdr_len);
+		jsonw_uint_field(json_wtr, "type_len", hdr->type_len);
+		jsonw_uint_field(json_wtr, "type_off", hdr->type_off);
+		jsonw_uint_field(json_wtr, "str_len", hdr->str_len);
+		jsonw_uint_field(json_wtr, "str_off", hdr->str_off);
+	} else {
+		printf("size %-10u\n", data_sz);
+		printf("magic 0x%-10x\nversion %-10d\nflags 0x%-10x\nhdr_len %-10u\n",
+		       hdr->magic, hdr->version, hdr->flags, hdr->hdr_len);
+		printf("type_len %-10u\ntype_off %-10u\n", hdr->type_len, hdr->type_off);
+		printf("str_len %-10u\nstr_off %-10u\n", hdr->str_len, hdr->str_off);
+	}
+
+	if (hdr->hdr_len < sizeof(struct btf_header) || data_sz <= hdr->hdr_len) {
+		if (json_output) {
+			jsonw_end_object(json_wtr);	/* end header object */
+			jsonw_end_object(json_wtr);	/* end metadata object */
+		}
+		return 0;
+	}
+
+	data_sz -= hdr->hdr_len;
+
+	if (hdr->layout_len > 0 && hdr->layout_off > 0) {
+		if ((long long)hdr->layout_off + hdr->layout_len <= data_sz) {
+			l = (void *)hdr + hdr->hdr_len + hdr->layout_off;
+			nr_kinds = hdr->layout_len / sizeof(*l);
+		}
+	}
+	if (json_output) {
+		jsonw_uint_field(json_wtr, "layout_len", hdr->layout_len);
+		jsonw_uint_field(json_wtr, "layout_offset", hdr->layout_off);
+		jsonw_end_object(json_wtr);		/* end header object */
+
+		if (nr_kinds > 0) {
+			jsonw_name(json_wtr, "layouts");
+			jsonw_start_array(json_wtr);
+			for (i = 0; i < nr_kinds; i++) {
+				jsonw_start_object(json_wtr);
+				jsonw_uint_field(json_wtr, "kind", i);
+				if (i < NR_BTF_KINDS)
+					jsonw_string_field(json_wtr, "name", btf_kind_str[i]);
+				else
+					jsonw_null_field(json_wtr, "name");
+				jsonw_uint_field(json_wtr, "info_sz", l[i].info_sz);
+				jsonw_uint_field(json_wtr, "elem_sz", l[i].elem_sz);
+				jsonw_uint_field(json_wtr, "flags", l[i].flags);
+				jsonw_end_object(json_wtr);
+			}
+			jsonw_end_array(json_wtr);
+		}
+		jsonw_end_object(json_wtr);		/* end metadata object */
+	} else {
+		printf("layout_len %-10u\nlayout_off %-10u\n",
+		       hdr->layout_len, hdr->layout_off);
+		for (i = 0; i < nr_kinds; i++) {
+			printf("kind %-4u %-10s info_sz %-4d elem_sz %-4d flags %-4d\n",
+			       i, i < NR_BTF_KINDS ? btf_kind_str[i] : "?",
+			       l[i].info_sz, l[i].elem_sz, l[i].flags);
+		}
+	}
+
+	return 0;
+}
+
 static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
 
 static struct btf *get_vmlinux_btf_from_sysfs(void)
@@ -880,7 +964,7 @@ static bool btf_is_kernel_module(__u32 btf_id)
 
 static int do_dump(int argc, char **argv)
 {
-	bool dump_c = false, sort_dump_c = true;
+	bool dump_c = false, sort_dump_c = true, dump_meta = false;
 	struct btf *btf = NULL, *base = NULL;
 	__u32 root_type_ids[MAX_ROOT_IDS];
 	bool have_id_filtering;
@@ -990,10 +1074,12 @@ static int do_dump(int argc, char **argv)
 			}
 			if (strcmp(*argv, "c") == 0) {
 				dump_c = true;
+			} else if (is_prefix(*argv, "meta")) {
+				dump_meta = true;
 			} else if (strcmp(*argv, "raw") == 0) {
 				dump_c = false;
 			} else {
-				p_err("unrecognized format specifier: '%s', possible values: raw, c",
+				p_err("unrecognized format specifier: '%s', possible values: raw, c, meta",
 				      *argv);
 				err = -EINVAL;
 				goto done;
@@ -1072,6 +1158,8 @@ static int do_dump(int argc, char **argv)
 			goto done;
 		}
 		err = dump_btf_c(btf, root_type_ids, root_type_cnt, sort_dump_c);
+	} else if (dump_meta) {
+		err = dump_btf_meta(btf);
 	} else {
 		err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
 	}
@@ -1446,7 +1534,7 @@ static int do_help(int argc, char **argv)
 		"       %1$s %2$s help\n"
 		"\n"
 		"       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
-		"       FORMAT  := { raw | c [unsorted] }\n"
+		"       FORMAT  := { raw | c [unsorted] | meta }\n"
 		"       " HELP_SPEC_MAP "\n"
 		"       " HELP_SPEC_PROGRAM "\n"
 		"       " HELP_SPEC_OPTIONS " |\n"
-- 
2.39.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.