1343 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2019 Facebook */3 4#include <errno.h>5#include <fcntl.h>6#include <linux/err.h>7#include <stdbool.h>8#include <stdio.h>9#include <string.h>10#include <unistd.h>11#include <linux/btf.h>12#include <sys/types.h>13#include <sys/stat.h>14 15#include <bpf/bpf.h>16#include <bpf/btf.h>17#include <bpf/hashmap.h>18#include <bpf/libbpf.h>19 20#include "json_writer.h"21#include "main.h"22 23#define KFUNC_DECL_TAG "bpf_kfunc"24 25static const char * const btf_kind_str[NR_BTF_KINDS] = {26 [BTF_KIND_UNKN] = "UNKNOWN",27 [BTF_KIND_INT] = "INT",28 [BTF_KIND_PTR] = "PTR",29 [BTF_KIND_ARRAY] = "ARRAY",30 [BTF_KIND_STRUCT] = "STRUCT",31 [BTF_KIND_UNION] = "UNION",32 [BTF_KIND_ENUM] = "ENUM",33 [BTF_KIND_FWD] = "FWD",34 [BTF_KIND_TYPEDEF] = "TYPEDEF",35 [BTF_KIND_VOLATILE] = "VOLATILE",36 [BTF_KIND_CONST] = "CONST",37 [BTF_KIND_RESTRICT] = "RESTRICT",38 [BTF_KIND_FUNC] = "FUNC",39 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",40 [BTF_KIND_VAR] = "VAR",41 [BTF_KIND_DATASEC] = "DATASEC",42 [BTF_KIND_FLOAT] = "FLOAT",43 [BTF_KIND_DECL_TAG] = "DECL_TAG",44 [BTF_KIND_TYPE_TAG] = "TYPE_TAG",45 [BTF_KIND_ENUM64] = "ENUM64",46};47 48struct sort_datum {49 int index;50 int type_rank;51 const char *sort_name;52 const char *own_name;53 __u64 disambig_hash;54};55 56static const char *btf_int_enc_str(__u8 encoding)57{58 switch (encoding) {59 case 0:60 return "(none)";61 case BTF_INT_SIGNED:62 return "SIGNED";63 case BTF_INT_CHAR:64 return "CHAR";65 case BTF_INT_BOOL:66 return "BOOL";67 default:68 return "UNKN";69 }70}71 72static const char *btf_var_linkage_str(__u32 linkage)73{74 switch (linkage) {75 case BTF_VAR_STATIC:76 return "static";77 case BTF_VAR_GLOBAL_ALLOCATED:78 return "global";79 case BTF_VAR_GLOBAL_EXTERN:80 return "extern";81 default:82 return "(unknown)";83 }84}85 86static const char *btf_func_linkage_str(const struct btf_type *t)87{88 switch (btf_vlen(t)) {89 case BTF_FUNC_STATIC:90 return "static";91 case BTF_FUNC_GLOBAL:92 return "global";93 case BTF_FUNC_EXTERN:94 return "extern";95 default:96 return "(unknown)";97 }98}99 100static const char *btf_str(const struct btf *btf, __u32 off)101{102 if (!off)103 return "(anon)";104 return btf__name_by_offset(btf, off) ? : "(invalid)";105}106 107static int btf_kind_safe(int kind)108{109 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;110}111 112static int dump_btf_type(const struct btf *btf, __u32 id,113 const struct btf_type *t)114{115 json_writer_t *w = json_wtr;116 int kind = btf_kind(t);117 118 if (json_output) {119 jsonw_start_object(w);120 jsonw_uint_field(w, "id", id);121 jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);122 jsonw_string_field(w, "name", btf_str(btf, t->name_off));123 } else {124 printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],125 btf_str(btf, t->name_off));126 }127 128 switch (kind) {129 case BTF_KIND_INT: {130 __u32 v = *(__u32 *)(t + 1);131 const char *enc;132 133 enc = btf_int_enc_str(BTF_INT_ENCODING(v));134 135 if (json_output) {136 jsonw_uint_field(w, "size", t->size);137 jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));138 jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));139 jsonw_string_field(w, "encoding", enc);140 } else {141 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",142 t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),143 enc);144 }145 break;146 }147 case BTF_KIND_PTR:148 case BTF_KIND_CONST:149 case BTF_KIND_VOLATILE:150 case BTF_KIND_RESTRICT:151 case BTF_KIND_TYPEDEF:152 case BTF_KIND_TYPE_TAG:153 if (json_output)154 jsonw_uint_field(w, "type_id", t->type);155 else156 printf(" type_id=%u", t->type);157 break;158 case BTF_KIND_ARRAY: {159 const struct btf_array *arr = (const void *)(t + 1);160 161 if (json_output) {162 jsonw_uint_field(w, "type_id", arr->type);163 jsonw_uint_field(w, "index_type_id", arr->index_type);164 jsonw_uint_field(w, "nr_elems", arr->nelems);165 } else {166 printf(" type_id=%u index_type_id=%u nr_elems=%u",167 arr->type, arr->index_type, arr->nelems);168 }169 break;170 }171 case BTF_KIND_STRUCT:172 case BTF_KIND_UNION: {173 const struct btf_member *m = (const void *)(t + 1);174 __u16 vlen = BTF_INFO_VLEN(t->info);175 int i;176 177 if (json_output) {178 jsonw_uint_field(w, "size", t->size);179 jsonw_uint_field(w, "vlen", vlen);180 jsonw_name(w, "members");181 jsonw_start_array(w);182 } else {183 printf(" size=%u vlen=%u", t->size, vlen);184 }185 for (i = 0; i < vlen; i++, m++) {186 const char *name = btf_str(btf, m->name_off);187 __u32 bit_off, bit_sz;188 189 if (BTF_INFO_KFLAG(t->info)) {190 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);191 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);192 } else {193 bit_off = m->offset;194 bit_sz = 0;195 }196 197 if (json_output) {198 jsonw_start_object(w);199 jsonw_string_field(w, "name", name);200 jsonw_uint_field(w, "type_id", m->type);201 jsonw_uint_field(w, "bits_offset", bit_off);202 if (bit_sz) {203 jsonw_uint_field(w, "bitfield_size",204 bit_sz);205 }206 jsonw_end_object(w);207 } else {208 printf("\n\t'%s' type_id=%u bits_offset=%u",209 name, m->type, bit_off);210 if (bit_sz)211 printf(" bitfield_size=%u", bit_sz);212 }213 }214 if (json_output)215 jsonw_end_array(w);216 break;217 }218 case BTF_KIND_ENUM: {219 const struct btf_enum *v = (const void *)(t + 1);220 __u16 vlen = BTF_INFO_VLEN(t->info);221 const char *encoding;222 int i;223 224 encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";225 if (json_output) {226 jsonw_string_field(w, "encoding", encoding);227 jsonw_uint_field(w, "size", t->size);228 jsonw_uint_field(w, "vlen", vlen);229 jsonw_name(w, "values");230 jsonw_start_array(w);231 } else {232 printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);233 }234 for (i = 0; i < vlen; i++, v++) {235 const char *name = btf_str(btf, v->name_off);236 237 if (json_output) {238 jsonw_start_object(w);239 jsonw_string_field(w, "name", name);240 if (btf_kflag(t))241 jsonw_int_field(w, "val", v->val);242 else243 jsonw_uint_field(w, "val", v->val);244 jsonw_end_object(w);245 } else {246 if (btf_kflag(t))247 printf("\n\t'%s' val=%d", name, v->val);248 else249 printf("\n\t'%s' val=%u", name, v->val);250 }251 }252 if (json_output)253 jsonw_end_array(w);254 break;255 }256 case BTF_KIND_ENUM64: {257 const struct btf_enum64 *v = btf_enum64(t);258 __u16 vlen = btf_vlen(t);259 const char *encoding;260 int i;261 262 encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";263 if (json_output) {264 jsonw_string_field(w, "encoding", encoding);265 jsonw_uint_field(w, "size", t->size);266 jsonw_uint_field(w, "vlen", vlen);267 jsonw_name(w, "values");268 jsonw_start_array(w);269 } else {270 printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);271 }272 for (i = 0; i < vlen; i++, v++) {273 const char *name = btf_str(btf, v->name_off);274 __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;275 276 if (json_output) {277 jsonw_start_object(w);278 jsonw_string_field(w, "name", name);279 if (btf_kflag(t))280 jsonw_int_field(w, "val", val);281 else282 jsonw_uint_field(w, "val", val);283 jsonw_end_object(w);284 } else {285 if (btf_kflag(t))286 printf("\n\t'%s' val=%lldLL", name,287 (unsigned long long)val);288 else289 printf("\n\t'%s' val=%lluULL", name,290 (unsigned long long)val);291 }292 }293 if (json_output)294 jsonw_end_array(w);295 break;296 }297 case BTF_KIND_FWD: {298 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"299 : "struct";300 301 if (json_output)302 jsonw_string_field(w, "fwd_kind", fwd_kind);303 else304 printf(" fwd_kind=%s", fwd_kind);305 break;306 }307 case BTF_KIND_FUNC: {308 const char *linkage = btf_func_linkage_str(t);309 310 if (json_output) {311 jsonw_uint_field(w, "type_id", t->type);312 jsonw_string_field(w, "linkage", linkage);313 } else {314 printf(" type_id=%u linkage=%s", t->type, linkage);315 }316 break;317 }318 case BTF_KIND_FUNC_PROTO: {319 const struct btf_param *p = (const void *)(t + 1);320 __u16 vlen = BTF_INFO_VLEN(t->info);321 int i;322 323 if (json_output) {324 jsonw_uint_field(w, "ret_type_id", t->type);325 jsonw_uint_field(w, "vlen", vlen);326 jsonw_name(w, "params");327 jsonw_start_array(w);328 } else {329 printf(" ret_type_id=%u vlen=%u", t->type, vlen);330 }331 for (i = 0; i < vlen; i++, p++) {332 const char *name = btf_str(btf, p->name_off);333 334 if (json_output) {335 jsonw_start_object(w);336 jsonw_string_field(w, "name", name);337 jsonw_uint_field(w, "type_id", p->type);338 jsonw_end_object(w);339 } else {340 printf("\n\t'%s' type_id=%u", name, p->type);341 }342 }343 if (json_output)344 jsonw_end_array(w);345 break;346 }347 case BTF_KIND_VAR: {348 const struct btf_var *v = (const void *)(t + 1);349 const char *linkage;350 351 linkage = btf_var_linkage_str(v->linkage);352 353 if (json_output) {354 jsonw_uint_field(w, "type_id", t->type);355 jsonw_string_field(w, "linkage", linkage);356 } else {357 printf(" type_id=%u, linkage=%s", t->type, linkage);358 }359 break;360 }361 case BTF_KIND_DATASEC: {362 const struct btf_var_secinfo *v = (const void *)(t + 1);363 const struct btf_type *vt;364 __u16 vlen = BTF_INFO_VLEN(t->info);365 int i;366 367 if (json_output) {368 jsonw_uint_field(w, "size", t->size);369 jsonw_uint_field(w, "vlen", vlen);370 jsonw_name(w, "vars");371 jsonw_start_array(w);372 } else {373 printf(" size=%u vlen=%u", t->size, vlen);374 }375 for (i = 0; i < vlen; i++, v++) {376 if (json_output) {377 jsonw_start_object(w);378 jsonw_uint_field(w, "type_id", v->type);379 jsonw_uint_field(w, "offset", v->offset);380 jsonw_uint_field(w, "size", v->size);381 jsonw_end_object(w);382 } else {383 printf("\n\ttype_id=%u offset=%u size=%u",384 v->type, v->offset, v->size);385 386 if (v->type < btf__type_cnt(btf)) {387 vt = btf__type_by_id(btf, v->type);388 printf(" (%s '%s')",389 btf_kind_str[btf_kind_safe(btf_kind(vt))],390 btf_str(btf, vt->name_off));391 }392 }393 }394 if (json_output)395 jsonw_end_array(w);396 break;397 }398 case BTF_KIND_FLOAT: {399 if (json_output)400 jsonw_uint_field(w, "size", t->size);401 else402 printf(" size=%u", t->size);403 break;404 }405 case BTF_KIND_DECL_TAG: {406 const struct btf_decl_tag *tag = (const void *)(t + 1);407 408 if (json_output) {409 jsonw_uint_field(w, "type_id", t->type);410 jsonw_int_field(w, "component_idx", tag->component_idx);411 } else {412 printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);413 }414 break;415 }416 default:417 break;418 }419 420 if (json_output)421 jsonw_end_object(json_wtr);422 else423 printf("\n");424 425 return 0;426}427 428static int dump_btf_raw(const struct btf *btf,429 __u32 *root_type_ids, int root_type_cnt)430{431 const struct btf_type *t;432 int i;433 434 if (json_output) {435 jsonw_start_object(json_wtr);436 jsonw_name(json_wtr, "types");437 jsonw_start_array(json_wtr);438 }439 440 if (root_type_cnt) {441 for (i = 0; i < root_type_cnt; i++) {442 t = btf__type_by_id(btf, root_type_ids[i]);443 dump_btf_type(btf, root_type_ids[i], t);444 }445 } else {446 const struct btf *base;447 int cnt = btf__type_cnt(btf);448 int start_id = 1;449 450 base = btf__base_btf(btf);451 if (base)452 start_id = btf__type_cnt(base);453 454 for (i = start_id; i < cnt; i++) {455 t = btf__type_by_id(btf, i);456 dump_btf_type(btf, i, t);457 }458 }459 460 if (json_output) {461 jsonw_end_array(json_wtr);462 jsonw_end_object(json_wtr);463 }464 return 0;465}466 467static int dump_btf_kfuncs(struct btf_dump *d, const struct btf *btf)468{469 LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts);470 int cnt = btf__type_cnt(btf);471 int i;472 473 printf("\n/* BPF kfuncs */\n");474 printf("#ifndef BPF_NO_KFUNC_PROTOTYPES\n");475 476 for (i = 1; i < cnt; i++) {477 const struct btf_type *t = btf__type_by_id(btf, i);478 const char *name;479 int err;480 481 if (!btf_is_decl_tag(t))482 continue;483 484 if (btf_decl_tag(t)->component_idx != -1)485 continue;486 487 name = btf__name_by_offset(btf, t->name_off);488 if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG)))489 continue;490 491 t = btf__type_by_id(btf, t->type);492 if (!btf_is_func(t))493 continue;494 495 printf("extern ");496 497 opts.field_name = btf__name_by_offset(btf, t->name_off);498 err = btf_dump__emit_type_decl(d, t->type, &opts);499 if (err)500 return err;501 502 printf(" __weak __ksym;\n");503 }504 505 printf("#endif\n\n");506 507 return 0;508}509 510static void __printf(2, 0) btf_dump_printf(void *ctx,511 const char *fmt, va_list args)512{513 vfprintf(stdout, fmt, args);514}515 516static int btf_type_rank(const struct btf *btf, __u32 index, bool has_name)517{518 const struct btf_type *t = btf__type_by_id(btf, index);519 const int kind = btf_kind(t);520 const int max_rank = 10;521 522 if (t->name_off)523 has_name = true;524 525 switch (kind) {526 case BTF_KIND_ENUM:527 case BTF_KIND_ENUM64:528 return has_name ? 1 : 0;529 case BTF_KIND_INT:530 case BTF_KIND_FLOAT:531 return 2;532 case BTF_KIND_STRUCT:533 case BTF_KIND_UNION:534 return has_name ? 3 : max_rank;535 case BTF_KIND_FUNC_PROTO:536 return has_name ? 4 : max_rank;537 case BTF_KIND_ARRAY:538 if (has_name)539 return btf_type_rank(btf, btf_array(t)->type, has_name);540 return max_rank;541 case BTF_KIND_TYPE_TAG:542 case BTF_KIND_CONST:543 case BTF_KIND_PTR:544 case BTF_KIND_VOLATILE:545 case BTF_KIND_RESTRICT:546 case BTF_KIND_TYPEDEF:547 case BTF_KIND_DECL_TAG:548 if (has_name)549 return btf_type_rank(btf, t->type, has_name);550 return max_rank;551 default:552 return max_rank;553 }554}555 556static const char *btf_type_sort_name(const struct btf *btf, __u32 index, bool from_ref)557{558 const struct btf_type *t = btf__type_by_id(btf, index);559 560 switch (btf_kind(t)) {561 case BTF_KIND_ENUM:562 case BTF_KIND_ENUM64: {563 int name_off = t->name_off;564 565 if (!from_ref && !name_off && btf_vlen(t))566 name_off = btf_kind(t) == BTF_KIND_ENUM64 ?567 btf_enum64(t)->name_off :568 btf_enum(t)->name_off;569 570 return btf__name_by_offset(btf, name_off);571 }572 case BTF_KIND_ARRAY:573 return btf_type_sort_name(btf, btf_array(t)->type, true);574 case BTF_KIND_TYPE_TAG:575 case BTF_KIND_CONST:576 case BTF_KIND_PTR:577 case BTF_KIND_VOLATILE:578 case BTF_KIND_RESTRICT:579 case BTF_KIND_TYPEDEF:580 case BTF_KIND_DECL_TAG:581 return btf_type_sort_name(btf, t->type, true);582 default:583 return btf__name_by_offset(btf, t->name_off);584 }585 return NULL;586}587 588static __u64 hasher(__u64 hash, __u64 val)589{590 return hash * 31 + val;591}592 593static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off)594{595 if (!name_off)596 return hash;597 598 return hasher(hash, str_hash(btf__name_by_offset(btf, name_off)));599}600 601static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members)602{603 const struct btf_type *t = btf__type_by_id(btf, id);604 int i;605 size_t hash = 0;606 607 hash = btf_name_hasher(hash, btf, t->name_off);608 609 switch (btf_kind(t)) {610 case BTF_KIND_ENUM:611 case BTF_KIND_ENUM64:612 for (i = 0; i < btf_vlen(t); i++) {613 __u32 name_off = btf_is_enum(t) ?614 btf_enum(t)[i].name_off :615 btf_enum64(t)[i].name_off;616 617 hash = btf_name_hasher(hash, btf, name_off);618 }619 break;620 case BTF_KIND_STRUCT:621 case BTF_KIND_UNION:622 if (!include_members)623 break;624 for (i = 0; i < btf_vlen(t); i++) {625 const struct btf_member *m = btf_members(t) + i;626 627 hash = btf_name_hasher(hash, btf, m->name_off);628 /* resolve field type's name and hash it as well */629 hash = hasher(hash, btf_type_disambig_hash(btf, m->type, false));630 }631 break;632 case BTF_KIND_TYPE_TAG:633 case BTF_KIND_CONST:634 case BTF_KIND_PTR:635 case BTF_KIND_VOLATILE:636 case BTF_KIND_RESTRICT:637 case BTF_KIND_TYPEDEF:638 case BTF_KIND_DECL_TAG:639 hash = hasher(hash, btf_type_disambig_hash(btf, t->type, include_members));640 break;641 case BTF_KIND_ARRAY: {642 struct btf_array *arr = btf_array(t);643 644 hash = hasher(hash, arr->nelems);645 hash = hasher(hash, btf_type_disambig_hash(btf, arr->type, include_members));646 break;647 }648 default:649 break;650 }651 return hash;652}653 654static int btf_type_compare(const void *left, const void *right)655{656 const struct sort_datum *d1 = (const struct sort_datum *)left;657 const struct sort_datum *d2 = (const struct sort_datum *)right;658 int r;659 660 r = d1->type_rank - d2->type_rank;661 r = r ?: strcmp(d1->sort_name, d2->sort_name);662 r = r ?: strcmp(d1->own_name, d2->own_name);663 if (r)664 return r;665 666 if (d1->disambig_hash != d2->disambig_hash)667 return d1->disambig_hash < d2->disambig_hash ? -1 : 1;668 669 return d1->index - d2->index;670}671 672static struct sort_datum *sort_btf_c(const struct btf *btf)673{674 struct sort_datum *datums;675 int n;676 677 n = btf__type_cnt(btf);678 datums = malloc(sizeof(struct sort_datum) * n);679 if (!datums)680 return NULL;681 682 for (int i = 0; i < n; ++i) {683 struct sort_datum *d = datums + i;684 const struct btf_type *t = btf__type_by_id(btf, i);685 686 d->index = i;687 d->type_rank = btf_type_rank(btf, i, false);688 d->sort_name = btf_type_sort_name(btf, i, false);689 d->own_name = btf__name_by_offset(btf, t->name_off);690 d->disambig_hash = btf_type_disambig_hash(btf, i, true);691 }692 693 qsort(datums, n, sizeof(struct sort_datum), btf_type_compare);694 695 return datums;696}697 698static int dump_btf_c(const struct btf *btf,699 __u32 *root_type_ids, int root_type_cnt, bool sort_dump)700{701 struct sort_datum *datums = NULL;702 struct btf_dump *d;703 int err = 0, i;704 705 d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);706 if (!d)707 return -errno;708 709 printf("#ifndef __VMLINUX_H__\n");710 printf("#define __VMLINUX_H__\n");711 printf("\n");712 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");713 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");714 printf("#endif\n\n");715 printf("#ifndef __ksym\n");716 printf("#define __ksym __attribute__((section(\".ksyms\")))\n");717 printf("#endif\n\n");718 printf("#ifndef __weak\n");719 printf("#define __weak __attribute__((weak))\n");720 printf("#endif\n\n");721 722 if (root_type_cnt) {723 for (i = 0; i < root_type_cnt; i++) {724 err = btf_dump__dump_type(d, root_type_ids[i]);725 if (err)726 goto done;727 }728 } else {729 int cnt = btf__type_cnt(btf);730 731 if (sort_dump)732 datums = sort_btf_c(btf);733 for (i = 1; i < cnt; i++) {734 int idx = datums ? datums[i].index : i;735 736 err = btf_dump__dump_type(d, idx);737 if (err)738 goto done;739 }740 741 err = dump_btf_kfuncs(d, btf);742 if (err)743 goto done;744 }745 746 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");747 printf("#pragma clang attribute pop\n");748 printf("#endif\n");749 printf("\n");750 printf("#endif /* __VMLINUX_H__ */\n");751 752done:753 free(datums);754 btf_dump__free(d);755 return err;756}757 758static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";759 760static struct btf *get_vmlinux_btf_from_sysfs(void)761{762 struct btf *base;763 764 base = btf__parse(sysfs_vmlinux, NULL);765 if (!base)766 p_err("failed to parse vmlinux BTF at '%s': %d\n",767 sysfs_vmlinux, -errno);768 769 return base;770}771 772#define BTF_NAME_BUFF_LEN 64773 774static bool btf_is_kernel_module(__u32 btf_id)775{776 struct bpf_btf_info btf_info = {};777 char btf_name[BTF_NAME_BUFF_LEN];778 int btf_fd;779 __u32 len;780 int err;781 782 btf_fd = bpf_btf_get_fd_by_id(btf_id);783 if (btf_fd < 0) {784 p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno));785 return false;786 }787 788 len = sizeof(btf_info);789 btf_info.name = ptr_to_u64(btf_name);790 btf_info.name_len = sizeof(btf_name);791 err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);792 close(btf_fd);793 if (err) {794 p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno));795 return false;796 }797 798 return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0;799}800 801static int do_dump(int argc, char **argv)802{803 bool dump_c = false, sort_dump_c = true;804 struct btf *btf = NULL, *base = NULL;805 __u32 root_type_ids[2];806 int root_type_cnt = 0;807 __u32 btf_id = -1;808 const char *src;809 int fd = -1;810 int err = 0;811 812 if (!REQ_ARGS(2)) {813 usage();814 return -1;815 }816 src = GET_ARG();817 if (is_prefix(src, "map")) {818 struct bpf_map_info info = {};819 __u32 len = sizeof(info);820 821 if (!REQ_ARGS(2)) {822 usage();823 return -1;824 }825 826 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);827 if (fd < 0)828 return -1;829 830 btf_id = info.btf_id;831 if (argc && is_prefix(*argv, "key")) {832 root_type_ids[root_type_cnt++] = info.btf_key_type_id;833 NEXT_ARG();834 } else if (argc && is_prefix(*argv, "value")) {835 root_type_ids[root_type_cnt++] = info.btf_value_type_id;836 NEXT_ARG();837 } else if (argc && is_prefix(*argv, "all")) {838 NEXT_ARG();839 } else if (argc && is_prefix(*argv, "kv")) {840 root_type_ids[root_type_cnt++] = info.btf_key_type_id;841 root_type_ids[root_type_cnt++] = info.btf_value_type_id;842 NEXT_ARG();843 } else {844 root_type_ids[root_type_cnt++] = info.btf_key_type_id;845 root_type_ids[root_type_cnt++] = info.btf_value_type_id;846 }847 } else if (is_prefix(src, "prog")) {848 struct bpf_prog_info info = {};849 __u32 len = sizeof(info);850 851 if (!REQ_ARGS(2)) {852 usage();853 return -1;854 }855 856 fd = prog_parse_fd(&argc, &argv);857 if (fd < 0)858 return -1;859 860 err = bpf_prog_get_info_by_fd(fd, &info, &len);861 if (err) {862 p_err("can't get prog info: %s", strerror(errno));863 goto done;864 }865 866 btf_id = info.btf_id;867 } else if (is_prefix(src, "id")) {868 char *endptr;869 870 btf_id = strtoul(*argv, &endptr, 0);871 if (*endptr) {872 p_err("can't parse %s as ID", *argv);873 return -1;874 }875 NEXT_ARG();876 } else if (is_prefix(src, "file")) {877 const char sysfs_prefix[] = "/sys/kernel/btf/";878 879 if (!base_btf &&880 strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&881 strcmp(*argv, sysfs_vmlinux) != 0)882 base = get_vmlinux_btf_from_sysfs();883 884 btf = btf__parse_split(*argv, base ?: base_btf);885 if (!btf) {886 err = -errno;887 p_err("failed to load BTF from %s: %s",888 *argv, strerror(errno));889 goto done;890 }891 NEXT_ARG();892 } else {893 err = -1;894 p_err("unrecognized BTF source specifier: '%s'", src);895 goto done;896 }897 898 while (argc) {899 if (is_prefix(*argv, "format")) {900 NEXT_ARG();901 if (argc < 1) {902 p_err("expecting value for 'format' option\n");903 err = -EINVAL;904 goto done;905 }906 if (strcmp(*argv, "c") == 0) {907 dump_c = true;908 } else if (strcmp(*argv, "raw") == 0) {909 dump_c = false;910 } else {911 p_err("unrecognized format specifier: '%s', possible values: raw, c",912 *argv);913 err = -EINVAL;914 goto done;915 }916 NEXT_ARG();917 } else if (is_prefix(*argv, "unsorted")) {918 sort_dump_c = false;919 NEXT_ARG();920 } else {921 p_err("unrecognized option: '%s'", *argv);922 err = -EINVAL;923 goto done;924 }925 }926 927 if (!btf) {928 if (!base_btf && btf_is_kernel_module(btf_id)) {929 p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)",930 sysfs_vmlinux);931 base_btf = get_vmlinux_btf_from_sysfs();932 }933 934 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);935 if (!btf) {936 err = -errno;937 p_err("get btf by id (%u): %s", btf_id, strerror(errno));938 goto done;939 }940 }941 942 if (dump_c) {943 if (json_output) {944 p_err("JSON output for C-syntax dump is not supported");945 err = -ENOTSUP;946 goto done;947 }948 err = dump_btf_c(btf, root_type_ids, root_type_cnt, sort_dump_c);949 } else {950 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);951 }952 953done:954 close(fd);955 btf__free(btf);956 btf__free(base);957 return err;958}959 960static int btf_parse_fd(int *argc, char ***argv)961{962 unsigned int id;963 char *endptr;964 int fd;965 966 if (!is_prefix(*argv[0], "id")) {967 p_err("expected 'id', got: '%s'?", **argv);968 return -1;969 }970 NEXT_ARGP();971 972 id = strtoul(**argv, &endptr, 0);973 if (*endptr) {974 p_err("can't parse %s as ID", **argv);975 return -1;976 }977 NEXT_ARGP();978 979 fd = bpf_btf_get_fd_by_id(id);980 if (fd < 0)981 p_err("can't get BTF object by id (%u): %s",982 id, strerror(errno));983 984 return fd;985}986 987static int988build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,989 void *info, __u32 *len)990{991 static const char * const names[] = {992 [BPF_OBJ_UNKNOWN] = "unknown",993 [BPF_OBJ_PROG] = "prog",994 [BPF_OBJ_MAP] = "map",995 };996 __u32 btf_id, id = 0;997 int err;998 int fd;999 1000 while (true) {1001 switch (type) {1002 case BPF_OBJ_PROG:1003 err = bpf_prog_get_next_id(id, &id);1004 break;1005 case BPF_OBJ_MAP:1006 err = bpf_map_get_next_id(id, &id);1007 break;1008 default:1009 err = -1;1010 p_err("unexpected object type: %d", type);1011 goto err_free;1012 }1013 if (err) {1014 if (errno == ENOENT) {1015 err = 0;1016 break;1017 }1018 p_err("can't get next %s: %s%s", names[type],1019 strerror(errno),1020 errno == EINVAL ? " -- kernel too old?" : "");1021 goto err_free;1022 }1023 1024 switch (type) {1025 case BPF_OBJ_PROG:1026 fd = bpf_prog_get_fd_by_id(id);1027 break;1028 case BPF_OBJ_MAP:1029 fd = bpf_map_get_fd_by_id(id);1030 break;1031 default:1032 err = -1;1033 p_err("unexpected object type: %d", type);1034 goto err_free;1035 }1036 if (fd < 0) {1037 if (errno == ENOENT)1038 continue;1039 p_err("can't get %s by id (%u): %s", names[type], id,1040 strerror(errno));1041 err = -1;1042 goto err_free;1043 }1044 1045 memset(info, 0, *len);1046 if (type == BPF_OBJ_PROG)1047 err = bpf_prog_get_info_by_fd(fd, info, len);1048 else1049 err = bpf_map_get_info_by_fd(fd, info, len);1050 close(fd);1051 if (err) {1052 p_err("can't get %s info: %s", names[type],1053 strerror(errno));1054 goto err_free;1055 }1056 1057 switch (type) {1058 case BPF_OBJ_PROG:1059 btf_id = ((struct bpf_prog_info *)info)->btf_id;1060 break;1061 case BPF_OBJ_MAP:1062 btf_id = ((struct bpf_map_info *)info)->btf_id;1063 break;1064 default:1065 err = -1;1066 p_err("unexpected object type: %d", type);1067 goto err_free;1068 }1069 if (!btf_id)1070 continue;1071 1072 err = hashmap__append(tab, btf_id, id);1073 if (err) {1074 p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",1075 btf_id, id, strerror(-err));1076 goto err_free;1077 }1078 }1079 1080 return 0;1081 1082err_free:1083 hashmap__free(tab);1084 return err;1085}1086 1087static int1088build_btf_tables(struct hashmap *btf_prog_table,1089 struct hashmap *btf_map_table)1090{1091 struct bpf_prog_info prog_info;1092 __u32 prog_len = sizeof(prog_info);1093 struct bpf_map_info map_info;1094 __u32 map_len = sizeof(map_info);1095 int err = 0;1096 1097 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,1098 &prog_len);1099 if (err)1100 return err;1101 1102 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,1103 &map_len);1104 if (err) {1105 hashmap__free(btf_prog_table);1106 return err;1107 }1108 1109 return 0;1110}1111 1112static void1113show_btf_plain(struct bpf_btf_info *info, int fd,1114 struct hashmap *btf_prog_table,1115 struct hashmap *btf_map_table)1116{1117 struct hashmap_entry *entry;1118 const char *name = u64_to_ptr(info->name);1119 int n;1120 1121 printf("%u: ", info->id);1122 if (info->kernel_btf)1123 printf("name [%s] ", name);1124 else if (name && name[0])1125 printf("name %s ", name);1126 else1127 printf("name <anon> ");1128 printf("size %uB", info->btf_size);1129 1130 n = 0;1131 hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {1132 printf("%s%lu", n++ == 0 ? " prog_ids " : ",", entry->value);1133 }1134 1135 n = 0;1136 hashmap__for_each_key_entry(btf_map_table, entry, info->id) {1137 printf("%s%lu", n++ == 0 ? " map_ids " : ",", entry->value);1138 }1139 1140 emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");1141 1142 printf("\n");1143}1144 1145static void1146show_btf_json(struct bpf_btf_info *info, int fd,1147 struct hashmap *btf_prog_table,1148 struct hashmap *btf_map_table)1149{1150 struct hashmap_entry *entry;1151 const char *name = u64_to_ptr(info->name);1152 1153 jsonw_start_object(json_wtr); /* btf object */1154 jsonw_uint_field(json_wtr, "id", info->id);1155 jsonw_uint_field(json_wtr, "size", info->btf_size);1156 1157 jsonw_name(json_wtr, "prog_ids");1158 jsonw_start_array(json_wtr); /* prog_ids */1159 hashmap__for_each_key_entry(btf_prog_table, entry, info->id) {1160 jsonw_uint(json_wtr, entry->value);1161 }1162 jsonw_end_array(json_wtr); /* prog_ids */1163 1164 jsonw_name(json_wtr, "map_ids");1165 jsonw_start_array(json_wtr); /* map_ids */1166 hashmap__for_each_key_entry(btf_map_table, entry, info->id) {1167 jsonw_uint(json_wtr, entry->value);1168 }1169 jsonw_end_array(json_wtr); /* map_ids */1170 1171 emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */1172 1173 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);1174 1175 if (name && name[0])1176 jsonw_string_field(json_wtr, "name", name);1177 1178 jsonw_end_object(json_wtr); /* btf object */1179}1180 1181static int1182show_btf(int fd, struct hashmap *btf_prog_table,1183 struct hashmap *btf_map_table)1184{1185 struct bpf_btf_info info;1186 __u32 len = sizeof(info);1187 char name[64];1188 int err;1189 1190 memset(&info, 0, sizeof(info));1191 err = bpf_btf_get_info_by_fd(fd, &info, &len);1192 if (err) {1193 p_err("can't get BTF object info: %s", strerror(errno));1194 return -1;1195 }1196 /* if kernel support emitting BTF object name, pass name pointer */1197 if (info.name_len) {1198 memset(&info, 0, sizeof(info));1199 info.name_len = sizeof(name);1200 info.name = ptr_to_u64(name);1201 len = sizeof(info);1202 1203 err = bpf_btf_get_info_by_fd(fd, &info, &len);1204 if (err) {1205 p_err("can't get BTF object info: %s", strerror(errno));1206 return -1;1207 }1208 }1209 1210 if (json_output)1211 show_btf_json(&info, fd, btf_prog_table, btf_map_table);1212 else1213 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);1214 1215 return 0;1216}1217 1218static int do_show(int argc, char **argv)1219{1220 struct hashmap *btf_prog_table;1221 struct hashmap *btf_map_table;1222 int err, fd = -1;1223 __u32 id = 0;1224 1225 if (argc == 2) {1226 fd = btf_parse_fd(&argc, &argv);1227 if (fd < 0)1228 return -1;1229 }1230 1231 if (argc) {1232 if (fd >= 0)1233 close(fd);1234 return BAD_ARG();1235 }1236 1237 btf_prog_table = hashmap__new(hash_fn_for_key_as_id,1238 equal_fn_for_key_as_id, NULL);1239 btf_map_table = hashmap__new(hash_fn_for_key_as_id,1240 equal_fn_for_key_as_id, NULL);1241 if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) {1242 hashmap__free(btf_prog_table);1243 hashmap__free(btf_map_table);1244 if (fd >= 0)1245 close(fd);1246 p_err("failed to create hashmap for object references");1247 return -1;1248 }1249 err = build_btf_tables(btf_prog_table, btf_map_table);1250 if (err) {1251 if (fd >= 0)1252 close(fd);1253 return err;1254 }1255 build_obj_refs_table(&refs_table, BPF_OBJ_BTF);1256 1257 if (fd >= 0) {1258 err = show_btf(fd, btf_prog_table, btf_map_table);1259 close(fd);1260 goto exit_free;1261 }1262 1263 if (json_output)1264 jsonw_start_array(json_wtr); /* root array */1265 1266 while (true) {1267 err = bpf_btf_get_next_id(id, &id);1268 if (err) {1269 if (errno == ENOENT) {1270 err = 0;1271 break;1272 }1273 p_err("can't get next BTF object: %s%s",1274 strerror(errno),1275 errno == EINVAL ? " -- kernel too old?" : "");1276 err = -1;1277 break;1278 }1279 1280 fd = bpf_btf_get_fd_by_id(id);1281 if (fd < 0) {1282 if (errno == ENOENT)1283 continue;1284 p_err("can't get BTF object by id (%u): %s",1285 id, strerror(errno));1286 err = -1;1287 break;1288 }1289 1290 err = show_btf(fd, btf_prog_table, btf_map_table);1291 close(fd);1292 if (err)1293 break;1294 }1295 1296 if (json_output)1297 jsonw_end_array(json_wtr); /* root array */1298 1299exit_free:1300 hashmap__free(btf_prog_table);1301 hashmap__free(btf_map_table);1302 delete_obj_refs_table(refs_table);1303 1304 return err;1305}1306 1307static int do_help(int argc, char **argv)1308{1309 if (json_output) {1310 jsonw_null(json_wtr);1311 return 0;1312 }1313 1314 fprintf(stderr,1315 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"1316 " %1$s %2$s dump BTF_SRC [format FORMAT]\n"1317 " %1$s %2$s help\n"1318 "\n"1319 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"1320 " FORMAT := { raw | c [unsorted] }\n"1321 " " HELP_SPEC_MAP "\n"1322 " " HELP_SPEC_PROGRAM "\n"1323 " " HELP_SPEC_OPTIONS " |\n"1324 " {-B|--base-btf} }\n"1325 "",1326 bin_name, "btf");1327 1328 return 0;1329}1330 1331static const struct cmd cmds[] = {1332 { "show", do_show },1333 { "list", do_show },1334 { "help", do_help },1335 { "dump", do_dump },1336 { 0 }1337};1338 1339int do_btf(int argc, char **argv)1340{1341 return cmd_select(cmds, argc, argv, do_help);1342}1343