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