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 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf); 584 err = libbpf_get_error(btf); 585 if (err) { 586 p_err("get btf by id (%u): %s", btf_id, strerror(err)); 587 goto done; 588 } 589 } 590 591 if (dump_c) { 592 if (json_output) { 593 p_err("JSON output for C-syntax dump is not supported"); 594 err = -ENOTSUP; 595 goto done; 596 } 597 err = dump_btf_c(btf, root_type_ids, root_type_cnt); 598 } else { 599 err = dump_btf_raw(btf, root_type_ids, root_type_cnt); 600 } 601 602 done: 603 close(fd); 604 btf__free(btf); 605 btf__free(base); 606 return err; 607 } 608 609 static int btf_parse_fd(int *argc, char ***argv) 610 { 611 unsigned int id; 612 char *endptr; 613 int fd; 614 615 if (!is_prefix(*argv[0], "id")) { 616 p_err("expected 'id', got: '%s'?", **argv); 617 return -1; 618 } 619 NEXT_ARGP(); 620 621 id = strtoul(**argv, &endptr, 0); 622 if (*endptr) { 623 p_err("can't parse %s as ID", **argv); 624 return -1; 625 } 626 NEXT_ARGP(); 627 628 fd = bpf_btf_get_fd_by_id(id); 629 if (fd < 0) 630 p_err("can't get BTF object by id (%u): %s", 631 id, strerror(errno)); 632 633 return fd; 634 } 635 636 static void delete_btf_table(struct btf_attach_table *tab) 637 { 638 struct btf_attach_point *obj; 639 struct hlist_node *tmp; 640 641 unsigned int bkt; 642 643 hash_for_each_safe(tab->table, bkt, tmp, obj, hash) { 644 hash_del(&obj->hash); 645 free(obj); 646 } 647 } 648 649 static int 650 build_btf_type_table(struct btf_attach_table *tab, enum bpf_obj_type type, 651 void *info, __u32 *len) 652 { 653 static const char * const names[] = { 654 [BPF_OBJ_UNKNOWN] = "unknown", 655 [BPF_OBJ_PROG] = "prog", 656 [BPF_OBJ_MAP] = "map", 657 }; 658 struct btf_attach_point *obj_node; 659 __u32 btf_id, id = 0; 660 int err; 661 int fd; 662 663 while (true) { 664 switch (type) { 665 case BPF_OBJ_PROG: 666 err = bpf_prog_get_next_id(id, &id); 667 break; 668 case BPF_OBJ_MAP: 669 err = bpf_map_get_next_id(id, &id); 670 break; 671 default: 672 err = -1; 673 p_err("unexpected object type: %d", type); 674 goto err_free; 675 } 676 if (err) { 677 if (errno == ENOENT) { 678 err = 0; 679 break; 680 } 681 p_err("can't get next %s: %s%s", names[type], 682 strerror(errno), 683 errno == EINVAL ? " -- kernel too old?" : ""); 684 goto err_free; 685 } 686 687 switch (type) { 688 case BPF_OBJ_PROG: 689 fd = bpf_prog_get_fd_by_id(id); 690 break; 691 case BPF_OBJ_MAP: 692 fd = bpf_map_get_fd_by_id(id); 693 break; 694 default: 695 err = -1; 696 p_err("unexpected object type: %d", type); 697 goto err_free; 698 } 699 if (fd < 0) { 700 if (errno == ENOENT) 701 continue; 702 p_err("can't get %s by id (%u): %s", names[type], id, 703 strerror(errno)); 704 err = -1; 705 goto err_free; 706 } 707 708 memset(info, 0, *len); 709 err = bpf_obj_get_info_by_fd(fd, info, len); 710 close(fd); 711 if (err) { 712 p_err("can't get %s info: %s", names[type], 713 strerror(errno)); 714 goto err_free; 715 } 716 717 switch (type) { 718 case BPF_OBJ_PROG: 719 btf_id = ((struct bpf_prog_info *)info)->btf_id; 720 break; 721 case BPF_OBJ_MAP: 722 btf_id = ((struct bpf_map_info *)info)->btf_id; 723 break; 724 default: 725 err = -1; 726 p_err("unexpected object type: %d", type); 727 goto err_free; 728 } 729 if (!btf_id) 730 continue; 731 732 obj_node = calloc(1, sizeof(*obj_node)); 733 if (!obj_node) { 734 p_err("failed to allocate memory: %s", strerror(errno)); 735 err = -ENOMEM; 736 goto err_free; 737 } 738 739 obj_node->obj_id = id; 740 obj_node->btf_id = btf_id; 741 hash_add(tab->table, &obj_node->hash, obj_node->btf_id); 742 } 743 744 return 0; 745 746 err_free: 747 delete_btf_table(tab); 748 return err; 749 } 750 751 static int 752 build_btf_tables(struct btf_attach_table *btf_prog_table, 753 struct btf_attach_table *btf_map_table) 754 { 755 struct bpf_prog_info prog_info; 756 __u32 prog_len = sizeof(prog_info); 757 struct bpf_map_info map_info; 758 __u32 map_len = sizeof(map_info); 759 int err = 0; 760 761 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info, 762 &prog_len); 763 if (err) 764 return err; 765 766 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info, 767 &map_len); 768 if (err) { 769 delete_btf_table(btf_prog_table); 770 return err; 771 } 772 773 return 0; 774 } 775 776 static void 777 show_btf_plain(struct bpf_btf_info *info, int fd, 778 struct btf_attach_table *btf_prog_table, 779 struct btf_attach_table *btf_map_table) 780 { 781 struct btf_attach_point *obj; 782 const char *name = u64_to_ptr(info->name); 783 int n; 784 785 printf("%u: ", info->id); 786 if (info->kernel_btf) 787 printf("name [%s] ", name); 788 else if (name && name[0]) 789 printf("name %s ", name); 790 else 791 printf("name <anon> "); 792 printf("size %uB", info->btf_size); 793 794 n = 0; 795 hash_for_each_possible(btf_prog_table->table, obj, hash, info->id) { 796 if (obj->btf_id == info->id) 797 printf("%s%u", n++ == 0 ? " prog_ids " : ",", 798 obj->obj_id); 799 } 800 801 n = 0; 802 hash_for_each_possible(btf_map_table->table, obj, hash, info->id) { 803 if (obj->btf_id == info->id) 804 printf("%s%u", n++ == 0 ? " map_ids " : ",", 805 obj->obj_id); 806 } 807 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); 808 809 printf("\n"); 810 } 811 812 static void 813 show_btf_json(struct bpf_btf_info *info, int fd, 814 struct btf_attach_table *btf_prog_table, 815 struct btf_attach_table *btf_map_table) 816 { 817 struct btf_attach_point *obj; 818 const char *name = u64_to_ptr(info->name); 819 820 jsonw_start_object(json_wtr); /* btf object */ 821 jsonw_uint_field(json_wtr, "id", info->id); 822 jsonw_uint_field(json_wtr, "size", info->btf_size); 823 824 jsonw_name(json_wtr, "prog_ids"); 825 jsonw_start_array(json_wtr); /* prog_ids */ 826 hash_for_each_possible(btf_prog_table->table, obj, hash, 827 info->id) { 828 if (obj->btf_id == info->id) 829 jsonw_uint(json_wtr, obj->obj_id); 830 } 831 jsonw_end_array(json_wtr); /* prog_ids */ 832 833 jsonw_name(json_wtr, "map_ids"); 834 jsonw_start_array(json_wtr); /* map_ids */ 835 hash_for_each_possible(btf_map_table->table, obj, hash, 836 info->id) { 837 if (obj->btf_id == info->id) 838 jsonw_uint(json_wtr, obj->obj_id); 839 } 840 jsonw_end_array(json_wtr); /* map_ids */ 841 842 emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */ 843 844 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf); 845 846 if (name && name[0]) 847 jsonw_string_field(json_wtr, "name", name); 848 849 jsonw_end_object(json_wtr); /* btf object */ 850 } 851 852 static int 853 show_btf(int fd, struct btf_attach_table *btf_prog_table, 854 struct btf_attach_table *btf_map_table) 855 { 856 struct bpf_btf_info info; 857 __u32 len = sizeof(info); 858 char name[64]; 859 int err; 860 861 memset(&info, 0, sizeof(info)); 862 err = bpf_obj_get_info_by_fd(fd, &info, &len); 863 if (err) { 864 p_err("can't get BTF object info: %s", strerror(errno)); 865 return -1; 866 } 867 /* if kernel support emitting BTF object name, pass name pointer */ 868 if (info.name_len) { 869 memset(&info, 0, sizeof(info)); 870 info.name_len = sizeof(name); 871 info.name = ptr_to_u64(name); 872 len = sizeof(info); 873 874 err = bpf_obj_get_info_by_fd(fd, &info, &len); 875 if (err) { 876 p_err("can't get BTF object info: %s", strerror(errno)); 877 return -1; 878 } 879 } 880 881 if (json_output) 882 show_btf_json(&info, fd, btf_prog_table, btf_map_table); 883 else 884 show_btf_plain(&info, fd, btf_prog_table, btf_map_table); 885 886 return 0; 887 } 888 889 static int do_show(int argc, char **argv) 890 { 891 struct btf_attach_table btf_prog_table; 892 struct btf_attach_table btf_map_table; 893 int err, fd = -1; 894 __u32 id = 0; 895 896 if (argc == 2) { 897 fd = btf_parse_fd(&argc, &argv); 898 if (fd < 0) 899 return -1; 900 } 901 902 if (argc) { 903 if (fd >= 0) 904 close(fd); 905 return BAD_ARG(); 906 } 907 908 hash_init(btf_prog_table.table); 909 hash_init(btf_map_table.table); 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 delete_btf_table(&btf_prog_table); 962 delete_btf_table(&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