Re: [PATCH v10 bpf-next 08/10] bpftool: add BTF dump "format meta" to dump header/metadata
Alexei Starovoitov <[email protected]>
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <CAADnVQLTwLSWaN8arz5NmCwqJxd3DPhtKn2is5AgrQ0AwYFi7A@mail.gmail.com> |
On Fri, Feb 27, 2026 at 2:05 AM Alan Maguire <[email protected]> wrote: > > 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_off": 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 | 91 ++++++++++++++++++++++- > 2 files changed, 89 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..08dc6a86bc85 100644 > --- a/tools/bpf/bpftool/btf.c > +++ b/tools/bpf/bpftool/btf.c > @@ -835,6 +835,87 @@ static int dump_btf_c(const struct btf *btf, > return err; > } > > +static int dump_btf_meta(const struct btf *btf) > +{ > + __u32 layout_off = 0, layout_len = 0; > + __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); I don't think this part is useful. People can hex dump it if they really want to. > + } 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 (data_sz >= hdr->hdr_len && hdr->hdr_len >= sizeof(struct btf_header)) { > + layout_off = hdr->layout_off; > + layout_len = hdr->layout_len; > + if (layout_len > 0 && > + (long long)layout_off + layout_len + hdr->hdr_len <= data_sz) { > + l = (void *)hdr + hdr->hdr_len + layout_off; > + nr_kinds = layout_len / sizeof(*l); > + } > + } else { > + if (!json_output) > + return 0; > + } > + > + /* unconditionally display (possibly empty) layout info for json only */ > + if (json_output) { > + jsonw_uint_field(json_wtr, "layout_len", layout_len); > + jsonw_uint_field(json_wtr, "layout_off", layout_off); > + jsonw_end_object(json_wtr); /* end header object */ > + > + 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); > + } This part, I guess, is ok-ish. I wouldn't do it either though. Feels like a debug feature.