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