blob: 0cd769adac66287c77d0b8ed6daee9e7324090d3 [file] [log] [blame]
Andrii Nakryikoc93cc692019-04-25 15:30:08 -07001// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2019 Facebook */
3
4#include <errno.h>
5#include <fcntl.h>
6#include <linux/err.h>
7#include <stdbool.h>
8#include <stdio.h>
9#include <string.h>
10#include <unistd.h>
Toke Høiland-Jørgensen229c3b42020-01-20 14:06:46 +010011#include <bpf/bpf.h>
12#include <bpf/btf.h>
13#include <bpf/libbpf.h>
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070014#include <linux/btf.h>
Quentin Monnet4d374ba02019-08-20 10:31:54 +010015#include <linux/hashtable.h>
Jiri Olsaa9436462019-10-24 15:30:25 +020016#include <sys/types.h>
17#include <sys/stat.h>
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070018
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070019#include "json_writer.h"
20#include "main.h"
21
22static const char * const btf_kind_str[NR_BTF_KINDS] = {
23 [BTF_KIND_UNKN] = "UNKNOWN",
24 [BTF_KIND_INT] = "INT",
25 [BTF_KIND_PTR] = "PTR",
26 [BTF_KIND_ARRAY] = "ARRAY",
27 [BTF_KIND_STRUCT] = "STRUCT",
28 [BTF_KIND_UNION] = "UNION",
29 [BTF_KIND_ENUM] = "ENUM",
30 [BTF_KIND_FWD] = "FWD",
31 [BTF_KIND_TYPEDEF] = "TYPEDEF",
32 [BTF_KIND_VOLATILE] = "VOLATILE",
33 [BTF_KIND_CONST] = "CONST",
34 [BTF_KIND_RESTRICT] = "RESTRICT",
35 [BTF_KIND_FUNC] = "FUNC",
36 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
37 [BTF_KIND_VAR] = "VAR",
38 [BTF_KIND_DATASEC] = "DATASEC",
Ilya Leoshkevich737e0f92021-02-26 21:22:50 +010039 [BTF_KIND_FLOAT] = "FLOAT",
Yonghong Song223f9032021-10-12 09:48:38 -070040 [BTF_KIND_DECL_TAG] = "DECL_TAG",
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070041};
42
Quentin Monnet4d374ba02019-08-20 10:31:54 +010043struct btf_attach_table {
44 DECLARE_HASHTABLE(table, 16);
45};
46
47struct btf_attach_point {
48 __u32 obj_id;
49 __u32 btf_id;
50 struct hlist_node hash;
51};
52
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070053static const char *btf_int_enc_str(__u8 encoding)
54{
55 switch (encoding) {
56 case 0:
57 return "(none)";
58 case BTF_INT_SIGNED:
59 return "SIGNED";
60 case BTF_INT_CHAR:
61 return "CHAR";
62 case BTF_INT_BOOL:
63 return "BOOL";
64 default:
65 return "UNKN";
66 }
67}
68
69static const char *btf_var_linkage_str(__u32 linkage)
70{
71 switch (linkage) {
72 case BTF_VAR_STATIC:
73 return "static";
74 case BTF_VAR_GLOBAL_ALLOCATED:
Andrii Nakryiko0dd7e452021-04-23 11:13:31 -070075 return "global";
76 case BTF_VAR_GLOBAL_EXTERN:
77 return "extern";
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070078 default:
79 return "(unknown)";
80 }
81}
82
Andrii Nakryiko41258282020-01-23 21:43:17 -080083static const char *btf_func_linkage_str(const struct btf_type *t)
84{
85 switch (btf_vlen(t)) {
86 case BTF_FUNC_STATIC:
87 return "static";
88 case BTF_FUNC_GLOBAL:
89 return "global";
90 case BTF_FUNC_EXTERN:
91 return "extern";
92 default:
93 return "(unknown)";
94 }
95}
96
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070097static const char *btf_str(const struct btf *btf, __u32 off)
98{
99 if (!off)
100 return "(anon)";
101 return btf__name_by_offset(btf, off) ? : "(invalid)";
102}
103
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700104static int btf_kind_safe(int kind)
105{
106 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
107}
108
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700109static int dump_btf_type(const struct btf *btf, __u32 id,
110 const struct btf_type *t)
111{
112 json_writer_t *w = json_wtr;
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700113 int kind = btf_kind(t);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700114
115 if (json_output) {
116 jsonw_start_object(w);
117 jsonw_uint_field(w, "id", id);
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700118 jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700119 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
120 } else {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700121 printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700122 btf_str(btf, t->name_off));
123 }
124
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700125 switch (kind) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700126 case BTF_KIND_INT: {
127 __u32 v = *(__u32 *)(t + 1);
128 const char *enc;
129
130 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
131
132 if (json_output) {
133 jsonw_uint_field(w, "size", t->size);
134 jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
135 jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
136 jsonw_string_field(w, "encoding", enc);
137 } else {
138 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
139 t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
140 enc);
141 }
142 break;
143 }
144 case BTF_KIND_PTR:
145 case BTF_KIND_CONST:
146 case BTF_KIND_VOLATILE:
147 case BTF_KIND_RESTRICT:
148 case BTF_KIND_TYPEDEF:
149 if (json_output)
150 jsonw_uint_field(w, "type_id", t->type);
151 else
152 printf(" type_id=%u", t->type);
153 break;
154 case BTF_KIND_ARRAY: {
155 const struct btf_array *arr = (const void *)(t + 1);
156
157 if (json_output) {
158 jsonw_uint_field(w, "type_id", arr->type);
159 jsonw_uint_field(w, "index_type_id", arr->index_type);
160 jsonw_uint_field(w, "nr_elems", arr->nelems);
161 } else {
162 printf(" type_id=%u index_type_id=%u nr_elems=%u",
163 arr->type, arr->index_type, arr->nelems);
164 }
165 break;
166 }
167 case BTF_KIND_STRUCT:
168 case BTF_KIND_UNION: {
169 const struct btf_member *m = (const void *)(t + 1);
170 __u16 vlen = BTF_INFO_VLEN(t->info);
171 int i;
172
173 if (json_output) {
174 jsonw_uint_field(w, "size", t->size);
175 jsonw_uint_field(w, "vlen", vlen);
176 jsonw_name(w, "members");
177 jsonw_start_array(w);
178 } else {
179 printf(" size=%u vlen=%u", t->size, vlen);
180 }
181 for (i = 0; i < vlen; i++, m++) {
182 const char *name = btf_str(btf, m->name_off);
183 __u32 bit_off, bit_sz;
184
185 if (BTF_INFO_KFLAG(t->info)) {
186 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
187 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
188 } else {
189 bit_off = m->offset;
190 bit_sz = 0;
191 }
192
193 if (json_output) {
194 jsonw_start_object(w);
195 jsonw_string_field(w, "name", name);
196 jsonw_uint_field(w, "type_id", m->type);
197 jsonw_uint_field(w, "bits_offset", bit_off);
198 if (bit_sz) {
199 jsonw_uint_field(w, "bitfield_size",
200 bit_sz);
201 }
202 jsonw_end_object(w);
203 } else {
204 printf("\n\t'%s' type_id=%u bits_offset=%u",
205 name, m->type, bit_off);
206 if (bit_sz)
207 printf(" bitfield_size=%u", bit_sz);
208 }
209 }
210 if (json_output)
211 jsonw_end_array(w);
212 break;
213 }
214 case BTF_KIND_ENUM: {
215 const struct btf_enum *v = (const void *)(t + 1);
216 __u16 vlen = BTF_INFO_VLEN(t->info);
217 int i;
218
219 if (json_output) {
220 jsonw_uint_field(w, "size", t->size);
221 jsonw_uint_field(w, "vlen", vlen);
222 jsonw_name(w, "values");
223 jsonw_start_array(w);
224 } else {
225 printf(" size=%u vlen=%u", t->size, vlen);
226 }
227 for (i = 0; i < vlen; i++, v++) {
228 const char *name = btf_str(btf, v->name_off);
229
230 if (json_output) {
231 jsonw_start_object(w);
232 jsonw_string_field(w, "name", name);
233 jsonw_uint_field(w, "val", v->val);
234 jsonw_end_object(w);
235 } else {
236 printf("\n\t'%s' val=%u", name, v->val);
237 }
238 }
239 if (json_output)
240 jsonw_end_array(w);
241 break;
242 }
243 case BTF_KIND_FWD: {
Andrii Nakryiko9c3ddee2019-05-16 23:21:29 -0700244 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
245 : "struct";
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700246
247 if (json_output)
248 jsonw_string_field(w, "fwd_kind", fwd_kind);
249 else
250 printf(" fwd_kind=%s", fwd_kind);
251 break;
252 }
Andrii Nakryiko41258282020-01-23 21:43:17 -0800253 case BTF_KIND_FUNC: {
254 const char *linkage = btf_func_linkage_str(t);
255
256 if (json_output) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700257 jsonw_uint_field(w, "type_id", t->type);
Andrii Nakryiko41258282020-01-23 21:43:17 -0800258 jsonw_string_field(w, "linkage", linkage);
259 } else {
260 printf(" type_id=%u linkage=%s", t->type, linkage);
261 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700262 break;
Andrii Nakryiko41258282020-01-23 21:43:17 -0800263 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700264 case BTF_KIND_FUNC_PROTO: {
265 const struct btf_param *p = (const void *)(t + 1);
266 __u16 vlen = BTF_INFO_VLEN(t->info);
267 int i;
268
269 if (json_output) {
270 jsonw_uint_field(w, "ret_type_id", t->type);
271 jsonw_uint_field(w, "vlen", vlen);
272 jsonw_name(w, "params");
273 jsonw_start_array(w);
274 } else {
275 printf(" ret_type_id=%u vlen=%u", t->type, vlen);
276 }
277 for (i = 0; i < vlen; i++, p++) {
278 const char *name = btf_str(btf, p->name_off);
279
280 if (json_output) {
281 jsonw_start_object(w);
282 jsonw_string_field(w, "name", name);
283 jsonw_uint_field(w, "type_id", p->type);
284 jsonw_end_object(w);
285 } else {
286 printf("\n\t'%s' type_id=%u", name, p->type);
287 }
288 }
289 if (json_output)
290 jsonw_end_array(w);
291 break;
292 }
293 case BTF_KIND_VAR: {
294 const struct btf_var *v = (const void *)(t + 1);
295 const char *linkage;
296
297 linkage = btf_var_linkage_str(v->linkage);
298
299 if (json_output) {
300 jsonw_uint_field(w, "type_id", t->type);
301 jsonw_string_field(w, "linkage", linkage);
302 } else {
303 printf(" type_id=%u, linkage=%s", t->type, linkage);
304 }
305 break;
306 }
307 case BTF_KIND_DATASEC: {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700308 const struct btf_var_secinfo *v = (const void *)(t + 1);
309 const struct btf_type *vt;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700310 __u16 vlen = BTF_INFO_VLEN(t->info);
311 int i;
312
313 if (json_output) {
314 jsonw_uint_field(w, "size", t->size);
315 jsonw_uint_field(w, "vlen", vlen);
316 jsonw_name(w, "vars");
317 jsonw_start_array(w);
318 } else {
319 printf(" size=%u vlen=%u", t->size, vlen);
320 }
321 for (i = 0; i < vlen; i++, v++) {
322 if (json_output) {
323 jsonw_start_object(w);
324 jsonw_uint_field(w, "type_id", v->type);
325 jsonw_uint_field(w, "offset", v->offset);
326 jsonw_uint_field(w, "size", v->size);
327 jsonw_end_object(w);
328 } else {
329 printf("\n\ttype_id=%u offset=%u size=%u",
330 v->type, v->offset, v->size);
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700331
Hengqi Chen58fc1552021-10-22 21:06:22 +0800332 if (v->type < btf__type_cnt(btf)) {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700333 vt = btf__type_by_id(btf, v->type);
334 printf(" (%s '%s')",
335 btf_kind_str[btf_kind_safe(btf_kind(vt))],
336 btf_str(btf, vt->name_off));
337 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700338 }
339 }
340 if (json_output)
341 jsonw_end_array(w);
342 break;
343 }
Ilya Leoshkevich737e0f92021-02-26 21:22:50 +0100344 case BTF_KIND_FLOAT: {
345 if (json_output)
346 jsonw_uint_field(w, "size", t->size);
347 else
348 printf(" size=%u", t->size);
349 break;
350 }
Yonghong Song223f9032021-10-12 09:48:38 -0700351 case BTF_KIND_DECL_TAG: {
352 const struct btf_decl_tag *tag = (const void *)(t + 1);
Yonghong Song5c07f2f2021-09-14 15:30:31 -0700353
354 if (json_output) {
355 jsonw_uint_field(w, "type_id", t->type);
356 jsonw_int_field(w, "component_idx", tag->component_idx);
357 } else {
358 printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
359 }
360 break;
361 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700362 default:
363 break;
364 }
365
366 if (json_output)
367 jsonw_end_object(json_wtr);
368 else
369 printf("\n");
370
371 return 0;
372}
373
374static int dump_btf_raw(const struct btf *btf,
375 __u32 *root_type_ids, int root_type_cnt)
376{
377 const struct btf_type *t;
378 int i;
379
380 if (json_output) {
381 jsonw_start_object(json_wtr);
382 jsonw_name(json_wtr, "types");
383 jsonw_start_array(json_wtr);
384 }
385
386 if (root_type_cnt) {
387 for (i = 0; i < root_type_cnt; i++) {
388 t = btf__type_by_id(btf, root_type_ids[i]);
389 dump_btf_type(btf, root_type_ids[i], t);
390 }
391 } else {
Andrii Nakryikofa452832020-12-01 22:52:43 -0800392 const struct btf *base;
Hengqi Chen58fc1552021-10-22 21:06:22 +0800393 int cnt = btf__type_cnt(btf);
Andrii Nakryiko75fa1772020-11-04 20:34:01 -0800394 int start_id = 1;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700395
Andrii Nakryikofa452832020-12-01 22:52:43 -0800396 base = btf__base_btf(btf);
397 if (base)
Hengqi Chen58fc1552021-10-22 21:06:22 +0800398 start_id = btf__type_cnt(base);
Andrii Nakryiko75fa1772020-11-04 20:34:01 -0800399
Hengqi Chen58fc1552021-10-22 21:06:22 +0800400 for (i = start_id; i < cnt; i++) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700401 t = btf__type_by_id(btf, i);
402 dump_btf_type(btf, i, t);
403 }
404 }
405
406 if (json_output) {
407 jsonw_end_array(json_wtr);
408 jsonw_end_object(json_wtr);
409 }
410 return 0;
411}
412
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700413static void __printf(2, 0) btf_dump_printf(void *ctx,
414 const char *fmt, va_list args)
415{
416 vfprintf(stdout, fmt, args);
417}
418
419static int dump_btf_c(const struct btf *btf,
420 __u32 *root_type_ids, int root_type_cnt)
421{
422 struct btf_dump *d;
423 int err = 0, i;
424
425 d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
426 if (IS_ERR(d))
427 return PTR_ERR(d);
428
Andrii Nakryikoca7dc272020-02-29 15:11:09 -0800429 printf("#ifndef __VMLINUX_H__\n");
430 printf("#define __VMLINUX_H__\n");
431 printf("\n");
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800432 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
433 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
434 printf("#endif\n\n");
435
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700436 if (root_type_cnt) {
437 for (i = 0; i < root_type_cnt; i++) {
438 err = btf_dump__dump_type(d, root_type_ids[i]);
439 if (err)
440 goto done;
441 }
442 } else {
Hengqi Chen58fc1552021-10-22 21:06:22 +0800443 int cnt = btf__type_cnt(btf);
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700444
Hengqi Chen58fc1552021-10-22 21:06:22 +0800445 for (i = 1; i < cnt; i++) {
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700446 err = btf_dump__dump_type(d, i);
447 if (err)
448 goto done;
449 }
450 }
451
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800452 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
453 printf("#pragma clang attribute pop\n");
454 printf("#endif\n");
Andrii Nakryikoca7dc272020-02-29 15:11:09 -0800455 printf("\n");
456 printf("#endif /* __VMLINUX_H__ */\n");
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800457
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700458done:
459 btf_dump__free(d);
460 return err;
461}
462
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700463static int do_dump(int argc, char **argv)
464{
Andrii Nakryikofa452832020-12-01 22:52:43 -0800465 struct btf *btf = NULL, *base = NULL;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700466 __u32 root_type_ids[2];
467 int root_type_cnt = 0;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700468 bool dump_c = false;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700469 __u32 btf_id = -1;
470 const char *src;
471 int fd = -1;
472 int err;
473
474 if (!REQ_ARGS(2)) {
475 usage();
476 return -1;
477 }
478 src = GET_ARG();
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700479 if (is_prefix(src, "map")) {
480 struct bpf_map_info info = {};
481 __u32 len = sizeof(info);
482
483 if (!REQ_ARGS(2)) {
484 usage();
485 return -1;
486 }
487
488 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
489 if (fd < 0)
490 return -1;
491
492 btf_id = info.btf_id;
493 if (argc && is_prefix(*argv, "key")) {
494 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
495 NEXT_ARG();
496 } else if (argc && is_prefix(*argv, "value")) {
497 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
498 NEXT_ARG();
499 } else if (argc && is_prefix(*argv, "all")) {
500 NEXT_ARG();
501 } else if (argc && is_prefix(*argv, "kv")) {
502 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
503 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
504 NEXT_ARG();
505 } else {
506 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
507 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
508 }
509 } else if (is_prefix(src, "prog")) {
510 struct bpf_prog_info info = {};
511 __u32 len = sizeof(info);
512
513 if (!REQ_ARGS(2)) {
514 usage();
515 return -1;
516 }
517
518 fd = prog_parse_fd(&argc, &argv);
519 if (fd < 0)
520 return -1;
521
522 err = bpf_obj_get_info_by_fd(fd, &info, &len);
523 if (err) {
524 p_err("can't get prog info: %s", strerror(errno));
525 goto done;
526 }
527
528 btf_id = info.btf_id;
529 } else if (is_prefix(src, "id")) {
530 char *endptr;
531
532 btf_id = strtoul(*argv, &endptr, 0);
533 if (*endptr) {
Quentin Monneted4a3982019-08-15 15:32:17 +0100534 p_err("can't parse %s as ID", *argv);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700535 return -1;
536 }
537 NEXT_ARG();
538 } else if (is_prefix(src, "file")) {
Andrii Nakryikofa452832020-12-01 22:52:43 -0800539 const char sysfs_prefix[] = "/sys/kernel/btf/";
540 const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
541
542 if (!base_btf &&
543 strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
544 strcmp(*argv, sysfs_vmlinux) != 0) {
545 base = btf__parse(sysfs_vmlinux, NULL);
546 if (libbpf_get_error(base)) {
547 p_err("failed to parse vmlinux BTF at '%s': %ld\n",
548 sysfs_vmlinux, libbpf_get_error(base));
549 base = NULL;
550 }
551 }
552
553 btf = btf__parse_split(*argv, base ?: base_btf);
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700554 if (IS_ERR(btf)) {
Tobias Klauserdc3ca5c2020-05-25 15:54:21 +0200555 err = -PTR_ERR(btf);
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700556 btf = NULL;
Toke Høiland-Jørgensen229c3b42020-01-20 14:06:46 +0100557 p_err("failed to load BTF from %s: %s",
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700558 *argv, strerror(err));
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700559 goto done;
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700560 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700561 NEXT_ARG();
562 } else {
563 err = -1;
564 p_err("unrecognized BTF source specifier: '%s'", src);
565 goto done;
566 }
567
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700568 while (argc) {
569 if (is_prefix(*argv, "format")) {
570 NEXT_ARG();
571 if (argc < 1) {
572 p_err("expecting value for 'format' option\n");
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800573 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700574 goto done;
575 }
576 if (strcmp(*argv, "c") == 0) {
577 dump_c = true;
578 } else if (strcmp(*argv, "raw") == 0) {
579 dump_c = false;
580 } else {
581 p_err("unrecognized format specifier: '%s', possible values: raw, c",
582 *argv);
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800583 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700584 goto done;
585 }
586 NEXT_ARG();
587 } else {
588 p_err("unrecognized option: '%s'", *argv);
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800589 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700590 goto done;
591 }
592 }
593
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700594 if (!btf) {
Quentin Monnet211ab782021-07-29 17:20:28 +0100595 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
Quentin Monnet86f4b7f2021-07-29 17:20:25 +0100596 err = libbpf_get_error(btf);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700597 if (err) {
598 p_err("get btf by id (%u): %s", btf_id, strerror(err));
599 goto done;
600 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700601 }
602
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700603 if (dump_c) {
604 if (json_output) {
605 p_err("JSON output for C-syntax dump is not supported");
606 err = -ENOTSUP;
607 goto done;
608 }
609 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
610 } else {
611 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
612 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700613
614done:
615 close(fd);
616 btf__free(btf);
Andrii Nakryikofa452832020-12-01 22:52:43 -0800617 btf__free(base);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700618 return err;
619}
620
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100621static int btf_parse_fd(int *argc, char ***argv)
622{
623 unsigned int id;
624 char *endptr;
625 int fd;
626
627 if (!is_prefix(*argv[0], "id")) {
628 p_err("expected 'id', got: '%s'?", **argv);
629 return -1;
630 }
631 NEXT_ARGP();
632
633 id = strtoul(**argv, &endptr, 0);
634 if (*endptr) {
635 p_err("can't parse %s as ID", **argv);
636 return -1;
637 }
638 NEXT_ARGP();
639
640 fd = bpf_btf_get_fd_by_id(id);
641 if (fd < 0)
642 p_err("can't get BTF object by id (%u): %s",
643 id, strerror(errno));
644
645 return fd;
646}
647
648static void delete_btf_table(struct btf_attach_table *tab)
649{
650 struct btf_attach_point *obj;
651 struct hlist_node *tmp;
652
653 unsigned int bkt;
654
655 hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
656 hash_del(&obj->hash);
657 free(obj);
658 }
659}
660
661static int
662build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
663 void *info, __u32 *len)
664{
665 static const char * const names[] = {
666 [BPF_OBJ_UNKNOWN] = "unknown",
667 [BPF_OBJ_PROG] = "prog",
668 [BPF_OBJ_MAP] = "map",
669 };
670 struct btf_attach_point *obj_node;
671 __u32 btf_id, id = 0;
672 int err;
673 int fd;
674
675 while (true) {
676 switch (type) {
677 case BPF_OBJ_PROG:
678 err = bpf_prog_get_next_id(id, &id);
679 break;
680 case BPF_OBJ_MAP:
681 err = bpf_map_get_next_id(id, &id);
682 break;
683 default:
684 err = -1;
685 p_err("unexpected object type: %d", type);
686 goto err_free;
687 }
688 if (err) {
689 if (errno == ENOENT) {
690 err = 0;
691 break;
692 }
693 p_err("can't get next %s: %s%s", names[type],
694 strerror(errno),
695 errno == EINVAL ? " -- kernel too old?" : "");
696 goto err_free;
697 }
698
699 switch (type) {
700 case BPF_OBJ_PROG:
701 fd = bpf_prog_get_fd_by_id(id);
702 break;
703 case BPF_OBJ_MAP:
704 fd = bpf_map_get_fd_by_id(id);
705 break;
706 default:
707 err = -1;
708 p_err("unexpected object type: %d", type);
709 goto err_free;
710 }
711 if (fd < 0) {
712 if (errno == ENOENT)
713 continue;
714 p_err("can't get %s by id (%u): %s", names[type], id,
715 strerror(errno));
716 err = -1;
717 goto err_free;
718 }
719
720 memset(info, 0, *len);
721 err = bpf_obj_get_info_by_fd(fd, info, len);
722 close(fd);
723 if (err) {
724 p_err("can't get %s info: %s", names[type],
725 strerror(errno));
726 goto err_free;
727 }
728
729 switch (type) {
730 case BPF_OBJ_PROG:
731 btf_id = ((struct bpf_prog_info *)info)->btf_id;
732 break;
733 case BPF_OBJ_MAP:
734 btf_id = ((struct bpf_map_info *)info)->btf_id;
735 break;
736 default:
737 err = -1;
738 p_err("unexpected object type: %d", type);
739 goto err_free;
740 }
741 if (!btf_id)
742 continue;
743
744 obj_node = calloc(1, sizeof(*obj_node));
745 if (!obj_node) {
746 p_err("failed to allocate memory: %s", strerror(errno));
Zhen Lei68878a52020-11-24 18:41:00 +0800747 err = -ENOMEM;
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100748 goto err_free;
749 }
750
751 obj_node->obj_id = id;
752 obj_node->btf_id = btf_id;
753 hash_add(tab->table, &obj_node->hash, obj_node->btf_id);
754 }
755
756 return 0;
757
758err_free:
759 delete_btf_table(tab);
760 return err;
761}
762
763static int
764build_btf_tables(struct btf_attach_table *btf_prog_table,
765 struct btf_attach_table *btf_map_table)
766{
767 struct bpf_prog_info prog_info;
768 __u32 prog_len = sizeof(prog_info);
769 struct bpf_map_info map_info;
770 __u32 map_len = sizeof(map_info);
771 int err = 0;
772
773 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
774 &prog_len);
775 if (err)
776 return err;
777
778 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
779 &map_len);
780 if (err) {
781 delete_btf_table(btf_prog_table);
782 return err;
783 }
784
785 return 0;
786}
787
788static void
789show_btf_plain(struct bpf_btf_info *info, int fd,
790 struct btf_attach_table *btf_prog_table,
791 struct btf_attach_table *btf_map_table)
792{
793 struct btf_attach_point *obj;
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800794 const char *name = u64_to_ptr(info->name);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100795 int n;
796
797 printf("%u: ", info->id);
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800798 if (info->kernel_btf)
799 printf("name [%s] ", name);
800 else if (name && name[0])
801 printf("name %s ", name);
Andrii Nakryiko71ccb502020-12-01 22:52:41 -0800802 else
803 printf("name <anon> ");
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100804 printf("size %uB", info->btf_size);
805
806 n = 0;
807 hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) {
808 if (obj->btf_id == info->id)
809 printf("%s%u", n++ == 0 ? " prog_ids " : ",",
810 obj->obj_id);
811 }
812
813 n = 0;
814 hash_for_each_possible(btf_map_table->table, obj, hash, info->id) {
815 if (obj->btf_id == info->id)
816 printf("%s%u", n++ == 0 ? " map_ids " : ",",
817 obj->obj_id);
818 }
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700819 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100820
821 printf("\n");
822}
823
824static void
825show_btf_json(struct bpf_btf_info *info, int fd,
826 struct btf_attach_table *btf_prog_table,
827 struct btf_attach_table *btf_map_table)
828{
829 struct btf_attach_point *obj;
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800830 const char *name = u64_to_ptr(info->name);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100831
832 jsonw_start_object(json_wtr); /* btf object */
833 jsonw_uint_field(json_wtr, "id", info->id);
834 jsonw_uint_field(json_wtr, "size", info->btf_size);
835
836 jsonw_name(json_wtr, "prog_ids");
837 jsonw_start_array(json_wtr); /* prog_ids */
838 hash_for_each_possible(btf_prog_table->table, obj, hash,
839 info->id) {
840 if (obj->btf_id == info->id)
841 jsonw_uint(json_wtr, obj->obj_id);
842 }
843 jsonw_end_array(json_wtr); /* prog_ids */
844
845 jsonw_name(json_wtr, "map_ids");
846 jsonw_start_array(json_wtr); /* map_ids */
847 hash_for_each_possible(btf_map_table->table, obj, hash,
848 info->id) {
849 if (obj->btf_id == info->id)
850 jsonw_uint(json_wtr, obj->obj_id);
851 }
852 jsonw_end_array(json_wtr); /* map_ids */
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700853
854 emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */
855
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800856 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
857
858 if (name && name[0])
859 jsonw_string_field(json_wtr, "name", name);
860
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100861 jsonw_end_object(json_wtr); /* btf object */
862}
863
864static int
865show_btf(int fd, struct btf_attach_table *btf_prog_table,
866 struct btf_attach_table *btf_map_table)
867{
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800868 struct bpf_btf_info info;
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100869 __u32 len = sizeof(info);
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800870 char name[64];
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100871 int err;
872
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800873 memset(&info, 0, sizeof(info));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100874 err = bpf_obj_get_info_by_fd(fd, &info, &len);
875 if (err) {
876 p_err("can't get BTF object info: %s", strerror(errno));
877 return -1;
878 }
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800879 /* if kernel support emitting BTF object name, pass name pointer */
880 if (info.name_len) {
881 memset(&info, 0, sizeof(info));
882 info.name_len = sizeof(name);
883 info.name = ptr_to_u64(name);
884 len = sizeof(info);
885
886 err = bpf_obj_get_info_by_fd(fd, &info, &len);
887 if (err) {
888 p_err("can't get BTF object info: %s", strerror(errno));
889 return -1;
890 }
891 }
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100892
893 if (json_output)
894 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
895 else
896 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
897
898 return 0;
899}
900
901static int do_show(int argc, char **argv)
902{
903 struct btf_attach_table btf_prog_table;
904 struct btf_attach_table btf_map_table;
905 int err, fd = -1;
906 __u32 id = 0;
907
908 if (argc == 2) {
909 fd = btf_parse_fd(&argc, &argv);
910 if (fd < 0)
911 return -1;
912 }
913
914 if (argc) {
915 if (fd >= 0)
916 close(fd);
917 return BAD_ARG();
918 }
919
920 hash_init(btf_prog_table.table);
921 hash_init(btf_map_table.table);
922 err = build_btf_tables(&btf_prog_table, &btf_map_table);
923 if (err) {
924 if (fd >= 0)
925 close(fd);
926 return err;
927 }
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700928 build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100929
930 if (fd >= 0) {
931 err = show_btf(fd, &btf_prog_table, &btf_map_table);
932 close(fd);
933 goto exit_free;
934 }
935
936 if (json_output)
937 jsonw_start_array(json_wtr); /* root array */
938
939 while (true) {
940 err = bpf_btf_get_next_id(id, &id);
941 if (err) {
942 if (errno == ENOENT) {
943 err = 0;
944 break;
945 }
946 p_err("can't get next BTF object: %s%s",
947 strerror(errno),
948 errno == EINVAL ? " -- kernel too old?" : "");
949 err = -1;
950 break;
951 }
952
953 fd = bpf_btf_get_fd_by_id(id);
954 if (fd < 0) {
955 if (errno == ENOENT)
956 continue;
957 p_err("can't get BTF object by id (%u): %s",
958 id, strerror(errno));
959 err = -1;
960 break;
961 }
962
963 err = show_btf(fd, &btf_prog_table, &btf_map_table);
964 close(fd);
965 if (err)
966 break;
967 }
968
969 if (json_output)
970 jsonw_end_array(json_wtr); /* root array */
971
972exit_free:
973 delete_btf_table(&btf_prog_table);
974 delete_btf_table(&btf_map_table);
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700975 delete_obj_refs_table(&refs_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100976
977 return err;
978}
979
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700980static int do_help(int argc, char **argv)
981{
982 if (json_output) {
983 jsonw_null(json_wtr);
984 return 0;
985 }
986
987 fprintf(stderr,
Quentin Monnet90040352020-05-23 02:07:51 +0100988 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
989 " %1$s %2$s dump BTF_SRC [format FORMAT]\n"
990 " %1$s %2$s help\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700991 "\n"
992 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700993 " FORMAT := { raw | c }\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700994 " " HELP_SPEC_MAP "\n"
995 " " HELP_SPEC_PROGRAM "\n"
Quentin Monnet8cc8c632021-07-30 22:54:34 +0100996 " " HELP_SPEC_OPTIONS " |\n"
997 " {-B|--base-btf} }\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700998 "",
Quentin Monnet90040352020-05-23 02:07:51 +0100999 bin_name, "btf");
Andrii Nakryikoc93cc692019-04-25 15:30:08 -07001000
1001 return 0;
1002}
1003
1004static const struct cmd cmds[] = {
Quentin Monnet4d374ba02019-08-20 10:31:54 +01001005 { "show", do_show },
1006 { "list", do_show },
Andrii Nakryikoc93cc692019-04-25 15:30:08 -07001007 { "help", do_help },
1008 { "dump", do_dump },
1009 { 0 }
1010};
1011
1012int do_btf(int argc, char **argv)
1013{
1014 return cmd_select(cmds, argc, argv, do_help);
1015}