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