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
btf_int_enc_str(__u8 encoding)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
btf_var_linkage_str(__u32 linkage)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
btf_func_linkage_str(const struct btf_type * t)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
btf_str(const struct btf * btf,__u32 off)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
btf_kind_safe(int kind)100 static int btf_kind_safe(int kind)
101 {
102 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
103 }
104
dump_btf_type(const struct btf * btf,__u32 id,const struct btf_type * t)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
dump_btf_raw(const struct btf * btf,__u32 * root_type_ids,int root_type_cnt)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
btf_dump_printf(void * ctx,const char * fmt,va_list args)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
dump_btf_c(const struct btf * btf,__u32 * root_type_ids,int root_type_cnt)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
do_dump(int argc,char ** argv)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
btf_parse_fd(int * argc,char *** argv)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
build_btf_type_table(struct hashmap * tab,enum bpf_obj_type type,void * info,__u32 * len)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
build_btf_tables(struct hashmap * btf_prog_table,struct hashmap * btf_map_table)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
show_btf_plain(struct bpf_btf_info * info,int fd,struct hashmap * btf_prog_table,struct hashmap * btf_map_table)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
show_btf_json(struct bpf_btf_info * info,int fd,struct hashmap * btf_prog_table,struct hashmap * btf_map_table)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
show_btf(int fd,struct hashmap * btf_prog_table,struct hashmap * btf_map_table)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
do_show(int argc,char ** argv)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
do_help(int argc,char ** argv)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
do_btf(int argc,char ** argv)1000 int do_btf(int argc, char **argv)
1001 {
1002 return cmd_select(cmds, argc, argv, do_help);
1003 }
1004