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