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