1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2019 Facebook */
13 #include <bpf/libbpf.h>
14 #include <linux/btf.h>
15 #include <linux/hashtable.h>
16 #include <sys/types.h>
20 #include "json_writer.h"
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",
42 struct btf_attach_table
{
43 DECLARE_HASHTABLE(table
, 16);
46 struct btf_attach_point
{
49 struct hlist_node hash
;
52 static const char *btf_int_enc_str(__u8 encoding
)
68 static const char *btf_var_linkage_str(__u32 linkage
)
73 case BTF_VAR_GLOBAL_ALLOCATED
:
74 return "global-alloc";
80 static const char *btf_func_linkage_str(const struct btf_type
*t
)
82 switch (btf_vlen(t
)) {
94 static const char *btf_str(const struct btf
*btf
, __u32 off
)
98 return btf__name_by_offset(btf
, off
) ? : "(invalid)";
101 static int dump_btf_type(const struct btf
*btf
, __u32 id
,
102 const struct btf_type
*t
)
104 json_writer_t
*w
= json_wtr
;
107 kind
= BTF_INFO_KIND(t
->info
);
108 safe_kind
= kind
<= BTF_KIND_MAX
? kind
: BTF_KIND_UNKN
;
111 jsonw_start_object(w
);
112 jsonw_uint_field(w
, "id", id
);
113 jsonw_string_field(w
, "kind", btf_kind_str
[safe_kind
]);
114 jsonw_string_field(w
, "name", btf_str(btf
, t
->name_off
));
116 printf("[%u] %s '%s'", id
, btf_kind_str
[safe_kind
],
117 btf_str(btf
, t
->name_off
));
120 switch (BTF_INFO_KIND(t
->info
)) {
122 __u32 v
= *(__u32
*)(t
+ 1);
125 enc
= btf_int_enc_str(BTF_INT_ENCODING(v
));
128 jsonw_uint_field(w
, "size", t
->size
);
129 jsonw_uint_field(w
, "bits_offset", BTF_INT_OFFSET(v
));
130 jsonw_uint_field(w
, "nr_bits", BTF_INT_BITS(v
));
131 jsonw_string_field(w
, "encoding", enc
);
133 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
134 t
->size
, BTF_INT_OFFSET(v
), BTF_INT_BITS(v
),
141 case BTF_KIND_VOLATILE
:
142 case BTF_KIND_RESTRICT
:
143 case BTF_KIND_TYPEDEF
:
145 jsonw_uint_field(w
, "type_id", t
->type
);
147 printf(" type_id=%u", t
->type
);
149 case BTF_KIND_ARRAY
: {
150 const struct btf_array
*arr
= (const void *)(t
+ 1);
153 jsonw_uint_field(w
, "type_id", arr
->type
);
154 jsonw_uint_field(w
, "index_type_id", arr
->index_type
);
155 jsonw_uint_field(w
, "nr_elems", arr
->nelems
);
157 printf(" type_id=%u index_type_id=%u nr_elems=%u",
158 arr
->type
, arr
->index_type
, arr
->nelems
);
162 case BTF_KIND_STRUCT
:
163 case BTF_KIND_UNION
: {
164 const struct btf_member
*m
= (const void *)(t
+ 1);
165 __u16 vlen
= BTF_INFO_VLEN(t
->info
);
169 jsonw_uint_field(w
, "size", t
->size
);
170 jsonw_uint_field(w
, "vlen", vlen
);
171 jsonw_name(w
, "members");
172 jsonw_start_array(w
);
174 printf(" size=%u vlen=%u", t
->size
, vlen
);
176 for (i
= 0; i
< vlen
; i
++, m
++) {
177 const char *name
= btf_str(btf
, m
->name_off
);
178 __u32 bit_off
, bit_sz
;
180 if (BTF_INFO_KFLAG(t
->info
)) {
181 bit_off
= BTF_MEMBER_BIT_OFFSET(m
->offset
);
182 bit_sz
= BTF_MEMBER_BITFIELD_SIZE(m
->offset
);
189 jsonw_start_object(w
);
190 jsonw_string_field(w
, "name", name
);
191 jsonw_uint_field(w
, "type_id", m
->type
);
192 jsonw_uint_field(w
, "bits_offset", bit_off
);
194 jsonw_uint_field(w
, "bitfield_size",
199 printf("\n\t'%s' type_id=%u bits_offset=%u",
200 name
, m
->type
, bit_off
);
202 printf(" bitfield_size=%u", bit_sz
);
209 case BTF_KIND_ENUM
: {
210 const struct btf_enum
*v
= (const void *)(t
+ 1);
211 __u16 vlen
= BTF_INFO_VLEN(t
->info
);
215 jsonw_uint_field(w
, "size", t
->size
);
216 jsonw_uint_field(w
, "vlen", vlen
);
217 jsonw_name(w
, "values");
218 jsonw_start_array(w
);
220 printf(" size=%u vlen=%u", t
->size
, vlen
);
222 for (i
= 0; i
< vlen
; i
++, v
++) {
223 const char *name
= btf_str(btf
, v
->name_off
);
226 jsonw_start_object(w
);
227 jsonw_string_field(w
, "name", name
);
228 jsonw_uint_field(w
, "val", v
->val
);
231 printf("\n\t'%s' val=%u", name
, v
->val
);
239 const char *fwd_kind
= BTF_INFO_KFLAG(t
->info
) ? "union"
243 jsonw_string_field(w
, "fwd_kind", fwd_kind
);
245 printf(" fwd_kind=%s", fwd_kind
);
248 case BTF_KIND_FUNC
: {
249 const char *linkage
= btf_func_linkage_str(t
);
252 jsonw_uint_field(w
, "type_id", t
->type
);
253 jsonw_string_field(w
, "linkage", linkage
);
255 printf(" type_id=%u linkage=%s", t
->type
, linkage
);
259 case BTF_KIND_FUNC_PROTO
: {
260 const struct btf_param
*p
= (const void *)(t
+ 1);
261 __u16 vlen
= BTF_INFO_VLEN(t
->info
);
265 jsonw_uint_field(w
, "ret_type_id", t
->type
);
266 jsonw_uint_field(w
, "vlen", vlen
);
267 jsonw_name(w
, "params");
268 jsonw_start_array(w
);
270 printf(" ret_type_id=%u vlen=%u", t
->type
, vlen
);
272 for (i
= 0; i
< vlen
; i
++, p
++) {
273 const char *name
= btf_str(btf
, p
->name_off
);
276 jsonw_start_object(w
);
277 jsonw_string_field(w
, "name", name
);
278 jsonw_uint_field(w
, "type_id", p
->type
);
281 printf("\n\t'%s' type_id=%u", name
, p
->type
);
289 const struct btf_var
*v
= (const void *)(t
+ 1);
292 linkage
= btf_var_linkage_str(v
->linkage
);
295 jsonw_uint_field(w
, "type_id", t
->type
);
296 jsonw_string_field(w
, "linkage", linkage
);
298 printf(" type_id=%u, linkage=%s", t
->type
, linkage
);
302 case BTF_KIND_DATASEC
: {
303 const struct btf_var_secinfo
*v
= (const void *)(t
+1);
304 __u16 vlen
= BTF_INFO_VLEN(t
->info
);
308 jsonw_uint_field(w
, "size", t
->size
);
309 jsonw_uint_field(w
, "vlen", vlen
);
310 jsonw_name(w
, "vars");
311 jsonw_start_array(w
);
313 printf(" size=%u vlen=%u", t
->size
, vlen
);
315 for (i
= 0; i
< vlen
; i
++, v
++) {
317 jsonw_start_object(w
);
318 jsonw_uint_field(w
, "type_id", v
->type
);
319 jsonw_uint_field(w
, "offset", v
->offset
);
320 jsonw_uint_field(w
, "size", v
->size
);
323 printf("\n\ttype_id=%u offset=%u size=%u",
324 v
->type
, v
->offset
, v
->size
);
336 jsonw_end_object(json_wtr
);
343 static int dump_btf_raw(const struct btf
*btf
,
344 __u32
*root_type_ids
, int root_type_cnt
)
346 const struct btf_type
*t
;
350 jsonw_start_object(json_wtr
);
351 jsonw_name(json_wtr
, "types");
352 jsonw_start_array(json_wtr
);
356 for (i
= 0; i
< root_type_cnt
; i
++) {
357 t
= btf__type_by_id(btf
, root_type_ids
[i
]);
358 dump_btf_type(btf
, root_type_ids
[i
], t
);
361 int cnt
= btf__get_nr_types(btf
);
363 for (i
= 1; i
<= cnt
; i
++) {
364 t
= btf__type_by_id(btf
, i
);
365 dump_btf_type(btf
, i
, t
);
370 jsonw_end_array(json_wtr
);
371 jsonw_end_object(json_wtr
);
376 static void __printf(2, 0) btf_dump_printf(void *ctx
,
377 const char *fmt
, va_list args
)
379 vfprintf(stdout
, fmt
, args
);
382 static int dump_btf_c(const struct btf
*btf
,
383 __u32
*root_type_ids
, int root_type_cnt
)
388 d
= btf_dump__new(btf
, NULL
, NULL
, btf_dump_printf
);
392 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
393 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
394 printf("#endif\n\n");
397 for (i
= 0; i
< root_type_cnt
; i
++) {
398 err
= btf_dump__dump_type(d
, root_type_ids
[i
]);
403 int cnt
= btf__get_nr_types(btf
);
405 for (i
= 1; i
<= cnt
; i
++) {
406 err
= btf_dump__dump_type(d
, i
);
412 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
413 printf("#pragma clang attribute pop\n");
421 static struct btf
*btf__parse_raw(const char *file
)
431 f
= fopen(file
, "rb");
435 buf
= malloc(st
.st_size
);
437 btf
= ERR_PTR(-ENOMEM
);
441 if ((size_t) st
.st_size
!= fread(buf
, 1, st
.st_size
, f
)) {
442 btf
= ERR_PTR(-EINVAL
);
446 btf
= btf__new(buf
, st
.st_size
);
455 static bool is_btf_raw(const char *file
)
460 fd
= open(file
, O_RDONLY
);
464 nb_read
= read(fd
, &magic
, sizeof(magic
));
466 return nb_read
== sizeof(magic
) && magic
== BTF_MAGIC
;
469 static int do_dump(int argc
, char **argv
)
471 struct btf
*btf
= NULL
;
472 __u32 root_type_ids
[2];
473 int root_type_cnt
= 0;
486 if (is_prefix(src
, "map")) {
487 struct bpf_map_info info
= {};
488 __u32 len
= sizeof(info
);
495 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
499 btf_id
= info
.btf_id
;
500 if (argc
&& is_prefix(*argv
, "key")) {
501 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
503 } else if (argc
&& is_prefix(*argv
, "value")) {
504 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
506 } else if (argc
&& is_prefix(*argv
, "all")) {
508 } else if (argc
&& is_prefix(*argv
, "kv")) {
509 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
510 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
513 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
514 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
516 } else if (is_prefix(src
, "prog")) {
517 struct bpf_prog_info info
= {};
518 __u32 len
= sizeof(info
);
525 fd
= prog_parse_fd(&argc
, &argv
);
529 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
531 p_err("can't get prog info: %s", strerror(errno
));
535 btf_id
= info
.btf_id
;
536 } else if (is_prefix(src
, "id")) {
539 btf_id
= strtoul(*argv
, &endptr
, 0);
541 p_err("can't parse %s as ID", *argv
);
545 } else if (is_prefix(src
, "file")) {
546 if (is_btf_raw(*argv
))
547 btf
= btf__parse_raw(*argv
);
549 btf
= btf__parse_elf(*argv
, NULL
);
554 p_err("failed to load BTF from %s: %s",
555 *argv
, strerror(err
));
561 p_err("unrecognized BTF source specifier: '%s'", src
);
566 if (is_prefix(*argv
, "format")) {
569 p_err("expecting value for 'format' option\n");
572 if (strcmp(*argv
, "c") == 0) {
574 } else if (strcmp(*argv
, "raw") == 0) {
577 p_err("unrecognized format specifier: '%s', possible values: raw, c",
583 p_err("unrecognized option: '%s'", *argv
);
589 err
= btf__get_from_id(btf_id
, &btf
);
591 p_err("get btf by id (%u): %s", btf_id
, strerror(err
));
596 p_err("can't find btf with ID (%u)", btf_id
);
603 p_err("JSON output for C-syntax dump is not supported");
607 err
= dump_btf_c(btf
, root_type_ids
, root_type_cnt
);
609 err
= dump_btf_raw(btf
, root_type_ids
, root_type_cnt
);
618 static int btf_parse_fd(int *argc
, char ***argv
)
624 if (!is_prefix(*argv
[0], "id")) {
625 p_err("expected 'id', got: '%s'?", **argv
);
630 id
= strtoul(**argv
, &endptr
, 0);
632 p_err("can't parse %s as ID", **argv
);
637 fd
= bpf_btf_get_fd_by_id(id
);
639 p_err("can't get BTF object by id (%u): %s",
640 id
, strerror(errno
));
645 static void delete_btf_table(struct btf_attach_table
*tab
)
647 struct btf_attach_point
*obj
;
648 struct hlist_node
*tmp
;
652 hash_for_each_safe(tab
->table
, bkt
, tmp
, obj
, hash
) {
653 hash_del(&obj
->hash
);
659 build_btf_type_table(struct btf_attach_table
*tab
, enum bpf_obj_type type
,
660 void *info
, __u32
*len
)
662 static const char * const names
[] = {
663 [BPF_OBJ_UNKNOWN
] = "unknown",
664 [BPF_OBJ_PROG
] = "prog",
665 [BPF_OBJ_MAP
] = "map",
667 struct btf_attach_point
*obj_node
;
668 __u32 btf_id
, id
= 0;
675 err
= bpf_prog_get_next_id(id
, &id
);
678 err
= bpf_map_get_next_id(id
, &id
);
682 p_err("unexpected object type: %d", type
);
686 if (errno
== ENOENT
) {
690 p_err("can't get next %s: %s%s", names
[type
],
692 errno
== EINVAL
? " -- kernel too old?" : "");
698 fd
= bpf_prog_get_fd_by_id(id
);
701 fd
= bpf_map_get_fd_by_id(id
);
705 p_err("unexpected object type: %d", type
);
711 p_err("can't get %s by id (%u): %s", names
[type
], id
,
717 memset(info
, 0, *len
);
718 err
= bpf_obj_get_info_by_fd(fd
, info
, len
);
721 p_err("can't get %s info: %s", names
[type
],
728 btf_id
= ((struct bpf_prog_info
*)info
)->btf_id
;
731 btf_id
= ((struct bpf_map_info
*)info
)->btf_id
;
735 p_err("unexpected object type: %d", type
);
741 obj_node
= calloc(1, sizeof(*obj_node
));
743 p_err("failed to allocate memory: %s", strerror(errno
));
747 obj_node
->obj_id
= id
;
748 obj_node
->btf_id
= btf_id
;
749 hash_add(tab
->table
, &obj_node
->hash
, obj_node
->btf_id
);
755 delete_btf_table(tab
);
760 build_btf_tables(struct btf_attach_table
*btf_prog_table
,
761 struct btf_attach_table
*btf_map_table
)
763 struct bpf_prog_info prog_info
;
764 __u32 prog_len
= sizeof(prog_info
);
765 struct bpf_map_info map_info
;
766 __u32 map_len
= sizeof(map_info
);
769 err
= build_btf_type_table(btf_prog_table
, BPF_OBJ_PROG
, &prog_info
,
774 err
= build_btf_type_table(btf_map_table
, BPF_OBJ_MAP
, &map_info
,
777 delete_btf_table(btf_prog_table
);
785 show_btf_plain(struct bpf_btf_info
*info
, int fd
,
786 struct btf_attach_table
*btf_prog_table
,
787 struct btf_attach_table
*btf_map_table
)
789 struct btf_attach_point
*obj
;
792 printf("%u: ", info
->id
);
793 printf("size %uB", info
->btf_size
);
796 hash_for_each_possible(btf_prog_table
->table
, obj
, hash
, info
->id
) {
797 if (obj
->btf_id
== info
->id
)
798 printf("%s%u", n
++ == 0 ? " prog_ids " : ",",
803 hash_for_each_possible(btf_map_table
->table
, obj
, hash
, info
->id
) {
804 if (obj
->btf_id
== info
->id
)
805 printf("%s%u", n
++ == 0 ? " map_ids " : ",",
813 show_btf_json(struct bpf_btf_info
*info
, int fd
,
814 struct btf_attach_table
*btf_prog_table
,
815 struct btf_attach_table
*btf_map_table
)
817 struct btf_attach_point
*obj
;
819 jsonw_start_object(json_wtr
); /* btf object */
820 jsonw_uint_field(json_wtr
, "id", info
->id
);
821 jsonw_uint_field(json_wtr
, "size", info
->btf_size
);
823 jsonw_name(json_wtr
, "prog_ids");
824 jsonw_start_array(json_wtr
); /* prog_ids */
825 hash_for_each_possible(btf_prog_table
->table
, obj
, hash
,
827 if (obj
->btf_id
== info
->id
)
828 jsonw_uint(json_wtr
, obj
->obj_id
);
830 jsonw_end_array(json_wtr
); /* prog_ids */
832 jsonw_name(json_wtr
, "map_ids");
833 jsonw_start_array(json_wtr
); /* map_ids */
834 hash_for_each_possible(btf_map_table
->table
, obj
, hash
,
836 if (obj
->btf_id
== info
->id
)
837 jsonw_uint(json_wtr
, obj
->obj_id
);
839 jsonw_end_array(json_wtr
); /* map_ids */
840 jsonw_end_object(json_wtr
); /* btf object */
844 show_btf(int fd
, struct btf_attach_table
*btf_prog_table
,
845 struct btf_attach_table
*btf_map_table
)
847 struct bpf_btf_info info
= {};
848 __u32 len
= sizeof(info
);
851 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
853 p_err("can't get BTF object info: %s", strerror(errno
));
858 show_btf_json(&info
, fd
, btf_prog_table
, btf_map_table
);
860 show_btf_plain(&info
, fd
, btf_prog_table
, btf_map_table
);
865 static int do_show(int argc
, char **argv
)
867 struct btf_attach_table btf_prog_table
;
868 struct btf_attach_table btf_map_table
;
873 fd
= btf_parse_fd(&argc
, &argv
);
884 hash_init(btf_prog_table
.table
);
885 hash_init(btf_map_table
.table
);
886 err
= build_btf_tables(&btf_prog_table
, &btf_map_table
);
894 err
= show_btf(fd
, &btf_prog_table
, &btf_map_table
);
900 jsonw_start_array(json_wtr
); /* root array */
903 err
= bpf_btf_get_next_id(id
, &id
);
905 if (errno
== ENOENT
) {
909 p_err("can't get next BTF object: %s%s",
911 errno
== EINVAL
? " -- kernel too old?" : "");
916 fd
= bpf_btf_get_fd_by_id(id
);
920 p_err("can't get BTF object by id (%u): %s",
921 id
, strerror(errno
));
926 err
= show_btf(fd
, &btf_prog_table
, &btf_map_table
);
933 jsonw_end_array(json_wtr
); /* root array */
936 delete_btf_table(&btf_prog_table
);
937 delete_btf_table(&btf_map_table
);
942 static int do_help(int argc
, char **argv
)
945 jsonw_null(json_wtr
);
950 "Usage: %s btf { show | list } [id BTF_ID]\n"
951 " %s btf dump BTF_SRC [format FORMAT]\n"
954 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
955 " FORMAT := { raw | c }\n"
956 " " HELP_SPEC_MAP
"\n"
957 " " HELP_SPEC_PROGRAM
"\n"
958 " " HELP_SPEC_OPTIONS
"\n"
960 bin_name
, bin_name
, bin_name
);
965 static const struct cmd cmds
[] = {
973 int do_btf(int argc
, char **argv
)
975 return cmd_select(cmds
, argc
, argv
, do_help
);