btf.c (23792B)
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 23static const char * const btf_kind_str[NR_BTF_KINDS] = { 24 [BTF_KIND_UNKN] = "UNKNOWN", 25 [BTF_KIND_INT] = "INT", 26 [BTF_KIND_PTR] = "PTR", 27 [BTF_KIND_ARRAY] = "ARRAY", 28 [BTF_KIND_STRUCT] = "STRUCT", 29 [BTF_KIND_UNION] = "UNION", 30 [BTF_KIND_ENUM] = "ENUM", 31 [BTF_KIND_FWD] = "FWD", 32 [BTF_KIND_TYPEDEF] = "TYPEDEF", 33 [BTF_KIND_VOLATILE] = "VOLATILE", 34 [BTF_KIND_CONST] = "CONST", 35 [BTF_KIND_RESTRICT] = "RESTRICT", 36 [BTF_KIND_FUNC] = "FUNC", 37 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", 38 [BTF_KIND_VAR] = "VAR", 39 [BTF_KIND_DATASEC] = "DATASEC", 40 [BTF_KIND_FLOAT] = "FLOAT", 41 [BTF_KIND_DECL_TAG] = "DECL_TAG", 42 [BTF_KIND_TYPE_TAG] = "TYPE_TAG", 43}; 44 45struct btf_attach_point { 46 __u32 obj_id; 47 __u32 btf_id; 48}; 49 50static const char *btf_int_enc_str(__u8 encoding) 51{ 52 switch (encoding) { 53 case 0: 54 return "(none)"; 55 case BTF_INT_SIGNED: 56 return "SIGNED"; 57 case BTF_INT_CHAR: 58 return "CHAR"; 59 case BTF_INT_BOOL: 60 return "BOOL"; 61 default: 62 return "UNKN"; 63 } 64} 65 66static const char *btf_var_linkage_str(__u32 linkage) 67{ 68 switch (linkage) { 69 case BTF_VAR_STATIC: 70 return "static"; 71 case BTF_VAR_GLOBAL_ALLOCATED: 72 return "global"; 73 case BTF_VAR_GLOBAL_EXTERN: 74 return "extern"; 75 default: 76 return "(unknown)"; 77 } 78} 79 80static const char *btf_func_linkage_str(const struct btf_type *t) 81{ 82 switch (btf_vlen(t)) { 83 case BTF_FUNC_STATIC: 84 return "static"; 85 case BTF_FUNC_GLOBAL: 86 return "global"; 87 case BTF_FUNC_EXTERN: 88 return "extern"; 89 default: 90 return "(unknown)"; 91 } 92} 93 94static const char *btf_str(const struct btf *btf, __u32 off) 95{ 96 if (!off) 97 return "(anon)"; 98 return btf__name_by_offset(btf, off) ? : "(invalid)"; 99} 100 101static int btf_kind_safe(int kind) 102{ 103 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN; 104} 105 106static int dump_btf_type(const struct btf *btf, __u32 id, 107 const struct btf_type *t) 108{ 109 json_writer_t *w = json_wtr; 110 int kind = btf_kind(t); 111 112 if (json_output) { 113 jsonw_start_object(w); 114 jsonw_uint_field(w, "id", id); 115 jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]); 116 jsonw_string_field(w, "name", btf_str(btf, t->name_off)); 117 } else { 118 printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)], 119 btf_str(btf, t->name_off)); 120 } 121 122 switch (kind) { 123 case BTF_KIND_INT: { 124 __u32 v = *(__u32 *)(t + 1); 125 const char *enc; 126 127 enc = btf_int_enc_str(BTF_INT_ENCODING(v)); 128 129 if (json_output) { 130 jsonw_uint_field(w, "size", t->size); 131 jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v)); 132 jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v)); 133 jsonw_string_field(w, "encoding", enc); 134 } else { 135 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s", 136 t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v), 137 enc); 138 } 139 break; 140 } 141 case BTF_KIND_PTR: 142 case BTF_KIND_CONST: 143 case BTF_KIND_VOLATILE: 144 case BTF_KIND_RESTRICT: 145 case BTF_KIND_TYPEDEF: 146 case BTF_KIND_TYPE_TAG: 147 if (json_output) 148 jsonw_uint_field(w, "type_id", t->type); 149 else 150 printf(" type_id=%u", t->type); 151 break; 152 case BTF_KIND_ARRAY: { 153 const struct btf_array *arr = (const void *)(t + 1); 154 155 if (json_output) { 156 jsonw_uint_field(w, "type_id", arr->type); 157 jsonw_uint_field(w, "index_type_id", arr->index_type); 158 jsonw_uint_field(w, "nr_elems", arr->nelems); 159 } else { 160 printf(" type_id=%u index_type_id=%u nr_elems=%u", 161 arr->type, arr->index_type, arr->nelems); 162 } 163 break; 164 } 165 case BTF_KIND_STRUCT: 166 case BTF_KIND_UNION: { 167 const struct btf_member *m = (const void *)(t + 1); 168 __u16 vlen = BTF_INFO_VLEN(t->info); 169 int i; 170 171 if (json_output) { 172 jsonw_uint_field(w, "size", t->size); 173 jsonw_uint_field(w, "vlen", vlen); 174 jsonw_name(w, "members"); 175 jsonw_start_array(w); 176 } else { 177 printf(" size=%u vlen=%u", t->size, vlen); 178 } 179 for (i = 0; i < vlen; i++, m++) { 180 const char *name = btf_str(btf, m->name_off); 181 __u32 bit_off, bit_sz; 182 183 if (BTF_INFO_KFLAG(t->info)) { 184 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset); 185 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset); 186 } else { 187 bit_off = m->offset; 188 bit_sz = 0; 189 } 190 191 if (json_output) { 192 jsonw_start_object(w); 193 jsonw_string_field(w, "name", name); 194 jsonw_uint_field(w, "type_id", m->type); 195 jsonw_uint_field(w, "bits_offset", bit_off); 196 if (bit_sz) { 197 jsonw_uint_field(w, "bitfield_size", 198 bit_sz); 199 } 200 jsonw_end_object(w); 201 } else { 202 printf("\n\t'%s' type_id=%u bits_offset=%u", 203 name, m->type, bit_off); 204 if (bit_sz) 205 printf(" bitfield_size=%u", bit_sz); 206 } 207 } 208 if (json_output) 209 jsonw_end_array(w); 210 break; 211 } 212 case BTF_KIND_ENUM: { 213 const struct btf_enum *v = (const void *)(t + 1); 214 __u16 vlen = BTF_INFO_VLEN(t->info); 215 int i; 216 217 if (json_output) { 218 jsonw_uint_field(w, "size", t->size); 219 jsonw_uint_field(w, "vlen", vlen); 220 jsonw_name(w, "values"); 221 jsonw_start_array(w); 222 } else { 223 printf(" size=%u vlen=%u", t->size, vlen); 224 } 225 for (i = 0; i < vlen; i++, v++) { 226 const char *name = btf_str(btf, v->name_off); 227 228 if (json_output) { 229 jsonw_start_object(w); 230 jsonw_string_field(w, "name", name); 231 jsonw_uint_field(w, "val", v->val); 232 jsonw_end_object(w); 233 } else { 234 printf("\n\t'%s' val=%u", name, v->val); 235 } 236 } 237 if (json_output) 238 jsonw_end_array(w); 239 break; 240 } 241 case BTF_KIND_FWD: { 242 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union" 243 : "struct"; 244 245 if (json_output) 246 jsonw_string_field(w, "fwd_kind", fwd_kind); 247 else 248 printf(" fwd_kind=%s", fwd_kind); 249 break; 250 } 251 case BTF_KIND_FUNC: { 252 const char *linkage = btf_func_linkage_str(t); 253 254 if (json_output) { 255 jsonw_uint_field(w, "type_id", t->type); 256 jsonw_string_field(w, "linkage", linkage); 257 } else { 258 printf(" type_id=%u linkage=%s", t->type, linkage); 259 } 260 break; 261 } 262 case BTF_KIND_FUNC_PROTO: { 263 const struct btf_param *p = (const void *)(t + 1); 264 __u16 vlen = BTF_INFO_VLEN(t->info); 265 int i; 266 267 if (json_output) { 268 jsonw_uint_field(w, "ret_type_id", t->type); 269 jsonw_uint_field(w, "vlen", vlen); 270 jsonw_name(w, "params"); 271 jsonw_start_array(w); 272 } else { 273 printf(" ret_type_id=%u vlen=%u", t->type, vlen); 274 } 275 for (i = 0; i < vlen; i++, p++) { 276 const char *name = btf_str(btf, p->name_off); 277 278 if (json_output) { 279 jsonw_start_object(w); 280 jsonw_string_field(w, "name", name); 281 jsonw_uint_field(w, "type_id", p->type); 282 jsonw_end_object(w); 283 } else { 284 printf("\n\t'%s' type_id=%u", name, p->type); 285 } 286 } 287 if (json_output) 288 jsonw_end_array(w); 289 break; 290 } 291 case BTF_KIND_VAR: { 292 const struct btf_var *v = (const void *)(t + 1); 293 const char *linkage; 294 295 linkage = btf_var_linkage_str(v->linkage); 296 297 if (json_output) { 298 jsonw_uint_field(w, "type_id", t->type); 299 jsonw_string_field(w, "linkage", linkage); 300 } else { 301 printf(" type_id=%u, linkage=%s", t->type, linkage); 302 } 303 break; 304 } 305 case BTF_KIND_DATASEC: { 306 const struct btf_var_secinfo *v = (const void *)(t + 1); 307 const struct btf_type *vt; 308 __u16 vlen = BTF_INFO_VLEN(t->info); 309 int i; 310 311 if (json_output) { 312 jsonw_uint_field(w, "size", t->size); 313 jsonw_uint_field(w, "vlen", vlen); 314 jsonw_name(w, "vars"); 315 jsonw_start_array(w); 316 } else { 317 printf(" size=%u vlen=%u", t->size, vlen); 318 } 319 for (i = 0; i < vlen; i++, v++) { 320 if (json_output) { 321 jsonw_start_object(w); 322 jsonw_uint_field(w, "type_id", v->type); 323 jsonw_uint_field(w, "offset", v->offset); 324 jsonw_uint_field(w, "size", v->size); 325 jsonw_end_object(w); 326 } else { 327 printf("\n\ttype_id=%u offset=%u size=%u", 328 v->type, v->offset, v->size); 329 330 if (v->type < btf__type_cnt(btf)) { 331 vt = btf__type_by_id(btf, v->type); 332 printf(" (%s '%s')", 333 btf_kind_str[btf_kind_safe(btf_kind(vt))], 334 btf_str(btf, vt->name_off)); 335 } 336 } 337 } 338 if (json_output) 339 jsonw_end_array(w); 340 break; 341 } 342 case BTF_KIND_FLOAT: { 343 if (json_output) 344 jsonw_uint_field(w, "size", t->size); 345 else 346 printf(" size=%u", t->size); 347 break; 348 } 349 case BTF_KIND_DECL_TAG: { 350 const struct btf_decl_tag *tag = (const void *)(t + 1); 351 352 if (json_output) { 353 jsonw_uint_field(w, "type_id", t->type); 354 jsonw_int_field(w, "component_idx", tag->component_idx); 355 } else { 356 printf(" type_id=%u component_idx=%d", t->type, tag->component_idx); 357 } 358 break; 359 } 360 default: 361 break; 362 } 363 364 if (json_output) 365 jsonw_end_object(json_wtr); 366 else 367 printf("\n"); 368 369 return 0; 370} 371 372static int dump_btf_raw(const struct btf *btf, 373 __u32 *root_type_ids, int root_type_cnt) 374{ 375 const struct btf_type *t; 376 int i; 377 378 if (json_output) { 379 jsonw_start_object(json_wtr); 380 jsonw_name(json_wtr, "types"); 381 jsonw_start_array(json_wtr); 382 } 383 384 if (root_type_cnt) { 385 for (i = 0; i < root_type_cnt; i++) { 386 t = btf__type_by_id(btf, root_type_ids[i]); 387 dump_btf_type(btf, root_type_ids[i], t); 388 } 389 } else { 390 const struct btf *base; 391 int cnt = btf__type_cnt(btf); 392 int start_id = 1; 393 394 base = btf__base_btf(btf); 395 if (base) 396 start_id = btf__type_cnt(base); 397 398 for (i = start_id; i < cnt; i++) { 399 t = btf__type_by_id(btf, i); 400 dump_btf_type(btf, i, t); 401 } 402 } 403 404 if (json_output) { 405 jsonw_end_array(json_wtr); 406 jsonw_end_object(json_wtr); 407 } 408 return 0; 409} 410 411static void __printf(2, 0) btf_dump_printf(void *ctx, 412 const char *fmt, va_list args) 413{ 414 vfprintf(stdout, fmt, args); 415} 416 417static int dump_btf_c(const struct btf *btf, 418 __u32 *root_type_ids, int root_type_cnt) 419{ 420 struct btf_dump *d; 421 int err = 0, i; 422 423 d = btf_dump__new(btf, btf_dump_printf, NULL, NULL); 424 err = libbpf_get_error(d); 425 if (err) 426 return err; 427 428 printf("#ifndef __VMLINUX_H__\n"); 429 printf("#define __VMLINUX_H__\n"); 430 printf("\n"); 431 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 432 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); 433 printf("#endif\n\n"); 434 435 if (root_type_cnt) { 436 for (i = 0; i < root_type_cnt; i++) { 437 err = btf_dump__dump_type(d, root_type_ids[i]); 438 if (err) 439 goto done; 440 } 441 } else { 442 int cnt = btf__type_cnt(btf); 443 444 for (i = 1; i < cnt; i++) { 445 err = btf_dump__dump_type(d, i); 446 if (err) 447 goto done; 448 } 449 } 450 451 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 452 printf("#pragma clang attribute pop\n"); 453 printf("#endif\n"); 454 printf("\n"); 455 printf("#endif /* __VMLINUX_H__ */\n"); 456 457done: 458 btf_dump__free(d); 459 return err; 460} 461 462static const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux"; 463 464static struct btf *get_vmlinux_btf_from_sysfs(void) 465{ 466 struct btf *base; 467 468 base = btf__parse(sysfs_vmlinux, NULL); 469 if (libbpf_get_error(base)) { 470 p_err("failed to parse vmlinux BTF at '%s': %ld\n", 471 sysfs_vmlinux, libbpf_get_error(base)); 472 base = NULL; 473 } 474 475 return base; 476} 477 478#define BTF_NAME_BUFF_LEN 64 479 480static bool btf_is_kernel_module(__u32 btf_id) 481{ 482 struct bpf_btf_info btf_info = {}; 483 char btf_name[BTF_NAME_BUFF_LEN]; 484 int btf_fd; 485 __u32 len; 486 int err; 487 488 btf_fd = bpf_btf_get_fd_by_id(btf_id); 489 if (btf_fd < 0) { 490 p_err("can't get BTF object by id (%u): %s", btf_id, strerror(errno)); 491 return false; 492 } 493 494 len = sizeof(btf_info); 495 btf_info.name = ptr_to_u64(btf_name); 496 btf_info.name_len = sizeof(btf_name); 497 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); 498 close(btf_fd); 499 if (err) { 500 p_err("can't get BTF (ID %u) object info: %s", btf_id, strerror(errno)); 501 return false; 502 } 503 504 return btf_info.kernel_btf && strncmp(btf_name, "vmlinux", sizeof(btf_name)) != 0; 505} 506 507static int do_dump(int argc, char **argv) 508{ 509 struct btf *btf = NULL, *base = NULL; 510 __u32 root_type_ids[2]; 511 int root_type_cnt = 0; 512 bool dump_c = false; 513 __u32 btf_id = -1; 514 const char *src; 515 int fd = -1; 516 int err; 517 518 if (!REQ_ARGS(2)) { 519 usage(); 520 return -1; 521 } 522 src = GET_ARG(); 523 if (is_prefix(src, "map")) { 524 struct bpf_map_info info = {}; 525 __u32 len = sizeof(info); 526 527 if (!REQ_ARGS(2)) { 528 usage(); 529 return -1; 530 } 531 532 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 533 if (fd < 0) 534 return -1; 535 536 btf_id = info.btf_id; 537 if (argc && is_prefix(*argv, "key")) { 538 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 539 NEXT_ARG(); 540 } else if (argc && is_prefix(*argv, "value")) { 541 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 542 NEXT_ARG(); 543 } else if (argc && is_prefix(*argv, "all")) { 544 NEXT_ARG(); 545 } else if (argc && is_prefix(*argv, "kv")) { 546 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 547 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 548 NEXT_ARG(); 549 } else { 550 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 551 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 552 } 553 } else if (is_prefix(src, "prog")) { 554 struct bpf_prog_info info = {}; 555 __u32 len = sizeof(info); 556 557 if (!REQ_ARGS(2)) { 558 usage(); 559 return -1; 560 } 561 562 fd = prog_parse_fd(&argc, &argv); 563 if (fd < 0) 564 return -1; 565 566 err = bpf_obj_get_info_by_fd(fd, &info, &len); 567 if (err) { 568 p_err("can't get prog info: %s", strerror(errno)); 569 goto done; 570 } 571 572 btf_id = info.btf_id; 573 } else if (is_prefix(src, "id")) { 574 char *endptr; 575 576 btf_id = strtoul(*argv, &endptr, 0); 577 if (*endptr) { 578 p_err("can't parse %s as ID", *argv); 579 return -1; 580 } 581 NEXT_ARG(); 582 } else if (is_prefix(src, "file")) { 583 const char sysfs_prefix[] = "/sys/kernel/btf/"; 584 585 if (!base_btf && 586 strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 && 587 strcmp(*argv, sysfs_vmlinux) != 0) 588 base = get_vmlinux_btf_from_sysfs(); 589 590 btf = btf__parse_split(*argv, base ?: base_btf); 591 err = libbpf_get_error(btf); 592 if (err) { 593 btf = NULL; 594 p_err("failed to load BTF from %s: %s", 595 *argv, strerror(err)); 596 goto done; 597 } 598 NEXT_ARG(); 599 } else { 600 err = -1; 601 p_err("unrecognized BTF source specifier: '%s'", src); 602 goto done; 603 } 604 605 while (argc) { 606 if (is_prefix(*argv, "format")) { 607 NEXT_ARG(); 608 if (argc < 1) { 609 p_err("expecting value for 'format' option\n"); 610 err = -EINVAL; 611 goto done; 612 } 613 if (strcmp(*argv, "c") == 0) { 614 dump_c = true; 615 } else if (strcmp(*argv, "raw") == 0) { 616 dump_c = false; 617 } else { 618 p_err("unrecognized format specifier: '%s', possible values: raw, c", 619 *argv); 620 err = -EINVAL; 621 goto done; 622 } 623 NEXT_ARG(); 624 } else { 625 p_err("unrecognized option: '%s'", *argv); 626 err = -EINVAL; 627 goto done; 628 } 629 } 630 631 if (!btf) { 632 if (!base_btf && btf_is_kernel_module(btf_id)) { 633 p_info("Warning: valid base BTF was not specified with -B option, falling back to standard base BTF (%s)", 634 sysfs_vmlinux); 635 base_btf = get_vmlinux_btf_from_sysfs(); 636 } 637 638 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf); 639 err = libbpf_get_error(btf); 640 if (err) { 641 p_err("get btf by id (%u): %s", btf_id, strerror(err)); 642 goto done; 643 } 644 } 645 646 if (dump_c) { 647 if (json_output) { 648 p_err("JSON output for C-syntax dump is not supported"); 649 err = -ENOTSUP; 650 goto done; 651 } 652 err = dump_btf_c(btf, root_type_ids, root_type_cnt); 653 } else { 654 err = dump_btf_raw(btf, root_type_ids, root_type_cnt); 655 } 656 657done: 658 close(fd); 659 btf__free(btf); 660 btf__free(base); 661 return err; 662} 663 664static int btf_parse_fd(int *argc, char ***argv) 665{ 666 unsigned int id; 667 char *endptr; 668 int fd; 669 670 if (!is_prefix(*argv[0], "id")) { 671 p_err("expected 'id', got: '%s'?", **argv); 672 return -1; 673 } 674 NEXT_ARGP(); 675 676 id = strtoul(**argv, &endptr, 0); 677 if (*endptr) { 678 p_err("can't parse %s as ID", **argv); 679 return -1; 680 } 681 NEXT_ARGP(); 682 683 fd = bpf_btf_get_fd_by_id(id); 684 if (fd < 0) 685 p_err("can't get BTF object by id (%u): %s", 686 id, strerror(errno)); 687 688 return fd; 689} 690 691static int 692build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type, 693 void *info, __u32 *len) 694{ 695 static const char * const names[] = { 696 [BPF_OBJ_UNKNOWN] = "unknown", 697 [BPF_OBJ_PROG] = "prog", 698 [BPF_OBJ_MAP] = "map", 699 }; 700 __u32 btf_id, id = 0; 701 int err; 702 int fd; 703 704 while (true) { 705 switch (type) { 706 case BPF_OBJ_PROG: 707 err = bpf_prog_get_next_id(id, &id); 708 break; 709 case BPF_OBJ_MAP: 710 err = bpf_map_get_next_id(id, &id); 711 break; 712 default: 713 err = -1; 714 p_err("unexpected object type: %d", type); 715 goto err_free; 716 } 717 if (err) { 718 if (errno == ENOENT) { 719 err = 0; 720 break; 721 } 722 p_err("can't get next %s: %s%s", names[type], 723 strerror(errno), 724 errno == EINVAL ? " -- kernel too old?" : ""); 725 goto err_free; 726 } 727 728 switch (type) { 729 case BPF_OBJ_PROG: 730 fd = bpf_prog_get_fd_by_id(id); 731 break; 732 case BPF_OBJ_MAP: 733 fd = bpf_map_get_fd_by_id(id); 734 break; 735 default: 736 err = -1; 737 p_err("unexpected object type: %d", type); 738 goto err_free; 739 } 740 if (fd < 0) { 741 if (errno == ENOENT) 742 continue; 743 p_err("can't get %s by id (%u): %s", names[type], id, 744 strerror(errno)); 745 err = -1; 746 goto err_free; 747 } 748 749 memset(info, 0, *len); 750 err = bpf_obj_get_info_by_fd(fd, info, len); 751 close(fd); 752 if (err) { 753 p_err("can't get %s info: %s", names[type], 754 strerror(errno)); 755 goto err_free; 756 } 757 758 switch (type) { 759 case BPF_OBJ_PROG: 760 btf_id = ((struct bpf_prog_info *)info)->btf_id; 761 break; 762 case BPF_OBJ_MAP: 763 btf_id = ((struct bpf_map_info *)info)->btf_id; 764 break; 765 default: 766 err = -1; 767 p_err("unexpected object type: %d", type); 768 goto err_free; 769 } 770 if (!btf_id) 771 continue; 772 773 err = hashmap__append(tab, u32_as_hash_field(btf_id), 774 u32_as_hash_field(id)); 775 if (err) { 776 p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s", 777 btf_id, id, strerror(errno)); 778 goto err_free; 779 } 780 } 781 782 return 0; 783 784err_free: 785 hashmap__free(tab); 786 return err; 787} 788 789static int 790build_btf_tables(struct hashmap *btf_prog_table, 791 struct hashmap *btf_map_table) 792{ 793 struct bpf_prog_info prog_info; 794 __u32 prog_len = sizeof(prog_info); 795 struct bpf_map_info map_info; 796 __u32 map_len = sizeof(map_info); 797 int err = 0; 798 799 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info, 800 &prog_len); 801 if (err) 802 return err; 803 804 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info, 805 &map_len); 806 if (err) { 807 hashmap__free(btf_prog_table); 808 return err; 809 } 810 811 return 0; 812} 813 814static void 815show_btf_plain(struct bpf_btf_info *info, int fd, 816 struct hashmap *btf_prog_table, 817 struct hashmap *btf_map_table) 818{ 819 struct hashmap_entry *entry; 820 const char *name = u64_to_ptr(info->name); 821 int n; 822 823 printf("%u: ", info->id); 824 if (info->kernel_btf) 825 printf("name [%s] ", name); 826 else if (name && name[0]) 827 printf("name %s ", name); 828 else 829 printf("name <anon> "); 830 printf("size %uB", info->btf_size); 831 832 n = 0; 833 hashmap__for_each_key_entry(btf_prog_table, entry, 834 u32_as_hash_field(info->id)) { 835 printf("%s%u", n++ == 0 ? " prog_ids " : ",", 836 hash_field_as_u32(entry->value)); 837 } 838 839 n = 0; 840 hashmap__for_each_key_entry(btf_map_table, entry, 841 u32_as_hash_field(info->id)) { 842 printf("%s%u", n++ == 0 ? " map_ids " : ",", 843 hash_field_as_u32(entry->value)); 844 } 845 846 emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 847 848 printf("\n"); 849} 850 851static void 852show_btf_json(struct bpf_btf_info *info, int fd, 853 struct hashmap *btf_prog_table, 854 struct hashmap *btf_map_table) 855{ 856 struct hashmap_entry *entry; 857 const char *name = u64_to_ptr(info->name); 858 859 jsonw_start_object(json_wtr); /* btf object */ 860 jsonw_uint_field(json_wtr, "id", info->id); 861 jsonw_uint_field(json_wtr, "size", info->btf_size); 862 863 jsonw_name(json_wtr, "prog_ids"); 864 jsonw_start_array(json_wtr); /* prog_ids */ 865 hashmap__for_each_key_entry(btf_prog_table, entry, 866 u32_as_hash_field(info->id)) { 867 jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 868 } 869 jsonw_end_array(json_wtr); /* prog_ids */ 870 871 jsonw_name(json_wtr, "map_ids"); 872 jsonw_start_array(json_wtr); /* map_ids */ 873 hashmap__for_each_key_entry(btf_map_table, entry, 874 u32_as_hash_field(info->id)) { 875 jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 876 } 877 jsonw_end_array(json_wtr); /* map_ids */ 878 879 emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */ 880 881 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf); 882 883 if (name && name[0]) 884 jsonw_string_field(json_wtr, "name", name); 885 886 jsonw_end_object(json_wtr); /* btf object */ 887} 888 889static int 890show_btf(int fd, struct hashmap *btf_prog_table, 891 struct hashmap *btf_map_table) 892{ 893 struct bpf_btf_info info; 894 __u32 len = sizeof(info); 895 char name[64]; 896 int err; 897 898 memset(&info, 0, sizeof(info)); 899 err = bpf_obj_get_info_by_fd(fd, &info, &len); 900 if (err) { 901 p_err("can't get BTF object info: %s", strerror(errno)); 902 return -1; 903 } 904 /* if kernel support emitting BTF object name, pass name pointer */ 905 if (info.name_len) { 906 memset(&info, 0, sizeof(info)); 907 info.name_len = sizeof(name); 908 info.name = ptr_to_u64(name); 909 len = sizeof(info); 910 911 err = bpf_obj_get_info_by_fd(fd, &info, &len); 912 if (err) { 913 p_err("can't get BTF object info: %s", strerror(errno)); 914 return -1; 915 } 916 } 917 918 if (json_output) 919 show_btf_json(&info, fd, btf_prog_table, btf_map_table); 920 else 921 show_btf_plain(&info, fd, btf_prog_table, btf_map_table); 922 923 return 0; 924} 925 926static int do_show(int argc, char **argv) 927{ 928 struct hashmap *btf_prog_table; 929 struct hashmap *btf_map_table; 930 int err, fd = -1; 931 __u32 id = 0; 932 933 if (argc == 2) { 934 fd = btf_parse_fd(&argc, &argv); 935 if (fd < 0) 936 return -1; 937 } 938 939 if (argc) { 940 if (fd >= 0) 941 close(fd); 942 return BAD_ARG(); 943 } 944 945 btf_prog_table = hashmap__new(hash_fn_for_key_as_id, 946 equal_fn_for_key_as_id, NULL); 947 btf_map_table = hashmap__new(hash_fn_for_key_as_id, 948 equal_fn_for_key_as_id, NULL); 949 if (IS_ERR(btf_prog_table) || IS_ERR(btf_map_table)) { 950 hashmap__free(btf_prog_table); 951 hashmap__free(btf_map_table); 952 if (fd >= 0) 953 close(fd); 954 p_err("failed to create hashmap for object references"); 955 return -1; 956 } 957 err = build_btf_tables(btf_prog_table, btf_map_table); 958 if (err) { 959 if (fd >= 0) 960 close(fd); 961 return err; 962 } 963 build_obj_refs_table(&refs_table, BPF_OBJ_BTF); 964 965 if (fd >= 0) { 966 err = show_btf(fd, btf_prog_table, btf_map_table); 967 close(fd); 968 goto exit_free; 969 } 970 971 if (json_output) 972 jsonw_start_array(json_wtr); /* root array */ 973 974 while (true) { 975 err = bpf_btf_get_next_id(id, &id); 976 if (err) { 977 if (errno == ENOENT) { 978 err = 0; 979 break; 980 } 981 p_err("can't get next BTF object: %s%s", 982 strerror(errno), 983 errno == EINVAL ? " -- kernel too old?" : ""); 984 err = -1; 985 break; 986 } 987 988 fd = bpf_btf_get_fd_by_id(id); 989 if (fd < 0) { 990 if (errno == ENOENT) 991 continue; 992 p_err("can't get BTF object by id (%u): %s", 993 id, strerror(errno)); 994 err = -1; 995 break; 996 } 997 998 err = show_btf(fd, btf_prog_table, btf_map_table); 999 close(fd); 1000 if (err) 1001 break; 1002 } 1003 1004 if (json_output) 1005 jsonw_end_array(json_wtr); /* root array */ 1006 1007exit_free: 1008 hashmap__free(btf_prog_table); 1009 hashmap__free(btf_map_table); 1010 delete_obj_refs_table(refs_table); 1011 1012 return err; 1013} 1014 1015static int do_help(int argc, char **argv) 1016{ 1017 if (json_output) { 1018 jsonw_null(json_wtr); 1019 return 0; 1020 } 1021 1022 fprintf(stderr, 1023 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n" 1024 " %1$s %2$s dump BTF_SRC [format FORMAT]\n" 1025 " %1$s %2$s help\n" 1026 "\n" 1027 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n" 1028 " FORMAT := { raw | c }\n" 1029 " " HELP_SPEC_MAP "\n" 1030 " " HELP_SPEC_PROGRAM "\n" 1031 " " HELP_SPEC_OPTIONS " |\n" 1032 " {-B|--base-btf} }\n" 1033 "", 1034 bin_name, "btf"); 1035 1036 return 0; 1037} 1038 1039static const struct cmd cmds[] = { 1040 { "show", do_show }, 1041 { "list", do_show }, 1042 { "help", do_help }, 1043 { "dump", do_dump }, 1044 { 0 } 1045}; 1046 1047int do_btf(int argc, char **argv) 1048{ 1049 return cmd_select(cmds, argc, argv, do_help); 1050}