Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: btf: Support dumping a specific types from file

Some projects, for example xdp-tools [0], prefer to check in a minimized
vmlinux.h rather than the complete file which can get rather large.

However, when you try to add a minimized version of a complex struct (eg
struct xfrm_state), things can get quite complex if you're trying to
manually untangle and deduplicate the dependencies.

This commit teaches bpftool to do a minimized dump of a specific types by
providing a optional root_id argument(s).

Example usage:

$ ./bpftool btf dump file ~/dev/linux/vmlinux | rg "STRUCT 'xfrm_state'"
[12643] STRUCT 'xfrm_state' size=912 vlen=58

$ ./bpftool btf dump file ~/dev/linux/vmlinux root_id 12643 format c
#ifndef __VMLINUX_H__
#define __VMLINUX_H__

[..]

struct xfrm_type_offload;

struct xfrm_sec_ctx;

struct xfrm_state {
possible_net_t xs_net;
union {
struct hlist_node gclist;
struct hlist_node bydst;
};
union {
struct hlist_node dev_gclist;
struct hlist_node bysrc;
};
struct hlist_node byspi;
[..]

[0]: https://github.com/xdp-project/xdp-tools/blob/master/headers/bpf/vmlinux.h

Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/04feb860c0a56a7da66f923551484e1483a72074.1734119028.git.dxu@dxuuu.xyz

authored by

Daniel Xu and committed by
Andrii Nakryiko
a812d92e 7f5819e1

+44 -4
+7 -2
tools/bpf/bpftool/Documentation/bpftool-btf.rst
··· 24 24 ============= 25 25 26 26 | **bpftool** **btf** { **show** | **list** } [**id** *BTF_ID*] 27 - | **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*] 27 + | **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*] [**root_id** *ROOT_ID*] 28 28 | **bpftool** **btf help** 29 29 | 30 30 | *BTF_SRC* := { **id** *BTF_ID* | **prog** *PROG* | **map** *MAP* [{**key** | **value** | **kv** | **all**}] | **file** *FILE* } ··· 43 43 that hold open file descriptors (FDs) against BTF objects. On such kernels 44 44 bpftool will automatically emit this information as well. 45 45 46 - bpftool btf dump *BTF_SRC* [format *FORMAT*] 46 + bpftool btf dump *BTF_SRC* [format *FORMAT*] [root_id *ROOT_ID*] 47 47 Dump BTF entries from a given *BTF_SRC*. 48 48 49 49 When **id** is specified, BTF object with that ID will be loaded and all ··· 66 66 (**raw**) or C-syntax (**c**) output formats are supported. With C-style 67 67 formatting, the output is sorted by default. Use the **unsorted** option 68 68 to avoid sorting the output. 69 + 70 + **root_id** option can be used to filter a dump to a single type and all 71 + its dependent types. It cannot be used with any other types of filtering 72 + (such as the "key", "value", or "kv" arguments when dumping BTF for a map). 73 + It can be passed multiple times to dump multiple types. 69 74 70 75 bpftool btf help 71 76 Print short help message.
+37 -2
tools/bpf/bpftool/btf.c
··· 27 27 #define KFUNC_DECL_TAG "bpf_kfunc" 28 28 #define FASTCALL_DECL_TAG "bpf_fastcall" 29 29 30 + #define MAX_ROOT_IDS 16 31 + 30 32 static const char * const btf_kind_str[NR_BTF_KINDS] = { 31 33 [BTF_KIND_UNKN] = "UNKNOWN", 32 34 [BTF_KIND_INT] = "INT", ··· 882 880 { 883 881 bool dump_c = false, sort_dump_c = true; 884 882 struct btf *btf = NULL, *base = NULL; 885 - __u32 root_type_ids[2]; 883 + __u32 root_type_ids[MAX_ROOT_IDS]; 884 + bool have_id_filtering; 886 885 int root_type_cnt = 0; 887 886 __u32 btf_id = -1; 888 887 const char *src; ··· 977 974 goto done; 978 975 } 979 976 977 + have_id_filtering = !!root_type_cnt; 978 + 980 979 while (argc) { 981 980 if (is_prefix(*argv, "format")) { 982 981 NEXT_ARG(); ··· 997 992 err = -EINVAL; 998 993 goto done; 999 994 } 995 + NEXT_ARG(); 996 + } else if (is_prefix(*argv, "root_id")) { 997 + __u32 root_id; 998 + char *end; 999 + 1000 + if (have_id_filtering) { 1001 + p_err("cannot use root_id with other type filtering"); 1002 + err = -EINVAL; 1003 + goto done; 1004 + } else if (root_type_cnt == MAX_ROOT_IDS) { 1005 + p_err("only %d root_id are supported", MAX_ROOT_IDS); 1006 + err = -E2BIG; 1007 + goto done; 1008 + } 1009 + 1010 + NEXT_ARG(); 1011 + root_id = strtoul(*argv, &end, 0); 1012 + if (*end) { 1013 + err = -1; 1014 + p_err("can't parse %s as root ID", *argv); 1015 + goto done; 1016 + } 1017 + for (i = 0; i < root_type_cnt; i++) { 1018 + if (root_type_ids[i] == root_id) { 1019 + err = -EINVAL; 1020 + p_err("duplicate root_id %d supplied", root_id); 1021 + goto done; 1022 + } 1023 + } 1024 + root_type_ids[root_type_cnt++] = root_id; 1000 1025 NEXT_ARG(); 1001 1026 } else if (is_prefix(*argv, "unsorted")) { 1002 1027 sort_dump_c = false; ··· 1438 1403 1439 1404 fprintf(stderr, 1440 1405 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n" 1441 - " %1$s %2$s dump BTF_SRC [format FORMAT]\n" 1406 + " %1$s %2$s dump BTF_SRC [format FORMAT] [root_id ROOT_ID]\n" 1442 1407 " %1$s %2$s help\n" 1443 1408 "\n" 1444 1409 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"