18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * resolve_btfids scans Elf object for .BTF_ids section and resolves 58c2ecf20Sopenharmony_ci * its symbols with BTF ID values. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Each symbol points to 4 bytes data and is expected to have 88c2ecf20Sopenharmony_ci * following name syntax: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * __BTF_ID__<type>__<symbol>[__<id>] 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * type is: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * func - lookup BTF_KIND_FUNC symbol with <symbol> name 158c2ecf20Sopenharmony_ci * and store its ID into the data: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * __BTF_ID__func__vfs_close__1: 188c2ecf20Sopenharmony_ci * .zero 4 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * struct - lookup BTF_KIND_STRUCT symbol with <symbol> name 218c2ecf20Sopenharmony_ci * and store its ID into the data: 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * __BTF_ID__struct__sk_buff__1: 248c2ecf20Sopenharmony_ci * .zero 4 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * union - lookup BTF_KIND_UNION symbol with <symbol> name 278c2ecf20Sopenharmony_ci * and store its ID into the data: 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * __BTF_ID__union__thread_union__1: 308c2ecf20Sopenharmony_ci * .zero 4 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * typedef - lookup BTF_KIND_TYPEDEF symbol with <symbol> name 338c2ecf20Sopenharmony_ci * and store its ID into the data: 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * __BTF_ID__typedef__pid_t__1: 368c2ecf20Sopenharmony_ci * .zero 4 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * set - store symbol size into first 4 bytes and sort following 398c2ecf20Sopenharmony_ci * ID list 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * __BTF_ID__set__list: 428c2ecf20Sopenharmony_ci * .zero 4 438c2ecf20Sopenharmony_ci * list: 448c2ecf20Sopenharmony_ci * __BTF_ID__func__vfs_getattr__3: 458c2ecf20Sopenharmony_ci * .zero 4 468c2ecf20Sopenharmony_ci * __BTF_ID__func__vfs_fallocate__4: 478c2ecf20Sopenharmony_ci * .zero 4 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define _GNU_SOURCE 518c2ecf20Sopenharmony_ci#include <stdio.h> 528c2ecf20Sopenharmony_ci#include <string.h> 538c2ecf20Sopenharmony_ci#include <unistd.h> 548c2ecf20Sopenharmony_ci#include <stdlib.h> 558c2ecf20Sopenharmony_ci#include <libelf.h> 568c2ecf20Sopenharmony_ci#include <gelf.h> 578c2ecf20Sopenharmony_ci#include <sys/stat.h> 588c2ecf20Sopenharmony_ci#include <fcntl.h> 598c2ecf20Sopenharmony_ci#include <errno.h> 608c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 618c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 628c2ecf20Sopenharmony_ci#include <linux/err.h> 638c2ecf20Sopenharmony_ci#include <btf.h> 648c2ecf20Sopenharmony_ci#include <libbpf.h> 658c2ecf20Sopenharmony_ci#include <parse-options.h> 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define BTF_IDS_SECTION ".BTF_ids" 688c2ecf20Sopenharmony_ci#define BTF_ID "__BTF_ID__" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define BTF_STRUCT "struct" 718c2ecf20Sopenharmony_ci#define BTF_UNION "union" 728c2ecf20Sopenharmony_ci#define BTF_TYPEDEF "typedef" 738c2ecf20Sopenharmony_ci#define BTF_FUNC "func" 748c2ecf20Sopenharmony_ci#define BTF_SET "set" 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define ADDR_CNT 100 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct btf_id { 798c2ecf20Sopenharmony_ci struct rb_node rb_node; 808c2ecf20Sopenharmony_ci char *name; 818c2ecf20Sopenharmony_ci union { 828c2ecf20Sopenharmony_ci int id; 838c2ecf20Sopenharmony_ci int cnt; 848c2ecf20Sopenharmony_ci }; 858c2ecf20Sopenharmony_ci int addr_cnt; 868c2ecf20Sopenharmony_ci Elf64_Addr addr[ADDR_CNT]; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct object { 908c2ecf20Sopenharmony_ci const char *path; 918c2ecf20Sopenharmony_ci const char *btf; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci struct { 948c2ecf20Sopenharmony_ci int fd; 958c2ecf20Sopenharmony_ci Elf *elf; 968c2ecf20Sopenharmony_ci Elf_Data *symbols; 978c2ecf20Sopenharmony_ci Elf_Data *idlist; 988c2ecf20Sopenharmony_ci int symbols_shndx; 998c2ecf20Sopenharmony_ci int idlist_shndx; 1008c2ecf20Sopenharmony_ci size_t strtabidx; 1018c2ecf20Sopenharmony_ci unsigned long idlist_addr; 1028c2ecf20Sopenharmony_ci } efile; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci struct rb_root sets; 1058c2ecf20Sopenharmony_ci struct rb_root structs; 1068c2ecf20Sopenharmony_ci struct rb_root unions; 1078c2ecf20Sopenharmony_ci struct rb_root typedefs; 1088c2ecf20Sopenharmony_ci struct rb_root funcs; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci int nr_funcs; 1118c2ecf20Sopenharmony_ci int nr_structs; 1128c2ecf20Sopenharmony_ci int nr_unions; 1138c2ecf20Sopenharmony_ci int nr_typedefs; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int verbose; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciint eprintf(int level, int var, const char *fmt, ...) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci va_list args; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (var >= level) { 1248c2ecf20Sopenharmony_ci va_start(args, fmt); 1258c2ecf20Sopenharmony_ci ret = vfprintf(stderr, fmt, args); 1268c2ecf20Sopenharmony_ci va_end(args); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#ifndef pr_fmt 1328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) fmt 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define pr_debug(fmt, ...) \ 1368c2ecf20Sopenharmony_ci eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__) 1378c2ecf20Sopenharmony_ci#define pr_debugN(n, fmt, ...) \ 1388c2ecf20Sopenharmony_ci eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__) 1398c2ecf20Sopenharmony_ci#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 1408c2ecf20Sopenharmony_ci#define pr_err(fmt, ...) \ 1418c2ecf20Sopenharmony_ci eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic bool is_btf_id(const char *name) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return name && !strncmp(name, BTF_ID, sizeof(BTF_ID) - 1); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct btf_id *btf_id__find(struct rb_root *root, const char *name) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct rb_node *p = root->rb_node; 1518c2ecf20Sopenharmony_ci struct btf_id *id; 1528c2ecf20Sopenharmony_ci int cmp; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci while (p) { 1558c2ecf20Sopenharmony_ci id = rb_entry(p, struct btf_id, rb_node); 1568c2ecf20Sopenharmony_ci cmp = strcmp(id->name, name); 1578c2ecf20Sopenharmony_ci if (cmp < 0) 1588c2ecf20Sopenharmony_ci p = p->rb_left; 1598c2ecf20Sopenharmony_ci else if (cmp > 0) 1608c2ecf20Sopenharmony_ci p = p->rb_right; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci return id; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci return NULL; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic struct btf_id* 1688c2ecf20Sopenharmony_cibtf_id__add(struct rb_root *root, char *name, bool unique) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct rb_node **p = &root->rb_node; 1718c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 1728c2ecf20Sopenharmony_ci struct btf_id *id; 1738c2ecf20Sopenharmony_ci int cmp; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci while (*p != NULL) { 1768c2ecf20Sopenharmony_ci parent = *p; 1778c2ecf20Sopenharmony_ci id = rb_entry(parent, struct btf_id, rb_node); 1788c2ecf20Sopenharmony_ci cmp = strcmp(id->name, name); 1798c2ecf20Sopenharmony_ci if (cmp < 0) 1808c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 1818c2ecf20Sopenharmony_ci else if (cmp > 0) 1828c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci return unique ? NULL : id; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci id = zalloc(sizeof(*id)); 1888c2ecf20Sopenharmony_ci if (id) { 1898c2ecf20Sopenharmony_ci pr_debug("adding symbol %s\n", name); 1908c2ecf20Sopenharmony_ci id->name = name; 1918c2ecf20Sopenharmony_ci rb_link_node(&id->rb_node, parent, p); 1928c2ecf20Sopenharmony_ci rb_insert_color(&id->rb_node, root); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci return id; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic char *get_id(const char *prefix_end) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci /* 2008c2ecf20Sopenharmony_ci * __BTF_ID__func__vfs_truncate__0 2018c2ecf20Sopenharmony_ci * prefix_end = ^ 2028c2ecf20Sopenharmony_ci * pos = ^ 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci int len = strlen(prefix_end); 2058c2ecf20Sopenharmony_ci int pos = sizeof("__") - 1; 2068c2ecf20Sopenharmony_ci char *p, *id; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (pos >= len) 2098c2ecf20Sopenharmony_ci return NULL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci id = strdup(prefix_end + pos); 2128c2ecf20Sopenharmony_ci if (id) { 2138c2ecf20Sopenharmony_ci /* 2148c2ecf20Sopenharmony_ci * __BTF_ID__func__vfs_truncate__0 2158c2ecf20Sopenharmony_ci * id = ^ 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * cut the unique id part 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci p = strrchr(id, '_'); 2208c2ecf20Sopenharmony_ci p--; 2218c2ecf20Sopenharmony_ci if (*p != '_') { 2228c2ecf20Sopenharmony_ci free(id); 2238c2ecf20Sopenharmony_ci return NULL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci *p = '\0'; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return id; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic struct btf_id *add_set(struct object *obj, char *name) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * __BTF_ID__set__name 2348c2ecf20Sopenharmony_ci * name = ^ 2358c2ecf20Sopenharmony_ci * id = ^ 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci char *id = name + sizeof(BTF_SET "__") - 1; 2388c2ecf20Sopenharmony_ci int len = strlen(name); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (id >= name + len) { 2418c2ecf20Sopenharmony_ci pr_err("FAILED to parse set name: %s\n", name); 2428c2ecf20Sopenharmony_ci return NULL; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return btf_id__add(&obj->sets, id, true); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci char *id; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci id = get_id(name + size); 2538c2ecf20Sopenharmony_ci if (!id) { 2548c2ecf20Sopenharmony_ci pr_err("FAILED to parse symbol name: %s\n", name); 2558c2ecf20Sopenharmony_ci return NULL; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return btf_id__add(root, id, false); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* Older libelf.h and glibc elf.h might not yet define the ELF compression types. */ 2628c2ecf20Sopenharmony_ci#ifndef SHF_COMPRESSED 2638c2ecf20Sopenharmony_ci#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ 2648c2ecf20Sopenharmony_ci#endif 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* 2678c2ecf20Sopenharmony_ci * The data of compressed section should be aligned to 4 2688c2ecf20Sopenharmony_ci * (for 32bit) or 8 (for 64 bit) bytes. The binutils ld 2698c2ecf20Sopenharmony_ci * sets sh_addralign to 1, which makes libelf fail with 2708c2ecf20Sopenharmony_ci * misaligned section error during the update: 2718c2ecf20Sopenharmony_ci * FAILED elf_update(WRITE): invalid section alignment 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * While waiting for ld fix, we fix the compressed sections 2748c2ecf20Sopenharmony_ci * sh_addralign value manualy. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic int compressed_section_fix(Elf *elf, Elf_Scn *scn, GElf_Shdr *sh) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int expected = gelf_getclass(elf) == ELFCLASS32 ? 4 : 8; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (!(sh->sh_flags & SHF_COMPRESSED)) 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (sh->sh_addralign == expected) 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci pr_debug2(" - fixing wrong alignment sh_addralign %u, expected %u\n", 2878c2ecf20Sopenharmony_ci sh->sh_addralign, expected); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci sh->sh_addralign = expected; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (gelf_update_shdr(scn, sh) == 0) { 2928c2ecf20Sopenharmony_ci printf("FAILED cannot update section header: %s\n", 2938c2ecf20Sopenharmony_ci elf_errmsg(-1)); 2948c2ecf20Sopenharmony_ci return -1; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int elf_collect(struct object *obj) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci Elf_Scn *scn = NULL; 3028c2ecf20Sopenharmony_ci size_t shdrstrndx; 3038c2ecf20Sopenharmony_ci int idx = 0; 3048c2ecf20Sopenharmony_ci Elf *elf; 3058c2ecf20Sopenharmony_ci int fd; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci fd = open(obj->path, O_RDWR, 0666); 3088c2ecf20Sopenharmony_ci if (fd == -1) { 3098c2ecf20Sopenharmony_ci pr_err("FAILED cannot open %s: %s\n", 3108c2ecf20Sopenharmony_ci obj->path, strerror(errno)); 3118c2ecf20Sopenharmony_ci return -1; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci elf_version(EV_CURRENT); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci elf = elf_begin(fd, ELF_C_RDWR_MMAP, NULL); 3178c2ecf20Sopenharmony_ci if (!elf) { 3188c2ecf20Sopenharmony_ci pr_err("FAILED cannot create ELF descriptor: %s\n", 3198c2ecf20Sopenharmony_ci elf_errmsg(-1)); 3208c2ecf20Sopenharmony_ci return -1; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci obj->efile.fd = fd; 3248c2ecf20Sopenharmony_ci obj->efile.elf = elf; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) { 3298c2ecf20Sopenharmony_ci pr_err("FAILED cannot get shdr str ndx\n"); 3308c2ecf20Sopenharmony_ci return -1; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Scan all the elf sections and look for save data 3358c2ecf20Sopenharmony_ci * from .BTF_ids section and symbols. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci while ((scn = elf_nextscn(elf, scn)) != NULL) { 3388c2ecf20Sopenharmony_ci Elf_Data *data; 3398c2ecf20Sopenharmony_ci GElf_Shdr sh; 3408c2ecf20Sopenharmony_ci char *name; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci idx++; 3438c2ecf20Sopenharmony_ci if (gelf_getshdr(scn, &sh) != &sh) { 3448c2ecf20Sopenharmony_ci pr_err("FAILED get section(%d) header\n", idx); 3458c2ecf20Sopenharmony_ci return -1; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci name = elf_strptr(elf, shdrstrndx, sh.sh_name); 3498c2ecf20Sopenharmony_ci if (!name) { 3508c2ecf20Sopenharmony_ci pr_err("FAILED get section(%d) name\n", idx); 3518c2ecf20Sopenharmony_ci return -1; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci data = elf_getdata(scn, 0); 3558c2ecf20Sopenharmony_ci if (!data) { 3568c2ecf20Sopenharmony_ci pr_err("FAILED to get section(%d) data from %s\n", 3578c2ecf20Sopenharmony_ci idx, name); 3588c2ecf20Sopenharmony_ci return -1; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci pr_debug2("section(%d) %s, size %ld, link %d, flags %lx, type=%d\n", 3628c2ecf20Sopenharmony_ci idx, name, (unsigned long) data->d_size, 3638c2ecf20Sopenharmony_ci (int) sh.sh_link, (unsigned long) sh.sh_flags, 3648c2ecf20Sopenharmony_ci (int) sh.sh_type); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (sh.sh_type == SHT_SYMTAB) { 3678c2ecf20Sopenharmony_ci obj->efile.symbols = data; 3688c2ecf20Sopenharmony_ci obj->efile.symbols_shndx = idx; 3698c2ecf20Sopenharmony_ci obj->efile.strtabidx = sh.sh_link; 3708c2ecf20Sopenharmony_ci } else if (!strcmp(name, BTF_IDS_SECTION)) { 3718c2ecf20Sopenharmony_ci obj->efile.idlist = data; 3728c2ecf20Sopenharmony_ci obj->efile.idlist_shndx = idx; 3738c2ecf20Sopenharmony_ci obj->efile.idlist_addr = sh.sh_addr; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (compressed_section_fix(elf, scn, &sh)) 3778c2ecf20Sopenharmony_ci return -1; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int symbols_collect(struct object *obj) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci Elf_Scn *scn = NULL; 3868c2ecf20Sopenharmony_ci int n, i, err = 0; 3878c2ecf20Sopenharmony_ci GElf_Shdr sh; 3888c2ecf20Sopenharmony_ci char *name; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci scn = elf_getscn(obj->efile.elf, obj->efile.symbols_shndx); 3918c2ecf20Sopenharmony_ci if (!scn) 3928c2ecf20Sopenharmony_ci return -1; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (gelf_getshdr(scn, &sh) != &sh) 3958c2ecf20Sopenharmony_ci return -1; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci n = sh.sh_size / sh.sh_entsize; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * Scan symbols and look for the ones starting with 4018c2ecf20Sopenharmony_ci * __BTF_ID__* over .BTF_ids section. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci for (i = 0; !err && i < n; i++) { 4048c2ecf20Sopenharmony_ci char *tmp, *prefix; 4058c2ecf20Sopenharmony_ci struct btf_id *id; 4068c2ecf20Sopenharmony_ci GElf_Sym sym; 4078c2ecf20Sopenharmony_ci int err = -1; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (!gelf_getsym(obj->efile.symbols, i, &sym)) 4108c2ecf20Sopenharmony_ci return -1; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (sym.st_shndx != obj->efile.idlist_shndx) 4138c2ecf20Sopenharmony_ci continue; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci name = elf_strptr(obj->efile.elf, obj->efile.strtabidx, 4168c2ecf20Sopenharmony_ci sym.st_name); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!is_btf_id(name)) 4198c2ecf20Sopenharmony_ci continue; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * __BTF_ID__TYPE__vfs_truncate__0 4238c2ecf20Sopenharmony_ci * prefix = ^ 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci prefix = name + sizeof(BTF_ID) - 1; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* struct */ 4288c2ecf20Sopenharmony_ci if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) { 4298c2ecf20Sopenharmony_ci obj->nr_structs++; 4308c2ecf20Sopenharmony_ci id = add_symbol(&obj->structs, prefix, sizeof(BTF_STRUCT) - 1); 4318c2ecf20Sopenharmony_ci /* union */ 4328c2ecf20Sopenharmony_ci } else if (!strncmp(prefix, BTF_UNION, sizeof(BTF_UNION) - 1)) { 4338c2ecf20Sopenharmony_ci obj->nr_unions++; 4348c2ecf20Sopenharmony_ci id = add_symbol(&obj->unions, prefix, sizeof(BTF_UNION) - 1); 4358c2ecf20Sopenharmony_ci /* typedef */ 4368c2ecf20Sopenharmony_ci } else if (!strncmp(prefix, BTF_TYPEDEF, sizeof(BTF_TYPEDEF) - 1)) { 4378c2ecf20Sopenharmony_ci obj->nr_typedefs++; 4388c2ecf20Sopenharmony_ci id = add_symbol(&obj->typedefs, prefix, sizeof(BTF_TYPEDEF) - 1); 4398c2ecf20Sopenharmony_ci /* func */ 4408c2ecf20Sopenharmony_ci } else if (!strncmp(prefix, BTF_FUNC, sizeof(BTF_FUNC) - 1)) { 4418c2ecf20Sopenharmony_ci obj->nr_funcs++; 4428c2ecf20Sopenharmony_ci id = add_symbol(&obj->funcs, prefix, sizeof(BTF_FUNC) - 1); 4438c2ecf20Sopenharmony_ci /* set */ 4448c2ecf20Sopenharmony_ci } else if (!strncmp(prefix, BTF_SET, sizeof(BTF_SET) - 1)) { 4458c2ecf20Sopenharmony_ci id = add_set(obj, prefix); 4468c2ecf20Sopenharmony_ci /* 4478c2ecf20Sopenharmony_ci * SET objects store list's count, which is encoded 4488c2ecf20Sopenharmony_ci * in symbol's size, together with 'cnt' field hence 4498c2ecf20Sopenharmony_ci * that - 1. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci if (id) 4528c2ecf20Sopenharmony_ci id->cnt = sym.st_size / sizeof(int) - 1; 4538c2ecf20Sopenharmony_ci } else { 4548c2ecf20Sopenharmony_ci pr_err("FAILED unsupported prefix %s\n", prefix); 4558c2ecf20Sopenharmony_ci return -1; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (!id) 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (id->addr_cnt >= ADDR_CNT) { 4628c2ecf20Sopenharmony_ci pr_err("FAILED symbol %s crossed the number of allowed lists", 4638c2ecf20Sopenharmony_ci id->name); 4648c2ecf20Sopenharmony_ci return -1; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci id->addr[id->addr_cnt++] = sym.st_value; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int symbols_resolve(struct object *obj) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci int nr_typedefs = obj->nr_typedefs; 4758c2ecf20Sopenharmony_ci int nr_structs = obj->nr_structs; 4768c2ecf20Sopenharmony_ci int nr_unions = obj->nr_unions; 4778c2ecf20Sopenharmony_ci int nr_funcs = obj->nr_funcs; 4788c2ecf20Sopenharmony_ci int err, type_id; 4798c2ecf20Sopenharmony_ci struct btf *btf; 4808c2ecf20Sopenharmony_ci __u32 nr; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci btf = btf__parse(obj->btf ?: obj->path, NULL); 4838c2ecf20Sopenharmony_ci err = libbpf_get_error(btf); 4848c2ecf20Sopenharmony_ci if (err) { 4858c2ecf20Sopenharmony_ci pr_err("FAILED: load BTF from %s: %s", 4868c2ecf20Sopenharmony_ci obj->path, strerror(err)); 4878c2ecf20Sopenharmony_ci return -1; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci err = -1; 4918c2ecf20Sopenharmony_ci nr = btf__get_nr_types(btf); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * Iterate all the BTF types and search for collected symbol IDs. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci for (type_id = 1; type_id <= nr; type_id++) { 4978c2ecf20Sopenharmony_ci const struct btf_type *type; 4988c2ecf20Sopenharmony_ci struct rb_root *root; 4998c2ecf20Sopenharmony_ci struct btf_id *id; 5008c2ecf20Sopenharmony_ci const char *str; 5018c2ecf20Sopenharmony_ci int *nr; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci type = btf__type_by_id(btf, type_id); 5048c2ecf20Sopenharmony_ci if (!type) { 5058c2ecf20Sopenharmony_ci pr_err("FAILED: malformed BTF, can't resolve type for ID %d\n", 5068c2ecf20Sopenharmony_ci type_id); 5078c2ecf20Sopenharmony_ci goto out; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (btf_is_func(type) && nr_funcs) { 5118c2ecf20Sopenharmony_ci nr = &nr_funcs; 5128c2ecf20Sopenharmony_ci root = &obj->funcs; 5138c2ecf20Sopenharmony_ci } else if (btf_is_struct(type) && nr_structs) { 5148c2ecf20Sopenharmony_ci nr = &nr_structs; 5158c2ecf20Sopenharmony_ci root = &obj->structs; 5168c2ecf20Sopenharmony_ci } else if (btf_is_union(type) && nr_unions) { 5178c2ecf20Sopenharmony_ci nr = &nr_unions; 5188c2ecf20Sopenharmony_ci root = &obj->unions; 5198c2ecf20Sopenharmony_ci } else if (btf_is_typedef(type) && nr_typedefs) { 5208c2ecf20Sopenharmony_ci nr = &nr_typedefs; 5218c2ecf20Sopenharmony_ci root = &obj->typedefs; 5228c2ecf20Sopenharmony_ci } else 5238c2ecf20Sopenharmony_ci continue; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci str = btf__name_by_offset(btf, type->name_off); 5268c2ecf20Sopenharmony_ci if (!str) { 5278c2ecf20Sopenharmony_ci pr_err("FAILED: malformed BTF, can't resolve name for ID %d\n", 5288c2ecf20Sopenharmony_ci type_id); 5298c2ecf20Sopenharmony_ci goto out; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci id = btf_id__find(root, str); 5338c2ecf20Sopenharmony_ci if (id) { 5348c2ecf20Sopenharmony_ci id->id = type_id; 5358c2ecf20Sopenharmony_ci (*nr)--; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci err = 0; 5408c2ecf20Sopenharmony_ciout: 5418c2ecf20Sopenharmony_ci btf__free(btf); 5428c2ecf20Sopenharmony_ci return err; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int id_patch(struct object *obj, struct btf_id *id) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci Elf_Data *data = obj->efile.idlist; 5488c2ecf20Sopenharmony_ci int *ptr = data->d_buf; 5498c2ecf20Sopenharmony_ci int i; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!id->id) { 5528c2ecf20Sopenharmony_ci pr_err("FAILED unresolved symbol %s\n", id->name); 5538c2ecf20Sopenharmony_ci return -EINVAL; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci for (i = 0; i < id->addr_cnt; i++) { 5578c2ecf20Sopenharmony_ci unsigned long addr = id->addr[i]; 5588c2ecf20Sopenharmony_ci unsigned long idx = addr - obj->efile.idlist_addr; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci pr_debug("patching addr %5lu: ID %7d [%s]\n", 5618c2ecf20Sopenharmony_ci idx, id->id, id->name); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (idx >= data->d_size) { 5648c2ecf20Sopenharmony_ci pr_err("FAILED patching index %lu out of bounds %lu\n", 5658c2ecf20Sopenharmony_ci idx, data->d_size); 5668c2ecf20Sopenharmony_ci return -1; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci idx = idx / sizeof(int); 5708c2ecf20Sopenharmony_ci ptr[idx] = id->id; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int __symbols_patch(struct object *obj, struct rb_root *root) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct rb_node *next; 5798c2ecf20Sopenharmony_ci struct btf_id *id; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci next = rb_first(root); 5828c2ecf20Sopenharmony_ci while (next) { 5838c2ecf20Sopenharmony_ci id = rb_entry(next, struct btf_id, rb_node); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (id_patch(obj, id)) 5868c2ecf20Sopenharmony_ci return -1; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci next = rb_next(next); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int cmp_id(const void *pa, const void *pb) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci const int *a = pa, *b = pb; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return *a - *b; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int sets_patch(struct object *obj) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci Elf_Data *data = obj->efile.idlist; 6038c2ecf20Sopenharmony_ci int *ptr = data->d_buf; 6048c2ecf20Sopenharmony_ci struct rb_node *next; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci next = rb_first(&obj->sets); 6078c2ecf20Sopenharmony_ci while (next) { 6088c2ecf20Sopenharmony_ci unsigned long addr, idx; 6098c2ecf20Sopenharmony_ci struct btf_id *id; 6108c2ecf20Sopenharmony_ci int *base; 6118c2ecf20Sopenharmony_ci int cnt; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci id = rb_entry(next, struct btf_id, rb_node); 6148c2ecf20Sopenharmony_ci addr = id->addr[0]; 6158c2ecf20Sopenharmony_ci idx = addr - obj->efile.idlist_addr; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* sets are unique */ 6188c2ecf20Sopenharmony_ci if (id->addr_cnt != 1) { 6198c2ecf20Sopenharmony_ci pr_err("FAILED malformed data for set '%s'\n", 6208c2ecf20Sopenharmony_ci id->name); 6218c2ecf20Sopenharmony_ci return -1; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci idx = idx / sizeof(int); 6258c2ecf20Sopenharmony_ci base = &ptr[idx] + 1; 6268c2ecf20Sopenharmony_ci cnt = ptr[idx]; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci pr_debug("sorting addr %5lu: cnt %6d [%s]\n", 6298c2ecf20Sopenharmony_ci (idx + 1) * sizeof(int), cnt, id->name); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci qsort(base, cnt, sizeof(int), cmp_id); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci next = rb_next(next); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int symbols_patch(struct object *obj) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci int err; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (__symbols_patch(obj, &obj->structs) || 6438c2ecf20Sopenharmony_ci __symbols_patch(obj, &obj->unions) || 6448c2ecf20Sopenharmony_ci __symbols_patch(obj, &obj->typedefs) || 6458c2ecf20Sopenharmony_ci __symbols_patch(obj, &obj->funcs) || 6468c2ecf20Sopenharmony_ci __symbols_patch(obj, &obj->sets)) 6478c2ecf20Sopenharmony_ci return -1; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (sets_patch(obj)) 6508c2ecf20Sopenharmony_ci return -1; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Set type to ensure endian translation occurs. */ 6538c2ecf20Sopenharmony_ci obj->efile.idlist->d_type = ELF_T_WORD; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci elf_flagdata(obj->efile.idlist, ELF_C_SET, ELF_F_DIRTY); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci err = elf_update(obj->efile.elf, ELF_C_WRITE); 6588c2ecf20Sopenharmony_ci if (err < 0) { 6598c2ecf20Sopenharmony_ci pr_err("FAILED elf_update(WRITE): %s\n", 6608c2ecf20Sopenharmony_ci elf_errmsg(-1)); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci pr_debug("update %s for %s\n", 6648c2ecf20Sopenharmony_ci err >= 0 ? "ok" : "failed", obj->path); 6658c2ecf20Sopenharmony_ci return err < 0 ? -1 : 0; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic const char * const resolve_btfids_usage[] = { 6698c2ecf20Sopenharmony_ci "resolve_btfids [<options>] <ELF object>", 6708c2ecf20Sopenharmony_ci NULL 6718c2ecf20Sopenharmony_ci}; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ciint main(int argc, const char **argv) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci bool no_fail = false; 6768c2ecf20Sopenharmony_ci struct object obj = { 6778c2ecf20Sopenharmony_ci .efile = { 6788c2ecf20Sopenharmony_ci .idlist_shndx = -1, 6798c2ecf20Sopenharmony_ci .symbols_shndx = -1, 6808c2ecf20Sopenharmony_ci }, 6818c2ecf20Sopenharmony_ci .structs = RB_ROOT, 6828c2ecf20Sopenharmony_ci .unions = RB_ROOT, 6838c2ecf20Sopenharmony_ci .typedefs = RB_ROOT, 6848c2ecf20Sopenharmony_ci .funcs = RB_ROOT, 6858c2ecf20Sopenharmony_ci .sets = RB_ROOT, 6868c2ecf20Sopenharmony_ci }; 6878c2ecf20Sopenharmony_ci struct option btfid_options[] = { 6888c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 6898c2ecf20Sopenharmony_ci "be more verbose (show errors, etc)"), 6908c2ecf20Sopenharmony_ci OPT_STRING(0, "btf", &obj.btf, "BTF data", 6918c2ecf20Sopenharmony_ci "BTF data"), 6928c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "no-fail", &no_fail, 6938c2ecf20Sopenharmony_ci "do not fail if " BTF_IDS_SECTION " section is not found"), 6948c2ecf20Sopenharmony_ci OPT_END() 6958c2ecf20Sopenharmony_ci }; 6968c2ecf20Sopenharmony_ci int err = -1; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, btfid_options, resolve_btfids_usage, 6998c2ecf20Sopenharmony_ci PARSE_OPT_STOP_AT_NON_OPTION); 7008c2ecf20Sopenharmony_ci if (argc != 1) 7018c2ecf20Sopenharmony_ci usage_with_options(resolve_btfids_usage, btfid_options); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci obj.path = argv[0]; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (elf_collect(&obj)) 7068c2ecf20Sopenharmony_ci goto out; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * We did not find .BTF_ids section or symbols section, 7108c2ecf20Sopenharmony_ci * nothing to do.. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci if (obj.efile.idlist_shndx == -1 || 7138c2ecf20Sopenharmony_ci obj.efile.symbols_shndx == -1) { 7148c2ecf20Sopenharmony_ci if (no_fail) 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci pr_err("FAILED to find needed sections\n"); 7178c2ecf20Sopenharmony_ci return -1; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (symbols_collect(&obj)) 7218c2ecf20Sopenharmony_ci goto out; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (symbols_resolve(&obj)) 7248c2ecf20Sopenharmony_ci goto out; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (symbols_patch(&obj)) 7278c2ecf20Sopenharmony_ci goto out; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci err = 0; 7308c2ecf20Sopenharmony_ciout: 7318c2ecf20Sopenharmony_ci if (obj.efile.elf) 7328c2ecf20Sopenharmony_ci elf_end(obj.efile.elf); 7338c2ecf20Sopenharmony_ci close(obj.efile.fd); 7348c2ecf20Sopenharmony_ci return err; 7358c2ecf20Sopenharmony_ci} 736