1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 3 /* 4 * resolve_btfids scans ELF object for .BTF_ids section and resolves 5 * its symbols with BTF ID values. 6 * 7 * Each symbol points to 4 bytes data and is expected to have 8 * following name syntax: 9 * 10 * __BTF_ID__<type>__<symbol>[__<id>] 11 * 12 * type is: 13 * 14 * func - lookup BTF_KIND_FUNC symbol with <symbol> name 15 * and store its ID into the data: 16 * 17 * __BTF_ID__func__vfs_close__1: 18 * .zero 4 19 * 20 * struct - lookup BTF_KIND_STRUCT symbol with <symbol> name 21 * and store its ID into the data: 22 * 23 * __BTF_ID__struct__sk_buff__1: 24 * .zero 4 25 * 26 * union - lookup BTF_KIND_UNION symbol with <symbol> name 27 * and store its ID into the data: 28 * 29 * __BTF_ID__union__thread_union__1: 30 * .zero 4 31 * 32 * typedef - lookup BTF_KIND_TYPEDEF symbol with <symbol> name 33 * and store its ID into the data: 34 * 35 * __BTF_ID__typedef__pid_t__1: 36 * .zero 4 37 * 38 * set - store symbol size into first 4 bytes and sort following 39 * ID list 40 * 41 * __BTF_ID__set__list: 42 * .zero 4 43 * list: 44 * __BTF_ID__func__vfs_getattr__3: 45 * .zero 4 46 * __BTF_ID__func__vfs_fallocate__4: 47 * .zero 4 48 * 49 * set8 - store symbol size into first 4 bytes and sort following 50 * ID list 51 * 52 * __BTF_ID__set8__list: 53 * .zero 8 54 * list: 55 * __BTF_ID__func__vfs_getattr__3: 56 * .zero 4 57 * .word (1 << 0) | (1 << 2) 58 * __BTF_ID__func__vfs_fallocate__5: 59 * .zero 4 60 * .word (1 << 3) | (1 << 1) | (1 << 2) 61 */ 62 63 #define _GNU_SOURCE 64 #include <stdio.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include <stdlib.h> 68 #include <libelf.h> 69 #include <gelf.h> 70 #include <sys/stat.h> 71 #include <fcntl.h> 72 #include <errno.h> 73 #include <linux/btf_ids.h> 74 #include <linux/rbtree.h> 75 #include <linux/zalloc.h> 76 #include <linux/err.h> 77 #include <bpf/btf.h> 78 #include <bpf/libbpf.h> 79 #include <subcmd/parse-options.h> 80 81 #define BTF_IDS_SECTION ".BTF_ids" 82 #define BTF_ID_PREFIX "__BTF_ID__" 83 84 #define BTF_STRUCT "struct" 85 #define BTF_UNION "union" 86 #define BTF_TYPEDEF "typedef" 87 #define BTF_FUNC "func" 88 #define BTF_SET "set" 89 #define BTF_SET8 "set8" 90 91 #define ADDR_CNT 100 92 93 #if __BYTE_ORDER == __LITTLE_ENDIAN 94 # define ELFDATANATIVE ELFDATA2LSB 95 #elif __BYTE_ORDER == __BIG_ENDIAN 96 # define ELFDATANATIVE ELFDATA2MSB 97 #else 98 # error "Unknown machine endianness!" 99 #endif 100 101 struct btf_id { 102 struct rb_node rb_node; 103 char *name; 104 union { 105 int id; 106 int cnt; 107 }; 108 int addr_cnt; 109 bool is_set; 110 bool is_set8; 111 Elf64_Addr addr[ADDR_CNT]; 112 }; 113 114 struct object { 115 const char *path; 116 const char *btf; 117 const char *base_btf_path; 118 119 struct { 120 int fd; 121 Elf *elf; 122 Elf_Data *symbols; 123 Elf_Data *idlist; 124 int symbols_shndx; 125 int idlist_shndx; 126 size_t strtabidx; 127 unsigned long idlist_addr; 128 int encoding; 129 } efile; 130 131 struct rb_root sets; 132 struct rb_root structs; 133 struct rb_root unions; 134 struct rb_root typedefs; 135 struct rb_root funcs; 136 137 int nr_funcs; 138 int nr_structs; 139 int nr_unions; 140 int nr_typedefs; 141 }; 142 143 static int verbose; 144 static int warnings; 145 146 static int eprintf(int level, int var, const char *fmt, ...) 147 { 148 va_list args; 149 int ret = 0; 150 151 if (var >= level) { 152 va_start(args, fmt); 153 ret = vfprintf(stderr, fmt, args); 154 va_end(args); 155 } 156 return ret; 157 } 158 159 #ifndef pr_fmt 160 #define pr_fmt(fmt) fmt 161 #endif 162 163 #define pr_debug(fmt, ...) \ 164 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__) 165 #define pr_debugN(n, fmt, ...) \ 166 eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__) 167 #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 168 #define pr_err(fmt, ...) \ 169 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 170 #define pr_info(fmt, ...) \ 171 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 172 173 static bool is_btf_id(const char *name) 174 { 175 return name && !strncmp(name, BTF_ID_PREFIX, sizeof(BTF_ID_PREFIX) - 1); 176 } 177 178 static struct btf_id *btf_id__find(struct rb_root *root, const char *name) 179 { 180 struct rb_node *p = root->rb_node; 181 struct btf_id *id; 182 int cmp; 183 184 while (p) { 185 id = rb_entry(p, struct btf_id, rb_node); 186 cmp = strcmp(id->name, name); 187 if (cmp < 0) 188 p = p->rb_left; 189 else if (cmp > 0) 190 p = p->rb_right; 191 else 192 return id; 193 } 194 return NULL; 195 } 196 197 static struct btf_id * 198 btf_id__add(struct rb_root *root, char *name, bool unique) 199 { 200 struct rb_node **p = &root->rb_node; 201 struct rb_node *parent = NULL; 202 struct btf_id *id; 203 int cmp; 204 205 while (*p != NULL) { 206 parent = *p; 207 id = rb_entry(parent, struct btf_id, rb_node); 208 cmp = strcmp(id->name, name); 209 if (cmp < 0) 210 p = &(*p)->rb_left; 211 else if (cmp > 0) 212 p = &(*p)->rb_right; 213 else 214 return unique ? NULL : id; 215 } 216 217 id = zalloc(sizeof(*id)); 218 if (id) { 219 pr_debug("adding symbol %s\n", name); 220 id->name = name; 221 rb_link_node(&id->rb_node, parent, p); 222 rb_insert_color(&id->rb_node, root); 223 } 224 return id; 225 } 226 227 static char *get_id(const char *prefix_end) 228 { 229 /* 230 * __BTF_ID__func__vfs_truncate__0 231 * prefix_end = ^ 232 * pos = ^ 233 */ 234 int len = strlen(prefix_end); 235 int pos = sizeof("__") - 1; 236 char *p, *id; 237 238 if (pos >= len) 239 return NULL; 240 241 id = strdup(prefix_end + pos); 242 if (id) { 243 /* 244 * __BTF_ID__func__vfs_truncate__0 245 * id = ^ 246 * 247 * cut the unique id part 248 */ 249 p = strrchr(id, '_'); 250 p--; 251 if (*p != '_') { 252 free(id); 253 return NULL; 254 } 255 *p = '\0'; 256 } 257 return id; 258 } 259 260 static struct btf_id *add_set(struct object *obj, char *name, bool is_set8) 261 { 262 /* 263 * __BTF_ID__set__name 264 * name = ^ 265 * id = ^ 266 */ 267 char *id = name + (is_set8 ? sizeof(BTF_SET8 "__") : sizeof(BTF_SET "__")) - 1; 268 int len = strlen(name); 269 270 if (id >= name + len) { 271 pr_err("FAILED to parse set name: %s\n", name); 272 return NULL; 273 } 274 275 return btf_id__add(&obj->sets, id, true); 276 } 277 278 static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size) 279 { 280 char *id; 281 282 id = get_id(name + size); 283 if (!id) { 284 pr_err("FAILED to parse symbol name: %s\n", name); 285 return NULL; 286 } 287 288 return btf_id__add(root, id, false); 289 } 290 291 /* Older libelf.h and glibc elf.h might not yet define the ELF compression types. */ 292 #ifndef SHF_COMPRESSED 293 #define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ 294 #endif 295 296 /* 297 * The data of compressed section should be aligned to 4 298 * (for 32bit) or 8 (for 64 bit) bytes. The binutils ld 299 * sets sh_addralign to 1, which makes libelf fail with 300 * misaligned section error during the update: 301 * FAILED elf_update(WRITE): invalid section alignment 302 * 303 * While waiting for ld fix, we fix the compressed sections 304 * sh_addralign value manualy. 305 */ 306 static int compressed_section_fix(Elf *elf, Elf_Scn *scn, GElf_Shdr *sh) 307 { 308 int expected = gelf_getclass(elf) == ELFCLASS32 ? 4 : 8; 309 310 if (!(sh->sh_flags & SHF_COMPRESSED)) 311 return 0; 312 313 if (sh->sh_addralign == expected) 314 return 0; 315 316 pr_debug2(" - fixing wrong alignment sh_addralign %u, expected %u\n", 317 sh->sh_addralign, expected); 318 319 sh->sh_addralign = expected; 320 321 if (gelf_update_shdr(scn, sh) == 0) { 322 pr_err("FAILED cannot update section header: %s\n", 323 elf_errmsg(-1)); 324 return -1; 325 } 326 return 0; 327 } 328 329 static int elf_collect(struct object *obj) 330 { 331 Elf_Scn *scn = NULL; 332 size_t shdrstrndx; 333 GElf_Ehdr ehdr; 334 int idx = 0; 335 Elf *elf; 336 int fd; 337 338 fd = open(obj->path, O_RDWR, 0666); 339 if (fd == -1) { 340 pr_err("FAILED cannot open %s: %s\n", 341 obj->path, strerror(errno)); 342 return -1; 343 } 344 345 elf_version(EV_CURRENT); 346 347 elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL); 348 if (!elf) { 349 close(fd); 350 pr_err("FAILED cannot create ELF descriptor: %s\n", 351 elf_errmsg(-1)); 352 return -1; 353 } 354 355 obj->efile.fd = fd; 356 obj->efile.elf = elf; 357 358 elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT); 359 360 if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) { 361 pr_err("FAILED cannot get shdr str ndx\n"); 362 return -1; 363 } 364 365 if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) { 366 pr_err("FAILED cannot get ELF header: %s\n", 367 elf_errmsg(-1)); 368 return -1; 369 } 370 obj->efile.encoding = ehdr.e_ident[EI_DATA]; 371 372 /* 373 * Scan all the elf sections and look for save data 374 * from .BTF_ids section and symbols. 375 */ 376 while ((scn = elf_nextscn(elf, scn)) != NULL) { 377 Elf_Data *data; 378 GElf_Shdr sh; 379 char *name; 380 381 idx++; 382 if (gelf_getshdr(scn, &sh) != &sh) { 383 pr_err("FAILED get section(%d) header\n", idx); 384 return -1; 385 } 386 387 name = elf_strptr(elf, shdrstrndx, sh.sh_name); 388 if (!name) { 389 pr_err("FAILED get section(%d) name\n", idx); 390 return -1; 391 } 392 393 data = elf_getdata(scn, 0); 394 if (!data) { 395 pr_err("FAILED to get section(%d) data from %s\n", 396 idx, name); 397 return -1; 398 } 399 400 pr_debug2("section(%d) %s, size %ld, link %d, flags %lx, type=%d\n", 401 idx, name, (unsigned long) data->d_size, 402 (int) sh.sh_link, (unsigned long) sh.sh_flags, 403 (int) sh.sh_type); 404 405 if (sh.sh_type == SHT_SYMTAB) { 406 obj->efile.symbols = data; 407 obj->efile.symbols_shndx = idx; 408 obj->efile.strtabidx = sh.sh_link; 409 } else if (!strcmp(name, BTF_IDS_SECTION)) { 410 obj->efile.idlist = data; 411 obj->efile.idlist_shndx = idx; 412 obj->efile.idlist_addr = sh.sh_addr; 413 } else if (!strcmp(name, BTF_BASE_ELF_SEC)) { 414 /* If a .BTF.base section is found, do not resolve 415 * BTF ids relative to vmlinux; resolve relative 416 * to the .BTF.base section instead. btf__parse_split() 417 * will take care of this once the base BTF it is 418 * passed is NULL. 419 */ 420 obj->base_btf_path = NULL; 421 } 422 423 if (compressed_section_fix(elf, scn, &sh)) 424 return -1; 425 } 426 427 return 0; 428 } 429 430 static int symbols_collect(struct object *obj) 431 { 432 Elf_Scn *scn = NULL; 433 int n, i; 434 GElf_Shdr sh; 435 char *name; 436 437 scn = elf_getscn(obj->efile.elf, obj->efile.symbols_shndx); 438 if (!scn) 439 return -1; 440 441 if (gelf_getshdr(scn, &sh) != &sh) 442 return -1; 443 444 n = sh.sh_size / sh.sh_entsize; 445 446 /* 447 * Scan symbols and look for the ones starting with 448 * __BTF_ID__* over .BTF_ids section. 449 */ 450 for (i = 0; i < n; i++) { 451 char *prefix; 452 struct btf_id *id; 453 GElf_Sym sym; 454 455 if (!gelf_getsym(obj->efile.symbols, i, &sym)) 456 return -1; 457 458 if (sym.st_shndx != obj->efile.idlist_shndx) 459 continue; 460 461 name = elf_strptr(obj->efile.elf, obj->efile.strtabidx, 462 sym.st_name); 463 464 if (!is_btf_id(name)) 465 continue; 466 467 /* 468 * __BTF_ID__TYPE__vfs_truncate__0 469 * prefix = ^ 470 */ 471 prefix = name + sizeof(BTF_ID_PREFIX) - 1; 472 473 /* struct */ 474 if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) { 475 obj->nr_structs++; 476 id = add_symbol(&obj->structs, prefix, sizeof(BTF_STRUCT) - 1); 477 /* union */ 478 } else if (!strncmp(prefix, BTF_UNION, sizeof(BTF_UNION) - 1)) { 479 obj->nr_unions++; 480 id = add_symbol(&obj->unions, prefix, sizeof(BTF_UNION) - 1); 481 /* typedef */ 482 } else if (!strncmp(prefix, BTF_TYPEDEF, sizeof(BTF_TYPEDEF) - 1)) { 483 obj->nr_typedefs++; 484 id = add_symbol(&obj->typedefs, prefix, sizeof(BTF_TYPEDEF) - 1); 485 /* func */ 486 } else if (!strncmp(prefix, BTF_FUNC, sizeof(BTF_FUNC) - 1)) { 487 obj->nr_funcs++; 488 id = add_symbol(&obj->funcs, prefix, sizeof(BTF_FUNC) - 1); 489 /* set8 */ 490 } else if (!strncmp(prefix, BTF_SET8, sizeof(BTF_SET8) - 1)) { 491 id = add_set(obj, prefix, true); 492 /* 493 * SET8 objects store list's count, which is encoded 494 * in symbol's size, together with 'cnt' field hence 495 * that - 1. 496 */ 497 if (id) { 498 id->cnt = sym.st_size / sizeof(uint64_t) - 1; 499 id->is_set8 = true; 500 } 501 /* set */ 502 } else if (!strncmp(prefix, BTF_SET, sizeof(BTF_SET) - 1)) { 503 id = add_set(obj, prefix, false); 504 /* 505 * SET objects store list's count, which is encoded 506 * in symbol's size, together with 'cnt' field hence 507 * that - 1. 508 */ 509 if (id) { 510 id->cnt = sym.st_size / sizeof(int) - 1; 511 id->is_set = true; 512 } 513 } else { 514 pr_err("FAILED unsupported prefix %s\n", prefix); 515 return -1; 516 } 517 518 if (!id) 519 return -ENOMEM; 520 521 if (id->addr_cnt >= ADDR_CNT) { 522 pr_err("FAILED symbol %s crossed the number of allowed lists\n", 523 id->name); 524 return -1; 525 } 526 id->addr[id->addr_cnt++] = sym.st_value; 527 } 528 529 return 0; 530 } 531 532 static int symbols_resolve(struct object *obj) 533 { 534 int nr_typedefs = obj->nr_typedefs; 535 int nr_structs = obj->nr_structs; 536 int nr_unions = obj->nr_unions; 537 int nr_funcs = obj->nr_funcs; 538 struct btf *base_btf = NULL; 539 int err, type_id; 540 struct btf *btf; 541 __u32 nr_types; 542 543 if (obj->base_btf_path) { 544 base_btf = btf__parse(obj->base_btf_path, NULL); 545 err = libbpf_get_error(base_btf); 546 if (err) { 547 pr_err("FAILED: load base BTF from %s: %s\n", 548 obj->base_btf_path, strerror(-err)); 549 return -1; 550 } 551 } 552 553 btf = btf__parse_split(obj->btf ?: obj->path, base_btf); 554 err = libbpf_get_error(btf); 555 if (err) { 556 pr_err("FAILED: load BTF from %s: %s\n", 557 obj->btf ?: obj->path, strerror(-err)); 558 goto out; 559 } 560 561 err = -1; 562 nr_types = btf__type_cnt(btf); 563 564 /* 565 * Iterate all the BTF types and search for collected symbol IDs. 566 */ 567 for (type_id = 1; type_id < nr_types; type_id++) { 568 const struct btf_type *type; 569 struct rb_root *root; 570 struct btf_id *id; 571 const char *str; 572 int *nr; 573 574 type = btf__type_by_id(btf, type_id); 575 if (!type) { 576 pr_err("FAILED: malformed BTF, can't resolve type for ID %d\n", 577 type_id); 578 goto out; 579 } 580 581 if (btf_is_func(type) && nr_funcs) { 582 nr = &nr_funcs; 583 root = &obj->funcs; 584 } else if (btf_is_struct(type) && nr_structs) { 585 nr = &nr_structs; 586 root = &obj->structs; 587 } else if (btf_is_union(type) && nr_unions) { 588 nr = &nr_unions; 589 root = &obj->unions; 590 } else if (btf_is_typedef(type) && nr_typedefs) { 591 nr = &nr_typedefs; 592 root = &obj->typedefs; 593 } else 594 continue; 595 596 str = btf__name_by_offset(btf, type->name_off); 597 if (!str) { 598 pr_err("FAILED: malformed BTF, can't resolve name for ID %d\n", 599 type_id); 600 goto out; 601 } 602 603 id = btf_id__find(root, str); 604 if (id) { 605 if (id->id) { 606 pr_info("WARN: multiple IDs found for '%s': %d, %d - using %d\n", 607 str, id->id, type_id, id->id); 608 warnings++; 609 } else { 610 id->id = type_id; 611 (*nr)--; 612 } 613 } 614 } 615 616 err = 0; 617 out: 618 btf__free(base_btf); 619 btf__free(btf); 620 return err; 621 } 622 623 static int id_patch(struct object *obj, struct btf_id *id) 624 { 625 Elf_Data *data = obj->efile.idlist; 626 int *ptr = data->d_buf; 627 int i; 628 629 /* For set, set8, id->id may be 0 */ 630 if (!id->id && !id->is_set && !id->is_set8) { 631 pr_err("WARN: resolve_btfids: unresolved symbol %s\n", id->name); 632 warnings++; 633 } 634 635 for (i = 0; i < id->addr_cnt; i++) { 636 unsigned long addr = id->addr[i]; 637 unsigned long idx = addr - obj->efile.idlist_addr; 638 639 pr_debug("patching addr %5lu: ID %7d [%s]\n", 640 idx, id->id, id->name); 641 642 if (idx >= data->d_size) { 643 pr_err("FAILED patching index %lu out of bounds %lu\n", 644 idx, data->d_size); 645 return -1; 646 } 647 648 idx = idx / sizeof(int); 649 ptr[idx] = id->id; 650 } 651 652 return 0; 653 } 654 655 static int __symbols_patch(struct object *obj, struct rb_root *root) 656 { 657 struct rb_node *next; 658 struct btf_id *id; 659 660 next = rb_first(root); 661 while (next) { 662 id = rb_entry(next, struct btf_id, rb_node); 663 664 if (id_patch(obj, id)) 665 return -1; 666 667 next = rb_next(next); 668 } 669 return 0; 670 } 671 672 static int cmp_id(const void *pa, const void *pb) 673 { 674 const int *a = pa, *b = pb; 675 676 return *a - *b; 677 } 678 679 static int sets_patch(struct object *obj) 680 { 681 Elf_Data *data = obj->efile.idlist; 682 struct rb_node *next; 683 684 next = rb_first(&obj->sets); 685 while (next) { 686 struct btf_id_set8 *set8 = NULL; 687 struct btf_id_set *set = NULL; 688 unsigned long addr, off; 689 struct btf_id *id; 690 691 id = rb_entry(next, struct btf_id, rb_node); 692 addr = id->addr[0]; 693 off = addr - obj->efile.idlist_addr; 694 695 /* sets are unique */ 696 if (id->addr_cnt != 1) { 697 pr_err("FAILED malformed data for set '%s'\n", 698 id->name); 699 return -1; 700 } 701 702 if (id->is_set) { 703 set = data->d_buf + off; 704 qsort(set->ids, set->cnt, sizeof(set->ids[0]), cmp_id); 705 } else { 706 set8 = data->d_buf + off; 707 /* 708 * Make sure id is at the beginning of the pairs 709 * struct, otherwise the below qsort would not work. 710 */ 711 BUILD_BUG_ON((u32 *)set8->pairs != &set8->pairs[0].id); 712 qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); 713 714 /* 715 * When ELF endianness does not match endianness of the 716 * host, libelf will do the translation when updating 717 * the ELF. This, however, corrupts SET8 flags which are 718 * already in the target endianness. So, let's bswap 719 * them to the host endianness and libelf will then 720 * correctly translate everything. 721 */ 722 if (obj->efile.encoding != ELFDATANATIVE) { 723 int i; 724 725 set8->flags = bswap_32(set8->flags); 726 for (i = 0; i < set8->cnt; i++) { 727 set8->pairs[i].flags = 728 bswap_32(set8->pairs[i].flags); 729 } 730 } 731 } 732 733 pr_debug("sorting addr %5lu: cnt %6d [%s]\n", 734 off, id->is_set ? set->cnt : set8->cnt, id->name); 735 736 next = rb_next(next); 737 } 738 return 0; 739 } 740 741 static int symbols_patch(struct object *obj) 742 { 743 off_t err; 744 745 if (__symbols_patch(obj, &obj->structs) || 746 __symbols_patch(obj, &obj->unions) || 747 __symbols_patch(obj, &obj->typedefs) || 748 __symbols_patch(obj, &obj->funcs) || 749 __symbols_patch(obj, &obj->sets)) 750 return -1; 751 752 if (sets_patch(obj)) 753 return -1; 754 755 /* Set type to ensure endian translation occurs. */ 756 obj->efile.idlist->d_type = ELF_T_WORD; 757 758 elf_flagdata(obj->efile.idlist, ELF_C_SET, ELF_F_DIRTY); 759 760 err = elf_update(obj->efile.elf, ELF_C_WRITE); 761 if (err < 0) { 762 pr_err("FAILED elf_update(WRITE): %s\n", 763 elf_errmsg(-1)); 764 } 765 766 pr_debug("update %s for %s\n", 767 err >= 0 ? "ok" : "failed", obj->path); 768 return err < 0 ? -1 : 0; 769 } 770 771 static const char * const resolve_btfids_usage[] = { 772 "resolve_btfids [<options>] <ELF object>", 773 NULL 774 }; 775 776 int main(int argc, const char **argv) 777 { 778 struct object obj = { 779 .efile = { 780 .idlist_shndx = -1, 781 .symbols_shndx = -1, 782 }, 783 .structs = RB_ROOT, 784 .unions = RB_ROOT, 785 .typedefs = RB_ROOT, 786 .funcs = RB_ROOT, 787 .sets = RB_ROOT, 788 }; 789 bool fatal_warnings = false; 790 struct option btfid_options[] = { 791 OPT_INCR('v', "verbose", &verbose, 792 "be more verbose (show errors, etc)"), 793 OPT_STRING(0, "btf", &obj.btf, "BTF data", 794 "BTF data"), 795 OPT_STRING('b', "btf_base", &obj.base_btf_path, "file", 796 "path of file providing base BTF"), 797 OPT_BOOLEAN(0, "fatal_warnings", &fatal_warnings, 798 "turn warnings into errors"), 799 OPT_END() 800 }; 801 int err = -1; 802 803 argc = parse_options(argc, argv, btfid_options, resolve_btfids_usage, 804 PARSE_OPT_STOP_AT_NON_OPTION); 805 if (argc != 1) 806 usage_with_options(resolve_btfids_usage, btfid_options); 807 808 obj.path = argv[0]; 809 810 if (elf_collect(&obj)) 811 goto out; 812 813 /* 814 * We did not find .BTF_ids section or symbols section, 815 * nothing to do.. 816 */ 817 if (obj.efile.idlist_shndx == -1 || 818 obj.efile.symbols_shndx == -1) { 819 pr_debug("Cannot find .BTF_ids or symbols sections, nothing to do\n"); 820 err = 0; 821 goto out; 822 } 823 824 if (symbols_collect(&obj)) 825 goto out; 826 827 if (symbols_resolve(&obj)) 828 goto out; 829 830 if (symbols_patch(&obj)) 831 goto out; 832 833 if (!(fatal_warnings && warnings)) 834 err = 0; 835 out: 836 if (obj.efile.elf) { 837 elf_end(obj.efile.elf); 838 close(obj.efile.fd); 839 } 840 return err; 841 } 842