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