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