15c742725SJiri Olsa // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 25c742725SJiri Olsa 35c742725SJiri Olsa #include <libelf.h> 45c742725SJiri Olsa #include <gelf.h> 55c742725SJiri Olsa #include <fcntl.h> 65c742725SJiri Olsa #include <linux/kernel.h> 75c742725SJiri Olsa 85c742725SJiri Olsa #include "libbpf_internal.h" 95c742725SJiri Olsa #include "str_error.h" 105c742725SJiri Olsa 115c742725SJiri Olsa #define STRERR_BUFSIZE 128 125c742725SJiri Olsa 13f90eb70dSJiri Olsa int elf_open(const char *binary_path, struct elf_fd *elf_fd) 14f90eb70dSJiri Olsa { 15f90eb70dSJiri Olsa char errmsg[STRERR_BUFSIZE]; 16f90eb70dSJiri Olsa int fd, ret; 17f90eb70dSJiri Olsa Elf *elf; 18f90eb70dSJiri Olsa 19f90eb70dSJiri Olsa if (elf_version(EV_CURRENT) == EV_NONE) { 20f90eb70dSJiri Olsa pr_warn("elf: failed to init libelf for %s\n", binary_path); 21f90eb70dSJiri Olsa return -LIBBPF_ERRNO__LIBELF; 22f90eb70dSJiri Olsa } 23f90eb70dSJiri Olsa fd = open(binary_path, O_RDONLY | O_CLOEXEC); 24f90eb70dSJiri Olsa if (fd < 0) { 25f90eb70dSJiri Olsa ret = -errno; 26f90eb70dSJiri Olsa pr_warn("elf: failed to open %s: %s\n", binary_path, 27f90eb70dSJiri Olsa libbpf_strerror_r(ret, errmsg, sizeof(errmsg))); 28f90eb70dSJiri Olsa return ret; 29f90eb70dSJiri Olsa } 30f90eb70dSJiri Olsa elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 31f90eb70dSJiri Olsa if (!elf) { 32f90eb70dSJiri Olsa pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1)); 33f90eb70dSJiri Olsa close(fd); 34f90eb70dSJiri Olsa return -LIBBPF_ERRNO__FORMAT; 35f90eb70dSJiri Olsa } 36f90eb70dSJiri Olsa elf_fd->fd = fd; 37f90eb70dSJiri Olsa elf_fd->elf = elf; 38f90eb70dSJiri Olsa return 0; 39f90eb70dSJiri Olsa } 40f90eb70dSJiri Olsa 41f90eb70dSJiri Olsa void elf_close(struct elf_fd *elf_fd) 42f90eb70dSJiri Olsa { 43f90eb70dSJiri Olsa if (!elf_fd) 44f90eb70dSJiri Olsa return; 45f90eb70dSJiri Olsa elf_end(elf_fd->elf); 46f90eb70dSJiri Olsa close(elf_fd->fd); 47f90eb70dSJiri Olsa } 48f90eb70dSJiri Olsa 495c742725SJiri Olsa /* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */ 505c742725SJiri Olsa static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn) 515c742725SJiri Olsa { 525c742725SJiri Olsa while ((scn = elf_nextscn(elf, scn)) != NULL) { 535c742725SJiri Olsa GElf_Shdr sh; 545c742725SJiri Olsa 555c742725SJiri Olsa if (!gelf_getshdr(scn, &sh)) 565c742725SJiri Olsa continue; 575c742725SJiri Olsa if (sh.sh_type == sh_type) 585c742725SJiri Olsa return scn; 595c742725SJiri Olsa } 605c742725SJiri Olsa return NULL; 615c742725SJiri Olsa } 625c742725SJiri Olsa 633774705dSJiri Olsa struct elf_sym { 643774705dSJiri Olsa const char *name; 653774705dSJiri Olsa GElf_Sym sym; 663774705dSJiri Olsa GElf_Shdr sh; 673774705dSJiri Olsa }; 683774705dSJiri Olsa 693774705dSJiri Olsa struct elf_sym_iter { 703774705dSJiri Olsa Elf *elf; 713774705dSJiri Olsa Elf_Data *syms; 723774705dSJiri Olsa size_t nr_syms; 733774705dSJiri Olsa size_t strtabidx; 743774705dSJiri Olsa size_t next_sym_idx; 753774705dSJiri Olsa struct elf_sym sym; 763774705dSJiri Olsa int st_type; 773774705dSJiri Olsa }; 783774705dSJiri Olsa 793774705dSJiri Olsa static int elf_sym_iter_new(struct elf_sym_iter *iter, 803774705dSJiri Olsa Elf *elf, const char *binary_path, 813774705dSJiri Olsa int sh_type, int st_type) 823774705dSJiri Olsa { 833774705dSJiri Olsa Elf_Scn *scn = NULL; 843774705dSJiri Olsa GElf_Ehdr ehdr; 853774705dSJiri Olsa GElf_Shdr sh; 863774705dSJiri Olsa 873774705dSJiri Olsa memset(iter, 0, sizeof(*iter)); 883774705dSJiri Olsa 893774705dSJiri Olsa if (!gelf_getehdr(elf, &ehdr)) { 903774705dSJiri Olsa pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1)); 913774705dSJiri Olsa return -EINVAL; 923774705dSJiri Olsa } 933774705dSJiri Olsa 943774705dSJiri Olsa scn = elf_find_next_scn_by_type(elf, sh_type, NULL); 953774705dSJiri Olsa if (!scn) { 963774705dSJiri Olsa pr_debug("elf: failed to find symbol table ELF sections in '%s'\n", 973774705dSJiri Olsa binary_path); 983774705dSJiri Olsa return -ENOENT; 993774705dSJiri Olsa } 1003774705dSJiri Olsa 1013774705dSJiri Olsa if (!gelf_getshdr(scn, &sh)) 1023774705dSJiri Olsa return -EINVAL; 1033774705dSJiri Olsa 1043774705dSJiri Olsa iter->strtabidx = sh.sh_link; 1053774705dSJiri Olsa iter->syms = elf_getdata(scn, 0); 1063774705dSJiri Olsa if (!iter->syms) { 1073774705dSJiri Olsa pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n", 1083774705dSJiri Olsa binary_path, elf_errmsg(-1)); 1093774705dSJiri Olsa return -EINVAL; 1103774705dSJiri Olsa } 1113774705dSJiri Olsa iter->nr_syms = iter->syms->d_size / sh.sh_entsize; 1123774705dSJiri Olsa iter->elf = elf; 1133774705dSJiri Olsa iter->st_type = st_type; 1143774705dSJiri Olsa return 0; 1153774705dSJiri Olsa } 1163774705dSJiri Olsa 1173774705dSJiri Olsa static struct elf_sym *elf_sym_iter_next(struct elf_sym_iter *iter) 1183774705dSJiri Olsa { 1193774705dSJiri Olsa struct elf_sym *ret = &iter->sym; 1203774705dSJiri Olsa GElf_Sym *sym = &ret->sym; 1213774705dSJiri Olsa const char *name = NULL; 1223774705dSJiri Olsa Elf_Scn *sym_scn; 1233774705dSJiri Olsa size_t idx; 1243774705dSJiri Olsa 1253774705dSJiri Olsa for (idx = iter->next_sym_idx; idx < iter->nr_syms; idx++) { 1263774705dSJiri Olsa if (!gelf_getsym(iter->syms, idx, sym)) 1273774705dSJiri Olsa continue; 1283774705dSJiri Olsa if (GELF_ST_TYPE(sym->st_info) != iter->st_type) 1293774705dSJiri Olsa continue; 1303774705dSJiri Olsa name = elf_strptr(iter->elf, iter->strtabidx, sym->st_name); 1313774705dSJiri Olsa if (!name) 1323774705dSJiri Olsa continue; 1333774705dSJiri Olsa sym_scn = elf_getscn(iter->elf, sym->st_shndx); 1343774705dSJiri Olsa if (!sym_scn) 1353774705dSJiri Olsa continue; 1363774705dSJiri Olsa if (!gelf_getshdr(sym_scn, &ret->sh)) 1373774705dSJiri Olsa continue; 1383774705dSJiri Olsa 1393774705dSJiri Olsa iter->next_sym_idx = idx + 1; 1403774705dSJiri Olsa ret->name = name; 1413774705dSJiri Olsa return ret; 1423774705dSJiri Olsa } 1433774705dSJiri Olsa 1443774705dSJiri Olsa return NULL; 1453774705dSJiri Olsa } 1463774705dSJiri Olsa 1473774705dSJiri Olsa 1483774705dSJiri Olsa /* Transform symbol's virtual address (absolute for binaries and relative 1493774705dSJiri Olsa * for shared libs) into file offset, which is what kernel is expecting 1503774705dSJiri Olsa * for uprobe/uretprobe attachment. 1513774705dSJiri Olsa * See Documentation/trace/uprobetracer.rst for more details. This is done 1523774705dSJiri Olsa * by looking up symbol's containing section's header and using iter's virtual 1533774705dSJiri Olsa * address (sh_addr) and corresponding file offset (sh_offset) to transform 1543774705dSJiri Olsa * sym.st_value (virtual address) into desired final file offset. 1553774705dSJiri Olsa */ 1563774705dSJiri Olsa static unsigned long elf_sym_offset(struct elf_sym *sym) 1573774705dSJiri Olsa { 1583774705dSJiri Olsa return sym->sym.st_value - sym->sh.sh_addr + sym->sh.sh_offset; 1593774705dSJiri Olsa } 1603774705dSJiri Olsa 1615c742725SJiri Olsa /* Find offset of function name in the provided ELF object. "binary_path" is 1625c742725SJiri Olsa * the path to the ELF binary represented by "elf", and only used for error 1635c742725SJiri Olsa * reporting matters. "name" matches symbol name or name@@LIB for library 1645c742725SJiri Olsa * functions. 1655c742725SJiri Olsa */ 1665c742725SJiri Olsa long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name) 1675c742725SJiri Olsa { 1685c742725SJiri Olsa int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; 1695c742725SJiri Olsa bool is_shared_lib, is_name_qualified; 1705c742725SJiri Olsa long ret = -ENOENT; 1715c742725SJiri Olsa size_t name_len; 1725c742725SJiri Olsa GElf_Ehdr ehdr; 1735c742725SJiri Olsa 1745c742725SJiri Olsa if (!gelf_getehdr(elf, &ehdr)) { 1755c742725SJiri Olsa pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1)); 1765c742725SJiri Olsa ret = -LIBBPF_ERRNO__FORMAT; 1775c742725SJiri Olsa goto out; 1785c742725SJiri Olsa } 1795c742725SJiri Olsa /* for shared lib case, we do not need to calculate relative offset */ 1805c742725SJiri Olsa is_shared_lib = ehdr.e_type == ET_DYN; 1815c742725SJiri Olsa 1825c742725SJiri Olsa name_len = strlen(name); 1835c742725SJiri Olsa /* Does name specify "@@LIB"? */ 1845c742725SJiri Olsa is_name_qualified = strstr(name, "@@") != NULL; 1855c742725SJiri Olsa 1865c742725SJiri Olsa /* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if 1875c742725SJiri Olsa * a binary is stripped, it may only have SHT_DYNSYM, and a fully-statically 1885c742725SJiri Olsa * linked binary may not have SHT_DYMSYM, so absence of a section should not be 1895c742725SJiri Olsa * reported as a warning/error. 1905c742725SJiri Olsa */ 1915c742725SJiri Olsa for (i = 0; i < ARRAY_SIZE(sh_types); i++) { 1923774705dSJiri Olsa struct elf_sym_iter iter; 1933774705dSJiri Olsa struct elf_sym *sym; 1945c742725SJiri Olsa int last_bind = -1; 1953774705dSJiri Olsa int cur_bind; 1965c742725SJiri Olsa 1973774705dSJiri Olsa ret = elf_sym_iter_new(&iter, elf, binary_path, sh_types[i], STT_FUNC); 1983774705dSJiri Olsa if (ret == -ENOENT) 1995c742725SJiri Olsa continue; 2003774705dSJiri Olsa if (ret) 2015c742725SJiri Olsa goto out; 2025c742725SJiri Olsa 2033774705dSJiri Olsa while ((sym = elf_sym_iter_next(&iter))) { 2045c742725SJiri Olsa /* User can specify func, func@@LIB or func@@LIB_VERSION. */ 2053774705dSJiri Olsa if (strncmp(sym->name, name, name_len) != 0) 2065c742725SJiri Olsa continue; 2075c742725SJiri Olsa /* ...but we don't want a search for "foo" to match 'foo2" also, so any 2085c742725SJiri Olsa * additional characters in sname should be of the form "@@LIB". 2095c742725SJiri Olsa */ 2103774705dSJiri Olsa if (!is_name_qualified && sym->name[name_len] != '\0' && sym->name[name_len] != '@') 2115c742725SJiri Olsa continue; 2125c742725SJiri Olsa 2133774705dSJiri Olsa cur_bind = GELF_ST_BIND(sym->sym.st_info); 2143774705dSJiri Olsa 2153774705dSJiri Olsa if (ret > 0) { 2165c742725SJiri Olsa /* handle multiple matches */ 2173774705dSJiri Olsa if (last_bind != STB_WEAK && cur_bind != STB_WEAK) { 2185c742725SJiri Olsa /* Only accept one non-weak bind. */ 2195c742725SJiri Olsa pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n", 2203774705dSJiri Olsa sym->name, name, binary_path); 2215c742725SJiri Olsa ret = -LIBBPF_ERRNO__FORMAT; 2225c742725SJiri Olsa goto out; 2233774705dSJiri Olsa } else if (cur_bind == STB_WEAK) { 2245c742725SJiri Olsa /* already have a non-weak bind, and 2255c742725SJiri Olsa * this is a weak bind, so ignore. 2265c742725SJiri Olsa */ 2275c742725SJiri Olsa continue; 2285c742725SJiri Olsa } 2295c742725SJiri Olsa } 2305c742725SJiri Olsa 2313774705dSJiri Olsa ret = elf_sym_offset(sym); 2323774705dSJiri Olsa last_bind = cur_bind; 2335c742725SJiri Olsa } 2345c742725SJiri Olsa if (ret > 0) 2355c742725SJiri Olsa break; 2365c742725SJiri Olsa } 2375c742725SJiri Olsa 2385c742725SJiri Olsa if (ret > 0) { 2395c742725SJiri Olsa pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path, 2405c742725SJiri Olsa ret); 2415c742725SJiri Olsa } else { 2425c742725SJiri Olsa if (ret == 0) { 2435c742725SJiri Olsa pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path, 2445c742725SJiri Olsa is_shared_lib ? "should not be 0 in a shared library" : 2455c742725SJiri Olsa "try using shared library path instead"); 2465c742725SJiri Olsa ret = -ENOENT; 2475c742725SJiri Olsa } else { 2485c742725SJiri Olsa pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path); 2495c742725SJiri Olsa } 2505c742725SJiri Olsa } 2515c742725SJiri Olsa out: 2525c742725SJiri Olsa return ret; 2535c742725SJiri Olsa } 2545c742725SJiri Olsa 2555c742725SJiri Olsa /* Find offset of function name in ELF object specified by path. "name" matches 2565c742725SJiri Olsa * symbol name or name@@LIB for library functions. 2575c742725SJiri Olsa */ 2585c742725SJiri Olsa long elf_find_func_offset_from_file(const char *binary_path, const char *name) 2595c742725SJiri Olsa { 260f90eb70dSJiri Olsa struct elf_fd elf_fd; 2615c742725SJiri Olsa long ret = -ENOENT; 2625c742725SJiri Olsa 263f90eb70dSJiri Olsa ret = elf_open(binary_path, &elf_fd); 264f90eb70dSJiri Olsa if (ret) 265f90eb70dSJiri Olsa return ret; 266f90eb70dSJiri Olsa ret = elf_find_func_offset(elf_fd.elf, binary_path, name); 267f90eb70dSJiri Olsa elf_close(&elf_fd); 2685c742725SJiri Olsa return ret; 2695c742725SJiri Olsa } 2707ace84c6SJiri Olsa 2717ace84c6SJiri Olsa struct symbol { 2727ace84c6SJiri Olsa const char *name; 2737ace84c6SJiri Olsa int bind; 2747ace84c6SJiri Olsa int idx; 2757ace84c6SJiri Olsa }; 2767ace84c6SJiri Olsa 2777ace84c6SJiri Olsa static int symbol_cmp(const void *a, const void *b) 2787ace84c6SJiri Olsa { 2797ace84c6SJiri Olsa const struct symbol *sym_a = a; 2807ace84c6SJiri Olsa const struct symbol *sym_b = b; 2817ace84c6SJiri Olsa 2827ace84c6SJiri Olsa return strcmp(sym_a->name, sym_b->name); 2837ace84c6SJiri Olsa } 2847ace84c6SJiri Olsa 2857ace84c6SJiri Olsa /* 2867ace84c6SJiri Olsa * Return offsets in @poffsets for symbols specified in @syms array argument. 2877ace84c6SJiri Olsa * On success returns 0 and offsets are returned in allocated array with @cnt 2887ace84c6SJiri Olsa * size, that needs to be released by the caller. 2897ace84c6SJiri Olsa */ 2907ace84c6SJiri Olsa int elf_resolve_syms_offsets(const char *binary_path, int cnt, 2917ace84c6SJiri Olsa const char **syms, unsigned long **poffsets) 2927ace84c6SJiri Olsa { 2937ace84c6SJiri Olsa int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; 2947ace84c6SJiri Olsa int err = 0, i, cnt_done = 0; 2957ace84c6SJiri Olsa unsigned long *offsets; 2967ace84c6SJiri Olsa struct symbol *symbols; 2977ace84c6SJiri Olsa struct elf_fd elf_fd; 2987ace84c6SJiri Olsa 2997ace84c6SJiri Olsa err = elf_open(binary_path, &elf_fd); 3007ace84c6SJiri Olsa if (err) 3017ace84c6SJiri Olsa return err; 3027ace84c6SJiri Olsa 3037ace84c6SJiri Olsa offsets = calloc(cnt, sizeof(*offsets)); 3047ace84c6SJiri Olsa symbols = calloc(cnt, sizeof(*symbols)); 3057ace84c6SJiri Olsa 3067ace84c6SJiri Olsa if (!offsets || !symbols) { 3077ace84c6SJiri Olsa err = -ENOMEM; 3087ace84c6SJiri Olsa goto out; 3097ace84c6SJiri Olsa } 3107ace84c6SJiri Olsa 3117ace84c6SJiri Olsa for (i = 0; i < cnt; i++) { 3127ace84c6SJiri Olsa symbols[i].name = syms[i]; 3137ace84c6SJiri Olsa symbols[i].idx = i; 3147ace84c6SJiri Olsa } 3157ace84c6SJiri Olsa 3167ace84c6SJiri Olsa qsort(symbols, cnt, sizeof(*symbols), symbol_cmp); 3177ace84c6SJiri Olsa 3187ace84c6SJiri Olsa for (i = 0; i < ARRAY_SIZE(sh_types); i++) { 3197ace84c6SJiri Olsa struct elf_sym_iter iter; 3207ace84c6SJiri Olsa struct elf_sym *sym; 3217ace84c6SJiri Olsa 3227ace84c6SJiri Olsa err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC); 3237ace84c6SJiri Olsa if (err == -ENOENT) 3247ace84c6SJiri Olsa continue; 3257ace84c6SJiri Olsa if (err) 3267ace84c6SJiri Olsa goto out; 3277ace84c6SJiri Olsa 3287ace84c6SJiri Olsa while ((sym = elf_sym_iter_next(&iter))) { 3297ace84c6SJiri Olsa unsigned long sym_offset = elf_sym_offset(sym); 3307ace84c6SJiri Olsa int bind = GELF_ST_BIND(sym->sym.st_info); 3317ace84c6SJiri Olsa struct symbol *found, tmp = { 3327ace84c6SJiri Olsa .name = sym->name, 3337ace84c6SJiri Olsa }; 3347ace84c6SJiri Olsa unsigned long *offset; 3357ace84c6SJiri Olsa 3367ace84c6SJiri Olsa found = bsearch(&tmp, symbols, cnt, sizeof(*symbols), symbol_cmp); 3377ace84c6SJiri Olsa if (!found) 3387ace84c6SJiri Olsa continue; 3397ace84c6SJiri Olsa 3407ace84c6SJiri Olsa offset = &offsets[found->idx]; 3417ace84c6SJiri Olsa if (*offset > 0) { 3427ace84c6SJiri Olsa /* same offset, no problem */ 3437ace84c6SJiri Olsa if (*offset == sym_offset) 3447ace84c6SJiri Olsa continue; 3457ace84c6SJiri Olsa /* handle multiple matches */ 3467ace84c6SJiri Olsa if (found->bind != STB_WEAK && bind != STB_WEAK) { 3477ace84c6SJiri Olsa /* Only accept one non-weak bind. */ 3487ace84c6SJiri Olsa pr_warn("elf: ambiguous match found '%s@%lu' in '%s' previous offset %lu\n", 3497ace84c6SJiri Olsa sym->name, sym_offset, binary_path, *offset); 3507ace84c6SJiri Olsa err = -ESRCH; 3517ace84c6SJiri Olsa goto out; 3527ace84c6SJiri Olsa } else if (bind == STB_WEAK) { 3537ace84c6SJiri Olsa /* already have a non-weak bind, and 3547ace84c6SJiri Olsa * this is a weak bind, so ignore. 3557ace84c6SJiri Olsa */ 3567ace84c6SJiri Olsa continue; 3577ace84c6SJiri Olsa } 3587ace84c6SJiri Olsa } else { 3597ace84c6SJiri Olsa cnt_done++; 3607ace84c6SJiri Olsa } 3617ace84c6SJiri Olsa *offset = sym_offset; 3627ace84c6SJiri Olsa found->bind = bind; 3637ace84c6SJiri Olsa } 3647ace84c6SJiri Olsa } 3657ace84c6SJiri Olsa 3667ace84c6SJiri Olsa if (cnt != cnt_done) { 3677ace84c6SJiri Olsa err = -ENOENT; 3687ace84c6SJiri Olsa goto out; 3697ace84c6SJiri Olsa } 3707ace84c6SJiri Olsa 3717ace84c6SJiri Olsa *poffsets = offsets; 3727ace84c6SJiri Olsa 3737ace84c6SJiri Olsa out: 3747ace84c6SJiri Olsa free(symbols); 3757ace84c6SJiri Olsa if (err) 3767ace84c6SJiri Olsa free(offsets); 3777ace84c6SJiri Olsa elf_close(&elf_fd); 3787ace84c6SJiri Olsa return err; 3797ace84c6SJiri Olsa } 380*e613d1d0SJiri Olsa 381*e613d1d0SJiri Olsa /* 382*e613d1d0SJiri Olsa * Return offsets in @poffsets for symbols specified by @pattern argument. 383*e613d1d0SJiri Olsa * On success returns 0 and offsets are returned in allocated @poffsets 384*e613d1d0SJiri Olsa * array with the @pctn size, that needs to be released by the caller. 385*e613d1d0SJiri Olsa */ 386*e613d1d0SJiri Olsa int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern, 387*e613d1d0SJiri Olsa unsigned long **poffsets, size_t *pcnt) 388*e613d1d0SJiri Olsa { 389*e613d1d0SJiri Olsa int sh_types[2] = { SHT_SYMTAB, SHT_DYNSYM }; 390*e613d1d0SJiri Olsa unsigned long *offsets = NULL; 391*e613d1d0SJiri Olsa size_t cap = 0, cnt = 0; 392*e613d1d0SJiri Olsa struct elf_fd elf_fd; 393*e613d1d0SJiri Olsa int err = 0, i; 394*e613d1d0SJiri Olsa 395*e613d1d0SJiri Olsa err = elf_open(binary_path, &elf_fd); 396*e613d1d0SJiri Olsa if (err) 397*e613d1d0SJiri Olsa return err; 398*e613d1d0SJiri Olsa 399*e613d1d0SJiri Olsa for (i = 0; i < ARRAY_SIZE(sh_types); i++) { 400*e613d1d0SJiri Olsa struct elf_sym_iter iter; 401*e613d1d0SJiri Olsa struct elf_sym *sym; 402*e613d1d0SJiri Olsa 403*e613d1d0SJiri Olsa err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC); 404*e613d1d0SJiri Olsa if (err == -ENOENT) 405*e613d1d0SJiri Olsa continue; 406*e613d1d0SJiri Olsa if (err) 407*e613d1d0SJiri Olsa goto out; 408*e613d1d0SJiri Olsa 409*e613d1d0SJiri Olsa while ((sym = elf_sym_iter_next(&iter))) { 410*e613d1d0SJiri Olsa if (!glob_match(sym->name, pattern)) 411*e613d1d0SJiri Olsa continue; 412*e613d1d0SJiri Olsa 413*e613d1d0SJiri Olsa err = libbpf_ensure_mem((void **) &offsets, &cap, sizeof(*offsets), 414*e613d1d0SJiri Olsa cnt + 1); 415*e613d1d0SJiri Olsa if (err) 416*e613d1d0SJiri Olsa goto out; 417*e613d1d0SJiri Olsa 418*e613d1d0SJiri Olsa offsets[cnt++] = elf_sym_offset(sym); 419*e613d1d0SJiri Olsa } 420*e613d1d0SJiri Olsa 421*e613d1d0SJiri Olsa /* If we found anything in the first symbol section, 422*e613d1d0SJiri Olsa * do not search others to avoid duplicates. 423*e613d1d0SJiri Olsa */ 424*e613d1d0SJiri Olsa if (cnt) 425*e613d1d0SJiri Olsa break; 426*e613d1d0SJiri Olsa } 427*e613d1d0SJiri Olsa 428*e613d1d0SJiri Olsa if (cnt) { 429*e613d1d0SJiri Olsa *poffsets = offsets; 430*e613d1d0SJiri Olsa *pcnt = cnt; 431*e613d1d0SJiri Olsa } else { 432*e613d1d0SJiri Olsa err = -ENOENT; 433*e613d1d0SJiri Olsa } 434*e613d1d0SJiri Olsa 435*e613d1d0SJiri Olsa out: 436*e613d1d0SJiri Olsa if (err) 437*e613d1d0SJiri Olsa free(offsets); 438*e613d1d0SJiri Olsa elf_close(&elf_fd); 439*e613d1d0SJiri Olsa return err; 440*e613d1d0SJiri Olsa } 441