1
2
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>
11#include <bpf.h>
12#include <libbpf.h>
13#include <linux/btf.h>
14#include <linux/hashtable.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <unistd.h>
18
19#include "btf.h"
20#include "json_writer.h"
21#include "main.h"
22
23static const char * const btf_kind_str[NR_BTF_KINDS] = {
24 [BTF_KIND_UNKN] = "UNKNOWN",
25 [BTF_KIND_INT] = "INT",
26 [BTF_KIND_PTR] = "PTR",
27 [BTF_KIND_ARRAY] = "ARRAY",
28 [BTF_KIND_STRUCT] = "STRUCT",
29 [BTF_KIND_UNION] = "UNION",
30 [BTF_KIND_ENUM] = "ENUM",
31 [BTF_KIND_FWD] = "FWD",
32 [BTF_KIND_TYPEDEF] = "TYPEDEF",
33 [BTF_KIND_VOLATILE] = "VOLATILE",
34 [BTF_KIND_CONST] = "CONST",
35 [BTF_KIND_RESTRICT] = "RESTRICT",
36 [BTF_KIND_FUNC] = "FUNC",
37 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
38 [BTF_KIND_VAR] = "VAR",
39 [BTF_KIND_DATASEC] = "DATASEC",
40};
41
42struct btf_attach_table {
43 DECLARE_HASHTABLE(table, 16);
44};
45
46struct btf_attach_point {
47 __u32 obj_id;
48 __u32 btf_id;
49 struct hlist_node hash;
50};
51
52static const char *btf_int_enc_str(__u8 encoding)
53{
54 switch (encoding) {
55 case 0:
56 return "(none)";
57 case BTF_INT_SIGNED:
58 return "SIGNED";
59 case BTF_INT_CHAR:
60 return "CHAR";
61 case BTF_INT_BOOL:
62 return "BOOL";
63 default:
64 return "UNKN";
65 }
66}
67
68static const char *btf_var_linkage_str(__u32 linkage)
69{
70 switch (linkage) {
71 case BTF_VAR_STATIC:
72 return "static";
73 case BTF_VAR_GLOBAL_ALLOCATED:
74 return "global-alloc";
75 default:
76 return "(unknown)";
77 }
78}
79
80static const char *btf_str(const struct btf *btf, __u32 off)
81{
82 if (!off)
83 return "(anon)";
84 return btf__name_by_offset(btf, off) ? : "(invalid)";
85}
86
87static int dump_btf_type(const struct btf *btf, __u32 id,
88 const struct btf_type *t)
89{
90 json_writer_t *w = json_wtr;
91 int kind, safe_kind;
92
93 kind = BTF_INFO_KIND(t->info);
94 safe_kind = kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
95
96 if (json_output) {
97 jsonw_start_object(w);
98 jsonw_uint_field(w, "id", id);
99 jsonw_string_field(w, "kind", btf_kind_str[safe_kind]);
100 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
101 } else {
102 printf("[%u] %s '%s'", id, btf_kind_str[safe_kind],
103 btf_str(btf, t->name_off));
104 }
105
106 switch (BTF_INFO_KIND(t->info)) {
107 case BTF_KIND_INT: {
108 __u32 v = *(__u32 *)(t + 1);
109 const char *enc;
110
111 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
112
113 if (json_output) {
114 jsonw_uint_field(w, "size", t->size);
115 jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
116 jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
117 jsonw_string_field(w, "encoding", enc);
118 } else {
119 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
120 t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
121 enc);
122 }
123 break;
124 }
125 case BTF_KIND_PTR:
126 case BTF_KIND_CONST:
127 case BTF_KIND_VOLATILE:
128 case BTF_KIND_RESTRICT:
129 case BTF_KIND_TYPEDEF:
130 if (json_output)
131 jsonw_uint_field(w, "type_id", t->type);
132 else
133 printf(" type_id=%u", t->type);
134 break;
135 case BTF_KIND_ARRAY: {
136 const struct btf_array *arr = (const void *)(t + 1);
137
138 if (json_output) {
139 jsonw_uint_field(w, "type_id", arr->type);
140 jsonw_uint_field(w, "index_type_id", arr->index_type);
141 jsonw_uint_field(w, "nr_elems", arr->nelems);
142 } else {
143 printf(" type_id=%u index_type_id=%u nr_elems=%u",
144 arr->type, arr->index_type, arr->nelems);
145 }
146 break;
147 }
148 case BTF_KIND_STRUCT:
149 case BTF_KIND_UNION: {
150 const struct btf_member *m = (const void *)(t + 1);
151 __u16 vlen = BTF_INFO_VLEN(t->info);
152 int i;
153
154 if (json_output) {
155 jsonw_uint_field(w, "size", t->size);
156 jsonw_uint_field(w, "vlen", vlen);
157 jsonw_name(w, "members");
158 jsonw_start_array(w);
159 } else {
160 printf(" size=%u vlen=%u", t->size, vlen);
161 }
162 for (i = 0; i < vlen; i++, m++) {
163 const char *name = btf_str(btf, m->name_off);
164 __u32 bit_off, bit_sz;
165
166 if (BTF_INFO_KFLAG(t->info)) {
167 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
168 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
169 } else {
170 bit_off = m->offset;
171 bit_sz = 0;
172 }
173
174 if (json_output) {
175 jsonw_start_object(w);
176 jsonw_string_field(w, "name", name);
177 jsonw_uint_field(w, "type_id", m->type);
178 jsonw_uint_field(w, "bits_offset", bit_off);
179 if (bit_sz) {
180 jsonw_uint_field(w, "bitfield_size",
181 bit_sz);
182 }
183 jsonw_end_object(w);
184 } else {
185 printf("\n\t'%s' type_id=%u bits_offset=%u",
186 name, m->type, bit_off);
187 if (bit_sz)
188 printf(" bitfield_size=%u", bit_sz);
189 }
190 }
191 if (json_output)
192 jsonw_end_array(w);
193 break;
194 }
195 case BTF_KIND_ENUM: {
196 const struct btf_enum *v = (const void *)(t + 1);
197 __u16 vlen = BTF_INFO_VLEN(t->info);
198 int i;
199
200 if (json_output) {
201 jsonw_uint_field(w, "size", t->size);
202 jsonw_uint_field(w, "vlen", vlen);
203 jsonw_name(w, "values");
204 jsonw_start_array(w);
205 } else {
206 printf(" size=%u vlen=%u", t->size, vlen);
207 }
208 for (i = 0; i < vlen; i++, v++) {
209 const char *name = btf_str(btf, v->name_off);
210
211 if (json_output) {
212 jsonw_start_object(w);
213 jsonw_string_field(w, "name", name);
214 jsonw_uint_field(w, "val", v->val);
215 jsonw_end_object(w);
216 } else {
217 printf("\n\t'%s' val=%u", name, v->val);
218 }
219 }
220 if (json_output)
221 jsonw_end_array(w);
222 break;
223 }
224 case BTF_KIND_FWD: {
225 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
226 : "struct";
227
228 if (json_output)
229 jsonw_string_field(w, "fwd_kind", fwd_kind);
230 else
231 printf(" fwd_kind=%s", fwd_kind);
232 break;
233 }
234 case BTF_KIND_FUNC:
235 if (json_output)
236 jsonw_uint_field(w, "type_id", t->type);
237 else
238 printf(" type_id=%u", t->type);
239 break;
240 case BTF_KIND_FUNC_PROTO: {
241 const struct btf_param *p = (const void *)(t + 1);
242 __u16 vlen = BTF_INFO_VLEN(t->info);
243 int i;
244
245 if (json_output) {
246 jsonw_uint_field(w, "ret_type_id", t->type);
247 jsonw_uint_field(w, "vlen", vlen);
248 jsonw_name(w, "params");
249 jsonw_start_array(w);
250 } else {
251 printf(" ret_type_id=%u vlen=%u", t->type, vlen);
252 }
253 for (i = 0; i < vlen; i++, p++) {
254 const char *name = btf_str(btf, p->name_off);
255
256 if (json_output) {
257 jsonw_start_object(w);
258 jsonw_string_field(w, "name", name);
259 jsonw_uint_field(w, "type_id", p->type);
260 jsonw_end_object(w);
261 } else {
262 printf("\n\t'%s' type_id=%u", name, p->type);
263 }
264 }
265 if (json_output)
266 jsonw_end_array(w);
267 break;
268 }
269 case BTF_KIND_VAR: {
270 const struct btf_var *v = (const void *)(t + 1);
271 const char *linkage;
272
273 linkage = btf_var_linkage_str(v->linkage);
274
275 if (json_output) {
276 jsonw_uint_field(w, "type_id", t->type);
277 jsonw_string_field(w, "linkage", linkage);
278 } else {
279 printf(" type_id=%u, linkage=%s", t->type, linkage);
280 }
281 break;
282 }
283 case BTF_KIND_DATASEC: {
284 const struct btf_var_secinfo *v = (const void *)(t+1);
285 __u16 vlen = BTF_INFO_VLEN(t->info);
286 int i;
287
288 if (json_output) {
289 jsonw_uint_field(w, "size", t->size);
290 jsonw_uint_field(w, "vlen", vlen);
291 jsonw_name(w, "vars");
292 jsonw_start_array(w);
293 } else {
294 printf(" size=%u vlen=%u", t->size, vlen);
295 }
296 for (i = 0; i < vlen; i++, v++) {
297 if (json_output) {
298 jsonw_start_object(w);
299 jsonw_uint_field(w, "type_id", v->type);
300 jsonw_uint_field(w, "offset", v->offset);
301 jsonw_uint_field(w, "size", v->size);
302 jsonw_end_object(w);
303 } else {
304 printf("\n\ttype_id=%u offset=%u size=%u",
305 v->type, v->offset, v->size);
306 }
307 }
308 if (json_output)
309 jsonw_end_array(w);
310 break;
311 }
312 default:
313 break;
314 }
315
316 if (json_output)
317 jsonw_end_object(json_wtr);
318 else
319 printf("\n");
320
321 return 0;
322}
323
324static int dump_btf_raw(const struct btf *btf,
325 __u32 *root_type_ids, int root_type_cnt)
326{
327 const struct btf_type *t;
328 int i;
329
330 if (json_output) {
331 jsonw_start_object(json_wtr);
332 jsonw_name(json_wtr, "types");
333 jsonw_start_array(json_wtr);
334 }
335
336 if (root_type_cnt) {
337 for (i = 0; i < root_type_cnt; i++) {
338 t = btf__type_by_id(btf, root_type_ids[i]);
339 dump_btf_type(btf, root_type_ids[i], t);
340 }
341 } else {
342 int cnt = btf__get_nr_types(btf);
343
344 for (i = 1; i <= cnt; i++) {
345 t = btf__type_by_id(btf, i);
346 dump_btf_type(btf, i, t);
347 }
348 }
349
350 if (json_output) {
351 jsonw_end_array(json_wtr);
352 jsonw_end_object(json_wtr);
353 }
354 return 0;
355}
356
357static void __printf(2, 0) btf_dump_printf(void *ctx,
358 const char *fmt, va_list args)
359{
360 vfprintf(stdout, fmt, args);
361}
362
363static int dump_btf_c(const struct btf *btf,
364 __u32 *root_type_ids, int root_type_cnt)
365{
366 struct btf_dump *d;
367 int err = 0, i;
368
369 d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
370 if (IS_ERR(d))
371 return PTR_ERR(d);
372
373 if (root_type_cnt) {
374 for (i = 0; i < root_type_cnt; i++) {
375 err = btf_dump__dump_type(d, root_type_ids[i]);
376 if (err)
377 goto done;
378 }
379 } else {
380 int cnt = btf__get_nr_types(btf);
381
382 for (i = 1; i <= cnt; i++) {
383 err = btf_dump__dump_type(d, i);
384 if (err)
385 goto done;
386 }
387 }
388
389done:
390 btf_dump__free(d);
391 return err;
392}
393
394static struct btf *btf__parse_raw(const char *file)
395{
396 struct btf *btf;
397 struct stat st;
398 __u8 *buf;
399 FILE *f;
400
401 if (stat(file, &st))
402 return NULL;
403
404 f = fopen(file, "rb");
405 if (!f)
406 return NULL;
407
408 buf = malloc(st.st_size);
409 if (!buf) {
410 btf = ERR_PTR(-ENOMEM);
411 goto exit_close;
412 }
413
414 if ((size_t) st.st_size != fread(buf, 1, st.st_size, f)) {
415 btf = ERR_PTR(-EINVAL);
416 goto exit_free;
417 }
418
419 btf = btf__new(buf, st.st_size);
420
421exit_free:
422 free(buf);
423exit_close:
424 fclose(f);
425 return btf;
426}
427
428static bool is_btf_raw(const char *file)
429{
430 __u16 magic = 0;
431 int fd, nb_read;
432
433 fd = open(file, O_RDONLY);
434 if (fd < 0)
435 return false;
436
437 nb_read = read(fd, &magic, sizeof(magic));
438 close(fd);
439 return nb_read == sizeof(magic) && magic == BTF_MAGIC;
440}
441
442static int do_dump(int argc, char **argv)
443{
444 struct btf *btf = NULL;
445 __u32 root_type_ids[2];
446 int root_type_cnt = 0;
447 bool dump_c = false;
448 __u32 btf_id = -1;
449 const char *src;
450 int fd = -1;
451 int err;
452
453 if (!REQ_ARGS(2)) {
454 usage();
455 return -1;
456 }
457 src = GET_ARG();
458
459 if (is_prefix(src, "map")) {
460 struct bpf_map_info info = {};
461 __u32 len = sizeof(info);
462
463 if (!REQ_ARGS(2)) {
464 usage();
465 return -1;
466 }
467
468 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
469 if (fd < 0)
470 return -1;
471
472 btf_id = info.btf_id;
473 if (argc && is_prefix(*argv, "key")) {
474 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
475 NEXT_ARG();
476 } else if (argc && is_prefix(*argv, "value")) {
477 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
478 NEXT_ARG();
479 } else if (argc && is_prefix(*argv, "all")) {
480 NEXT_ARG();
481 } else if (argc && is_prefix(*argv, "kv")) {
482 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
483 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
484 NEXT_ARG();
485 } else {
486 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
487 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
488 }
489 } else if (is_prefix(src, "prog")) {
490 struct bpf_prog_info info = {};
491 __u32 len = sizeof(info);
492
493 if (!REQ_ARGS(2)) {
494 usage();
495 return -1;
496 }
497
498 fd = prog_parse_fd(&argc, &argv);
499 if (fd < 0)
500 return -1;
501
502 err = bpf_obj_get_info_by_fd(fd, &info, &len);
503 if (err) {
504 p_err("can't get prog info: %s", strerror(errno));
505 goto done;
506 }
507
508 btf_id = info.btf_id;
509 } else if (is_prefix(src, "id")) {
510 char *endptr;
511
512 btf_id = strtoul(*argv, &endptr, 0);
513 if (*endptr) {
514 p_err("can't parse %s as ID", *argv);
515 return -1;
516 }
517 NEXT_ARG();
518 } else if (is_prefix(src, "file")) {
519 if (is_btf_raw(*argv))
520 btf = btf__parse_raw(*argv);
521 else
522 btf = btf__parse_elf(*argv, NULL);
523
524 if (IS_ERR(btf)) {
525 err = PTR_ERR(btf);
526 btf = NULL;
527 p_err("failed to load BTF from %s: %s",
528 *argv, strerror(err));
529 goto done;
530 }
531 NEXT_ARG();
532 } else {
533 err = -1;
534 p_err("unrecognized BTF source specifier: '%s'", src);
535 goto done;
536 }
537
538 while (argc) {
539 if (is_prefix(*argv, "format")) {
540 NEXT_ARG();
541 if (argc < 1) {
542 p_err("expecting value for 'format' option\n");
543 goto done;
544 }
545 if (strcmp(*argv, "c") == 0) {
546 dump_c = true;
547 } else if (strcmp(*argv, "raw") == 0) {
548 dump_c = false;
549 } else {
550 p_err("unrecognized format specifier: '%s', possible values: raw, c",
551 *argv);
552 goto done;
553 }
554 NEXT_ARG();
555 } else {
556 p_err("unrecognized option: '%s'", *argv);
557 goto done;
558 }
559 }
560
561 if (!btf) {
562 err = btf__get_from_id(btf_id, &btf);
563 if (err) {
564 p_err("get btf by id (%u): %s", btf_id, strerror(err));
565 goto done;
566 }
567 if (!btf) {
568 err = ENOENT;
569 p_err("can't find btf with ID (%u)", btf_id);
570 goto done;
571 }
572 }
573
574 if (dump_c) {
575 if (json_output) {
576 p_err("JSON output for C-syntax dump is not supported");
577 err = -ENOTSUP;
578 goto done;
579 }
580 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
581 } else {
582 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
583 }
584
585done:
586 close(fd);
587 btf__free(btf);
588 return err;
589}
590
591static int btf_parse_fd(int *argc, char ***argv)
592{
593 unsigned int id;
594 char *endptr;
595 int fd;
596
597 if (!is_prefix(*argv[0], "id")) {
598 p_err("expected 'id', got: '%s'?", **argv);
599 return -1;
600 }
601 NEXT_ARGP();
602
603 id = strtoul(**argv, &endptr, 0);
604 if (*endptr) {
605 p_err("can't parse %s as ID", **argv);
606 return -1;
607 }
608 NEXT_ARGP();
609
610 fd = bpf_btf_get_fd_by_id(id);
611 if (fd < 0)
612 p_err("can't get BTF object by id (%u): %s",
613 id, strerror(errno));
614
615 return fd;
616}
617
618static void delete_btf_table(struct btf_attach_table *tab)
619{
620 struct btf_attach_point *obj;
621 struct hlist_node *tmp;
622
623 unsigned int bkt;
624
625 hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
626 hash_del(&obj->hash);
627 free(obj);
628 }
629}
630
631static int
632build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
633 void *info, __u32 *len)
634{
635 static const char * const names[] = {
636 [BPF_OBJ_UNKNOWN] = "unknown",
637 [BPF_OBJ_PROG] = "prog",
638 [BPF_OBJ_MAP] = "map",
639 };
640 struct btf_attach_point *obj_node;
641 __u32 btf_id, id = 0;
642 int err;
643 int fd;
644
645 while (true) {
646 switch (type) {
647 case BPF_OBJ_PROG:
648 err = bpf_prog_get_next_id(id, &id);
649 break;
650 case BPF_OBJ_MAP:
651 err = bpf_map_get_next_id(id, &id);
652 break;
653 default:
654 err = -1;
655 p_err("unexpected object type: %d", type);
656 goto err_free;
657 }
658 if (err) {
659 if (errno == ENOENT) {
660 err = 0;
661 break;
662 }
663 p_err("can't get next %s: %s%s", names[type],
664 strerror(errno),
665 errno == EINVAL ? " -- kernel too old?" : "");
666 goto err_free;
667 }
668
669 switch (type) {
670 case BPF_OBJ_PROG:
671 fd = bpf_prog_get_fd_by_id(id);
672 break;
673 case BPF_OBJ_MAP:
674 fd = bpf_map_get_fd_by_id(id);
675 break;
676 default:
677 err = -1;
678 p_err("unexpected object type: %d", type);
679 goto err_free;
680 }
681 if (fd < 0) {
682 if (errno == ENOENT)
683 continue;
684 p_err("can't get %s by id (%u): %s", names[type], id,
685 strerror(errno));
686 err = -1;
687 goto err_free;
688 }
689
690 memset(info, 0, *len);
691 err = bpf_obj_get_info_by_fd(fd, info, len);
692 close(fd);
693 if (err) {
694 p_err("can't get %s info: %s", names[type],
695 strerror(errno));
696 goto err_free;
697 }
698
699 switch (type) {
700 case BPF_OBJ_PROG:
701 btf_id = ((struct bpf_prog_info *)info)->btf_id;
702 break;
703 case BPF_OBJ_MAP:
704 btf_id = ((struct bpf_map_info *)info)->btf_id;
705 break;
706 default:
707 err = -1;
708 p_err("unexpected object type: %d", type);
709 goto err_free;
710 }
711 if (!btf_id)
712 continue;
713
714 obj_node = calloc(1, sizeof(*obj_node));
715 if (!obj_node) {
716 p_err("failed to allocate memory: %s", strerror(errno));
717 goto err_free;
718 }
719
720 obj_node->obj_id = id;
721 obj_node->btf_id = btf_id;
722 hash_add(tab->table, &obj_node->hash, obj_node->btf_id);
723 }
724
725 return 0;
726
727err_free:
728 delete_btf_table(tab);
729 return err;
730}
731
732static int
733build_btf_tables(struct btf_attach_table *btf_prog_table,
734 struct btf_attach_table *btf_map_table)
735{
736 struct bpf_prog_info prog_info;
737 __u32 prog_len = sizeof(prog_info);
738 struct bpf_map_info map_info;
739 __u32 map_len = sizeof(map_info);
740 int err = 0;
741
742 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
743 &prog_len);
744 if (err)
745 return err;
746
747 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
748 &map_len);
749 if (err) {
750 delete_btf_table(btf_prog_table);
751 return err;
752 }
753
754 return 0;
755}
756
757static void
758show_btf_plain(struct bpf_btf_info *info, int fd,
759 struct btf_attach_table *btf_prog_table,
760 struct btf_attach_table *btf_map_table)
761{
762 struct btf_attach_point *obj;
763 int n;
764
765 printf("%u: ", info->id);
766 printf("size %uB", info->btf_size);
767
768 n = 0;
769 hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) {
770 if (obj->btf_id == info->id)
771 printf("%s%u", n++ == 0 ? " prog_ids " : ",",
772 obj->obj_id);
773 }
774
775 n = 0;
776 hash_for_each_possible(btf_map_table->table, obj, hash, info->id) {
777 if (obj->btf_id == info->id)
778 printf("%s%u", n++ == 0 ? " map_ids " : ",",
779 obj->obj_id);
780 }
781
782 printf("\n");
783}
784
785static void
786show_btf_json(struct bpf_btf_info *info, int fd,
787 struct btf_attach_table *btf_prog_table,
788 struct btf_attach_table *btf_map_table)
789{
790 struct btf_attach_point *obj;
791
792 jsonw_start_object(json_wtr);
793 jsonw_uint_field(json_wtr, "id", info->id);
794 jsonw_uint_field(json_wtr, "size", info->btf_size);
795
796 jsonw_name(json_wtr, "prog_ids");
797 jsonw_start_array(json_wtr);
798 hash_for_each_possible(btf_prog_table->table, obj, hash,
799 info->id) {
800 if (obj->btf_id == info->id)
801 jsonw_uint(json_wtr, obj->obj_id);
802 }
803 jsonw_end_array(json_wtr);
804
805 jsonw_name(json_wtr, "map_ids");
806 jsonw_start_array(json_wtr);
807 hash_for_each_possible(btf_map_table->table, obj, hash,
808 info->id) {
809 if (obj->btf_id == info->id)
810 jsonw_uint(json_wtr, obj->obj_id);
811 }
812 jsonw_end_array(json_wtr);
813 jsonw_end_object(json_wtr);
814}
815
816static int
817show_btf(int fd, struct btf_attach_table *btf_prog_table,
818 struct btf_attach_table *btf_map_table)
819{
820 struct bpf_btf_info info = {};
821 __u32 len = sizeof(info);
822 int err;
823
824 err = bpf_obj_get_info_by_fd(fd, &info, &len);
825 if (err) {
826 p_err("can't get BTF object info: %s", strerror(errno));
827 return -1;
828 }
829
830 if (json_output)
831 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
832 else
833 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
834
835 return 0;
836}
837
838static int do_show(int argc, char **argv)
839{
840 struct btf_attach_table btf_prog_table;
841 struct btf_attach_table btf_map_table;
842 int err, fd = -1;
843 __u32 id = 0;
844
845 if (argc == 2) {
846 fd = btf_parse_fd(&argc, &argv);
847 if (fd < 0)
848 return -1;
849 }
850
851 if (argc) {
852 if (fd >= 0)
853 close(fd);
854 return BAD_ARG();
855 }
856
857 hash_init(btf_prog_table.table);
858 hash_init(btf_map_table.table);
859 err = build_btf_tables(&btf_prog_table, &btf_map_table);
860 if (err) {
861 if (fd >= 0)
862 close(fd);
863 return err;
864 }
865
866 if (fd >= 0) {
867 err = show_btf(fd, &btf_prog_table, &btf_map_table);
868 close(fd);
869 goto exit_free;
870 }
871
872 if (json_output)
873 jsonw_start_array(json_wtr);
874
875 while (true) {
876 err = bpf_btf_get_next_id(id, &id);
877 if (err) {
878 if (errno == ENOENT) {
879 err = 0;
880 break;
881 }
882 p_err("can't get next BTF object: %s%s",
883 strerror(errno),
884 errno == EINVAL ? " -- kernel too old?" : "");
885 err = -1;
886 break;
887 }
888
889 fd = bpf_btf_get_fd_by_id(id);
890 if (fd < 0) {
891 if (errno == ENOENT)
892 continue;
893 p_err("can't get BTF object by id (%u): %s",
894 id, strerror(errno));
895 err = -1;
896 break;
897 }
898
899 err = show_btf(fd, &btf_prog_table, &btf_map_table);
900 close(fd);
901 if (err)
902 break;
903 }
904
905 if (json_output)
906 jsonw_end_array(json_wtr);
907
908exit_free:
909 delete_btf_table(&btf_prog_table);
910 delete_btf_table(&btf_map_table);
911
912 return err;
913}
914
915static int do_help(int argc, char **argv)
916{
917 if (json_output) {
918 jsonw_null(json_wtr);
919 return 0;
920 }
921
922 fprintf(stderr,
923 "Usage: %s btf { show | list } [id BTF_ID]\n"
924 " %s btf dump BTF_SRC [format FORMAT]\n"
925 " %s btf help\n"
926 "\n"
927 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
928 " FORMAT := { raw | c }\n"
929 " " HELP_SPEC_MAP "\n"
930 " " HELP_SPEC_PROGRAM "\n"
931 " " HELP_SPEC_OPTIONS "\n"
932 "",
933 bin_name, bin_name, bin_name);
934
935 return 0;
936}
937
938static const struct cmd cmds[] = {
939 { "show", do_show },
940 { "list", do_show },
941 { "help", do_help },
942 { "dump", do_dump },
943 { 0 }
944};
945
946int do_btf(int argc, char **argv)
947{
948 return cmd_select(cmds, argc, argv, do_help);
949}
950