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