0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 #define _GNU_SOURCE
0064 #include <stdio.h>
0065 #include <string.h>
0066 #include <unistd.h>
0067 #include <stdlib.h>
0068 #include <libelf.h>
0069 #include <gelf.h>
0070 #include <sys/stat.h>
0071 #include <fcntl.h>
0072 #include <errno.h>
0073 #include <linux/rbtree.h>
0074 #include <linux/zalloc.h>
0075 #include <linux/err.h>
0076 #include <bpf/btf.h>
0077 #include <bpf/libbpf.h>
0078 #include <parse-options.h>
0079
0080 #define BTF_IDS_SECTION ".BTF_ids"
0081 #define BTF_ID "__BTF_ID__"
0082
0083 #define BTF_STRUCT "struct"
0084 #define BTF_UNION "union"
0085 #define BTF_TYPEDEF "typedef"
0086 #define BTF_FUNC "func"
0087 #define BTF_SET "set"
0088 #define BTF_SET8 "set8"
0089
0090 #define ADDR_CNT 100
0091
0092 struct btf_id {
0093 struct rb_node rb_node;
0094 char *name;
0095 union {
0096 int id;
0097 int cnt;
0098 };
0099 int addr_cnt;
0100 bool is_set;
0101 bool is_set8;
0102 Elf64_Addr addr[ADDR_CNT];
0103 };
0104
0105 struct object {
0106 const char *path;
0107 const char *btf;
0108 const char *base_btf_path;
0109
0110 struct {
0111 int fd;
0112 Elf *elf;
0113 Elf_Data *symbols;
0114 Elf_Data *idlist;
0115 int symbols_shndx;
0116 int idlist_shndx;
0117 size_t strtabidx;
0118 unsigned long idlist_addr;
0119 } efile;
0120
0121 struct rb_root sets;
0122 struct rb_root structs;
0123 struct rb_root unions;
0124 struct rb_root typedefs;
0125 struct rb_root funcs;
0126
0127 int nr_funcs;
0128 int nr_structs;
0129 int nr_unions;
0130 int nr_typedefs;
0131 };
0132
0133 static int verbose;
0134
0135 static int eprintf(int level, int var, const char *fmt, ...)
0136 {
0137 va_list args;
0138 int ret = 0;
0139
0140 if (var >= level) {
0141 va_start(args, fmt);
0142 ret = vfprintf(stderr, fmt, args);
0143 va_end(args);
0144 }
0145 return ret;
0146 }
0147
0148 #ifndef pr_fmt
0149 #define pr_fmt(fmt) fmt
0150 #endif
0151
0152 #define pr_debug(fmt, ...) \
0153 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
0154 #define pr_debugN(n, fmt, ...) \
0155 eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__)
0156 #define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
0157 #define pr_err(fmt, ...) \
0158 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
0159 #define pr_info(fmt, ...) \
0160 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
0161
0162 static bool is_btf_id(const char *name)
0163 {
0164 return name && !strncmp(name, BTF_ID, sizeof(BTF_ID) - 1);
0165 }
0166
0167 static struct btf_id *btf_id__find(struct rb_root *root, const char *name)
0168 {
0169 struct rb_node *p = root->rb_node;
0170 struct btf_id *id;
0171 int cmp;
0172
0173 while (p) {
0174 id = rb_entry(p, struct btf_id, rb_node);
0175 cmp = strcmp(id->name, name);
0176 if (cmp < 0)
0177 p = p->rb_left;
0178 else if (cmp > 0)
0179 p = p->rb_right;
0180 else
0181 return id;
0182 }
0183 return NULL;
0184 }
0185
0186 static struct btf_id *
0187 btf_id__add(struct rb_root *root, char *name, bool unique)
0188 {
0189 struct rb_node **p = &root->rb_node;
0190 struct rb_node *parent = NULL;
0191 struct btf_id *id;
0192 int cmp;
0193
0194 while (*p != NULL) {
0195 parent = *p;
0196 id = rb_entry(parent, struct btf_id, rb_node);
0197 cmp = strcmp(id->name, name);
0198 if (cmp < 0)
0199 p = &(*p)->rb_left;
0200 else if (cmp > 0)
0201 p = &(*p)->rb_right;
0202 else
0203 return unique ? NULL : id;
0204 }
0205
0206 id = zalloc(sizeof(*id));
0207 if (id) {
0208 pr_debug("adding symbol %s\n", name);
0209 id->name = name;
0210 rb_link_node(&id->rb_node, parent, p);
0211 rb_insert_color(&id->rb_node, root);
0212 }
0213 return id;
0214 }
0215
0216 static char *get_id(const char *prefix_end)
0217 {
0218
0219
0220
0221
0222
0223 int len = strlen(prefix_end);
0224 int pos = sizeof("__") - 1;
0225 char *p, *id;
0226
0227 if (pos >= len)
0228 return NULL;
0229
0230 id = strdup(prefix_end + pos);
0231 if (id) {
0232
0233
0234
0235
0236
0237
0238 p = strrchr(id, '_');
0239 p--;
0240 if (*p != '_') {
0241 free(id);
0242 return NULL;
0243 }
0244 *p = '\0';
0245 }
0246 return id;
0247 }
0248
0249 static struct btf_id *add_set(struct object *obj, char *name, bool is_set8)
0250 {
0251
0252
0253
0254
0255
0256 char *id = name + (is_set8 ? sizeof(BTF_SET8 "__") : sizeof(BTF_SET "__")) - 1;
0257 int len = strlen(name);
0258
0259 if (id >= name + len) {
0260 pr_err("FAILED to parse set name: %s\n", name);
0261 return NULL;
0262 }
0263
0264 return btf_id__add(&obj->sets, id, true);
0265 }
0266
0267 static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
0268 {
0269 char *id;
0270
0271 id = get_id(name + size);
0272 if (!id) {
0273 pr_err("FAILED to parse symbol name: %s\n", name);
0274 return NULL;
0275 }
0276
0277 return btf_id__add(root, id, false);
0278 }
0279
0280
0281 #ifndef SHF_COMPRESSED
0282 #define SHF_COMPRESSED (1 << 11)
0283 #endif
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295 static int compressed_section_fix(Elf *elf, Elf_Scn *scn, GElf_Shdr *sh)
0296 {
0297 int expected = gelf_getclass(elf) == ELFCLASS32 ? 4 : 8;
0298
0299 if (!(sh->sh_flags & SHF_COMPRESSED))
0300 return 0;
0301
0302 if (sh->sh_addralign == expected)
0303 return 0;
0304
0305 pr_debug2(" - fixing wrong alignment sh_addralign %u, expected %u\n",
0306 sh->sh_addralign, expected);
0307
0308 sh->sh_addralign = expected;
0309
0310 if (gelf_update_shdr(scn, sh) == 0) {
0311 pr_err("FAILED cannot update section header: %s\n",
0312 elf_errmsg(-1));
0313 return -1;
0314 }
0315 return 0;
0316 }
0317
0318 static int elf_collect(struct object *obj)
0319 {
0320 Elf_Scn *scn = NULL;
0321 size_t shdrstrndx;
0322 int idx = 0;
0323 Elf *elf;
0324 int fd;
0325
0326 fd = open(obj->path, O_RDWR, 0666);
0327 if (fd == -1) {
0328 pr_err("FAILED cannot open %s: %s\n",
0329 obj->path, strerror(errno));
0330 return -1;
0331 }
0332
0333 elf_version(EV_CURRENT);
0334
0335 elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL);
0336 if (!elf) {
0337 close(fd);
0338 pr_err("FAILED cannot create ELF descriptor: %s\n",
0339 elf_errmsg(-1));
0340 return -1;
0341 }
0342
0343 obj->efile.fd = fd;
0344 obj->efile.elf = elf;
0345
0346 elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT);
0347
0348 if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) {
0349 pr_err("FAILED cannot get shdr str ndx\n");
0350 return -1;
0351 }
0352
0353
0354
0355
0356
0357 while ((scn = elf_nextscn(elf, scn)) != NULL) {
0358 Elf_Data *data;
0359 GElf_Shdr sh;
0360 char *name;
0361
0362 idx++;
0363 if (gelf_getshdr(scn, &sh) != &sh) {
0364 pr_err("FAILED get section(%d) header\n", idx);
0365 return -1;
0366 }
0367
0368 name = elf_strptr(elf, shdrstrndx, sh.sh_name);
0369 if (!name) {
0370 pr_err("FAILED get section(%d) name\n", idx);
0371 return -1;
0372 }
0373
0374 data = elf_getdata(scn, 0);
0375 if (!data) {
0376 pr_err("FAILED to get section(%d) data from %s\n",
0377 idx, name);
0378 return -1;
0379 }
0380
0381 pr_debug2("section(%d) %s, size %ld, link %d, flags %lx, type=%d\n",
0382 idx, name, (unsigned long) data->d_size,
0383 (int) sh.sh_link, (unsigned long) sh.sh_flags,
0384 (int) sh.sh_type);
0385
0386 if (sh.sh_type == SHT_SYMTAB) {
0387 obj->efile.symbols = data;
0388 obj->efile.symbols_shndx = idx;
0389 obj->efile.strtabidx = sh.sh_link;
0390 } else if (!strcmp(name, BTF_IDS_SECTION)) {
0391 obj->efile.idlist = data;
0392 obj->efile.idlist_shndx = idx;
0393 obj->efile.idlist_addr = sh.sh_addr;
0394 }
0395
0396 if (compressed_section_fix(elf, scn, &sh))
0397 return -1;
0398 }
0399
0400 return 0;
0401 }
0402
0403 static int symbols_collect(struct object *obj)
0404 {
0405 Elf_Scn *scn = NULL;
0406 int n, i;
0407 GElf_Shdr sh;
0408 char *name;
0409
0410 scn = elf_getscn(obj->efile.elf, obj->efile.symbols_shndx);
0411 if (!scn)
0412 return -1;
0413
0414 if (gelf_getshdr(scn, &sh) != &sh)
0415 return -1;
0416
0417 n = sh.sh_size / sh.sh_entsize;
0418
0419
0420
0421
0422
0423 for (i = 0; i < n; i++) {
0424 char *prefix;
0425 struct btf_id *id;
0426 GElf_Sym sym;
0427
0428 if (!gelf_getsym(obj->efile.symbols, i, &sym))
0429 return -1;
0430
0431 if (sym.st_shndx != obj->efile.idlist_shndx)
0432 continue;
0433
0434 name = elf_strptr(obj->efile.elf, obj->efile.strtabidx,
0435 sym.st_name);
0436
0437 if (!is_btf_id(name))
0438 continue;
0439
0440
0441
0442
0443
0444 prefix = name + sizeof(BTF_ID) - 1;
0445
0446
0447 if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) {
0448 obj->nr_structs++;
0449 id = add_symbol(&obj->structs, prefix, sizeof(BTF_STRUCT) - 1);
0450
0451 } else if (!strncmp(prefix, BTF_UNION, sizeof(BTF_UNION) - 1)) {
0452 obj->nr_unions++;
0453 id = add_symbol(&obj->unions, prefix, sizeof(BTF_UNION) - 1);
0454
0455 } else if (!strncmp(prefix, BTF_TYPEDEF, sizeof(BTF_TYPEDEF) - 1)) {
0456 obj->nr_typedefs++;
0457 id = add_symbol(&obj->typedefs, prefix, sizeof(BTF_TYPEDEF) - 1);
0458
0459 } else if (!strncmp(prefix, BTF_FUNC, sizeof(BTF_FUNC) - 1)) {
0460 obj->nr_funcs++;
0461 id = add_symbol(&obj->funcs, prefix, sizeof(BTF_FUNC) - 1);
0462
0463 } else if (!strncmp(prefix, BTF_SET8, sizeof(BTF_SET8) - 1)) {
0464 id = add_set(obj, prefix, true);
0465
0466
0467
0468
0469
0470 if (id) {
0471 id->cnt = sym.st_size / sizeof(uint64_t) - 1;
0472 id->is_set8 = true;
0473 }
0474
0475 } else if (!strncmp(prefix, BTF_SET, sizeof(BTF_SET) - 1)) {
0476 id = add_set(obj, prefix, false);
0477
0478
0479
0480
0481
0482 if (id) {
0483 id->cnt = sym.st_size / sizeof(int) - 1;
0484 id->is_set = true;
0485 }
0486 } else {
0487 pr_err("FAILED unsupported prefix %s\n", prefix);
0488 return -1;
0489 }
0490
0491 if (!id)
0492 return -ENOMEM;
0493
0494 if (id->addr_cnt >= ADDR_CNT) {
0495 pr_err("FAILED symbol %s crossed the number of allowed lists\n",
0496 id->name);
0497 return -1;
0498 }
0499 id->addr[id->addr_cnt++] = sym.st_value;
0500 }
0501
0502 return 0;
0503 }
0504
0505 static int symbols_resolve(struct object *obj)
0506 {
0507 int nr_typedefs = obj->nr_typedefs;
0508 int nr_structs = obj->nr_structs;
0509 int nr_unions = obj->nr_unions;
0510 int nr_funcs = obj->nr_funcs;
0511 struct btf *base_btf = NULL;
0512 int err, type_id;
0513 struct btf *btf;
0514 __u32 nr_types;
0515
0516 if (obj->base_btf_path) {
0517 base_btf = btf__parse(obj->base_btf_path, NULL);
0518 err = libbpf_get_error(base_btf);
0519 if (err) {
0520 pr_err("FAILED: load base BTF from %s: %s\n",
0521 obj->base_btf_path, strerror(-err));
0522 return -1;
0523 }
0524 }
0525
0526 btf = btf__parse_split(obj->btf ?: obj->path, base_btf);
0527 err = libbpf_get_error(btf);
0528 if (err) {
0529 pr_err("FAILED: load BTF from %s: %s\n",
0530 obj->btf ?: obj->path, strerror(-err));
0531 goto out;
0532 }
0533
0534 err = -1;
0535 nr_types = btf__type_cnt(btf);
0536
0537
0538
0539
0540 for (type_id = 1; type_id < nr_types; type_id++) {
0541 const struct btf_type *type;
0542 struct rb_root *root;
0543 struct btf_id *id;
0544 const char *str;
0545 int *nr;
0546
0547 type = btf__type_by_id(btf, type_id);
0548 if (!type) {
0549 pr_err("FAILED: malformed BTF, can't resolve type for ID %d\n",
0550 type_id);
0551 goto out;
0552 }
0553
0554 if (btf_is_func(type) && nr_funcs) {
0555 nr = &nr_funcs;
0556 root = &obj->funcs;
0557 } else if (btf_is_struct(type) && nr_structs) {
0558 nr = &nr_structs;
0559 root = &obj->structs;
0560 } else if (btf_is_union(type) && nr_unions) {
0561 nr = &nr_unions;
0562 root = &obj->unions;
0563 } else if (btf_is_typedef(type) && nr_typedefs) {
0564 nr = &nr_typedefs;
0565 root = &obj->typedefs;
0566 } else
0567 continue;
0568
0569 str = btf__name_by_offset(btf, type->name_off);
0570 if (!str) {
0571 pr_err("FAILED: malformed BTF, can't resolve name for ID %d\n",
0572 type_id);
0573 goto out;
0574 }
0575
0576 id = btf_id__find(root, str);
0577 if (id) {
0578 if (id->id) {
0579 pr_info("WARN: multiple IDs found for '%s': %d, %d - using %d\n",
0580 str, id->id, type_id, id->id);
0581 } else {
0582 id->id = type_id;
0583 (*nr)--;
0584 }
0585 }
0586 }
0587
0588 err = 0;
0589 out:
0590 btf__free(base_btf);
0591 btf__free(btf);
0592 return err;
0593 }
0594
0595 static int id_patch(struct object *obj, struct btf_id *id)
0596 {
0597 Elf_Data *data = obj->efile.idlist;
0598 int *ptr = data->d_buf;
0599 int i;
0600
0601
0602 if (!id->id && !id->is_set && !id->is_set8)
0603 pr_err("WARN: resolve_btfids: unresolved symbol %s\n", id->name);
0604
0605 for (i = 0; i < id->addr_cnt; i++) {
0606 unsigned long addr = id->addr[i];
0607 unsigned long idx = addr - obj->efile.idlist_addr;
0608
0609 pr_debug("patching addr %5lu: ID %7d [%s]\n",
0610 idx, id->id, id->name);
0611
0612 if (idx >= data->d_size) {
0613 pr_err("FAILED patching index %lu out of bounds %lu\n",
0614 idx, data->d_size);
0615 return -1;
0616 }
0617
0618 idx = idx / sizeof(int);
0619 ptr[idx] = id->id;
0620 }
0621
0622 return 0;
0623 }
0624
0625 static int __symbols_patch(struct object *obj, struct rb_root *root)
0626 {
0627 struct rb_node *next;
0628 struct btf_id *id;
0629
0630 next = rb_first(root);
0631 while (next) {
0632 id = rb_entry(next, struct btf_id, rb_node);
0633
0634 if (id_patch(obj, id))
0635 return -1;
0636
0637 next = rb_next(next);
0638 }
0639 return 0;
0640 }
0641
0642 static int cmp_id(const void *pa, const void *pb)
0643 {
0644 const int *a = pa, *b = pb;
0645
0646 return *a - *b;
0647 }
0648
0649 static int sets_patch(struct object *obj)
0650 {
0651 Elf_Data *data = obj->efile.idlist;
0652 int *ptr = data->d_buf;
0653 struct rb_node *next;
0654
0655 next = rb_first(&obj->sets);
0656 while (next) {
0657 unsigned long addr, idx;
0658 struct btf_id *id;
0659 int *base;
0660 int cnt;
0661
0662 id = rb_entry(next, struct btf_id, rb_node);
0663 addr = id->addr[0];
0664 idx = addr - obj->efile.idlist_addr;
0665
0666
0667 if (id->addr_cnt != 1) {
0668 pr_err("FAILED malformed data for set '%s'\n",
0669 id->name);
0670 return -1;
0671 }
0672
0673 idx = idx / sizeof(int);
0674 base = &ptr[idx] + (id->is_set8 ? 2 : 1);
0675 cnt = ptr[idx];
0676
0677 pr_debug("sorting addr %5lu: cnt %6d [%s]\n",
0678 (idx + 1) * sizeof(int), cnt, id->name);
0679
0680 qsort(base, cnt, id->is_set8 ? sizeof(uint64_t) : sizeof(int), cmp_id);
0681
0682 next = rb_next(next);
0683 }
0684 return 0;
0685 }
0686
0687 static int symbols_patch(struct object *obj)
0688 {
0689 int err;
0690
0691 if (__symbols_patch(obj, &obj->structs) ||
0692 __symbols_patch(obj, &obj->unions) ||
0693 __symbols_patch(obj, &obj->typedefs) ||
0694 __symbols_patch(obj, &obj->funcs) ||
0695 __symbols_patch(obj, &obj->sets))
0696 return -1;
0697
0698 if (sets_patch(obj))
0699 return -1;
0700
0701
0702 obj->efile.idlist->d_type = ELF_T_WORD;
0703
0704 elf_flagdata(obj->efile.idlist, ELF_C_SET, ELF_F_DIRTY);
0705
0706 err = elf_update(obj->efile.elf, ELF_C_WRITE);
0707 if (err < 0) {
0708 pr_err("FAILED elf_update(WRITE): %s\n",
0709 elf_errmsg(-1));
0710 }
0711
0712 pr_debug("update %s for %s\n",
0713 err >= 0 ? "ok" : "failed", obj->path);
0714 return err < 0 ? -1 : 0;
0715 }
0716
0717 static const char * const resolve_btfids_usage[] = {
0718 "resolve_btfids [<options>] <ELF object>",
0719 NULL
0720 };
0721
0722 int main(int argc, const char **argv)
0723 {
0724 struct object obj = {
0725 .efile = {
0726 .idlist_shndx = -1,
0727 .symbols_shndx = -1,
0728 },
0729 .structs = RB_ROOT,
0730 .unions = RB_ROOT,
0731 .typedefs = RB_ROOT,
0732 .funcs = RB_ROOT,
0733 .sets = RB_ROOT,
0734 };
0735 struct option btfid_options[] = {
0736 OPT_INCR('v', "verbose", &verbose,
0737 "be more verbose (show errors, etc)"),
0738 OPT_STRING(0, "btf", &obj.btf, "BTF data",
0739 "BTF data"),
0740 OPT_STRING('b', "btf_base", &obj.base_btf_path, "file",
0741 "path of file providing base BTF"),
0742 OPT_END()
0743 };
0744 int err = -1;
0745
0746 argc = parse_options(argc, argv, btfid_options, resolve_btfids_usage,
0747 PARSE_OPT_STOP_AT_NON_OPTION);
0748 if (argc != 1)
0749 usage_with_options(resolve_btfids_usage, btfid_options);
0750
0751 obj.path = argv[0];
0752
0753 if (elf_collect(&obj))
0754 goto out;
0755
0756
0757
0758
0759
0760 if (obj.efile.idlist_shndx == -1 ||
0761 obj.efile.symbols_shndx == -1) {
0762 pr_debug("Cannot find .BTF_ids or symbols sections, nothing to do\n");
0763 err = 0;
0764 goto out;
0765 }
0766
0767 if (symbols_collect(&obj))
0768 goto out;
0769
0770 if (symbols_resolve(&obj))
0771 goto out;
0772
0773 if (symbols_patch(&obj))
0774 goto out;
0775
0776 err = 0;
0777 out:
0778 if (obj.efile.elf) {
0779 elf_end(obj.efile.elf);
0780 close(obj.efile.fd);
0781 }
0782 return err;
0783 }