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