Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2019 Facebook */
0003 
0004 #include <errno.h>
0005 #include <fcntl.h>
0006 #include <linux/err.h>
0007 #include <stdbool.h>
0008 #include <stdio.h>
0009 #include <string.h>
0010 #include <unistd.h>
0011 #include <linux/btf.h>
0012 #include <sys/types.h>
0013 #include <sys/stat.h>
0014 
0015 #include <bpf/bpf.h>
0016 #include <bpf/btf.h>
0017 #include <bpf/hashmap.h>
0018 #include <bpf/libbpf.h>
0019 
0020 #include "json_writer.h"
0021 #include "main.h"
0022 
0023 static const char * const btf_kind_str[NR_BTF_KINDS] = {
0024     [BTF_KIND_UNKN]     = "UNKNOWN",
0025     [BTF_KIND_INT]      = "INT",
0026     [BTF_KIND_PTR]      = "PTR",
0027     [BTF_KIND_ARRAY]    = "ARRAY",
0028     [BTF_KIND_STRUCT]   = "STRUCT",
0029     [BTF_KIND_UNION]    = "UNION",
0030     [BTF_KIND_ENUM]     = "ENUM",
0031     [BTF_KIND_FWD]      = "FWD",
0032     [BTF_KIND_TYPEDEF]  = "TYPEDEF",
0033     [BTF_KIND_VOLATILE] = "VOLATILE",
0034     [BTF_KIND_CONST]    = "CONST",
0035     [BTF_KIND_RESTRICT] = "RESTRICT",
0036     [BTF_KIND_FUNC]     = "FUNC",
0037     [BTF_KIND_FUNC_PROTO]   = "FUNC_PROTO",
0038     [BTF_KIND_VAR]      = "VAR",
0039     [BTF_KIND_DATASEC]  = "DATASEC",
0040     [BTF_KIND_FLOAT]    = "FLOAT",
0041     [BTF_KIND_DECL_TAG] = "DECL_TAG",
0042     [BTF_KIND_TYPE_TAG] = "TYPE_TAG",
0043     [BTF_KIND_ENUM64]   = "ENUM64",
0044 };
0045 
0046 struct btf_attach_point {
0047     __u32 obj_id;
0048     __u32 btf_id;
0049 };
0050 
0051 static const char *btf_int_enc_str(__u8 encoding)
0052 {
0053     switch (encoding) {
0054     case 0:
0055         return "(none)";
0056     case BTF_INT_SIGNED:
0057         return "SIGNED";
0058     case BTF_INT_CHAR:
0059         return "CHAR";
0060     case BTF_INT_BOOL:
0061         return "BOOL";
0062     default:
0063         return "UNKN";
0064     }
0065 }
0066 
0067 static const char *btf_var_linkage_str(__u32 linkage)
0068 {
0069     switch (linkage) {
0070     case BTF_VAR_STATIC:
0071         return "static";
0072     case BTF_VAR_GLOBAL_ALLOCATED:
0073         return "global";
0074     case BTF_VAR_GLOBAL_EXTERN:
0075         return "extern";
0076     default:
0077         return "(unknown)";
0078     }
0079 }
0080 
0081 static const char *btf_func_linkage_str(const struct btf_type *t)
0082 {
0083     switch (btf_vlen(t)) {
0084     case BTF_FUNC_STATIC:
0085         return "static";
0086     case BTF_FUNC_GLOBAL:
0087         return "global";
0088     case BTF_FUNC_EXTERN:
0089         return "extern";
0090     default:
0091         return "(unknown)";
0092     }
0093 }
0094 
0095 static const char *btf_str(const struct btf *btf, __u32 off)
0096 {
0097     if (!off)
0098         return "(anon)";
0099     return btf__name_by_offset(btf, off) ? : "(invalid)";
0100 }
0101 
0102 static int btf_kind_safe(int kind)
0103 {
0104     return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
0105 }
0106 
0107 static int dump_btf_type(const struct btf *btf, __u32 id,
0108              const struct btf_type *t)
0109 {
0110     json_writer_t *w = json_wtr;
0111     int kind = btf_kind(t);
0112 
0113     if (json_output) {
0114         jsonw_start_object(w);
0115         jsonw_uint_field(w, "id", id);
0116         jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
0117         jsonw_string_field(w, "name", btf_str(btf, t->name_off));
0118     } else {
0119         printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
0120                btf_str(btf, t->name_off));
0121     }
0122 
0123     switch (kind) {
0124     case BTF_KIND_INT: {
0125         __u32 v = *(__u32 *)(t + 1);
0126         const char *enc;
0127 
0128         enc = btf_int_enc_str(BTF_INT_ENCODING(v));
0129 
0130         if (json_output) {
0131             jsonw_uint_field(w, "size", t->size);
0132             jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
0133             jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
0134             jsonw_string_field(w, "encoding", enc);
0135         } else {
0136             printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
0137                    t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
0138                    enc);
0139         }
0140         break;
0141     }
0142     case BTF_KIND_PTR:
0143     case BTF_KIND_CONST:
0144     case BTF_KIND_VOLATILE:
0145     case BTF_KIND_RESTRICT:
0146     case BTF_KIND_TYPEDEF:
0147     case BTF_KIND_TYPE_TAG:
0148         if (json_output)
0149             jsonw_uint_field(w, "type_id", t->type);
0150         else
0151             printf(" type_id=%u", t->type);
0152         break;
0153     case BTF_KIND_ARRAY: {
0154         const struct btf_array *arr = (const void *)(t + 1);
0155 
0156         if (json_output) {
0157             jsonw_uint_field(w, "type_id", arr->type);
0158             jsonw_uint_field(w, "index_type_id", arr->index_type);
0159             jsonw_uint_field(w, "nr_elems", arr->nelems);
0160         } else {
0161             printf(" type_id=%u index_type_id=%u nr_elems=%u",
0162                    arr->type, arr->index_type, arr->nelems);
0163         }
0164         break;
0165     }
0166     case BTF_KIND_STRUCT:
0167     case BTF_KIND_UNION: {
0168         const struct btf_member *m = (const void *)(t + 1);
0169         __u16 vlen = BTF_INFO_VLEN(t->info);
0170         int i;
0171 
0172         if (json_output) {
0173             jsonw_uint_field(w, "size", t->size);
0174             jsonw_uint_field(w, "vlen", vlen);
0175             jsonw_name(w, "members");
0176             jsonw_start_array(w);
0177         } else {
0178             printf(" size=%u vlen=%u", t->size, vlen);
0179         }
0180         for (i = 0; i < vlen; i++, m++) {
0181             const char *name = btf_str(btf, m->name_off);
0182             __u32 bit_off, bit_sz;
0183 
0184             if (BTF_INFO_KFLAG(t->info)) {
0185                 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
0186                 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
0187             } else {
0188                 bit_off = m->offset;
0189                 bit_sz = 0;
0190             }
0191 
0192             if (json_output) {
0193                 jsonw_start_object(w);
0194                 jsonw_string_field(w, "name", name);
0195                 jsonw_uint_field(w, "type_id", m->type);
0196                 jsonw_uint_field(w, "bits_offset", bit_off);
0197                 if (bit_sz) {
0198                     jsonw_uint_field(w, "bitfield_size",
0199                              bit_sz);
0200                 }
0201                 jsonw_end_object(w);
0202             } else {
0203                 printf("\n\t'%s' type_id=%u bits_offset=%u",
0204                        name, m->type, bit_off);
0205                 if (bit_sz)
0206                     printf(" bitfield_size=%u", bit_sz);
0207             }
0208         }
0209         if (json_output)
0210             jsonw_end_array(w);
0211         break;
0212     }
0213     case BTF_KIND_ENUM: {
0214         const struct btf_enum *v = (const void *)(t + 1);
0215         __u16 vlen = BTF_INFO_VLEN(t->info);
0216         const char *encoding;
0217         int i;
0218 
0219         encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
0220         if (json_output) {
0221             jsonw_string_field(w, "encoding", encoding);
0222             jsonw_uint_field(w, "size", t->size);
0223             jsonw_uint_field(w, "vlen", vlen);
0224             jsonw_name(w, "values");
0225             jsonw_start_array(w);
0226         } else {
0227             printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
0228         }
0229         for (i = 0; i < vlen; i++, v++) {
0230             const char *name = btf_str(btf, v->name_off);
0231 
0232             if (json_output) {
0233                 jsonw_start_object(w);
0234                 jsonw_string_field(w, "name", name);
0235                 if (btf_kflag(t))
0236                     jsonw_int_field(w, "val", v->val);
0237                 else
0238                     jsonw_uint_field(w, "val", v->val);
0239                 jsonw_end_object(w);
0240             } else {
0241                 if (btf_kflag(t))
0242                     printf("\n\t'%s' val=%d", name, v->val);
0243                 else
0244                     printf("\n\t'%s' val=%u", name, v->val);
0245             }
0246         }
0247         if (json_output)
0248             jsonw_end_array(w);
0249         break;
0250     }
0251     case BTF_KIND_ENUM64: {
0252         const struct btf_enum64 *v = btf_enum64(t);
0253         __u16 vlen = btf_vlen(t);
0254         const char *encoding;
0255         int i;
0256 
0257         encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
0258         if (json_output) {
0259             jsonw_string_field(w, "encoding", encoding);
0260             jsonw_uint_field(w, "size", t->size);
0261             jsonw_uint_field(w, "vlen", vlen);
0262             jsonw_name(w, "values");
0263             jsonw_start_array(w);
0264         } else {
0265             printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
0266         }
0267         for (i = 0; i < vlen; i++, v++) {
0268             const char *name = btf_str(btf, v->name_off);
0269             __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
0270 
0271             if (json_output) {
0272                 jsonw_start_object(w);
0273                 jsonw_string_field(w, "name", name);
0274                 if (btf_kflag(t))
0275                     jsonw_int_field(w, "val", val);
0276                 else
0277                     jsonw_uint_field(w, "val", val);
0278                 jsonw_end_object(w);
0279             } else {
0280                 if (btf_kflag(t))
0281                     printf("\n\t'%s' val=%lldLL", name,
0282                            (unsigned long long)val);
0283                 else
0284                     printf("\n\t'%s' val=%lluULL", name,
0285                            (unsigned long long)val);
0286             }
0287         }
0288         if (json_output)
0289             jsonw_end_array(w);
0290         break;
0291     }
0292     case BTF_KIND_FWD: {
0293         const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
0294                                    : "struct";
0295 
0296         if (json_output)
0297             jsonw_string_field(w, "fwd_kind", fwd_kind);
0298         else
0299             printf(" fwd_kind=%s", fwd_kind);
0300         break;
0301     }
0302     case BTF_KIND_FUNC: {
0303         const char *linkage = btf_func_linkage_str(t);
0304 
0305         if (json_output) {
0306             jsonw_uint_field(w, "type_id", t->type);
0307             jsonw_string_field(w, "linkage", linkage);
0308         } else {
0309             printf(" type_id=%u linkage=%s", t->type, linkage);
0310         }
0311         break;
0312     }
0313     case BTF_KIND_FUNC_PROTO: {
0314         const struct btf_param *p = (const void *)(t + 1);
0315         __u16 vlen = BTF_INFO_VLEN(t->info);
0316         int i;
0317 
0318         if (json_output) {
0319             jsonw_uint_field(w, "ret_type_id", t->type);
0320             jsonw_uint_field(w, "vlen", vlen);
0321             jsonw_name(w, "params");
0322             jsonw_start_array(w);
0323         } else {
0324             printf(" ret_type_id=%u vlen=%u", t->type, vlen);
0325         }
0326         for (i = 0; i < vlen; i++, p++) {
0327             const char *name = btf_str(btf, p->name_off);
0328 
0329             if (json_output) {
0330                 jsonw_start_object(w);
0331                 jsonw_string_field(w, "name", name);
0332                 jsonw_uint_field(w, "type_id", p->type);
0333                 jsonw_end_object(w);
0334             } else {
0335                 printf("\n\t'%s' type_id=%u", name, p->type);
0336             }
0337         }
0338         if (json_output)
0339             jsonw_end_array(w);
0340         break;
0341     }
0342     case BTF_KIND_VAR: {
0343         const struct btf_var *v = (const void *)(t + 1);
0344         const char *linkage;
0345 
0346         linkage = btf_var_linkage_str(v->linkage);
0347 
0348         if (json_output) {
0349             jsonw_uint_field(w, "type_id", t->type);
0350             jsonw_string_field(w, "linkage", linkage);
0351         } else {
0352             printf(" type_id=%u, linkage=%s", t->type, linkage);
0353         }
0354         break;
0355     }
0356     case BTF_KIND_DATASEC: {
0357         const struct btf_var_secinfo *v = (const void *)(t + 1);
0358         const struct btf_type *vt;
0359         __u16 vlen = BTF_INFO_VLEN(t->info);
0360         int i;
0361 
0362         if (json_output) {
0363             jsonw_uint_field(w, "size", t->size);
0364             jsonw_uint_field(w, "vlen", vlen);
0365             jsonw_name(w, "vars");
0366             jsonw_start_array(w);
0367         } else {
0368             printf(" size=%u vlen=%u", t->size, vlen);
0369         }
0370         for (i = 0; i < vlen; i++, v++) {
0371             if (json_output) {
0372                 jsonw_start_object(w);
0373                 jsonw_uint_field(w, "type_id", v->type);
0374                 jsonw_uint_field(w, "offset", v->offset);
0375                 jsonw_uint_field(w, "size", v->size);
0376                 jsonw_end_object(w);
0377             } else {
0378                 printf("\n\ttype_id=%u offset=%u size=%u",
0379                        v->type, v->offset, v->size);
0380 
0381                 if (v->type < btf__type_cnt(btf)) {
0382                     vt = btf__type_by_id(btf, v->type);
0383                     printf(" (%s '%s')",
0384                            btf_kind_str[btf_kind_safe(btf_kind(vt))],
0385                            btf_str(btf, vt->name_off));
0386                 }
0387             }
0388         }
0389         if (json_output)
0390             jsonw_end_array(w);
0391         break;
0392     }
0393     case BTF_KIND_FLOAT: {
0394         if (json_output)
0395             jsonw_uint_field(w, "size", t->size);
0396         else
0397             printf(" size=%u", t->size);
0398         break;
0399     }
0400     case BTF_KIND_DECL_TAG: {
0401         const struct btf_decl_tag *tag = (const void *)(t + 1);
0402 
0403         if (json_output) {
0404             jsonw_uint_field(w, "type_id", t->type);
0405             jsonw_int_field(w, "component_idx", tag->component_idx);
0406         } else {
0407             printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
0408         }
0409         break;
0410     }
0411     default:
0412         break;
0413     }
0414 
0415     if (json_output)
0416         jsonw_end_object(json_wtr);
0417     else
0418         printf("\n");
0419 
0420     return 0;
0421 }
0422 
0423 static int dump_btf_raw(const struct btf *btf,
0424             __u32 *root_type_ids, int root_type_cnt)
0425 {
0426     const struct btf_type *t;
0427     int i;
0428 
0429     if (json_output) {
0430         jsonw_start_object(json_wtr);
0431         jsonw_name(json_wtr, "types");
0432         jsonw_start_array(json_wtr);
0433     }
0434 
0435     if (root_type_cnt) {
0436         for (i = 0; i < root_type_cnt; i++) {
0437             t = btf__type_by_id(btf, root_type_ids[i]);
0438             dump_btf_type(btf, root_type_ids[i], t);
0439         }
0440     } else {
0441         const struct btf *base;
0442         int cnt = btf__type_cnt(btf);
0443         int start_id = 1;
0444 
0445         base = btf__base_btf(btf);
0446         if (base)
0447             start_id = btf__type_cnt(base);
0448 
0449         for (i = start_id; i < cnt; i++) {
0450             t = btf__type_by_id(btf, i);
0451             dump_btf_type(btf, i, t);
0452         }
0453     }
0454 
0455     if (json_output) {
0456         jsonw_end_array(json_wtr);
0457         jsonw_end_object(json_wtr);
0458     }
0459     return 0;
0460 }
0461 
0462 static void __printf(2, 0) btf_dump_printf(void *ctx,
0463                        const char *fmt, va_list args)
0464 {
0465     vfprintf(stdout, fmt, args);
0466 }
0467 
0468 static int dump_btf_c(const struct btf *btf,
0469               __u32 *root_type_ids, int root_type_cnt)
0470 {
0471     struct btf_dump *d;
0472     int err = 0, i;
0473 
0474     d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
0475     err = libbpf_get_error(d);
0476     if (err)
0477         return err;
0478 
0479     printf("#ifndef __VMLINUX_H__\n");
0480     printf("#define __VMLINUX_H__\n");
0481     printf("\n");
0482     printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
0483     printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
0484     printf("#endif\n\n");
0485 
0486     if (root_type_cnt) {
0487         for (i = 0; i < root_type_cnt; i++) {
0488             err = btf_dump__dump_type(d, root_type_ids[i]);
0489             if (err)
0490                 goto done;
0491         }
0492     } else {
0493         int cnt = btf__type_cnt(btf);
0494 
0495         for (i = 1; i < cnt; i++) {
0496             err = btf_dump__dump_type(d, i);
0497             if (err)
0498                 goto done;
0499         }
0500     }
0501 
0502     printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
0503     printf("#pragma clang attribute pop\n");
0504     printf("#endif\n");
0505     printf("\n");
0506     printf("#endif /* __VMLINUX_H__ */\n");
0507 
0508 done:
0509     btf_dump__free(d);
0510     return err;
0511 }
0512 
0513 static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
0514 
0515 static struct btf *get_vmlinux_btf_from_sysfs(void)
0516 {
0517     struct btf *base;
0518 
0519     base = btf__parse(sysfs_vmlinux, NULL);
0520     if (libbpf_get_error(base)) {
0521         p_err("failed to parse vmlinux BTF at '%s': %ld\n",
0522               sysfs_vmlinux, libbpf_get_error(base));
0523         base = NULL;
0524     }
0525 
0526     return base;
0527 }
0528 
0529 #define BTF_NAME_BUFF_LEN 64
0530 
0531 static bool btf_is_kernel_module(__u32 btf_id)
0532 {
0533     struct bpf_btf_info btf_info = {};
0534     char btf_name[BTF_NAME_BUFF_LEN];
0535     int btf_fd;
0536     __u32 len;
0537     int err;
0538 
0539     btf_fd = bpf_btf_get_fd_by_id(btf_id);
0540     if (btf_fd < 0) {
0541         p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));
0542         return false;
0543     }
0544 
0545     len = sizeof(btf_info);
0546     btf_info.name = ptr_to_u64(btf_name);
0547     btf_info.name_len = sizeof(btf_name);
0548     err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
0549     close(btf_fd);
0550     if (err) {
0551         p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));
0552         return false;
0553     }
0554 
0555     return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;
0556 }
0557 
0558 static int do_dump(int argc, char **argv)
0559 {
0560     struct btf *btf = NULL, *base = NULL;
0561     __u32 root_type_ids[2];
0562     int root_type_cnt = 0;
0563     bool dump_c = false;
0564     __u32 btf_id = -1;
0565     const char *src;
0566     int fd = -1;
0567     int err;
0568 
0569     if (!REQ_ARGS(2)) {
0570         usage();
0571         return -1;
0572     }
0573     src = GET_ARG();
0574     if (is_prefix(src, "map")) {
0575         struct bpf_map_info info = {};
0576         __u32 len = sizeof(info);
0577 
0578         if (!REQ_ARGS(2)) {
0579             usage();
0580             return -1;
0581         }
0582 
0583         fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
0584         if (fd < 0)
0585             return -1;
0586 
0587         btf_id = info.btf_id;
0588         if (argc && is_prefix(*argv, "key")) {
0589             root_type_ids[root_type_cnt++] = info.btf_key_type_id;
0590             NEXT_ARG();
0591         } else if (argc && is_prefix(*argv, "value")) {
0592             root_type_ids[root_type_cnt++] = info.btf_value_type_id;
0593             NEXT_ARG();
0594         } else if (argc && is_prefix(*argv, "all")) {
0595             NEXT_ARG();
0596         } else if (argc && is_prefix(*argv, "kv")) {
0597             root_type_ids[root_type_cnt++] = info.btf_key_type_id;
0598             root_type_ids[root_type_cnt++] = info.btf_value_type_id;
0599             NEXT_ARG();
0600         } else {
0601             root_type_ids[root_type_cnt++] = info.btf_key_type_id;
0602             root_type_ids[root_type_cnt++] = info.btf_value_type_id;
0603         }
0604     } else if (is_prefix(src, "prog")) {
0605         struct bpf_prog_info info = {};
0606         __u32 len = sizeof(info);
0607 
0608         if (!REQ_ARGS(2)) {
0609             usage();
0610             return -1;
0611         }
0612 
0613         fd = prog_parse_fd(&argc, &argv);
0614         if (fd < 0)
0615             return -1;
0616 
0617         err = bpf_obj_get_info_by_fd(fd, &info, &len);
0618         if (err) {
0619             p_err("can't get prog info: %s", strerror(errno));
0620             goto done;
0621         }
0622 
0623         btf_id = info.btf_id;
0624     } else if (is_prefix(src, "id")) {
0625         char *endptr;
0626 
0627         btf_id = strtoul(*argv, &endptr, 0);
0628         if (*endptr) {
0629             p_err("can't parse %s as ID", *argv);
0630             return -1;
0631         }
0632         NEXT_ARG();
0633     } else if (is_prefix(src, "file")) {
0634         const char sysfs_prefix[] = "/sys/kernel/btf/";
0635 
0636         if (!base_btf &&
0637             strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
0638             strcmp(*argv, sysfs_vmlinux) != 0)
0639             base = get_vmlinux_btf_from_sysfs();
0640 
0641         btf = btf__parse_split(*argv, base ?: base_btf);
0642         err = libbpf_get_error(btf);
0643         if (err) {
0644             btf = NULL;
0645             p_err("failed to load BTF from %s: %s",
0646                   *argv, strerror(err));
0647             goto done;
0648         }
0649         NEXT_ARG();
0650     } else {
0651         err = -1;
0652         p_err("unrecognized BTF source specifier: '%s'", src);
0653         goto done;
0654     }
0655 
0656     while (argc) {
0657         if (is_prefix(*argv, "format")) {
0658             NEXT_ARG();
0659             if (argc < 1) {
0660                 p_err("expecting value for 'format' option\n");
0661                 err = -EINVAL;
0662                 goto done;
0663             }
0664             if (strcmp(*argv, "c") == 0) {
0665                 dump_c = true;
0666             } else if (strcmp(*argv, "raw") == 0) {
0667                 dump_c = false;
0668             } else {
0669                 p_err("unrecognized format specifier: '%s', possible values: raw, c",
0670                       *argv);
0671                 err = -EINVAL;
0672                 goto done;
0673             }
0674             NEXT_ARG();
0675         } else {
0676             p_err("unrecognized option: '%s'", *argv);
0677             err = -EINVAL;
0678             goto done;
0679         }
0680     }
0681 
0682     if (!btf) {
0683         if (!base_btf && btf_is_kernel_module(btf_id)) {
0684             p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",
0685                    sysfs_vmlinux);
0686             base_btf = get_vmlinux_btf_from_sysfs();
0687         }
0688 
0689         btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
0690         err = libbpf_get_error(btf);
0691         if (err) {
0692             p_err("get btf by id (%u): %s", btf_id, strerror(err));
0693             goto done;
0694         }
0695     }
0696 
0697     if (dump_c) {
0698         if (json_output) {
0699             p_err("JSON output for C-syntax dump is not supported");
0700             err = -ENOTSUP;
0701             goto done;
0702         }
0703         err = dump_btf_c(btf, root_type_ids, root_type_cnt);
0704     } else {
0705         err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
0706     }
0707 
0708 done:
0709     close(fd);
0710     btf__free(btf);
0711     btf__free(base);
0712     return err;
0713 }
0714 
0715 static int btf_parse_fd(int *argc, char ***argv)
0716 {
0717     unsigned int id;
0718     char *endptr;
0719     int fd;
0720 
0721     if (!is_prefix(*argv[0], "id")) {
0722         p_err("expected 'id', got: '%s'?", **argv);
0723         return -1;
0724     }
0725     NEXT_ARGP();
0726 
0727     id = strtoul(**argv, &endptr, 0);
0728     if (*endptr) {
0729         p_err("can't parse %s as ID", **argv);
0730         return -1;
0731     }
0732     NEXT_ARGP();
0733 
0734     fd = bpf_btf_get_fd_by_id(id);
0735     if (fd < 0)
0736         p_err("can't get BTF object by id (%u): %s",
0737               id, strerror(errno));
0738 
0739     return fd;
0740 }
0741 
0742 static int
0743 build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
0744              void *info, __u32 *len)
0745 {
0746     static const char * const names[] = {
0747         [BPF_OBJ_UNKNOWN]   = "unknown",
0748         [BPF_OBJ_PROG]      = "prog",
0749         [BPF_OBJ_MAP]       = "map",
0750     };
0751     __u32 btf_id, id = 0;
0752     int err;
0753     int fd;
0754 
0755     while (true) {
0756         switch (type) {
0757         case BPF_OBJ_PROG:
0758             err = bpf_prog_get_next_id(id, &id);
0759             break;
0760         case BPF_OBJ_MAP:
0761             err = bpf_map_get_next_id(id, &id);
0762             break;
0763         default:
0764             err = -1;
0765             p_err("unexpected object type: %d", type);
0766             goto err_free;
0767         }
0768         if (err) {
0769             if (errno == ENOENT) {
0770                 err = 0;
0771                 break;
0772             }
0773             p_err("can't get next %s: %s%s", names[type],
0774                   strerror(errno),
0775                   errno == EINVAL ? " -- kernel too old?" : "");
0776             goto err_free;
0777         }
0778 
0779         switch (type) {
0780         case BPF_OBJ_PROG:
0781             fd = bpf_prog_get_fd_by_id(id);
0782             break;
0783         case BPF_OBJ_MAP:
0784             fd = bpf_map_get_fd_by_id(id);
0785             break;
0786         default:
0787             err = -1;
0788             p_err("unexpected object type: %d", type);
0789             goto err_free;
0790         }
0791         if (fd < 0) {
0792             if (errno == ENOENT)
0793                 continue;
0794             p_err("can't get %s by id (%u): %s", names[type], id,
0795                   strerror(errno));
0796             err = -1;
0797             goto err_free;
0798         }
0799 
0800         memset(info, 0, *len);
0801         err = bpf_obj_get_info_by_fd(fd, info, len);
0802         close(fd);
0803         if (err) {
0804             p_err("can't get %s info: %s", names[type],
0805                   strerror(errno));
0806             goto err_free;
0807         }
0808 
0809         switch (type) {
0810         case BPF_OBJ_PROG:
0811             btf_id = ((struct bpf_prog_info *)info)->btf_id;
0812             break;
0813         case BPF_OBJ_MAP:
0814             btf_id = ((struct bpf_map_info *)info)->btf_id;
0815             break;
0816         default:
0817             err = -1;
0818             p_err("unexpected object type: %d", type);
0819             goto err_free;
0820         }
0821         if (!btf_id)
0822             continue;
0823 
0824         err = hashmap__append(tab, u32_as_hash_field(btf_id),
0825                       u32_as_hash_field(id));
0826         if (err) {
0827             p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
0828                   btf_id, id, strerror(errno));
0829             goto err_free;
0830         }
0831     }
0832 
0833     return 0;
0834 
0835 err_free:
0836     hashmap__free(tab);
0837     return err;
0838 }
0839 
0840 static int
0841 build_btf_tables(struct hashmap *btf_prog_table,
0842          struct hashmap *btf_map_table)
0843 {
0844     struct bpf_prog_info prog_info;
0845     __u32 prog_len = sizeof(prog_info);
0846     struct bpf_map_info map_info;
0847     __u32 map_len = sizeof(map_info);
0848     int err = 0;
0849 
0850     err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
0851                    &prog_len);
0852     if (err)
0853         return err;
0854 
0855     err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
0856                    &map_len);
0857     if (err) {
0858         hashmap__free(btf_prog_table);
0859         return err;
0860     }
0861 
0862     return 0;
0863 }
0864 
0865 static void
0866 show_btf_plain(struct bpf_btf_info *info, int fd,
0867            struct hashmap *btf_prog_table,
0868            struct hashmap *btf_map_table)
0869 {
0870     struct hashmap_entry *entry;
0871     const char *name = u64_to_ptr(info->name);
0872     int n;
0873 
0874     printf("%u: ", info->id);
0875     if (info->kernel_btf)
0876         printf("name [%s]  ", name);
0877     else if (name && name[0])
0878         printf("name %s  ", name);
0879     else
0880         printf("name <anon>  ");
0881     printf("size %uB", info->btf_size);
0882 
0883     n = 0;
0884     hashmap__for_each_key_entry(btf_prog_table, entry,
0885                     u32_as_hash_field(info->id)) {
0886         printf("%s%u", n++ == 0 ? "  prog_ids " : ",",
0887                hash_field_as_u32(entry->value));
0888     }
0889 
0890     n = 0;
0891     hashmap__for_each_key_entry(btf_map_table, entry,
0892                     u32_as_hash_field(info->id)) {
0893         printf("%s%u", n++ == 0 ? "  map_ids " : ",",
0894                hash_field_as_u32(entry->value));
0895     }
0896 
0897     emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
0898 
0899     printf("\n");
0900 }
0901 
0902 static void
0903 show_btf_json(struct bpf_btf_info *info, int fd,
0904           struct hashmap *btf_prog_table,
0905           struct hashmap *btf_map_table)
0906 {
0907     struct hashmap_entry *entry;
0908     const char *name = u64_to_ptr(info->name);
0909 
0910     jsonw_start_object(json_wtr);   /* btf object */
0911     jsonw_uint_field(json_wtr, "id", info->id);
0912     jsonw_uint_field(json_wtr, "size", info->btf_size);
0913 
0914     jsonw_name(json_wtr, "prog_ids");
0915     jsonw_start_array(json_wtr);    /* prog_ids */
0916     hashmap__for_each_key_entry(btf_prog_table, entry,
0917                     u32_as_hash_field(info->id)) {
0918         jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
0919     }
0920     jsonw_end_array(json_wtr);  /* prog_ids */
0921 
0922     jsonw_name(json_wtr, "map_ids");
0923     jsonw_start_array(json_wtr);    /* map_ids */
0924     hashmap__for_each_key_entry(btf_map_table, entry,
0925                     u32_as_hash_field(info->id)) {
0926         jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
0927     }
0928     jsonw_end_array(json_wtr);  /* map_ids */
0929 
0930     emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
0931 
0932     jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
0933 
0934     if (name && name[0])
0935         jsonw_string_field(json_wtr, "name", name);
0936 
0937     jsonw_end_object(json_wtr); /* btf object */
0938 }
0939 
0940 static int
0941 show_btf(int fd, struct hashmap *btf_prog_table,
0942      struct hashmap *btf_map_table)
0943 {
0944     struct bpf_btf_info info;
0945     __u32 len = sizeof(info);
0946     char name[64];
0947     int err;
0948 
0949     memset(&info, 0, sizeof(info));
0950     err = bpf_obj_get_info_by_fd(fd, &info, &len);
0951     if (err) {
0952         p_err("can't get BTF object info: %s", strerror(errno));
0953         return -1;
0954     }
0955     /* if kernel support emitting BTF object name, pass name pointer */
0956     if (info.name_len) {
0957         memset(&info, 0, sizeof(info));
0958         info.name_len = sizeof(name);
0959         info.name = ptr_to_u64(name);
0960         len = sizeof(info);
0961 
0962         err = bpf_obj_get_info_by_fd(fd, &info, &len);
0963         if (err) {
0964             p_err("can't get BTF object info: %s", strerror(errno));
0965             return -1;
0966         }
0967     }
0968 
0969     if (json_output)
0970         show_btf_json(&info, fd, btf_prog_table, btf_map_table);
0971     else
0972         show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
0973 
0974     return 0;
0975 }
0976 
0977 static int do_show(int argc, char **argv)
0978 {
0979     struct hashmap *btf_prog_table;
0980     struct hashmap *btf_map_table;
0981     int err, fd = -1;
0982     __u32 id = 0;
0983 
0984     if (argc == 2) {
0985         fd = btf_parse_fd(&argc, &argv);
0986         if (fd < 0)
0987             return -1;
0988     }
0989 
0990     if (argc) {
0991         if (fd >= 0)
0992             close(fd);
0993         return BAD_ARG();
0994     }
0995 
0996     btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
0997                       equal_fn_for_key_as_id, NULL);
0998     btf_map_table = hashmap__new(hash_fn_for_key_as_id,
0999                      equal_fn_for_key_as_id, NULL);
1000     if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {
1001         hashmap__free(btf_prog_table);
1002         hashmap__free(btf_map_table);
1003         if (fd >= 0)
1004             close(fd);
1005         p_err("failed to create hashmap for object references");
1006         return -1;
1007     }
1008     err = build_btf_tables(btf_prog_table, btf_map_table);
1009     if (err) {
1010         if (fd >= 0)
1011             close(fd);
1012         return err;
1013     }
1014     build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
1015 
1016     if (fd >= 0) {
1017         err = show_btf(fd, btf_prog_table, btf_map_table);
1018         close(fd);
1019         goto exit_free;
1020     }
1021 
1022     if (json_output)
1023         jsonw_start_array(json_wtr);    /* root array */
1024 
1025     while (true) {
1026         err = bpf_btf_get_next_id(id, &id);
1027         if (err) {
1028             if (errno == ENOENT) {
1029                 err = 0;
1030                 break;
1031             }
1032             p_err("can't get next BTF object: %s%s",
1033                   strerror(errno),
1034                   errno == EINVAL ? " -- kernel too old?" : "");
1035             err = -1;
1036             break;
1037         }
1038 
1039         fd = bpf_btf_get_fd_by_id(id);
1040         if (fd < 0) {
1041             if (errno == ENOENT)
1042                 continue;
1043             p_err("can't get BTF object by id (%u): %s",
1044                   id, strerror(errno));
1045             err = -1;
1046             break;
1047         }
1048 
1049         err = show_btf(fd, btf_prog_table, btf_map_table);
1050         close(fd);
1051         if (err)
1052             break;
1053     }
1054 
1055     if (json_output)
1056         jsonw_end_array(json_wtr);  /* root array */
1057 
1058 exit_free:
1059     hashmap__free(btf_prog_table);
1060     hashmap__free(btf_map_table);
1061     delete_obj_refs_table(refs_table);
1062 
1063     return err;
1064 }
1065 
1066 static int do_help(int argc, char **argv)
1067 {
1068     if (json_output) {
1069         jsonw_null(json_wtr);
1070         return 0;
1071     }
1072 
1073     fprintf(stderr,
1074         "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
1075         "       %1$s %2$s dump BTF_SRC [format FORMAT]\n"
1076         "       %1$s %2$s help\n"
1077         "\n"
1078         "       BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
1079         "       FORMAT  := { raw | c }\n"
1080         "       " HELP_SPEC_MAP "\n"
1081         "       " HELP_SPEC_PROGRAM "\n"
1082         "       " HELP_SPEC_OPTIONS " |\n"
1083         "                    {-B|--base-btf} }\n"
1084         "",
1085         bin_name, "btf");
1086 
1087     return 0;
1088 }
1089 
1090 static const struct cmd cmds[] = {
1091     { "show",   do_show },
1092     { "list",   do_show },
1093     { "help",   do_help },
1094     { "dump",   do_dump },
1095     { 0 }
1096 };
1097 
1098 int do_btf(int argc, char **argv)
1099 {
1100     return cmd_select(cmds, argc, argv, do_help);
1101 }