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