]>
Commit | Line | Data |
---|---|---|
8c061865 AI |
1 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | ||
3 | ============== | |
4 | BPF drgn tools | |
5 | ============== | |
6 | ||
7 | drgn scripts is a convenient and easy to use mechanism to retrieve arbitrary | |
8 | kernel data structures. drgn is not relying on kernel UAPI to read the data. | |
9 | Instead it's reading directly from ``/proc/kcore`` or vmcore and pretty prints | |
10 | the data based on DWARF debug information from vmlinux. | |
11 | ||
12 | This document describes BPF related drgn tools. | |
13 | ||
14 | See `drgn/tools`_ for all tools available at the moment and `drgn/doc`_ for | |
15 | more details on drgn itself. | |
16 | ||
17 | bpf_inspect.py | |
18 | -------------- | |
19 | ||
20 | Description | |
21 | =========== | |
22 | ||
23 | `bpf_inspect.py`_ is a tool intended to inspect BPF programs and maps. It can | |
24 | iterate over all programs and maps in the system and print basic information | |
25 | about these objects, including id, type and name. | |
26 | ||
27 | The main use-case `bpf_inspect.py`_ covers is to show BPF programs of types | |
28 | ``BPF_PROG_TYPE_EXT`` and ``BPF_PROG_TYPE_TRACING`` attached to other BPF | |
29 | programs via ``freplace``/``fentry``/``fexit`` mechanisms, since there is no | |
30 | user-space API to get this information. | |
31 | ||
32 | Getting started | |
33 | =============== | |
34 | ||
35 | List BPF programs (full names are obtained from BTF):: | |
36 | ||
37 | % sudo bpf_inspect.py prog | |
38 | 27: BPF_PROG_TYPE_TRACEPOINT tracepoint__tcp__tcp_send_reset | |
39 | 4632: BPF_PROG_TYPE_CGROUP_SOCK_ADDR tw_ipt_bind | |
40 | 49464: BPF_PROG_TYPE_RAW_TRACEPOINT raw_tracepoint__sched_process_exit | |
41 | ||
42 | List BPF maps:: | |
43 | ||
44 | % sudo bpf_inspect.py map | |
45 | 2577: BPF_MAP_TYPE_HASH tw_ipt_vips | |
46 | 4050: BPF_MAP_TYPE_STACK_TRACE stack_traces | |
47 | 4069: BPF_MAP_TYPE_PERCPU_ARRAY ned_dctcp_cntr | |
48 | ||
49 | Find BPF programs attached to BPF program ``test_pkt_access``:: | |
50 | ||
51 | % sudo bpf_inspect.py p | grep test_pkt_access | |
52 | 650: BPF_PROG_TYPE_SCHED_CLS test_pkt_access | |
53 | 654: BPF_PROG_TYPE_TRACING test_main linked:[650->25: BPF_TRAMP_FEXIT test_pkt_access->test_pkt_access()] | |
54 | 655: BPF_PROG_TYPE_TRACING test_subprog1 linked:[650->29: BPF_TRAMP_FEXIT test_pkt_access->test_pkt_access_subprog1()] | |
55 | 656: BPF_PROG_TYPE_TRACING test_subprog2 linked:[650->31: BPF_TRAMP_FEXIT test_pkt_access->test_pkt_access_subprog2()] | |
56 | 657: BPF_PROG_TYPE_TRACING test_subprog3 linked:[650->21: BPF_TRAMP_FEXIT test_pkt_access->test_pkt_access_subprog3()] | |
57 | 658: BPF_PROG_TYPE_EXT new_get_skb_len linked:[650->16: BPF_TRAMP_REPLACE test_pkt_access->get_skb_len()] | |
58 | 659: BPF_PROG_TYPE_EXT new_get_skb_ifindex linked:[650->23: BPF_TRAMP_REPLACE test_pkt_access->get_skb_ifindex()] | |
59 | 660: BPF_PROG_TYPE_EXT new_get_constant linked:[650->19: BPF_TRAMP_REPLACE test_pkt_access->get_constant()] | |
60 | ||
61 | It can be seen that there is a program ``test_pkt_access``, id 650 and there | |
62 | are multiple other tracing and ext programs attached to functions in | |
63 | ``test_pkt_access``. | |
64 | ||
65 | For example the line:: | |
66 | ||
67 | 658: BPF_PROG_TYPE_EXT new_get_skb_len linked:[650->16: BPF_TRAMP_REPLACE test_pkt_access->get_skb_len()] | |
68 | ||
69 | , means that BPF program id 658, type ``BPF_PROG_TYPE_EXT``, name | |
70 | ``new_get_skb_len`` replaces (``BPF_TRAMP_REPLACE``) function ``get_skb_len()`` | |
71 | that has BTF id 16 in BPF program id 650, name ``test_pkt_access``. | |
72 | ||
73 | Getting help: | |
74 | ||
75 | .. code-block:: none | |
76 | ||
77 | % sudo bpf_inspect.py | |
78 | usage: bpf_inspect.py [-h] {prog,p,map,m} ... | |
79 | ||
80 | drgn script to list BPF programs or maps and their properties | |
81 | unavailable via kernel API. | |
82 | ||
83 | See https://github.com/osandov/drgn/ for more details on drgn. | |
84 | ||
85 | optional arguments: | |
86 | -h, --help show this help message and exit | |
87 | ||
88 | subcommands: | |
89 | {prog,p,map,m} | |
90 | prog (p) list BPF programs | |
91 | map (m) list BPF maps | |
92 | ||
93 | Customization | |
94 | ============= | |
95 | ||
96 | The script is intended to be customized by developers to print relevant | |
97 | information about BPF programs, maps and other objects. | |
98 | ||
99 | For example, to print ``struct bpf_prog_aux`` for BPF program id 53077: | |
100 | ||
101 | .. code-block:: none | |
102 | ||
103 | % git diff | |
104 | diff --git a/tools/bpf_inspect.py b/tools/bpf_inspect.py | |
105 | index 650e228..aea2357 100755 | |
106 | --- a/tools/bpf_inspect.py | |
107 | +++ b/tools/bpf_inspect.py | |
108 | @@ -112,7 +112,9 @@ def list_bpf_progs(args): | |
109 | if linked: | |
110 | linked = f" linked:[{linked}]" | |
111 | ||
112 | - print(f"{id_:>6}: {type_:32} {name:32} {linked}") | |
113 | + if id_ == 53077: | |
114 | + print(f"{id_:>6}: {type_:32} {name:32}") | |
115 | + print(f"{bpf_prog.aux}") | |
116 | ||
117 | ||
118 | def list_bpf_maps(args): | |
119 | ||
120 | It produces the output:: | |
121 | ||
122 | % sudo bpf_inspect.py p | |
123 | 53077: BPF_PROG_TYPE_XDP tw_xdp_policer | |
124 | *(struct bpf_prog_aux *)0xffff8893fad4b400 = { | |
125 | .refcnt = (atomic64_t){ | |
126 | .counter = (long)58, | |
127 | }, | |
128 | .used_map_cnt = (u32)1, | |
129 | .max_ctx_offset = (u32)8, | |
130 | .max_pkt_offset = (u32)15, | |
131 | .max_tp_access = (u32)0, | |
132 | .stack_depth = (u32)8, | |
133 | .id = (u32)53077, | |
134 | .func_cnt = (u32)0, | |
135 | .func_idx = (u32)0, | |
136 | .attach_btf_id = (u32)0, | |
137 | .linked_prog = (struct bpf_prog *)0x0, | |
138 | .verifier_zext = (bool)0, | |
139 | .offload_requested = (bool)0, | |
140 | .attach_btf_trace = (bool)0, | |
141 | .func_proto_unreliable = (bool)0, | |
142 | .trampoline_prog_type = (enum bpf_tramp_prog_type)BPF_TRAMP_FENTRY, | |
143 | .trampoline = (struct bpf_trampoline *)0x0, | |
144 | .tramp_hlist = (struct hlist_node){ | |
145 | .next = (struct hlist_node *)0x0, | |
146 | .pprev = (struct hlist_node **)0x0, | |
147 | }, | |
148 | .attach_func_proto = (const struct btf_type *)0x0, | |
149 | .attach_func_name = (const char *)0x0, | |
150 | .func = (struct bpf_prog **)0x0, | |
151 | .jit_data = (void *)0x0, | |
152 | .poke_tab = (struct bpf_jit_poke_descriptor *)0x0, | |
153 | .size_poke_tab = (u32)0, | |
154 | .ksym_tnode = (struct latch_tree_node){ | |
155 | .node = (struct rb_node [2]){ | |
156 | { | |
157 | .__rb_parent_color = (unsigned long)18446612956263126665, | |
158 | .rb_right = (struct rb_node *)0x0, | |
159 | .rb_left = (struct rb_node *)0xffff88a0be3d0088, | |
160 | }, | |
161 | { | |
162 | .__rb_parent_color = (unsigned long)18446612956263126689, | |
163 | .rb_right = (struct rb_node *)0x0, | |
164 | .rb_left = (struct rb_node *)0xffff88a0be3d00a0, | |
165 | }, | |
166 | }, | |
167 | }, | |
168 | .ksym_lnode = (struct list_head){ | |
169 | .next = (struct list_head *)0xffff88bf481830b8, | |
170 | .prev = (struct list_head *)0xffff888309f536b8, | |
171 | }, | |
172 | .ops = (const struct bpf_prog_ops *)xdp_prog_ops+0x0 = 0xffffffff820fa350, | |
173 | .used_maps = (struct bpf_map **)0xffff889ff795de98, | |
174 | .prog = (struct bpf_prog *)0xffffc9000cf2d000, | |
175 | .user = (struct user_struct *)root_user+0x0 = 0xffffffff82444820, | |
176 | .load_time = (u64)2408348759285319, | |
177 | .cgroup_storage = (struct bpf_map *[2]){}, | |
178 | .name = (char [16])"tw_xdp_policer", | |
179 | .security = (void *)0xffff889ff795d548, | |
180 | .offload = (struct bpf_prog_offload *)0x0, | |
181 | .btf = (struct btf *)0xffff8890ce6d0580, | |
182 | .func_info = (struct bpf_func_info *)0xffff889ff795d240, | |
183 | .func_info_aux = (struct bpf_func_info_aux *)0xffff889ff795de20, | |
184 | .linfo = (struct bpf_line_info *)0xffff888a707afc00, | |
185 | .jited_linfo = (void **)0xffff8893fad48600, | |
186 | .func_info_cnt = (u32)1, | |
187 | .nr_linfo = (u32)37, | |
188 | .linfo_idx = (u32)0, | |
189 | .num_exentries = (u32)0, | |
190 | .extable = (struct exception_table_entry *)0xffffffffa032d950, | |
191 | .stats = (struct bpf_prog_stats *)0x603fe3a1f6d0, | |
192 | .work = (struct work_struct){ | |
193 | .data = (atomic_long_t){ | |
194 | .counter = (long)0, | |
195 | }, | |
196 | .entry = (struct list_head){ | |
197 | .next = (struct list_head *)0x0, | |
198 | .prev = (struct list_head *)0x0, | |
199 | }, | |
200 | .func = (work_func_t)0x0, | |
201 | }, | |
202 | .rcu = (struct callback_head){ | |
203 | .next = (struct callback_head *)0x0, | |
204 | .func = (void (*)(struct callback_head *))0x0, | |
205 | }, | |
206 | } | |
207 | ||
208 | ||
209 | .. Links | |
210 | .. _drgn/doc: https://drgn.readthedocs.io/en/latest/ | |
211 | .. _drgn/tools: https://github.com/osandov/drgn/tree/master/tools | |
212 | .. _bpf_inspect.py: | |
213 | https://github.com/osandov/drgn/blob/master/tools/bpf_inspect.py |