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