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