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