985610c3f19335f48d35fd9e6a9c663a8f3f8a6d
[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
19 #include "json_writer.h"
20 #include "main.h"
21
22 static 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",
39         [BTF_KIND_FLOAT]        = "FLOAT",
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         case BTF_KIND_FLOAT: {
332                 if (json_output)
333                         jsonw_uint_field(w, "size", t->size);
334                 else
335                         printf(" size=%u", t->size);
336                 break;
337         }
338         default:
339                 break;
340         }
341
342         if (json_output)
343                 jsonw_end_object(json_wtr);
344         else
345                 printf("\n");
346
347         return 0;
348 }
349
350 static int dump_btf_raw(const struct btf *btf,
351                         __u32 *root_type_ids, int root_type_cnt)
352 {
353         const struct btf_type *t;
354         int i;
355
356         if (json_output) {
357                 jsonw_start_object(json_wtr);
358                 jsonw_name(json_wtr, "types");
359                 jsonw_start_array(json_wtr);
360         }
361
362         if (root_type_cnt) {
363                 for (i = 0; i < root_type_cnt; i++) {
364                         t = btf__type_by_id(btf, root_type_ids[i]);
365                         dump_btf_type(btf, root_type_ids[i], t);
366                 }
367         } else {
368                 const struct btf *base;
369                 int cnt = btf__get_nr_types(btf);
370                 int start_id = 1;
371
372                 base = btf__base_btf(btf);
373                 if (base)
374                         start_id = btf__get_nr_types(base) + 1;
375
376                 for (i = start_id; i <= cnt; i++) {
377                         t = btf__type_by_id(btf, i);
378                         dump_btf_type(btf, i, t);
379                 }
380         }
381
382         if (json_output) {
383                 jsonw_end_array(json_wtr);
384                 jsonw_end_object(json_wtr);
385         }
386         return 0;
387 }
388
389 static void __printf(2, 0) btf_dump_printf(void *ctx,
390                                            const char *fmt, va_list args)
391 {
392         vfprintf(stdout, fmt, args);
393 }
394
395 static int dump_btf_c(const struct btf *btf,
396                       __u32 *root_type_ids, int root_type_cnt)
397 {
398         struct btf_dump *d;
399         int err = 0, i;
400
401         d = btf_dump__new(btf, NULL, NULL, btf_dump_printf);
402         if (IS_ERR(d))
403                 return PTR_ERR(d);
404
405         printf("#ifndef __VMLINUX_H__\n");
406         printf("#define __VMLINUX_H__\n");
407         printf("\n");
408         printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
409         printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
410         printf("#endif\n\n");
411
412         if (root_type_cnt) {
413                 for (i = 0; i < root_type_cnt; i++) {
414                         err = btf_dump__dump_type(d, root_type_ids[i]);
415                         if (err)
416                                 goto done;
417                 }
418         } else {
419                 int cnt = btf__get_nr_types(btf);
420
421                 for (i = 1; i <= cnt; i++) {
422                         err = btf_dump__dump_type(d, i);
423                         if (err)
424                                 goto done;
425                 }
426         }
427
428         printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
429         printf("#pragma clang attribute pop\n");
430         printf("#endif\n");
431         printf("\n");
432         printf("#endif /* __VMLINUX_H__ */\n");
433
434 done:
435         btf_dump__free(d);
436         return err;
437 }
438
439 static int do_dump(int argc, char **argv)
440 {
441         struct btf *btf = NULL, *base = NULL;
442         __u32 root_type_ids[2];
443         int root_type_cnt = 0;
444         bool dump_c = false;
445         __u32 btf_id = -1;
446         const char *src;
447         int fd = -1;
448         int err;
449
450         if (!REQ_ARGS(2)) {
451                 usage();
452                 return -1;
453         }
454         src = GET_ARG();
455         if (is_prefix(src, "map")) {
456                 struct bpf_map_info info = {};
457                 __u32 len = sizeof(info);
458
459                 if (!REQ_ARGS(2)) {
460                         usage();
461                         return -1;
462                 }
463
464                 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
465                 if (fd < 0)
466                         return -1;
467
468                 btf_id = info.btf_id;
469                 if (argc && is_prefix(*argv, "key")) {
470                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
471                         NEXT_ARG();
472                 } else if (argc && is_prefix(*argv, "value")) {
473                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
474                         NEXT_ARG();
475                 } else if (argc && is_prefix(*argv, "all")) {
476                         NEXT_ARG();
477                 } else if (argc && is_prefix(*argv, "kv")) {
478                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
479                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
480                         NEXT_ARG();
481                 } else {
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                 }
485         } else if (is_prefix(src, "prog")) {
486                 struct bpf_prog_info info = {};
487                 __u32 len = sizeof(info);
488
489                 if (!REQ_ARGS(2)) {
490                         usage();
491                         return -1;
492                 }
493
494                 fd = prog_parse_fd(&argc, &argv);
495                 if (fd < 0)
496                         return -1;
497
498                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
499                 if (err) {
500                         p_err("can't get prog info: %s", strerror(errno));
501                         goto done;
502                 }
503
504                 btf_id = info.btf_id;
505         } else if (is_prefix(src, "id")) {
506                 char *endptr;
507
508                 btf_id = strtoul(*argv, &endptr, 0);
509                 if (*endptr) {
510                         p_err("can't parse %s as ID", *argv);
511                         return -1;
512                 }
513                 NEXT_ARG();
514         } else if (is_prefix(src, "file")) {
515                 const char sysfs_prefix[] = "/sys/kernel/btf/";
516                 const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
517
518                 if (!base_btf &&
519                     strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
520                     strcmp(*argv, sysfs_vmlinux) != 0) {
521                         base = btf__parse(sysfs_vmlinux, NULL);
522                         if (libbpf_get_error(base)) {
523                                 p_err("failed to parse vmlinux BTF at '%s': %ld\n",
524                                       sysfs_vmlinux, libbpf_get_error(base));
525                                 base = NULL;
526                         }
527                 }
528
529                 btf = btf__parse_split(*argv, base ?: base_btf);
530                 if (IS_ERR(btf)) {
531                         err = -PTR_ERR(btf);
532                         btf = NULL;
533                         p_err("failed to load BTF from %s: %s",
534                               *argv, strerror(err));
535                         goto done;
536                 }
537                 NEXT_ARG();
538         } else {
539                 err = -1;
540                 p_err("unrecognized BTF source specifier: '%s'", src);
541                 goto done;
542         }
543
544         while (argc) {
545                 if (is_prefix(*argv, "format")) {
546                         NEXT_ARG();
547                         if (argc < 1) {
548                                 p_err("expecting value for 'format' option\n");
549                                 goto done;
550                         }
551                         if (strcmp(*argv, "c") == 0) {
552                                 dump_c = true;
553                         } else if (strcmp(*argv, "raw") == 0) {
554                                 dump_c = false;
555                         } else {
556                                 p_err("unrecognized format specifier: '%s', possible values: raw, c",
557                                       *argv);
558                                 goto done;
559                         }
560                         NEXT_ARG();
561                 } else {
562                         p_err("unrecognized option: '%s'", *argv);
563                         goto done;
564                 }
565         }
566
567         if (!btf) {
568                 err = btf__get_from_id(btf_id, &btf);
569                 if (err) {
570                         p_err("get btf by id (%u): %s", btf_id, strerror(err));
571                         goto done;
572                 }
573                 if (!btf) {
574                         err = -ENOENT;
575                         p_err("can't find btf with ID (%u)", btf_id);
576                         goto done;
577                 }
578         }
579
580         if (dump_c) {
581                 if (json_output) {
582                         p_err("JSON output for C-syntax dump is not supported");
583                         err = -ENOTSUP;
584                         goto done;
585                 }
586                 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
587         } else {
588                 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
589         }
590
591 done:
592         close(fd);
593         btf__free(btf);
594         btf__free(base);
595         return err;
596 }
597
598 static int btf_parse_fd(int *argc, char ***argv)
599 {
600         unsigned int id;
601         char *endptr;
602         int fd;
603
604         if (!is_prefix(*argv[0], "id")) {
605                 p_err("expected 'id', got: '%s'?", **argv);
606                 return -1;
607         }
608         NEXT_ARGP();
609
610         id = strtoul(**argv, &endptr, 0);
611         if (*endptr) {
612                 p_err("can't parse %s as ID", **argv);
613                 return -1;
614         }
615         NEXT_ARGP();
616
617         fd = bpf_btf_get_fd_by_id(id);
618         if (fd < 0)
619                 p_err("can't get BTF object by id (%u): %s",
620                       id, strerror(errno));
621
622         return fd;
623 }
624
625 static void delete_btf_table(struct btf_attach_table *tab)
626 {
627         struct btf_attach_point *obj;
628         struct hlist_node *tmp;
629
630         unsigned int bkt;
631
632         hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
633                 hash_del(&obj->hash);
634                 free(obj);
635         }
636 }
637
638 static int
639 build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type,
640                      void *info, __u32 *len)
641 {
642         static const char * const names[] = {
643                 [BPF_OBJ_UNKNOWN]       = "unknown",
644                 [BPF_OBJ_PROG]          = "prog",
645                 [BPF_OBJ_MAP]           = "map",
646         };
647         struct btf_attach_point *obj_node;
648         __u32 btf_id, id = 0;
649         int err;
650         int fd;
651
652         while (true) {
653                 switch (type) {
654                 case BPF_OBJ_PROG:
655                         err = bpf_prog_get_next_id(id, &id);
656                         break;
657                 case BPF_OBJ_MAP:
658                         err = bpf_map_get_next_id(id, &id);
659                         break;
660                 default:
661                         err = -1;
662                         p_err("unexpected object type: %d", type);
663                         goto err_free;
664                 }
665                 if (err) {
666                         if (errno == ENOENT) {
667                                 err = 0;
668                                 break;
669                         }
670                         p_err("can't get next %s: %s%s", names[type],
671                               strerror(errno),
672                               errno == EINVAL ? " -- kernel too old?" : "");
673                         goto err_free;
674                 }
675
676                 switch (type) {
677                 case BPF_OBJ_PROG:
678                         fd = bpf_prog_get_fd_by_id(id);
679                         break;
680                 case BPF_OBJ_MAP:
681                         fd = bpf_map_get_fd_by_id(id);
682                         break;
683                 default:
684                         err = -1;
685                         p_err("unexpected object type: %d", type);
686                         goto err_free;
687                 }
688                 if (fd < 0) {
689                         if (errno == ENOENT)
690                                 continue;
691                         p_err("can't get %s by id (%u): %s", names[type], id,
692                               strerror(errno));
693                         err = -1;
694                         goto err_free;
695                 }
696
697                 memset(info, 0, *len);
698                 err = bpf_obj_get_info_by_fd(fd, info, len);
699                 close(fd);
700                 if (err) {
701                         p_err("can't get %s info: %s", names[type],
702                               strerror(errno));
703                         goto err_free;
704                 }
705
706                 switch (type) {
707                 case BPF_OBJ_PROG:
708                         btf_id = ((struct bpf_prog_info *)info)->btf_id;
709                         break;
710                 case BPF_OBJ_MAP:
711                         btf_id = ((struct bpf_map_info *)info)->btf_id;
712                         break;
713                 default:
714                         err = -1;
715                         p_err("unexpected object type: %d", type);
716                         goto err_free;
717                 }
718                 if (!btf_id)
719                         continue;
720
721                 obj_node = calloc(1, sizeof(*obj_node));
722                 if (!obj_node) {
723                         p_err("failed to allocate memory: %s", strerror(errno));
724                         err = -ENOMEM;
725                         goto err_free;
726                 }
727
728                 obj_node->obj_id = id;
729                 obj_node->btf_id = btf_id;
730                 hash_add(tab->table, &obj_node->hash, obj_node->btf_id);
731         }
732
733         return 0;
734
735 err_free:
736         delete_btf_table(tab);
737         return err;
738 }
739
740 static int
741 build_btf_tables(struct btf_attach_table *btf_prog_table,
742                  struct btf_attach_table *btf_map_table)
743 {
744         struct bpf_prog_info prog_info;
745         __u32 prog_len = sizeof(prog_info);
746         struct bpf_map_info map_info;
747         __u32 map_len = sizeof(map_info);
748         int err = 0;
749
750         err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
751                                    &prog_len);
752         if (err)
753                 return err;
754
755         err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
756                                    &map_len);
757         if (err) {
758                 delete_btf_table(btf_prog_table);
759                 return err;
760         }
761
762         return 0;
763 }
764
765 static void
766 show_btf_plain(struct bpf_btf_info *info, int fd,
767                struct btf_attach_table *btf_prog_table,
768                struct btf_attach_table *btf_map_table)
769 {
770         struct btf_attach_point *obj;
771         const char *name = u64_to_ptr(info->name);
772         int n;
773
774         printf("%u: ", info->id);
775         if (info->kernel_btf)
776                 printf("name [%s]  ", name);
777         else if (name && name[0])
778                 printf("name %s  ", name);
779         else
780                 printf("name <anon>  ");
781         printf("size %uB", info->btf_size);
782
783         n = 0;
784         hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) {
785                 if (obj->btf_id == info->id)
786                         printf("%s%u", n++ == 0 ? "  prog_ids " : ",",
787                                obj->obj_id);
788         }
789
790         n = 0;
791         hash_for_each_possible(btf_map_table->table, obj, hash, info->id) {
792                 if (obj->btf_id == info->id)
793                         printf("%s%u", n++ == 0 ? "  map_ids " : ",",
794                                obj->obj_id);
795         }
796         emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
797
798         printf("\n");
799 }
800
801 static void
802 show_btf_json(struct bpf_btf_info *info, int fd,
803               struct btf_attach_table *btf_prog_table,
804               struct btf_attach_table *btf_map_table)
805 {
806         struct btf_attach_point *obj;
807         const char *name = u64_to_ptr(info->name);
808
809         jsonw_start_object(json_wtr);   /* btf object */
810         jsonw_uint_field(json_wtr, "id", info->id);
811         jsonw_uint_field(json_wtr, "size", info->btf_size);
812
813         jsonw_name(json_wtr, "prog_ids");
814         jsonw_start_array(json_wtr);    /* prog_ids */
815         hash_for_each_possible(btf_prog_table->table, obj, hash,
816                                info->id) {
817                 if (obj->btf_id == info->id)
818                         jsonw_uint(json_wtr, obj->obj_id);
819         }
820         jsonw_end_array(json_wtr);      /* prog_ids */
821
822         jsonw_name(json_wtr, "map_ids");
823         jsonw_start_array(json_wtr);    /* map_ids */
824         hash_for_each_possible(btf_map_table->table, obj, hash,
825                                info->id) {
826                 if (obj->btf_id == info->id)
827                         jsonw_uint(json_wtr, obj->obj_id);
828         }
829         jsonw_end_array(json_wtr);      /* map_ids */
830
831         emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */
832
833         jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
834
835         if (name && name[0])
836                 jsonw_string_field(json_wtr, "name", name);
837
838         jsonw_end_object(json_wtr);     /* btf object */
839 }
840
841 static int
842 show_btf(int fd, struct btf_attach_table *btf_prog_table,
843          struct btf_attach_table *btf_map_table)
844 {
845         struct bpf_btf_info info;
846         __u32 len = sizeof(info);
847         char name[64];
848         int err;
849
850         memset(&info, 0, sizeof(info));
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         /* if kernel support emitting BTF object name, pass name pointer */
857         if (info.name_len) {
858                 memset(&info, 0, sizeof(info));
859                 info.name_len = sizeof(name);
860                 info.name = ptr_to_u64(name);
861                 len = sizeof(info);
862
863                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
864                 if (err) {
865                         p_err("can't get BTF object info: %s", strerror(errno));
866                         return -1;
867                 }
868         }
869
870         if (json_output)
871                 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
872         else
873                 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
874
875         return 0;
876 }
877
878 static int do_show(int argc, char **argv)
879 {
880         struct btf_attach_table btf_prog_table;
881         struct btf_attach_table btf_map_table;
882         int err, fd = -1;
883         __u32 id = 0;
884
885         if (argc == 2) {
886                 fd = btf_parse_fd(&argc, &argv);
887                 if (fd < 0)
888                         return -1;
889         }
890
891         if (argc) {
892                 if (fd >= 0)
893                         close(fd);
894                 return BAD_ARG();
895         }
896
897         hash_init(btf_prog_table.table);
898         hash_init(btf_map_table.table);
899         err = build_btf_tables(&btf_prog_table, &btf_map_table);
900         if (err) {
901                 if (fd >= 0)
902                         close(fd);
903                 return err;
904         }
905         build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
906
907         if (fd >= 0) {
908                 err = show_btf(fd, &btf_prog_table, &btf_map_table);
909                 close(fd);
910                 goto exit_free;
911         }
912
913         if (json_output)
914                 jsonw_start_array(json_wtr);    /* root array */
915
916         while (true) {
917                 err = bpf_btf_get_next_id(id, &id);
918                 if (err) {
919                         if (errno == ENOENT) {
920                                 err = 0;
921                                 break;
922                         }
923                         p_err("can't get next BTF object: %s%s",
924                               strerror(errno),
925                               errno == EINVAL ? " -- kernel too old?" : "");
926                         err = -1;
927                         break;
928                 }
929
930                 fd = bpf_btf_get_fd_by_id(id);
931                 if (fd < 0) {
932                         if (errno == ENOENT)
933                                 continue;
934                         p_err("can't get BTF object by id (%u): %s",
935                               id, strerror(errno));
936                         err = -1;
937                         break;
938                 }
939
940                 err = show_btf(fd, &btf_prog_table, &btf_map_table);
941                 close(fd);
942                 if (err)
943                         break;
944         }
945
946         if (json_output)
947                 jsonw_end_array(json_wtr);      /* root array */
948
949 exit_free:
950         delete_btf_table(&btf_prog_table);
951         delete_btf_table(&btf_map_table);
952         delete_obj_refs_table(&refs_table);
953
954         return err;
955 }
956
957 static int do_help(int argc, char **argv)
958 {
959         if (json_output) {
960                 jsonw_null(json_wtr);
961                 return 0;
962         }
963
964         fprintf(stderr,
965                 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
966                 "       %1$s %2$s dump BTF_SRC [format FORMAT]\n"
967                 "       %1$s %2$s help\n"
968                 "\n"
969                 "       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
970                 "       FORMAT  := { raw | c }\n"
971                 "       " HELP_SPEC_MAP "\n"
972                 "       " HELP_SPEC_PROGRAM "\n"
973                 "       " HELP_SPEC_OPTIONS "\n"
974                 "",
975                 bin_name, "btf");
976
977         return 0;
978 }
979
980 static const struct cmd cmds[] = {
981         { "show",       do_show },
982         { "list",       do_show },
983         { "help",       do_help },
984         { "dump",       do_dump },
985         { 0 }
986 };
987
988 int do_btf(int argc, char **argv)
989 {
990         return cmd_select(cmds, argc, argv, do_help);
991 }