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