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 __VMLINUX_H__\n");
393 printf("#define __VMLINUX_H__\n");
395 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
396 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
397 printf("#endif\n\n");
400 for (i
= 0; i
< root_type_cnt
; i
++) {
401 err
= btf_dump__dump_type(d
, root_type_ids
[i
]);
406 int cnt
= btf__get_nr_types(btf
);
408 for (i
= 1; i
<= cnt
; i
++) {
409 err
= btf_dump__dump_type(d
, i
);
415 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
416 printf("#pragma clang attribute pop\n");
419 printf("#endif /* __VMLINUX_H__ */\n");
426 static struct btf
*btf__parse_raw(const char *file
)
436 f
= fopen(file
, "rb");
440 buf
= malloc(st
.st_size
);
442 btf
= ERR_PTR(-ENOMEM
);
446 if ((size_t) st
.st_size
!= fread(buf
, 1, st
.st_size
, f
)) {
447 btf
= ERR_PTR(-EINVAL
);
451 btf
= btf__new(buf
, st
.st_size
);
460 static bool is_btf_raw(const char *file
)
465 fd
= open(file
, O_RDONLY
);
469 nb_read
= read(fd
, &magic
, sizeof(magic
));
471 return nb_read
== sizeof(magic
) && magic
== BTF_MAGIC
;
474 static int do_dump(int argc
, char **argv
)
476 struct btf
*btf
= NULL
;
477 __u32 root_type_ids
[2];
478 int root_type_cnt
= 0;
491 if (is_prefix(src
, "map")) {
492 struct bpf_map_info info
= {};
493 __u32 len
= sizeof(info
);
500 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
504 btf_id
= info
.btf_id
;
505 if (argc
&& is_prefix(*argv
, "key")) {
506 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
508 } else if (argc
&& is_prefix(*argv
, "value")) {
509 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
511 } else if (argc
&& is_prefix(*argv
, "all")) {
513 } else if (argc
&& is_prefix(*argv
, "kv")) {
514 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
515 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
518 root_type_ids
[root_type_cnt
++] = info
.btf_key_type_id
;
519 root_type_ids
[root_type_cnt
++] = info
.btf_value_type_id
;
521 } else if (is_prefix(src
, "prog")) {
522 struct bpf_prog_info info
= {};
523 __u32 len
= sizeof(info
);
530 fd
= prog_parse_fd(&argc
, &argv
);
534 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
536 p_err("can't get prog info: %s", strerror(errno
));
540 btf_id
= info
.btf_id
;
541 } else if (is_prefix(src
, "id")) {
544 btf_id
= strtoul(*argv
, &endptr
, 0);
546 p_err("can't parse %s as ID", *argv
);
550 } else if (is_prefix(src
, "file")) {
551 if (is_btf_raw(*argv
))
552 btf
= btf__parse_raw(*argv
);
554 btf
= btf__parse_elf(*argv
, NULL
);
559 p_err("failed to load BTF from %s: %s",
560 *argv
, strerror(err
));
566 p_err("unrecognized BTF source specifier: '%s'", src
);
571 if (is_prefix(*argv
, "format")) {
574 p_err("expecting value for 'format' option\n");
577 if (strcmp(*argv
, "c") == 0) {
579 } else if (strcmp(*argv
, "raw") == 0) {
582 p_err("unrecognized format specifier: '%s', possible values: raw, c",
588 p_err("unrecognized option: '%s'", *argv
);
594 err
= btf__get_from_id(btf_id
, &btf
);
596 p_err("get btf by id (%u): %s", btf_id
, strerror(err
));
601 p_err("can't find btf with ID (%u)", btf_id
);
608 p_err("JSON output for C-syntax dump is not supported");
612 err
= dump_btf_c(btf
, root_type_ids
, root_type_cnt
);
614 err
= dump_btf_raw(btf
, root_type_ids
, root_type_cnt
);
623 static int btf_parse_fd(int *argc
, char ***argv
)
629 if (!is_prefix(*argv
[0], "id")) {
630 p_err("expected 'id', got: '%s'?", **argv
);
635 id
= strtoul(**argv
, &endptr
, 0);
637 p_err("can't parse %s as ID", **argv
);
642 fd
= bpf_btf_get_fd_by_id(id
);
644 p_err("can't get BTF object by id (%u): %s",
645 id
, strerror(errno
));
650 static void delete_btf_table(struct btf_attach_table
*tab
)
652 struct btf_attach_point
*obj
;
653 struct hlist_node
*tmp
;
657 hash_for_each_safe(tab
->table
, bkt
, tmp
, obj
, hash
) {
658 hash_del(&obj
->hash
);
664 build_btf_type_table(struct btf_attach_table
*tab
, enum bpf_obj_type type
,
665 void *info
, __u32
*len
)
667 static const char * const names
[] = {
668 [BPF_OBJ_UNKNOWN
] = "unknown",
669 [BPF_OBJ_PROG
] = "prog",
670 [BPF_OBJ_MAP
] = "map",
672 struct btf_attach_point
*obj_node
;
673 __u32 btf_id
, id
= 0;
680 err
= bpf_prog_get_next_id(id
, &id
);
683 err
= bpf_map_get_next_id(id
, &id
);
687 p_err("unexpected object type: %d", type
);
691 if (errno
== ENOENT
) {
695 p_err("can't get next %s: %s%s", names
[type
],
697 errno
== EINVAL
? " -- kernel too old?" : "");
703 fd
= bpf_prog_get_fd_by_id(id
);
706 fd
= bpf_map_get_fd_by_id(id
);
710 p_err("unexpected object type: %d", type
);
716 p_err("can't get %s by id (%u): %s", names
[type
], id
,
722 memset(info
, 0, *len
);
723 err
= bpf_obj_get_info_by_fd(fd
, info
, len
);
726 p_err("can't get %s info: %s", names
[type
],
733 btf_id
= ((struct bpf_prog_info
*)info
)->btf_id
;
736 btf_id
= ((struct bpf_map_info
*)info
)->btf_id
;
740 p_err("unexpected object type: %d", type
);
746 obj_node
= calloc(1, sizeof(*obj_node
));
748 p_err("failed to allocate memory: %s", strerror(errno
));
752 obj_node
->obj_id
= id
;
753 obj_node
->btf_id
= btf_id
;
754 hash_add(tab
->table
, &obj_node
->hash
, obj_node
->btf_id
);
760 delete_btf_table(tab
);
765 build_btf_tables(struct btf_attach_table
*btf_prog_table
,
766 struct btf_attach_table
*btf_map_table
)
768 struct bpf_prog_info prog_info
;
769 __u32 prog_len
= sizeof(prog_info
);
770 struct bpf_map_info map_info
;
771 __u32 map_len
= sizeof(map_info
);
774 err
= build_btf_type_table(btf_prog_table
, BPF_OBJ_PROG
, &prog_info
,
779 err
= build_btf_type_table(btf_map_table
, BPF_OBJ_MAP
, &map_info
,
782 delete_btf_table(btf_prog_table
);
790 show_btf_plain(struct bpf_btf_info
*info
, int fd
,
791 struct btf_attach_table
*btf_prog_table
,
792 struct btf_attach_table
*btf_map_table
)
794 struct btf_attach_point
*obj
;
797 printf("%u: ", info
->id
);
798 printf("size %uB", info
->btf_size
);
801 hash_for_each_possible(btf_prog_table
->table
, obj
, hash
, info
->id
) {
802 if (obj
->btf_id
== info
->id
)
803 printf("%s%u", n
++ == 0 ? " prog_ids " : ",",
808 hash_for_each_possible(btf_map_table
->table
, obj
, hash
, info
->id
) {
809 if (obj
->btf_id
== info
->id
)
810 printf("%s%u", n
++ == 0 ? " map_ids " : ",",
818 show_btf_json(struct bpf_btf_info
*info
, int fd
,
819 struct btf_attach_table
*btf_prog_table
,
820 struct btf_attach_table
*btf_map_table
)
822 struct btf_attach_point
*obj
;
824 jsonw_start_object(json_wtr
); /* btf object */
825 jsonw_uint_field(json_wtr
, "id", info
->id
);
826 jsonw_uint_field(json_wtr
, "size", info
->btf_size
);
828 jsonw_name(json_wtr
, "prog_ids");
829 jsonw_start_array(json_wtr
); /* prog_ids */
830 hash_for_each_possible(btf_prog_table
->table
, obj
, hash
,
832 if (obj
->btf_id
== info
->id
)
833 jsonw_uint(json_wtr
, obj
->obj_id
);
835 jsonw_end_array(json_wtr
); /* prog_ids */
837 jsonw_name(json_wtr
, "map_ids");
838 jsonw_start_array(json_wtr
); /* map_ids */
839 hash_for_each_possible(btf_map_table
->table
, obj
, hash
,
841 if (obj
->btf_id
== info
->id
)
842 jsonw_uint(json_wtr
, obj
->obj_id
);
844 jsonw_end_array(json_wtr
); /* map_ids */
845 jsonw_end_object(json_wtr
); /* btf object */
849 show_btf(int fd
, struct btf_attach_table
*btf_prog_table
,
850 struct btf_attach_table
*btf_map_table
)
852 struct bpf_btf_info info
= {};
853 __u32 len
= sizeof(info
);
856 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
858 p_err("can't get BTF object info: %s", strerror(errno
));
863 show_btf_json(&info
, fd
, btf_prog_table
, btf_map_table
);
865 show_btf_plain(&info
, fd
, btf_prog_table
, btf_map_table
);
870 static int do_show(int argc
, char **argv
)
872 struct btf_attach_table btf_prog_table
;
873 struct btf_attach_table btf_map_table
;
878 fd
= btf_parse_fd(&argc
, &argv
);
889 hash_init(btf_prog_table
.table
);
890 hash_init(btf_map_table
.table
);
891 err
= build_btf_tables(&btf_prog_table
, &btf_map_table
);
899 err
= show_btf(fd
, &btf_prog_table
, &btf_map_table
);
905 jsonw_start_array(json_wtr
); /* root array */
908 err
= bpf_btf_get_next_id(id
, &id
);
910 if (errno
== ENOENT
) {
914 p_err("can't get next BTF object: %s%s",
916 errno
== EINVAL
? " -- kernel too old?" : "");
921 fd
= bpf_btf_get_fd_by_id(id
);
925 p_err("can't get BTF object by id (%u): %s",
926 id
, strerror(errno
));
931 err
= show_btf(fd
, &btf_prog_table
, &btf_map_table
);
938 jsonw_end_array(json_wtr
); /* root array */
941 delete_btf_table(&btf_prog_table
);
942 delete_btf_table(&btf_map_table
);
947 static int do_help(int argc
, char **argv
)
950 jsonw_null(json_wtr
);
955 "Usage: %s btf { show | list } [id BTF_ID]\n"
956 " %s btf dump BTF_SRC [format FORMAT]\n"
959 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
960 " FORMAT := { raw | c }\n"
961 " " HELP_SPEC_MAP
"\n"
962 " " HELP_SPEC_PROGRAM
"\n"
963 " " HELP_SPEC_OPTIONS
"\n"
965 bin_name
, bin_name
, bin_name
);
970 static const struct cmd cmds
[] = {
978 int do_btf(int argc
, char **argv
)
980 return cmd_select(cmds
, argc
, argv
, do_help
);