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 [BTF_KIND_TYPE_TAG] = "TYPE_TAG", 43 }; 44 45 struct btf_attach_point { 46 __u32 obj_id; 47 __u32 btf_id; 48 }; 49 50 static 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 66 static 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 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 btf_kind_safe(int kind) 102 { 103 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN; 104 } 105 106 static 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 372 static 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 411 static void __printf(2, 0) btf_dump_printf(void *ctx, 412 const char *fmt, va_list args) 413 { 414 vfprintf(stdout, fmt, args); 415 } 416 417 static 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 if (IS_ERR(d)) 425 return PTR_ERR(d); 426 427 printf("#ifndef __VMLINUX_H__\n"); 428 printf("#define __VMLINUX_H__\n"); 429 printf("\n"); 430 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 431 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n"); 432 printf("#endif\n\n"); 433 434 if (root_type_cnt) { 435 for (i = 0; i < root_type_cnt; i++) { 436 err = btf_dump__dump_type(d, root_type_ids[i]); 437 if (err) 438 goto done; 439 } 440 } else { 441 int cnt = btf__type_cnt(btf); 442 443 for (i = 1; i < cnt; i++) { 444 err = btf_dump__dump_type(d, i); 445 if (err) 446 goto done; 447 } 448 } 449 450 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n"); 451 printf("#pragma clang attribute pop\n"); 452 printf("#endif\n"); 453 printf("\n"); 454 printf("#endif /* __VMLINUX_H__ */\n"); 455 456 done: 457 btf_dump__free(d); 458 return err; 459 } 460 461 static int do_dump(int argc, char **argv) 462 { 463 struct btf *btf = NULL, *base = NULL; 464 __u32 root_type_ids[2]; 465 int root_type_cnt = 0; 466 bool dump_c = false; 467 __u32 btf_id = -1; 468 const char *src; 469 int fd = -1; 470 int err; 471 472 if (!REQ_ARGS(2)) { 473 usage(); 474 return -1; 475 } 476 src = GET_ARG(); 477 if (is_prefix(src, "map")) { 478 struct bpf_map_info info = {}; 479 __u32 len = sizeof(info); 480 481 if (!REQ_ARGS(2)) { 482 usage(); 483 return -1; 484 } 485 486 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 487 if (fd < 0) 488 return -1; 489 490 btf_id = info.btf_id; 491 if (argc && is_prefix(*argv, "key")) { 492 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 493 NEXT_ARG(); 494 } else if (argc && is_prefix(*argv, "value")) { 495 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 496 NEXT_ARG(); 497 } else if (argc && is_prefix(*argv, "all")) { 498 NEXT_ARG(); 499 } else if (argc && is_prefix(*argv, "kv")) { 500 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 501 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 502 NEXT_ARG(); 503 } else { 504 root_type_ids[root_type_cnt++] = info.btf_key_type_id; 505 root_type_ids[root_type_cnt++] = info.btf_value_type_id; 506 } 507 } else if (is_prefix(src, "prog")) { 508 struct bpf_prog_info info = {}; 509 __u32 len = sizeof(info); 510 511 if (!REQ_ARGS(2)) { 512 usage(); 513 return -1; 514 } 515 516 fd = prog_parse_fd(&argc, &argv); 517 if (fd < 0) 518 return -1; 519 520 err = bpf_obj_get_info_by_fd(fd, &info, &len); 521 if (err) { 522 p_err("can't get prog info: %s", strerror(errno)); 523 goto done; 524 } 525 526 btf_id = info.btf_id; 527 } else if (is_prefix(src, "id")) { 528 char *endptr; 529 530 btf_id = strtoul(*argv, &endptr, 0); 531 if (*endptr) { 532 p_err("can't parse %s as ID", *argv); 533 return -1; 534 } 535 NEXT_ARG(); 536 } else if (is_prefix(src, "file")) { 537 const char sysfs_prefix[] = "/sys/kernel/btf/"; 538 const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux"; 539 540 if (!base_btf && 541 strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 && 542 strcmp(*argv, sysfs_vmlinux) != 0) { 543 base = btf__parse(sysfs_vmlinux, NULL); 544 if (libbpf_get_error(base)) { 545 p_err("failed to parse vmlinux BTF at '%s': %ld\n", 546 sysfs_vmlinux, libbpf_get_error(base)); 547 base = NULL; 548 } 549 } 550 551 btf = btf__parse_split(*argv, base ?: base_btf); 552 if (IS_ERR(btf)) { 553 err = -PTR_ERR(btf); 554 btf = NULL; 555 p_err("failed to load BTF from %s: %s", 556 *argv, strerror(err)); 557 goto done; 558 } 559 NEXT_ARG(); 560 } else { 561 err = -1; 562 p_err("unrecognized BTF source specifier: '%s'", src); 563 goto done; 564 } 565 566 while (argc) { 567 if (is_prefix(*argv, "format")) { 568 NEXT_ARG(); 569 if (argc < 1) { 570 p_err("expecting value for 'format' option\n"); 571 err = -EINVAL; 572 goto done; 573 } 574 if (strcmp(*argv, "c") == 0) { 575 dump_c = true; 576 } else if (strcmp(*argv, "raw") == 0) { 577 dump_c = false; 578 } else { 579 p_err("unrecognized format specifier: '%s', possible values: raw, c", 580 *argv); 581 err = -EINVAL; 582 goto done; 583 } 584 NEXT_ARG(); 585 } else { 586 p_err("unrecognized option: '%s'", *argv); 587 err = -EINVAL; 588 goto done; 589 } 590 } 591 592 if (!btf) { 593 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf); 594 err = libbpf_get_error(btf); 595 if (err) { 596 p_err("get btf by id (%u): %s", btf_id, strerror(err)); 597 goto done; 598 } 599 } 600 601 if (dump_c) { 602 if (json_output) { 603 p_err("JSON output for C-syntax dump is not supported"); 604 err = -ENOTSUP; 605 goto done; 606 } 607 err = dump_btf_c(btf, root_type_ids, root_type_cnt); 608 } else { 609 err = dump_btf_raw(btf, root_type_ids, root_type_cnt); 610 } 611 612 done: 613 close(fd); 614 btf__free(btf); 615 btf__free(base); 616 return err; 617 } 618 619 static int btf_parse_fd(int *argc, char ***argv) 620 { 621 unsigned int id; 622 char *endptr; 623 int fd; 624 625 if (!is_prefix(*argv[0], "id")) { 626 p_err("expected 'id', got: '%s'?", **argv); 627 return -1; 628 } 629 NEXT_ARGP(); 630 631 id = strtoul(**argv, &endptr, 0); 632 if (*endptr) { 633 p_err("can't parse %s as ID", **argv); 634 return -1; 635 } 636 NEXT_ARGP(); 637 638 fd = bpf_btf_get_fd_by_id(id); 639 if (fd < 0) 640 p_err("can't get BTF object by id (%u): %s", 641 id, strerror(errno)); 642 643 return fd; 644 } 645 646 static int 647 build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type, 648 void *info, __u32 *len) 649 { 650 static const char * const names[] = { 651 [BPF_OBJ_UNKNOWN] = "unknown", 652 [BPF_OBJ_PROG] = "prog", 653 [BPF_OBJ_MAP] = "map", 654 }; 655 __u32 btf_id, id = 0; 656 int err; 657 int fd; 658 659 while (true) { 660 switch (type) { 661 case BPF_OBJ_PROG: 662 err = bpf_prog_get_next_id(id, &id); 663 break; 664 case BPF_OBJ_MAP: 665 err = bpf_map_get_next_id(id, &id); 666 break; 667 default: 668 err = -1; 669 p_err("unexpected object type: %d", type); 670 goto err_free; 671 } 672 if (err) { 673 if (errno == ENOENT) { 674 err = 0; 675 break; 676 } 677 p_err("can't get next %s: %s%s", names[type], 678 strerror(errno), 679 errno == EINVAL ? " -- kernel too old?" : ""); 680 goto err_free; 681 } 682 683 switch (type) { 684 case BPF_OBJ_PROG: 685 fd = bpf_prog_get_fd_by_id(id); 686 break; 687 case BPF_OBJ_MAP: 688 fd = bpf_map_get_fd_by_id(id); 689 break; 690 default: 691 err = -1; 692 p_err("unexpected object type: %d", type); 693 goto err_free; 694 } 695 if (fd < 0) { 696 if (errno == ENOENT) 697 continue; 698 p_err("can't get %s by id (%u): %s", names[type], id, 699 strerror(errno)); 700 err = -1; 701 goto err_free; 702 } 703 704 memset(info, 0, *len); 705 err = bpf_obj_get_info_by_fd(fd, info, len); 706 close(fd); 707 if (err) { 708 p_err("can't get %s info: %s", names[type], 709 strerror(errno)); 710 goto err_free; 711 } 712 713 switch (type) { 714 case BPF_OBJ_PROG: 715 btf_id = ((struct bpf_prog_info *)info)->btf_id; 716 break; 717 case BPF_OBJ_MAP: 718 btf_id = ((struct bpf_map_info *)info)->btf_id; 719 break; 720 default: 721 err = -1; 722 p_err("unexpected object type: %d", type); 723 goto err_free; 724 } 725 if (!btf_id) 726 continue; 727 728 err = hashmap__append(tab, u32_as_hash_field(btf_id), 729 u32_as_hash_field(id)); 730 if (err) { 731 p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s", 732 btf_id, id, strerror(errno)); 733 goto err_free; 734 } 735 } 736 737 return 0; 738 739 err_free: 740 hashmap__free(tab); 741 return err; 742 } 743 744 static int 745 build_btf_tables(struct hashmap *btf_prog_table, 746 struct hashmap *btf_map_table) 747 { 748 struct bpf_prog_info prog_info; 749 __u32 prog_len = sizeof(prog_info); 750 struct bpf_map_info map_info; 751 __u32 map_len = sizeof(map_info); 752 int err = 0; 753 754 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info, 755 &prog_len); 756 if (err) 757 return err; 758 759 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info, 760 &map_len); 761 if (err) { 762 hashmap__free(btf_prog_table); 763 return err; 764 } 765 766 return 0; 767 } 768 769 static void 770 show_btf_plain(struct bpf_btf_info *info, int fd, 771 struct hashmap *btf_prog_table, 772 struct hashmap *btf_map_table) 773 { 774 struct hashmap_entry *entry; 775 const char *name = u64_to_ptr(info->name); 776 int n; 777 778 printf("%u: ", info->id); 779 if (info->kernel_btf) 780 printf("name [%s] ", name); 781 else if (name && name[0]) 782 printf("name %s ", name); 783 else 784 printf("name <anon> "); 785 printf("size %uB", info->btf_size); 786 787 n = 0; 788 hashmap__for_each_key_entry(btf_prog_table, entry, 789 u32_as_hash_field(info->id)) { 790 printf("%s%u", n++ == 0 ? " prog_ids " : ",", 791 hash_field_as_u32(entry->value)); 792 } 793 794 n = 0; 795 hashmap__for_each_key_entry(btf_map_table, entry, 796 u32_as_hash_field(info->id)) { 797 printf("%s%u", n++ == 0 ? " map_ids " : ",", 798 hash_field_as_u32(entry->value)); 799 } 800 801 emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 802 803 printf("\n"); 804 } 805 806 static void 807 show_btf_json(struct bpf_btf_info *info, int fd, 808 struct hashmap *btf_prog_table, 809 struct hashmap *btf_map_table) 810 { 811 struct hashmap_entry *entry; 812 const char *name = u64_to_ptr(info->name); 813 814 jsonw_start_object(json_wtr); /* btf object */ 815 jsonw_uint_field(json_wtr, "id", info->id); 816 jsonw_uint_field(json_wtr, "size", info->btf_size); 817 818 jsonw_name(json_wtr, "prog_ids"); 819 jsonw_start_array(json_wtr); /* prog_ids */ 820 hashmap__for_each_key_entry(btf_prog_table, entry, 821 u32_as_hash_field(info->id)) { 822 jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 823 } 824 jsonw_end_array(json_wtr); /* prog_ids */ 825 826 jsonw_name(json_wtr, "map_ids"); 827 jsonw_start_array(json_wtr); /* map_ids */ 828 hashmap__for_each_key_entry(btf_map_table, entry, 829 u32_as_hash_field(info->id)) { 830 jsonw_uint(json_wtr, hash_field_as_u32(entry->value)); 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 hashmap *btf_prog_table, 846 struct hashmap *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 hashmap *btf_prog_table; 884 struct hashmap *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 btf_prog_table = hashmap__new(hash_fn_for_key_as_id, 901 equal_fn_for_key_as_id, NULL); 902 btf_map_table = hashmap__new(hash_fn_for_key_as_id, 903 equal_fn_for_key_as_id, NULL); 904 if (!btf_prog_table || !btf_map_table) { 905 hashmap__free(btf_prog_table); 906 hashmap__free(btf_map_table); 907 if (fd >= 0) 908 close(fd); 909 p_err("failed to create hashmap for object references"); 910 return -1; 911 } 912 err = build_btf_tables(btf_prog_table, btf_map_table); 913 if (err) { 914 if (fd >= 0) 915 close(fd); 916 return err; 917 } 918 build_obj_refs_table(&refs_table, BPF_OBJ_BTF); 919 920 if (fd >= 0) { 921 err = show_btf(fd, btf_prog_table, btf_map_table); 922 close(fd); 923 goto exit_free; 924 } 925 926 if (json_output) 927 jsonw_start_array(json_wtr); /* root array */ 928 929 while (true) { 930 err = bpf_btf_get_next_id(id, &id); 931 if (err) { 932 if (errno == ENOENT) { 933 err = 0; 934 break; 935 } 936 p_err("can't get next BTF object: %s%s", 937 strerror(errno), 938 errno == EINVAL ? " -- kernel too old?" : ""); 939 err = -1; 940 break; 941 } 942 943 fd = bpf_btf_get_fd_by_id(id); 944 if (fd < 0) { 945 if (errno == ENOENT) 946 continue; 947 p_err("can't get BTF object by id (%u): %s", 948 id, strerror(errno)); 949 err = -1; 950 break; 951 } 952 953 err = show_btf(fd, btf_prog_table, btf_map_table); 954 close(fd); 955 if (err) 956 break; 957 } 958 959 if (json_output) 960 jsonw_end_array(json_wtr); /* root array */ 961 962 exit_free: 963 hashmap__free(btf_prog_table); 964 hashmap__free(btf_map_table); 965 delete_obj_refs_table(refs_table); 966 967 return err; 968 } 969 970 static int do_help(int argc, char **argv) 971 { 972 if (json_output) { 973 jsonw_null(json_wtr); 974 return 0; 975 } 976 977 fprintf(stderr, 978 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n" 979 " %1$s %2$s dump BTF_SRC [format FORMAT]\n" 980 " %1$s %2$s help\n" 981 "\n" 982 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n" 983 " FORMAT := { raw | c }\n" 984 " " HELP_SPEC_MAP "\n" 985 " " HELP_SPEC_PROGRAM "\n" 986 " " HELP_SPEC_OPTIONS " |\n" 987 " {-B|--base-btf} }\n" 988 "", 989 bin_name, "btf"); 990 991 return 0; 992 } 993 994 static const struct cmd cmds[] = { 995 { "show", do_show }, 996 { "list", do_show }, 997 { "help", do_help }, 998 { "dump", do_dump }, 999 { 0 } 1000 }; 1001 1002 int do_btf(int argc, char **argv) 1003 { 1004 return cmd_select(cmds, argc, argv, do_help); 1005 } 1006