GNU Linux-libre 6.9.1-gnu
[releases.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 <linux/btf.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14
15 #include <bpf/bpf.h>
16 #include <bpf/btf.h>
17 #include <bpf/hashmap.h>
18 #include <bpf/libbpf.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         [BTF_KIND_FLOAT]        = "FLOAT",
41         [BTF_KIND_DECL_TAG]     = "DECL_TAG",
42         [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
43         [BTF_KIND_ENUM64]       = "ENUM64",
44 };
45
46 static const char *btf_int_enc_str(__u8 encoding)
47 {
48         switch (encoding) {
49         case 0:
50                 return "(none)";
51         case BTF_INT_SIGNED:
52                 return "SIGNED";
53         case BTF_INT_CHAR:
54                 return "CHAR";
55         case BTF_INT_BOOL:
56                 return "BOOL";
57         default:
58                 return "UNKN";
59         }
60 }
61
62 static const char *btf_var_linkage_str(__u32 linkage)
63 {
64         switch (linkage) {
65         case BTF_VAR_STATIC:
66                 return "static";
67         case BTF_VAR_GLOBAL_ALLOCATED:
68                 return "global";
69         case BTF_VAR_GLOBAL_EXTERN:
70                 return "extern";
71         default:
72                 return "(unknown)";
73         }
74 }
75
76 static const char *btf_func_linkage_str(const struct btf_type *t)
77 {
78         switch (btf_vlen(t)) {
79         case BTF_FUNC_STATIC:
80                 return "static";
81         case BTF_FUNC_GLOBAL:
82                 return "global";
83         case BTF_FUNC_EXTERN:
84                 return "extern";
85         default:
86                 return "(unknown)";
87         }
88 }
89
90 static const char *btf_str(const struct btf *btf, __u32 off)
91 {
92         if (!off)
93                 return "(anon)";
94         return btf__name_by_offset(btf, off) ? : "(invalid)";
95 }
96
97 static int btf_kind_safe(int kind)
98 {
99         return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
100 }
101
102 static int dump_btf_type(const struct btf *btf, __u32 id,
103                          const struct btf_type *t)
104 {
105         json_writer_t *w = json_wtr;
106         int kind = btf_kind(t);
107
108         if (json_output) {
109                 jsonw_start_object(w);
110                 jsonw_uint_field(w, "id", id);
111                 jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
112                 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
113         } else {
114                 printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
115                        btf_str(btf, t->name_off));
116         }
117
118         switch (kind) {
119         case BTF_KIND_INT: {
120                 __u32 v = *(__u32 *)(t + 1);
121                 const char *enc;
122
123                 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
124
125                 if (json_output) {
126                         jsonw_uint_field(w, "size", t->size);
127                         jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
128                         jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
129                         jsonw_string_field(w, "encoding", enc);
130                 } else {
131                         printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
132                                t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
133                                enc);
134                 }
135                 break;
136         }
137         case BTF_KIND_PTR:
138         case BTF_KIND_CONST:
139         case BTF_KIND_VOLATILE:
140         case BTF_KIND_RESTRICT:
141         case BTF_KIND_TYPEDEF:
142         case BTF_KIND_TYPE_TAG:
143                 if (json_output)
144                         jsonw_uint_field(w, "type_id", t->type);
145                 else
146                         printf(" type_id=%u", t->type);
147                 break;
148         case BTF_KIND_ARRAY: {
149                 const struct btf_array *arr = (const void *)(t + 1);
150
151                 if (json_output) {
152                         jsonw_uint_field(w, "type_id", arr->type);
153                         jsonw_uint_field(w, "index_type_id", arr->index_type);
154                         jsonw_uint_field(w, "nr_elems", arr->nelems);
155                 } else {
156                         printf(" type_id=%u index_type_id=%u nr_elems=%u",
157                                arr->type, arr->index_type, arr->nelems);
158                 }
159                 break;
160         }
161         case BTF_KIND_STRUCT:
162         case BTF_KIND_UNION: {
163                 const struct btf_member *m = (const void *)(t + 1);
164                 __u16 vlen = BTF_INFO_VLEN(t->info);
165                 int i;
166
167                 if (json_output) {
168                         jsonw_uint_field(w, "size", t->size);
169                         jsonw_uint_field(w, "vlen", vlen);
170                         jsonw_name(w, "members");
171                         jsonw_start_array(w);
172                 } else {
173                         printf(" size=%u vlen=%u", t->size, vlen);
174                 }
175                 for (i = 0; i < vlen; i++, m++) {
176                         const char *name = btf_str(btf, m->name_off);
177                         __u32 bit_off, bit_sz;
178
179                         if (BTF_INFO_KFLAG(t->info)) {
180                                 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
181                                 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
182                         } else {
183                                 bit_off = m->offset;
184                                 bit_sz = 0;
185                         }
186
187                         if (json_output) {
188                                 jsonw_start_object(w);
189                                 jsonw_string_field(w, "name", name);
190                                 jsonw_uint_field(w, "type_id", m->type);
191                                 jsonw_uint_field(w, "bits_offset", bit_off);
192                                 if (bit_sz) {
193                                         jsonw_uint_field(w, "bitfield_size",
194                                                          bit_sz);
195                                 }
196                                 jsonw_end_object(w);
197                         } else {
198                                 printf("\n\t'%s' type_id=%u bits_offset=%u",
199                                        name, m->type, bit_off);
200                                 if (bit_sz)
201                                         printf(" bitfield_size=%u", bit_sz);
202                         }
203                 }
204                 if (json_output)
205                         jsonw_end_array(w);
206                 break;
207         }
208         case BTF_KIND_ENUM: {
209                 const struct btf_enum *v = (const void *)(t + 1);
210                 __u16 vlen = BTF_INFO_VLEN(t->info);
211                 const char *encoding;
212                 int i;
213
214                 encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
215                 if (json_output) {
216                         jsonw_string_field(w, "encoding", encoding);
217                         jsonw_uint_field(w, "size", t->size);
218                         jsonw_uint_field(w, "vlen", vlen);
219                         jsonw_name(w, "values");
220                         jsonw_start_array(w);
221                 } else {
222                         printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
223                 }
224                 for (i = 0; i < vlen; i++, v++) {
225                         const char *name = btf_str(btf, v->name_off);
226
227                         if (json_output) {
228                                 jsonw_start_object(w);
229                                 jsonw_string_field(w, "name", name);
230                                 if (btf_kflag(t))
231                                         jsonw_int_field(w, "val", v->val);
232                                 else
233                                         jsonw_uint_field(w, "val", v->val);
234                                 jsonw_end_object(w);
235                         } else {
236                                 if (btf_kflag(t))
237                                         printf("\n\t'%s' val=%d", name, v->val);
238                                 else
239                                         printf("\n\t'%s' val=%u", name, v->val);
240                         }
241                 }
242                 if (json_output)
243                         jsonw_end_array(w);
244                 break;
245         }
246         case BTF_KIND_ENUM64: {
247                 const struct btf_enum64 *v = btf_enum64(t);
248                 __u16 vlen = btf_vlen(t);
249                 const char *encoding;
250                 int i;
251
252                 encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
253                 if (json_output) {
254                         jsonw_string_field(w, "encoding", encoding);
255                         jsonw_uint_field(w, "size", t->size);
256                         jsonw_uint_field(w, "vlen", vlen);
257                         jsonw_name(w, "values");
258                         jsonw_start_array(w);
259                 } else {
260                         printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
261                 }
262                 for (i = 0; i < vlen; i++, v++) {
263                         const char *name = btf_str(btf, v->name_off);
264                         __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
265
266                         if (json_output) {
267                                 jsonw_start_object(w);
268                                 jsonw_string_field(w, "name", name);
269                                 if (btf_kflag(t))
270                                         jsonw_int_field(w, "val", val);
271                                 else
272                                         jsonw_uint_field(w, "val", val);
273                                 jsonw_end_object(w);
274                         } else {
275                                 if (btf_kflag(t))
276                                         printf("\n\t'%s' val=%lldLL", name,
277                                                (unsigned long long)val);
278                                 else
279                                         printf("\n\t'%s' val=%lluULL", name,
280                                                (unsigned long long)val);
281                         }
282                 }
283                 if (json_output)
284                         jsonw_end_array(w);
285                 break;
286         }
287         case BTF_KIND_FWD: {
288                 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
289                                                                : "struct";
290
291                 if (json_output)
292                         jsonw_string_field(w, "fwd_kind", fwd_kind);
293                 else
294                         printf(" fwd_kind=%s", fwd_kind);
295                 break;
296         }
297         case BTF_KIND_FUNC: {
298                 const char *linkage = btf_func_linkage_str(t);
299
300                 if (json_output) {
301                         jsonw_uint_field(w, "type_id", t->type);
302                         jsonw_string_field(w, "linkage", linkage);
303                 } else {
304                         printf(" type_id=%u linkage=%s", t->type, linkage);
305                 }
306                 break;
307         }
308         case BTF_KIND_FUNC_PROTO: {
309                 const struct btf_param *p = (const void *)(t + 1);
310                 __u16 vlen = BTF_INFO_VLEN(t->info);
311                 int i;
312
313                 if (json_output) {
314                         jsonw_uint_field(w, "ret_type_id", t->type);
315                         jsonw_uint_field(w, "vlen", vlen);
316                         jsonw_name(w, "params");
317                         jsonw_start_array(w);
318                 } else {
319                         printf(" ret_type_id=%u vlen=%u", t->type, vlen);
320                 }
321                 for (i = 0; i < vlen; i++, p++) {
322                         const char *name = btf_str(btf, p->name_off);
323
324                         if (json_output) {
325                                 jsonw_start_object(w);
326                                 jsonw_string_field(w, "name", name);
327                                 jsonw_uint_field(w, "type_id", p->type);
328                                 jsonw_end_object(w);
329                         } else {
330                                 printf("\n\t'%s' type_id=%u", name, p->type);
331                         }
332                 }
333                 if (json_output)
334                         jsonw_end_array(w);
335                 break;
336         }
337         case BTF_KIND_VAR: {
338                 const struct btf_var *v = (const void *)(t + 1);
339                 const char *linkage;
340
341                 linkage = btf_var_linkage_str(v->linkage);
342
343                 if (json_output) {
344                         jsonw_uint_field(w, "type_id", t->type);
345                         jsonw_string_field(w, "linkage", linkage);
346                 } else {
347                         printf(" type_id=%u, linkage=%s", t->type, linkage);
348                 }
349                 break;
350         }
351         case BTF_KIND_DATASEC: {
352                 const struct btf_var_secinfo *v = (const void *)(t + 1);
353                 const struct btf_type *vt;
354                 __u16 vlen = BTF_INFO_VLEN(t->info);
355                 int i;
356
357                 if (json_output) {
358                         jsonw_uint_field(w, "size", t->size);
359                         jsonw_uint_field(w, "vlen", vlen);
360                         jsonw_name(w, "vars");
361                         jsonw_start_array(w);
362                 } else {
363                         printf(" size=%u vlen=%u", t->size, vlen);
364                 }
365                 for (i = 0; i < vlen; i++, v++) {
366                         if (json_output) {
367                                 jsonw_start_object(w);
368                                 jsonw_uint_field(w, "type_id", v->type);
369                                 jsonw_uint_field(w, "offset", v->offset);
370                                 jsonw_uint_field(w, "size", v->size);
371                                 jsonw_end_object(w);
372                         } else {
373                                 printf("\n\ttype_id=%u offset=%u size=%u",
374                                        v->type, v->offset, v->size);
375
376                                 if (v->type < btf__type_cnt(btf)) {
377                                         vt = btf__type_by_id(btf, v->type);
378                                         printf(" (%s '%s')",
379                                                btf_kind_str[btf_kind_safe(btf_kind(vt))],
380                                                btf_str(btf, vt->name_off));
381                                 }
382                         }
383                 }
384                 if (json_output)
385                         jsonw_end_array(w);
386                 break;
387         }
388         case BTF_KIND_FLOAT: {
389                 if (json_output)
390                         jsonw_uint_field(w, "size", t->size);
391                 else
392                         printf(" size=%u", t->size);
393                 break;
394         }
395         case BTF_KIND_DECL_TAG: {
396                 const struct btf_decl_tag *tag = (const void *)(t + 1);
397
398                 if (json_output) {
399                         jsonw_uint_field(w, "type_id", t->type);
400                         jsonw_int_field(w, "component_idx", tag->component_idx);
401                 } else {
402                         printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
403                 }
404                 break;
405         }
406         default:
407                 break;
408         }
409
410         if (json_output)
411                 jsonw_end_object(json_wtr);
412         else
413                 printf("\n");
414
415         return 0;
416 }
417
418 static int dump_btf_raw(const struct btf *btf,
419                         __u32 *root_type_ids, int root_type_cnt)
420 {
421         const struct btf_type *t;
422         int i;
423
424         if (json_output) {
425                 jsonw_start_object(json_wtr);
426                 jsonw_name(json_wtr, "types");
427                 jsonw_start_array(json_wtr);
428         }
429
430         if (root_type_cnt) {
431                 for (i = 0; i < root_type_cnt; i++) {
432                         t = btf__type_by_id(btf, root_type_ids[i]);
433                         dump_btf_type(btf, root_type_ids[i], t);
434                 }
435         } else {
436                 const struct btf *base;
437                 int cnt = btf__type_cnt(btf);
438                 int start_id = 1;
439
440                 base = btf__base_btf(btf);
441                 if (base)
442                         start_id = btf__type_cnt(base);
443
444                 for (i = start_id; i < cnt; i++) {
445                         t = btf__type_by_id(btf, i);
446                         dump_btf_type(btf, i, t);
447                 }
448         }
449
450         if (json_output) {
451                 jsonw_end_array(json_wtr);
452                 jsonw_end_object(json_wtr);
453         }
454         return 0;
455 }
456
457 static void __printf(2, 0) btf_dump_printf(void *ctx,
458                                            const char *fmt, va_list args)
459 {
460         vfprintf(stdout, fmt, args);
461 }
462
463 static int dump_btf_c(const struct btf *btf,
464                       __u32 *root_type_ids, int root_type_cnt)
465 {
466         struct btf_dump *d;
467         int err = 0, i;
468
469         d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
470         if (!d)
471                 return -errno;
472
473         printf("#ifndef __VMLINUX_H__\n");
474         printf("#define __VMLINUX_H__\n");
475         printf("\n");
476         printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
477         printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
478         printf("#endif\n\n");
479
480         if (root_type_cnt) {
481                 for (i = 0; i < root_type_cnt; i++) {
482                         err = btf_dump__dump_type(d, root_type_ids[i]);
483                         if (err)
484                                 goto done;
485                 }
486         } else {
487                 int cnt = btf__type_cnt(btf);
488
489                 for (i = 1; i < cnt; i++) {
490                         err = btf_dump__dump_type(d, i);
491                         if (err)
492                                 goto done;
493                 }
494         }
495
496         printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
497         printf("#pragma clang attribute pop\n");
498         printf("#endif\n");
499         printf("\n");
500         printf("#endif /* __VMLINUX_H__ */\n");
501
502 done:
503         btf_dump__free(d);
504         return err;
505 }
506
507 static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
508
509 static struct btf *get_vmlinux_btf_from_sysfs(void)
510 {
511         struct btf *base;
512
513         base = btf__parse(sysfs_vmlinux, NULL);
514         if (!base)
515                 p_err("failed to parse vmlinux BTF at '%s': %d\n",
516                       sysfs_vmlinux, -errno);
517
518         return base;
519 }
520
521 #define BTF_NAME_BUFF_LEN 64
522
523 static bool btf_is_kernel_module(__u32 btf_id)
524 {
525         struct bpf_btf_info btf_info = {};
526         char btf_name[BTF_NAME_BUFF_LEN];
527         int btf_fd;
528         __u32 len;
529         int err;
530
531         btf_fd = bpf_btf_get_fd_by_id(btf_id);
532         if (btf_fd < 0) {
533                 p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));
534                 return false;
535         }
536
537         len = sizeof(btf_info);
538         btf_info.name = ptr_to_u64(btf_name);
539         btf_info.name_len = sizeof(btf_name);
540         err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
541         close(btf_fd);
542         if (err) {
543                 p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));
544                 return false;
545         }
546
547         return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;
548 }
549
550 static int do_dump(int argc, char **argv)
551 {
552         struct btf *btf = NULL, *base = NULL;
553         __u32 root_type_ids[2];
554         int root_type_cnt = 0;
555         bool dump_c = false;
556         __u32 btf_id = -1;
557         const char *src;
558         int fd = -1;
559         int err = 0;
560
561         if (!REQ_ARGS(2)) {
562                 usage();
563                 return -1;
564         }
565         src = GET_ARG();
566         if (is_prefix(src, "map")) {
567                 struct bpf_map_info info = {};
568                 __u32 len = sizeof(info);
569
570                 if (!REQ_ARGS(2)) {
571                         usage();
572                         return -1;
573                 }
574
575                 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
576                 if (fd < 0)
577                         return -1;
578
579                 btf_id = info.btf_id;
580                 if (argc && is_prefix(*argv, "key")) {
581                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
582                         NEXT_ARG();
583                 } else if (argc && is_prefix(*argv, "value")) {
584                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
585                         NEXT_ARG();
586                 } else if (argc && is_prefix(*argv, "all")) {
587                         NEXT_ARG();
588                 } else if (argc && is_prefix(*argv, "kv")) {
589                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
590                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
591                         NEXT_ARG();
592                 } else {
593                         root_type_ids[root_type_cnt++] = info.btf_key_type_id;
594                         root_type_ids[root_type_cnt++] = info.btf_value_type_id;
595                 }
596         } else if (is_prefix(src, "prog")) {
597                 struct bpf_prog_info info = {};
598                 __u32 len = sizeof(info);
599
600                 if (!REQ_ARGS(2)) {
601                         usage();
602                         return -1;
603                 }
604
605                 fd = prog_parse_fd(&argc, &argv);
606                 if (fd < 0)
607                         return -1;
608
609                 err = bpf_prog_get_info_by_fd(fd, &info, &len);
610                 if (err) {
611                         p_err("can't get prog info: %s", strerror(errno));
612                         goto done;
613                 }
614
615                 btf_id = info.btf_id;
616         } else if (is_prefix(src, "id")) {
617                 char *endptr;
618
619                 btf_id = strtoul(*argv, &endptr, 0);
620                 if (*endptr) {
621                         p_err("can't parse %s as ID", *argv);
622                         return -1;
623                 }
624                 NEXT_ARG();
625         } else if (is_prefix(src, "file")) {
626                 const char sysfs_prefix[] = "/sys/kernel/btf/";
627
628                 if (!base_btf &&
629                     strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
630                     strcmp(*argv, sysfs_vmlinux) != 0)
631                         base = get_vmlinux_btf_from_sysfs();
632
633                 btf = btf__parse_split(*argv, base ?: base_btf);
634                 if (!btf) {
635                         err = -errno;
636                         p_err("failed to load BTF from %s: %s",
637                               *argv, strerror(errno));
638                         goto done;
639                 }
640                 NEXT_ARG();
641         } else {
642                 err = -1;
643                 p_err("unrecognized BTF source specifier: '%s'", src);
644                 goto done;
645         }
646
647         while (argc) {
648                 if (is_prefix(*argv, "format")) {
649                         NEXT_ARG();
650                         if (argc < 1) {
651                                 p_err("expecting value for 'format' option\n");
652                                 err = -EINVAL;
653                                 goto done;
654                         }
655                         if (strcmp(*argv, "c") == 0) {
656                                 dump_c = true;
657                         } else if (strcmp(*argv, "raw") == 0) {
658                                 dump_c = false;
659                         } else {
660                                 p_err("unrecognized format specifier: '%s', possible values: raw, c",
661                                       *argv);
662                                 err = -EINVAL;
663                                 goto done;
664                         }
665                         NEXT_ARG();
666                 } else {
667                         p_err("unrecognized option: '%s'", *argv);
668                         err = -EINVAL;
669                         goto done;
670                 }
671         }
672
673         if (!btf) {
674                 if (!base_btf && btf_is_kernel_module(btf_id)) {
675                         p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",
676                                sysfs_vmlinux);
677                         base_btf = get_vmlinux_btf_from_sysfs();
678                 }
679
680                 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
681                 if (!btf) {
682                         err = -errno;
683                         p_err("get btf by id (%u): %s", btf_id, strerror(errno));
684                         goto done;
685                 }
686         }
687
688         if (dump_c) {
689                 if (json_output) {
690                         p_err("JSON output for C-syntax dump is not supported");
691                         err = -ENOTSUP;
692                         goto done;
693                 }
694                 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
695         } else {
696                 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
697         }
698
699 done:
700         close(fd);
701         btf__free(btf);
702         btf__free(base);
703         return err;
704 }
705
706 static int btf_parse_fd(int *argc, char ***argv)
707 {
708         unsigned int id;
709         char *endptr;
710         int fd;
711
712         if (!is_prefix(*argv[0], "id")) {
713                 p_err("expected 'id', got: '%s'?", **argv);
714                 return -1;
715         }
716         NEXT_ARGP();
717
718         id = strtoul(**argv, &endptr, 0);
719         if (*endptr) {
720                 p_err("can't parse %s as ID", **argv);
721                 return -1;
722         }
723         NEXT_ARGP();
724
725         fd = bpf_btf_get_fd_by_id(id);
726         if (fd < 0)
727                 p_err("can't get BTF object by id (%u): %s",
728                       id, strerror(errno));
729
730         return fd;
731 }
732
733 static int
734 build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
735                      void *info, __u32 *len)
736 {
737         static const char * const names[] = {
738                 [BPF_OBJ_UNKNOWN]       = "unknown",
739                 [BPF_OBJ_PROG]          = "prog",
740                 [BPF_OBJ_MAP]           = "map",
741         };
742         __u32 btf_id, id = 0;
743         int err;
744         int fd;
745
746         while (true) {
747                 switch (type) {
748                 case BPF_OBJ_PROG:
749                         err = bpf_prog_get_next_id(id, &id);
750                         break;
751                 case BPF_OBJ_MAP:
752                         err = bpf_map_get_next_id(id, &id);
753                         break;
754                 default:
755                         err = -1;
756                         p_err("unexpected object type: %d", type);
757                         goto err_free;
758                 }
759                 if (err) {
760                         if (errno == ENOENT) {
761                                 err = 0;
762                                 break;
763                         }
764                         p_err("can't get next %s: %s%s", names[type],
765                               strerror(errno),
766                               errno == EINVAL ? " -- kernel too old?" : "");
767                         goto err_free;
768                 }
769
770                 switch (type) {
771                 case BPF_OBJ_PROG:
772                         fd = bpf_prog_get_fd_by_id(id);
773                         break;
774                 case BPF_OBJ_MAP:
775                         fd = bpf_map_get_fd_by_id(id);
776                         break;
777                 default:
778                         err = -1;
779                         p_err("unexpected object type: %d", type);
780                         goto err_free;
781                 }
782                 if (fd < 0) {
783                         if (errno == ENOENT)
784                                 continue;
785                         p_err("can't get %s by id (%u): %s", names[type], id,
786                               strerror(errno));
787                         err = -1;
788                         goto err_free;
789                 }
790
791                 memset(info, 0, *len);
792                 if (type == BPF_OBJ_PROG)
793                         err = bpf_prog_get_info_by_fd(fd, info, len);
794                 else
795                         err = bpf_map_get_info_by_fd(fd, info, len);
796                 close(fd);
797                 if (err) {
798                         p_err("can't get %s info: %s", names[type],
799                               strerror(errno));
800                         goto err_free;
801                 }
802
803                 switch (type) {
804                 case BPF_OBJ_PROG:
805                         btf_id = ((struct bpf_prog_info *)info)->btf_id;
806                         break;
807                 case BPF_OBJ_MAP:
808                         btf_id = ((struct bpf_map_info *)info)->btf_id;
809                         break;
810                 default:
811                         err = -1;
812                         p_err("unexpected object type: %d", type);
813                         goto err_free;
814                 }
815                 if (!btf_id)
816                         continue;
817
818                 err = hashmap__append(tab, btf_id, id);
819                 if (err) {
820                         p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
821                               btf_id, id, strerror(-err));
822                         goto err_free;
823                 }
824         }
825
826         return 0;
827
828 err_free:
829         hashmap__free(tab);
830         return err;
831 }
832
833 static int
834 build_btf_tables(struct hashmap *btf_prog_table,
835                  struct hashmap *btf_map_table)
836 {
837         struct bpf_prog_info prog_info;
838         __u32 prog_len = sizeof(prog_info);
839         struct bpf_map_info map_info;
840         __u32 map_len = sizeof(map_info);
841         int err = 0;
842
843         err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
844                                    &prog_len);
845         if (err)
846                 return err;
847
848         err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
849                                    &map_len);
850         if (err) {
851                 hashmap__free(btf_prog_table);
852                 return err;
853         }
854
855         return 0;
856 }
857
858 static void
859 show_btf_plain(struct bpf_btf_info *info, int fd,
860                struct hashmap *btf_prog_table,
861                struct hashmap *btf_map_table)
862 {
863         struct hashmap_entry *entry;
864         const char *name = u64_to_ptr(info->name);
865         int n;
866
867         printf("%u: ", info->id);
868         if (info->kernel_btf)
869                 printf("name [%s]  ", name);
870         else if (name && name[0])
871                 printf("name %s  ", name);
872         else
873                 printf("name <anon>  ");
874         printf("size %uB", info->btf_size);
875
876         n = 0;
877         hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
878                 printf("%s%lu", n++ == 0 ? "  prog_ids " : ",", entry->value);
879         }
880
881         n = 0;
882         hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
883                 printf("%s%lu", n++ == 0 ? "  map_ids " : ",", entry->value);
884         }
885
886         emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
887
888         printf("\n");
889 }
890
891 static void
892 show_btf_json(struct bpf_btf_info *info, int fd,
893               struct hashmap *btf_prog_table,
894               struct hashmap *btf_map_table)
895 {
896         struct hashmap_entry *entry;
897         const char *name = u64_to_ptr(info->name);
898
899         jsonw_start_object(json_wtr);   /* btf object */
900         jsonw_uint_field(json_wtr, "id", info->id);
901         jsonw_uint_field(json_wtr, "size", info->btf_size);
902
903         jsonw_name(json_wtr, "prog_ids");
904         jsonw_start_array(json_wtr);    /* prog_ids */
905         hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {
906                 jsonw_uint(json_wtr, entry->value);
907         }
908         jsonw_end_array(json_wtr);      /* prog_ids */
909
910         jsonw_name(json_wtr, "map_ids");
911         jsonw_start_array(json_wtr);    /* map_ids */
912         hashmap__for_each_key_entry(btf_map_table, entry, info->id) {
913                 jsonw_uint(json_wtr, entry->value);
914         }
915         jsonw_end_array(json_wtr);      /* map_ids */
916
917         emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
918
919         jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
920
921         if (name && name[0])
922                 jsonw_string_field(json_wtr, "name", name);
923
924         jsonw_end_object(json_wtr);     /* btf object */
925 }
926
927 static int
928 show_btf(int fd, struct hashmap *btf_prog_table,
929          struct hashmap *btf_map_table)
930 {
931         struct bpf_btf_info info;
932         __u32 len = sizeof(info);
933         char name[64];
934         int err;
935
936         memset(&info, 0, sizeof(info));
937         err = bpf_btf_get_info_by_fd(fd, &info, &len);
938         if (err) {
939                 p_err("can't get BTF object info: %s", strerror(errno));
940                 return -1;
941         }
942         /* if kernel support emitting BTF object name, pass name pointer */
943         if (info.name_len) {
944                 memset(&info, 0, sizeof(info));
945                 info.name_len = sizeof(name);
946                 info.name = ptr_to_u64(name);
947                 len = sizeof(info);
948
949                 err = bpf_btf_get_info_by_fd(fd, &info, &len);
950                 if (err) {
951                         p_err("can't get BTF object info: %s", strerror(errno));
952                         return -1;
953                 }
954         }
955
956         if (json_output)
957                 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
958         else
959                 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
960
961         return 0;
962 }
963
964 static int do_show(int argc, char **argv)
965 {
966         struct hashmap *btf_prog_table;
967         struct hashmap *btf_map_table;
968         int err, fd = -1;
969         __u32 id = 0;
970
971         if (argc == 2) {
972                 fd = btf_parse_fd(&argc, &argv);
973                 if (fd < 0)
974                         return -1;
975         }
976
977         if (argc) {
978                 if (fd >= 0)
979                         close(fd);
980                 return BAD_ARG();
981         }
982
983         btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
984                                       equal_fn_for_key_as_id, NULL);
985         btf_map_table = hashmap__new(hash_fn_for_key_as_id,
986                                      equal_fn_for_key_as_id, NULL);
987         if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {
988                 hashmap__free(btf_prog_table);
989                 hashmap__free(btf_map_table);
990                 if (fd >= 0)
991                         close(fd);
992                 p_err("failed to create hashmap for object references");
993                 return -1;
994         }
995         err = build_btf_tables(btf_prog_table, btf_map_table);
996         if (err) {
997                 if (fd >= 0)
998                         close(fd);
999                 return err;
1000         }
1001         build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
1002
1003         if (fd >= 0) {
1004                 err = show_btf(fd, btf_prog_table, btf_map_table);
1005                 close(fd);
1006                 goto exit_free;
1007         }
1008
1009         if (json_output)
1010                 jsonw_start_array(json_wtr);    /* root array */
1011
1012         while (true) {
1013                 err = bpf_btf_get_next_id(id, &id);
1014                 if (err) {
1015                         if (errno == ENOENT) {
1016                                 err = 0;
1017                                 break;
1018                         }
1019                         p_err("can't get next BTF object: %s%s",
1020                               strerror(errno),
1021                               errno == EINVAL ? " -- kernel too old?" : "");
1022                         err = -1;
1023                         break;
1024                 }
1025
1026                 fd = bpf_btf_get_fd_by_id(id);
1027                 if (fd < 0) {
1028                         if (errno == ENOENT)
1029                                 continue;
1030                         p_err("can't get BTF object by id (%u): %s",
1031                               id, strerror(errno));
1032                         err = -1;
1033                         break;
1034                 }
1035
1036                 err = show_btf(fd, btf_prog_table, btf_map_table);
1037                 close(fd);
1038                 if (err)
1039                         break;
1040         }
1041
1042         if (json_output)
1043                 jsonw_end_array(json_wtr);      /* root array */
1044
1045 exit_free:
1046         hashmap__free(btf_prog_table);
1047         hashmap__free(btf_map_table);
1048         delete_obj_refs_table(refs_table);
1049
1050         return err;
1051 }
1052
1053 static int do_help(int argc, char **argv)
1054 {
1055         if (json_output) {
1056                 jsonw_null(json_wtr);
1057                 return 0;
1058         }
1059
1060         fprintf(stderr,
1061                 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
1062                 "       %1$s %2$s dump BTF_SRC [format FORMAT]\n"
1063                 "       %1$s %2$s help\n"
1064                 "\n"
1065                 "       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
1066                 "       FORMAT  := { raw | c }\n"
1067                 "       " HELP_SPEC_MAP "\n"
1068                 "       " HELP_SPEC_PROGRAM "\n"
1069                 "       " HELP_SPEC_OPTIONS " |\n"
1070                 "                    {-B|--base-btf} }\n"
1071                 "",
1072                 bin_name, "btf");
1073
1074         return 0;
1075 }
1076
1077 static const struct cmd cmds[] = {
1078         { "show",       do_show },
1079         { "list",       do_show },
1080         { "help",       do_help },
1081         { "dump",       do_dump },
1082         { 0 }
1083 };
1084
1085 int do_btf(int argc, char **argv)
1086 {
1087         return cmd_select(cmds, argc, argv, do_help);
1088 }