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