xref: /openbmc/linux/tools/lib/bpf/btf.c (revision 59842c54)
11bc38b8fSAlexei Starovoitov // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
28a138aedSMartin KaFai Lau /* Copyright (c) 2018 Facebook */
38a138aedSMartin KaFai Lau 
43289959bSAndrii Nakryiko #include <byteswap.h>
5cdb2f920SArnaldo Carvalho de Melo #include <endian.h>
696408c43SYonghong Song #include <stdio.h>
78a138aedSMartin KaFai Lau #include <stdlib.h>
88a138aedSMartin KaFai Lau #include <string.h>
9e6c64855SAndrii Nakryiko #include <fcntl.h>
108a138aedSMartin KaFai Lau #include <unistd.h>
118a138aedSMartin KaFai Lau #include <errno.h>
12fb2426adSMartin KaFai Lau #include <sys/utsname.h>
13fb2426adSMartin KaFai Lau #include <sys/param.h>
14fb2426adSMartin KaFai Lau #include <sys/stat.h>
15fb2426adSMartin KaFai Lau #include <linux/kernel.h>
168a138aedSMartin KaFai Lau #include <linux/err.h>
178a138aedSMartin KaFai Lau #include <linux/btf.h>
18e6c64855SAndrii Nakryiko #include <gelf.h>
198a138aedSMartin KaFai Lau #include "btf.h"
208a138aedSMartin KaFai Lau #include "bpf.h"
218461ef8bSYonghong Song #include "libbpf.h"
22d72386feSAndrii Nakryiko #include "libbpf_internal.h"
232fc3fc0bSAndrii Nakryiko #include "hashmap.h"
2490d76d3eSAndrii Nakryiko #include "strset.h"
258a138aedSMartin KaFai Lau 
26fb2426adSMartin KaFai Lau #define BTF_MAX_NR_TYPES 0x7fffffffU
27fb2426adSMartin KaFai Lau #define BTF_MAX_STR_OFFSET 0x7fffffffU
288a138aedSMartin KaFai Lau 
298a138aedSMartin KaFai Lau static struct btf_type btf_void;
308a138aedSMartin KaFai Lau 
318a138aedSMartin KaFai Lau struct btf {
323289959bSAndrii Nakryiko 	/* raw BTF data in native endianness */
33b8604247SAndrii Nakryiko 	void *raw_data;
343289959bSAndrii Nakryiko 	/* raw BTF data in non-native endianness */
353289959bSAndrii Nakryiko 	void *raw_data_swapped;
36b8604247SAndrii Nakryiko 	__u32 raw_size;
373289959bSAndrii Nakryiko 	/* whether target endianness differs from the native one */
383289959bSAndrii Nakryiko 	bool swapped_endian;
39b8604247SAndrii Nakryiko 
40b8604247SAndrii Nakryiko 	/*
419141f75aSAndrii Nakryiko 	 * When BTF is loaded from an ELF or raw memory it is stored
429141f75aSAndrii Nakryiko 	 * in a contiguous memory block. The hdr, type_data, and, strs_data
439141f75aSAndrii Nakryiko 	 * point inside that memory region to their respective parts of BTF
449141f75aSAndrii Nakryiko 	 * representation:
45b8604247SAndrii Nakryiko 	 *
46b8604247SAndrii Nakryiko 	 * +--------------------------------+
47b8604247SAndrii Nakryiko 	 * |  Header  |  Types  |  Strings  |
48b8604247SAndrii Nakryiko 	 * +--------------------------------+
49b8604247SAndrii Nakryiko 	 * ^          ^         ^
50b8604247SAndrii Nakryiko 	 * |          |         |
51b8604247SAndrii Nakryiko 	 * hdr        |         |
52b8604247SAndrii Nakryiko 	 * types_data-+         |
53b8604247SAndrii Nakryiko 	 * strs_data------------+
54919d2b1dSAndrii Nakryiko 	 *
55919d2b1dSAndrii Nakryiko 	 * If BTF data is later modified, e.g., due to types added or
56919d2b1dSAndrii Nakryiko 	 * removed, BTF deduplication performed, etc, this contiguous
57919d2b1dSAndrii Nakryiko 	 * representation is broken up into three independently allocated
58919d2b1dSAndrii Nakryiko 	 * memory regions to be able to modify them independently.
59919d2b1dSAndrii Nakryiko 	 * raw_data is nulled out at that point, but can be later allocated
606a886de0SHengqi Chen 	 * and cached again if user calls btf__raw_data(), at which point
61919d2b1dSAndrii Nakryiko 	 * raw_data will contain a contiguous copy of header, types, and
62919d2b1dSAndrii Nakryiko 	 * strings:
63919d2b1dSAndrii Nakryiko 	 *
64919d2b1dSAndrii Nakryiko 	 * +----------+  +---------+  +-----------+
65919d2b1dSAndrii Nakryiko 	 * |  Header  |  |  Types  |  |  Strings  |
66919d2b1dSAndrii Nakryiko 	 * +----------+  +---------+  +-----------+
67919d2b1dSAndrii Nakryiko 	 * ^             ^            ^
68919d2b1dSAndrii Nakryiko 	 * |             |            |
69919d2b1dSAndrii Nakryiko 	 * hdr           |            |
70919d2b1dSAndrii Nakryiko 	 * types_data----+            |
7190d76d3eSAndrii Nakryiko 	 * strset__data(strs_set)-----+
72919d2b1dSAndrii Nakryiko 	 *
73919d2b1dSAndrii Nakryiko 	 *               +----------+---------+-----------+
74919d2b1dSAndrii Nakryiko 	 *               |  Header  |  Types  |  Strings  |
75919d2b1dSAndrii Nakryiko 	 * raw_data----->+----------+---------+-----------+
76b8604247SAndrii Nakryiko 	 */
778a138aedSMartin KaFai Lau 	struct btf_header *hdr;
78919d2b1dSAndrii Nakryiko 
79b8604247SAndrii Nakryiko 	void *types_data;
80919d2b1dSAndrii Nakryiko 	size_t types_data_cap; /* used size stored in hdr->type_len */
81b8604247SAndrii Nakryiko 
82ba451366SAndrii Nakryiko 	/* type ID to `struct btf_type *` lookup index
83ba451366SAndrii Nakryiko 	 * type_offs[0] corresponds to the first non-VOID type:
84ba451366SAndrii Nakryiko 	 *   - for base BTF it's type [1];
85ba451366SAndrii Nakryiko 	 *   - for split BTF it's the first non-base BTF type.
86ba451366SAndrii Nakryiko 	 */
87740e69c3SAndrii Nakryiko 	__u32 *type_offs;
88192f5a1fSAndrii Nakryiko 	size_t type_offs_cap;
89ba451366SAndrii Nakryiko 	/* number of types in this BTF instance:
90ba451366SAndrii Nakryiko 	 *   - doesn't include special [0] void type;
91ba451366SAndrii Nakryiko 	 *   - for split BTF counts number of types added on top of base BTF.
92ba451366SAndrii Nakryiko 	 */
935b891af7SMartin KaFai Lau 	__u32 nr_types;
94ba451366SAndrii Nakryiko 	/* if not NULL, points to the base BTF on top of which the current
95ba451366SAndrii Nakryiko 	 * split BTF is based
96ba451366SAndrii Nakryiko 	 */
97ba451366SAndrii Nakryiko 	struct btf *base_btf;
98ba451366SAndrii Nakryiko 	/* BTF type ID of the first type in this BTF instance:
99ba451366SAndrii Nakryiko 	 *   - for base BTF it's equal to 1;
100ba451366SAndrii Nakryiko 	 *   - for split BTF it's equal to biggest type ID of base BTF plus 1.
101ba451366SAndrii Nakryiko 	 */
102ba451366SAndrii Nakryiko 	int start_id;
103ba451366SAndrii Nakryiko 	/* logical string offset of this BTF instance:
104ba451366SAndrii Nakryiko 	 *   - for base BTF it's equal to 0;
105ba451366SAndrii Nakryiko 	 *   - for split BTF it's equal to total size of base BTF's string section size.
106ba451366SAndrii Nakryiko 	 */
107ba451366SAndrii Nakryiko 	int start_str_off;
108b8604247SAndrii Nakryiko 
10990d76d3eSAndrii Nakryiko 	/* only one of strs_data or strs_set can be non-NULL, depending on
11090d76d3eSAndrii Nakryiko 	 * whether BTF is in a modifiable state (strs_set is used) or not
11190d76d3eSAndrii Nakryiko 	 * (strs_data points inside raw_data)
11290d76d3eSAndrii Nakryiko 	 */
113919d2b1dSAndrii Nakryiko 	void *strs_data;
11490d76d3eSAndrii Nakryiko 	/* a set of unique strings */
11590d76d3eSAndrii Nakryiko 	struct strset *strs_set;
116919d2b1dSAndrii Nakryiko 	/* whether strings are already deduplicated */
117919d2b1dSAndrii Nakryiko 	bool strs_deduped;
11888a82c2aSAndrii Nakryiko 
119b8604247SAndrii Nakryiko 	/* BTF object FD, if loaded into kernel */
1208a138aedSMartin KaFai Lau 	int fd;
121b8604247SAndrii Nakryiko 
122b8604247SAndrii Nakryiko 	/* Pointer size (in bytes) for a target architecture of this BTF */
12344ad23dfSAndrii Nakryiko 	int ptr_sz;
1248a138aedSMartin KaFai Lau };
1258a138aedSMartin KaFai Lau 
ptr_to_u64(const void * ptr)126d7f5b5e0SYonghong Song static inline __u64 ptr_to_u64(const void *ptr)
127d7f5b5e0SYonghong Song {
128d7f5b5e0SYonghong Song 	return (__u64) (unsigned long) ptr;
129d7f5b5e0SYonghong Song }
130d7f5b5e0SYonghong Song 
131192f5a1fSAndrii Nakryiko /* Ensure given dynamically allocated memory region pointed to by *data* with
132192f5a1fSAndrii Nakryiko  * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough
1339bbdfad8SDaniel Müller  * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements
134192f5a1fSAndrii Nakryiko  * are already used. At most *max_cnt* elements can be ever allocated.
135192f5a1fSAndrii Nakryiko  * If necessary, memory is reallocated and all existing data is copied over,
136192f5a1fSAndrii Nakryiko  * new pointer to the memory region is stored at *data, new memory region
137192f5a1fSAndrii Nakryiko  * capacity (in number of elements) is stored in *cap.
138192f5a1fSAndrii Nakryiko  * On success, memory pointer to the beginning of unused memory is returned.
139192f5a1fSAndrii Nakryiko  * On error, NULL is returned.
140192f5a1fSAndrii Nakryiko  */
libbpf_add_mem(void ** data,size_t * cap_cnt,size_t elem_sz,size_t cur_cnt,size_t max_cnt,size_t add_cnt)1413b029e06SAndrii Nakryiko void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
142192f5a1fSAndrii Nakryiko 		     size_t cur_cnt, size_t max_cnt, size_t add_cnt)
1438a138aedSMartin KaFai Lau {
144192f5a1fSAndrii Nakryiko 	size_t new_cnt;
145192f5a1fSAndrii Nakryiko 	void *new_data;
1468a138aedSMartin KaFai Lau 
147192f5a1fSAndrii Nakryiko 	if (cur_cnt + add_cnt <= *cap_cnt)
148192f5a1fSAndrii Nakryiko 		return *data + cur_cnt * elem_sz;
1498a138aedSMartin KaFai Lau 
150192f5a1fSAndrii Nakryiko 	/* requested more than the set limit */
151192f5a1fSAndrii Nakryiko 	if (cur_cnt + add_cnt > max_cnt)
152192f5a1fSAndrii Nakryiko 		return NULL;
1538a138aedSMartin KaFai Lau 
154192f5a1fSAndrii Nakryiko 	new_cnt = *cap_cnt;
155192f5a1fSAndrii Nakryiko 	new_cnt += new_cnt / 4;		  /* expand by 25% */
156192f5a1fSAndrii Nakryiko 	if (new_cnt < 16)		  /* but at least 16 elements */
157192f5a1fSAndrii Nakryiko 		new_cnt = 16;
158192f5a1fSAndrii Nakryiko 	if (new_cnt > max_cnt)		  /* but not exceeding a set limit */
159192f5a1fSAndrii Nakryiko 		new_cnt = max_cnt;
160192f5a1fSAndrii Nakryiko 	if (new_cnt < cur_cnt + add_cnt)  /* also ensure we have enough memory */
161192f5a1fSAndrii Nakryiko 		new_cnt = cur_cnt + add_cnt;
1628a138aedSMartin KaFai Lau 
163192f5a1fSAndrii Nakryiko 	new_data = libbpf_reallocarray(*data, new_cnt, elem_sz);
164192f5a1fSAndrii Nakryiko 	if (!new_data)
165192f5a1fSAndrii Nakryiko 		return NULL;
1668a138aedSMartin KaFai Lau 
167192f5a1fSAndrii Nakryiko 	/* zero out newly allocated portion of memory */
168192f5a1fSAndrii Nakryiko 	memset(new_data + (*cap_cnt) * elem_sz, 0, (new_cnt - *cap_cnt) * elem_sz);
169192f5a1fSAndrii Nakryiko 
170192f5a1fSAndrii Nakryiko 	*data = new_data;
171192f5a1fSAndrii Nakryiko 	*cap_cnt = new_cnt;
172192f5a1fSAndrii Nakryiko 	return new_data + cur_cnt * elem_sz;
1738a138aedSMartin KaFai Lau }
1748a138aedSMartin KaFai Lau 
1759c6c5c48SAndrii Nakryiko /* Ensure given dynamically allocated memory region has enough allocated space
1769c6c5c48SAndrii Nakryiko  * to accommodate *need_cnt* elements of size *elem_sz* bytes each
1779c6c5c48SAndrii Nakryiko  */
libbpf_ensure_mem(void ** data,size_t * cap_cnt,size_t elem_sz,size_t need_cnt)1783b029e06SAndrii Nakryiko int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt)
1799c6c5c48SAndrii Nakryiko {
1809c6c5c48SAndrii Nakryiko 	void *p;
1819c6c5c48SAndrii Nakryiko 
1829c6c5c48SAndrii Nakryiko 	if (need_cnt <= *cap_cnt)
1839c6c5c48SAndrii Nakryiko 		return 0;
1849c6c5c48SAndrii Nakryiko 
1853b029e06SAndrii Nakryiko 	p = libbpf_add_mem(data, cap_cnt, elem_sz, *cap_cnt, SIZE_MAX, need_cnt - *cap_cnt);
1869c6c5c48SAndrii Nakryiko 	if (!p)
1879c6c5c48SAndrii Nakryiko 		return -ENOMEM;
1889c6c5c48SAndrii Nakryiko 
1899c6c5c48SAndrii Nakryiko 	return 0;
1909c6c5c48SAndrii Nakryiko }
1919c6c5c48SAndrii Nakryiko 
btf_add_type_offs_mem(struct btf * btf,size_t add_cnt)1927ca61121SAndrii Nakryiko static void *btf_add_type_offs_mem(struct btf *btf, size_t add_cnt)
1937ca61121SAndrii Nakryiko {
1947ca61121SAndrii Nakryiko 	return libbpf_add_mem((void **)&btf->type_offs, &btf->type_offs_cap, sizeof(__u32),
1957ca61121SAndrii Nakryiko 			      btf->nr_types, BTF_MAX_NR_TYPES, add_cnt);
1967ca61121SAndrii Nakryiko }
1977ca61121SAndrii Nakryiko 
btf_add_type_idx_entry(struct btf * btf,__u32 type_off)198192f5a1fSAndrii Nakryiko static int btf_add_type_idx_entry(struct btf *btf, __u32 type_off)
199192f5a1fSAndrii Nakryiko {
200192f5a1fSAndrii Nakryiko 	__u32 *p;
2018a138aedSMartin KaFai Lau 
2027ca61121SAndrii Nakryiko 	p = btf_add_type_offs_mem(btf, 1);
203192f5a1fSAndrii Nakryiko 	if (!p)
204192f5a1fSAndrii Nakryiko 		return -ENOMEM;
205192f5a1fSAndrii Nakryiko 
206192f5a1fSAndrii Nakryiko 	*p = type_off;
2078a138aedSMartin KaFai Lau 	return 0;
2088a138aedSMartin KaFai Lau }
2098a138aedSMartin KaFai Lau 
btf_bswap_hdr(struct btf_header * h)2103289959bSAndrii Nakryiko static void btf_bswap_hdr(struct btf_header *h)
2113289959bSAndrii Nakryiko {
2123289959bSAndrii Nakryiko 	h->magic = bswap_16(h->magic);
2133289959bSAndrii Nakryiko 	h->hdr_len = bswap_32(h->hdr_len);
2143289959bSAndrii Nakryiko 	h->type_off = bswap_32(h->type_off);
2153289959bSAndrii Nakryiko 	h->type_len = bswap_32(h->type_len);
2163289959bSAndrii Nakryiko 	h->str_off = bswap_32(h->str_off);
2173289959bSAndrii Nakryiko 	h->str_len = bswap_32(h->str_len);
2183289959bSAndrii Nakryiko }
2193289959bSAndrii Nakryiko 
btf_parse_hdr(struct btf * btf)2208461ef8bSYonghong Song static int btf_parse_hdr(struct btf *btf)
2218a138aedSMartin KaFai Lau {
2223289959bSAndrii Nakryiko 	struct btf_header *hdr = btf->hdr;
2235b891af7SMartin KaFai Lau 	__u32 meta_left;
2248a138aedSMartin KaFai Lau 
225b8604247SAndrii Nakryiko 	if (btf->raw_size < sizeof(struct btf_header)) {
2268461ef8bSYonghong Song 		pr_debug("BTF header not found\n");
2278a138aedSMartin KaFai Lau 		return -EINVAL;
2288a138aedSMartin KaFai Lau 	}
2298a138aedSMartin KaFai Lau 
2303289959bSAndrii Nakryiko 	if (hdr->magic == bswap_16(BTF_MAGIC)) {
2313289959bSAndrii Nakryiko 		btf->swapped_endian = true;
2323289959bSAndrii Nakryiko 		if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) {
2333289959bSAndrii Nakryiko 			pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n",
2343289959bSAndrii Nakryiko 				bswap_32(hdr->hdr_len));
2353289959bSAndrii Nakryiko 			return -ENOTSUP;
2363289959bSAndrii Nakryiko 		}
2373289959bSAndrii Nakryiko 		btf_bswap_hdr(hdr);
2383289959bSAndrii Nakryiko 	} else if (hdr->magic != BTF_MAGIC) {
2398461ef8bSYonghong Song 		pr_debug("Invalid BTF magic: %x\n", hdr->magic);
2408a138aedSMartin KaFai Lau 		return -EINVAL;
2418a138aedSMartin KaFai Lau 	}
2428a138aedSMartin KaFai Lau 
243c825f5feSAndrii Nakryiko 	if (btf->raw_size < hdr->hdr_len) {
244c825f5feSAndrii Nakryiko 		pr_debug("BTF header len %u larger than data size %u\n",
245c825f5feSAndrii Nakryiko 			 hdr->hdr_len, btf->raw_size);
246c825f5feSAndrii Nakryiko 		return -EINVAL;
247c825f5feSAndrii Nakryiko 	}
248c825f5feSAndrii Nakryiko 
249c825f5feSAndrii Nakryiko 	meta_left = btf->raw_size - hdr->hdr_len;
2505245dafeSAndrii Nakryiko 	if (meta_left < (long long)hdr->str_off + hdr->str_len) {
251d8123624SAndrii Nakryiko 		pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
2528a138aedSMartin KaFai Lau 		return -EINVAL;
2538a138aedSMartin KaFai Lau 	}
2548a138aedSMartin KaFai Lau 
2555245dafeSAndrii Nakryiko 	if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
256d8123624SAndrii Nakryiko 		pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
257d8123624SAndrii Nakryiko 			 hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
2588a138aedSMartin KaFai Lau 		return -EINVAL;
2598a138aedSMartin KaFai Lau 	}
2608a138aedSMartin KaFai Lau 
261d8123624SAndrii Nakryiko 	if (hdr->type_off % 4) {
2628461ef8bSYonghong Song 		pr_debug("BTF type section is not aligned to 4 bytes\n");
2638a138aedSMartin KaFai Lau 		return -EINVAL;
2648a138aedSMartin KaFai Lau 	}
2658a138aedSMartin KaFai Lau 
2668a138aedSMartin KaFai Lau 	return 0;
2678a138aedSMartin KaFai Lau }
2688a138aedSMartin KaFai Lau 
btf_parse_str_sec(struct btf * btf)2698461ef8bSYonghong Song static int btf_parse_str_sec(struct btf *btf)
2708a138aedSMartin KaFai Lau {
2718a138aedSMartin KaFai Lau 	const struct btf_header *hdr = btf->hdr;
272b8604247SAndrii Nakryiko 	const char *start = btf->strs_data;
2738a138aedSMartin KaFai Lau 	const char *end = start + btf->hdr->str_len;
2748a138aedSMartin KaFai Lau 
275ba451366SAndrii Nakryiko 	if (btf->base_btf && hdr->str_len == 0)
276ba451366SAndrii Nakryiko 		return 0;
277ba451366SAndrii Nakryiko 	if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_STR_OFFSET || end[-1]) {
2788461ef8bSYonghong Song 		pr_debug("Invalid BTF string section\n");
2798a138aedSMartin KaFai Lau 		return -EINVAL;
2808a138aedSMartin KaFai Lau 	}
281ba451366SAndrii Nakryiko 	if (!btf->base_btf && start[0]) {
282ba451366SAndrii Nakryiko 		pr_debug("Invalid BTF string section\n");
283ba451366SAndrii Nakryiko 		return -EINVAL;
284ba451366SAndrii Nakryiko 	}
2858a138aedSMartin KaFai Lau 	return 0;
2868a138aedSMartin KaFai Lau }
2878a138aedSMartin KaFai Lau 
btf_type_size(const struct btf_type * t)288740e69c3SAndrii Nakryiko static int btf_type_size(const struct btf_type *t)
28969eaab04SAndrii Nakryiko {
2903289959bSAndrii Nakryiko 	const int base_size = sizeof(struct btf_type);
291b03bc685SAndrii Nakryiko 	__u16 vlen = btf_vlen(t);
29269eaab04SAndrii Nakryiko 
293b03bc685SAndrii Nakryiko 	switch (btf_kind(t)) {
29469eaab04SAndrii Nakryiko 	case BTF_KIND_FWD:
29569eaab04SAndrii Nakryiko 	case BTF_KIND_CONST:
29669eaab04SAndrii Nakryiko 	case BTF_KIND_VOLATILE:
29769eaab04SAndrii Nakryiko 	case BTF_KIND_RESTRICT:
29869eaab04SAndrii Nakryiko 	case BTF_KIND_PTR:
29969eaab04SAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
30069eaab04SAndrii Nakryiko 	case BTF_KIND_FUNC:
30122541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
3022dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
30369eaab04SAndrii Nakryiko 		return base_size;
30469eaab04SAndrii Nakryiko 	case BTF_KIND_INT:
30569eaab04SAndrii Nakryiko 		return base_size + sizeof(__u32);
30669eaab04SAndrii Nakryiko 	case BTF_KIND_ENUM:
30769eaab04SAndrii Nakryiko 		return base_size + vlen * sizeof(struct btf_enum);
308dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
309dffbbdc2SYonghong Song 		return base_size + vlen * sizeof(struct btf_enum64);
31069eaab04SAndrii Nakryiko 	case BTF_KIND_ARRAY:
31169eaab04SAndrii Nakryiko 		return base_size + sizeof(struct btf_array);
31269eaab04SAndrii Nakryiko 	case BTF_KIND_STRUCT:
31369eaab04SAndrii Nakryiko 	case BTF_KIND_UNION:
31469eaab04SAndrii Nakryiko 		return base_size + vlen * sizeof(struct btf_member);
31569eaab04SAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO:
31669eaab04SAndrii Nakryiko 		return base_size + vlen * sizeof(struct btf_param);
3171713d68bSDaniel Borkmann 	case BTF_KIND_VAR:
3181713d68bSDaniel Borkmann 		return base_size + sizeof(struct btf_var);
3191713d68bSDaniel Borkmann 	case BTF_KIND_DATASEC:
3201713d68bSDaniel Borkmann 		return base_size + vlen * sizeof(struct btf_var_secinfo);
321223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
322223f903eSYonghong Song 		return base_size + sizeof(struct btf_decl_tag);
32369eaab04SAndrii Nakryiko 	default:
324b03bc685SAndrii Nakryiko 		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
32569eaab04SAndrii Nakryiko 		return -EINVAL;
32669eaab04SAndrii Nakryiko 	}
32769eaab04SAndrii Nakryiko }
32869eaab04SAndrii Nakryiko 
btf_bswap_type_base(struct btf_type * t)3293289959bSAndrii Nakryiko static void btf_bswap_type_base(struct btf_type *t)
3303289959bSAndrii Nakryiko {
3313289959bSAndrii Nakryiko 	t->name_off = bswap_32(t->name_off);
3323289959bSAndrii Nakryiko 	t->info = bswap_32(t->info);
3333289959bSAndrii Nakryiko 	t->type = bswap_32(t->type);
3343289959bSAndrii Nakryiko }
3353289959bSAndrii Nakryiko 
btf_bswap_type_rest(struct btf_type * t)3363289959bSAndrii Nakryiko static int btf_bswap_type_rest(struct btf_type *t)
3373289959bSAndrii Nakryiko {
3383289959bSAndrii Nakryiko 	struct btf_var_secinfo *v;
339dffbbdc2SYonghong Song 	struct btf_enum64 *e64;
3403289959bSAndrii Nakryiko 	struct btf_member *m;
3413289959bSAndrii Nakryiko 	struct btf_array *a;
3423289959bSAndrii Nakryiko 	struct btf_param *p;
3433289959bSAndrii Nakryiko 	struct btf_enum *e;
3443289959bSAndrii Nakryiko 	__u16 vlen = btf_vlen(t);
3453289959bSAndrii Nakryiko 	int i;
3463289959bSAndrii Nakryiko 
3473289959bSAndrii Nakryiko 	switch (btf_kind(t)) {
3483289959bSAndrii Nakryiko 	case BTF_KIND_FWD:
3493289959bSAndrii Nakryiko 	case BTF_KIND_CONST:
3503289959bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
3513289959bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
3523289959bSAndrii Nakryiko 	case BTF_KIND_PTR:
3533289959bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
3543289959bSAndrii Nakryiko 	case BTF_KIND_FUNC:
35522541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
3562dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
3573289959bSAndrii Nakryiko 		return 0;
3583289959bSAndrii Nakryiko 	case BTF_KIND_INT:
3593289959bSAndrii Nakryiko 		*(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1));
3603289959bSAndrii Nakryiko 		return 0;
3613289959bSAndrii Nakryiko 	case BTF_KIND_ENUM:
3623289959bSAndrii Nakryiko 		for (i = 0, e = btf_enum(t); i < vlen; i++, e++) {
3633289959bSAndrii Nakryiko 			e->name_off = bswap_32(e->name_off);
3643289959bSAndrii Nakryiko 			e->val = bswap_32(e->val);
3653289959bSAndrii Nakryiko 		}
3663289959bSAndrii Nakryiko 		return 0;
367dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
368dffbbdc2SYonghong Song 		for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) {
369dffbbdc2SYonghong Song 			e64->name_off = bswap_32(e64->name_off);
370dffbbdc2SYonghong Song 			e64->val_lo32 = bswap_32(e64->val_lo32);
371dffbbdc2SYonghong Song 			e64->val_hi32 = bswap_32(e64->val_hi32);
372dffbbdc2SYonghong Song 		}
373dffbbdc2SYonghong Song 		return 0;
3743289959bSAndrii Nakryiko 	case BTF_KIND_ARRAY:
3753289959bSAndrii Nakryiko 		a = btf_array(t);
3763289959bSAndrii Nakryiko 		a->type = bswap_32(a->type);
3773289959bSAndrii Nakryiko 		a->index_type = bswap_32(a->index_type);
3783289959bSAndrii Nakryiko 		a->nelems = bswap_32(a->nelems);
3793289959bSAndrii Nakryiko 		return 0;
3803289959bSAndrii Nakryiko 	case BTF_KIND_STRUCT:
3813289959bSAndrii Nakryiko 	case BTF_KIND_UNION:
3823289959bSAndrii Nakryiko 		for (i = 0, m = btf_members(t); i < vlen; i++, m++) {
3833289959bSAndrii Nakryiko 			m->name_off = bswap_32(m->name_off);
3843289959bSAndrii Nakryiko 			m->type = bswap_32(m->type);
3853289959bSAndrii Nakryiko 			m->offset = bswap_32(m->offset);
3863289959bSAndrii Nakryiko 		}
3873289959bSAndrii Nakryiko 		return 0;
3883289959bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO:
3893289959bSAndrii Nakryiko 		for (i = 0, p = btf_params(t); i < vlen; i++, p++) {
3903289959bSAndrii Nakryiko 			p->name_off = bswap_32(p->name_off);
3913289959bSAndrii Nakryiko 			p->type = bswap_32(p->type);
3923289959bSAndrii Nakryiko 		}
3933289959bSAndrii Nakryiko 		return 0;
3943289959bSAndrii Nakryiko 	case BTF_KIND_VAR:
3953289959bSAndrii Nakryiko 		btf_var(t)->linkage = bswap_32(btf_var(t)->linkage);
3963289959bSAndrii Nakryiko 		return 0;
3973289959bSAndrii Nakryiko 	case BTF_KIND_DATASEC:
3983289959bSAndrii Nakryiko 		for (i = 0, v = btf_var_secinfos(t); i < vlen; i++, v++) {
3993289959bSAndrii Nakryiko 			v->type = bswap_32(v->type);
4003289959bSAndrii Nakryiko 			v->offset = bswap_32(v->offset);
4013289959bSAndrii Nakryiko 			v->size = bswap_32(v->size);
4023289959bSAndrii Nakryiko 		}
4033289959bSAndrii Nakryiko 		return 0;
404223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
405223f903eSYonghong Song 		btf_decl_tag(t)->component_idx = bswap_32(btf_decl_tag(t)->component_idx);
4065b84bd10SYonghong Song 		return 0;
4073289959bSAndrii Nakryiko 	default:
4083289959bSAndrii Nakryiko 		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
4093289959bSAndrii Nakryiko 		return -EINVAL;
4103289959bSAndrii Nakryiko 	}
4113289959bSAndrii Nakryiko }
4123289959bSAndrii Nakryiko 
btf_parse_type_sec(struct btf * btf)4138461ef8bSYonghong Song static int btf_parse_type_sec(struct btf *btf)
4148a138aedSMartin KaFai Lau {
4158a138aedSMartin KaFai Lau 	struct btf_header *hdr = btf->hdr;
416b8604247SAndrii Nakryiko 	void *next_type = btf->types_data;
417740e69c3SAndrii Nakryiko 	void *end_type = next_type + hdr->type_len;
418ba451366SAndrii Nakryiko 	int err, type_size;
419740e69c3SAndrii Nakryiko 
4203289959bSAndrii Nakryiko 	while (next_type + sizeof(struct btf_type) <= end_type) {
4213289959bSAndrii Nakryiko 		if (btf->swapped_endian)
4223289959bSAndrii Nakryiko 			btf_bswap_type_base(next_type);
423740e69c3SAndrii Nakryiko 
424740e69c3SAndrii Nakryiko 		type_size = btf_type_size(next_type);
425740e69c3SAndrii Nakryiko 		if (type_size < 0)
426740e69c3SAndrii Nakryiko 			return type_size;
4273289959bSAndrii Nakryiko 		if (next_type + type_size > end_type) {
428ba451366SAndrii Nakryiko 			pr_warn("BTF type [%d] is malformed\n", btf->start_id + btf->nr_types);
4293289959bSAndrii Nakryiko 			return -EINVAL;
4303289959bSAndrii Nakryiko 		}
4313289959bSAndrii Nakryiko 
4323289959bSAndrii Nakryiko 		if (btf->swapped_endian && btf_bswap_type_rest(next_type))
4333289959bSAndrii Nakryiko 			return -EINVAL;
4343289959bSAndrii Nakryiko 
4353289959bSAndrii Nakryiko 		err = btf_add_type_idx_entry(btf, next_type - btf->types_data);
4363289959bSAndrii Nakryiko 		if (err)
4373289959bSAndrii Nakryiko 			return err;
438740e69c3SAndrii Nakryiko 
439740e69c3SAndrii Nakryiko 		next_type += type_size;
440740e69c3SAndrii Nakryiko 		btf->nr_types++;
4418a138aedSMartin KaFai Lau 	}
4428a138aedSMartin KaFai Lau 
4433289959bSAndrii Nakryiko 	if (next_type != end_type) {
4443289959bSAndrii Nakryiko 		pr_warn("BTF types data is malformed\n");
4453289959bSAndrii Nakryiko 		return -EINVAL;
4463289959bSAndrii Nakryiko 	}
4473289959bSAndrii Nakryiko 
4488a138aedSMartin KaFai Lau 	return 0;
4498a138aedSMartin KaFai Lau }
4508a138aedSMartin KaFai Lau 
btf__type_cnt(const struct btf * btf)4516a886de0SHengqi Chen __u32 btf__type_cnt(const struct btf *btf)
4526a886de0SHengqi Chen {
4536a886de0SHengqi Chen 	return btf->start_id + btf->nr_types;
4546a886de0SHengqi Chen }
4556a886de0SHengqi Chen 
btf__base_btf(const struct btf * btf)4560cfdcd63SAndrii Nakryiko const struct btf *btf__base_btf(const struct btf *btf)
4570cfdcd63SAndrii Nakryiko {
4580cfdcd63SAndrii Nakryiko 	return btf->base_btf;
4590cfdcd63SAndrii Nakryiko }
4600cfdcd63SAndrii Nakryiko 
461740e69c3SAndrii Nakryiko /* internal helper returning non-const pointer to a type */
btf_type_by_id(const struct btf * btf,__u32 type_id)46274753e14SAlexei Starovoitov struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id)
463740e69c3SAndrii Nakryiko {
464740e69c3SAndrii Nakryiko 	if (type_id == 0)
465740e69c3SAndrii Nakryiko 		return &btf_void;
466ba451366SAndrii Nakryiko 	if (type_id < btf->start_id)
467ba451366SAndrii Nakryiko 		return btf_type_by_id(btf->base_btf, type_id);
468ba451366SAndrii Nakryiko 	return btf->types_data + btf->type_offs[type_id - btf->start_id];
469740e69c3SAndrii Nakryiko }
470740e69c3SAndrii Nakryiko 
btf__type_by_id(const struct btf * btf,__u32 type_id)47138d5d3b3SMartin KaFai Lau const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
4728a138aedSMartin KaFai Lau {
473ba451366SAndrii Nakryiko 	if (type_id >= btf->start_id + btf->nr_types)
474e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, NULL;
475740e69c3SAndrii Nakryiko 	return btf_type_by_id((struct btf *)btf, type_id);
4768a138aedSMartin KaFai Lau }
4778a138aedSMartin KaFai Lau 
determine_ptr_size(const struct btf * btf)47844ad23dfSAndrii Nakryiko static int determine_ptr_size(const struct btf *btf)
47944ad23dfSAndrii Nakryiko {
480610cd93bSDouglas Raillard 	static const char * const long_aliases[] = {
481610cd93bSDouglas Raillard 		"long",
482610cd93bSDouglas Raillard 		"long int",
483610cd93bSDouglas Raillard 		"int long",
484610cd93bSDouglas Raillard 		"unsigned long",
485610cd93bSDouglas Raillard 		"long unsigned",
486610cd93bSDouglas Raillard 		"unsigned long int",
487610cd93bSDouglas Raillard 		"unsigned int long",
488610cd93bSDouglas Raillard 		"long unsigned int",
489610cd93bSDouglas Raillard 		"long int unsigned",
490610cd93bSDouglas Raillard 		"int unsigned long",
491610cd93bSDouglas Raillard 		"int long unsigned",
492610cd93bSDouglas Raillard 	};
49344ad23dfSAndrii Nakryiko 	const struct btf_type *t;
49444ad23dfSAndrii Nakryiko 	const char *name;
495610cd93bSDouglas Raillard 	int i, j, n;
49644ad23dfSAndrii Nakryiko 
497ba451366SAndrii Nakryiko 	if (btf->base_btf && btf->base_btf->ptr_sz > 0)
498ba451366SAndrii Nakryiko 		return btf->base_btf->ptr_sz;
499ba451366SAndrii Nakryiko 
5006a886de0SHengqi Chen 	n = btf__type_cnt(btf);
5016a886de0SHengqi Chen 	for (i = 1; i < n; i++) {
50244ad23dfSAndrii Nakryiko 		t = btf__type_by_id(btf, i);
50344ad23dfSAndrii Nakryiko 		if (!btf_is_int(t))
50444ad23dfSAndrii Nakryiko 			continue;
50544ad23dfSAndrii Nakryiko 
506610cd93bSDouglas Raillard 		if (t->size != 4 && t->size != 8)
507610cd93bSDouglas Raillard 			continue;
508610cd93bSDouglas Raillard 
50944ad23dfSAndrii Nakryiko 		name = btf__name_by_offset(btf, t->name_off);
51044ad23dfSAndrii Nakryiko 		if (!name)
51144ad23dfSAndrii Nakryiko 			continue;
51244ad23dfSAndrii Nakryiko 
513610cd93bSDouglas Raillard 		for (j = 0; j < ARRAY_SIZE(long_aliases); j++) {
514610cd93bSDouglas Raillard 			if (strcmp(name, long_aliases[j]) == 0)
51544ad23dfSAndrii Nakryiko 				return t->size;
51644ad23dfSAndrii Nakryiko 		}
51744ad23dfSAndrii Nakryiko 	}
51844ad23dfSAndrii Nakryiko 
51944ad23dfSAndrii Nakryiko 	return -1;
52044ad23dfSAndrii Nakryiko }
52144ad23dfSAndrii Nakryiko 
btf_ptr_sz(const struct btf * btf)52244ad23dfSAndrii Nakryiko static size_t btf_ptr_sz(const struct btf *btf)
52344ad23dfSAndrii Nakryiko {
52444ad23dfSAndrii Nakryiko 	if (!btf->ptr_sz)
52544ad23dfSAndrii Nakryiko 		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
52644ad23dfSAndrii Nakryiko 	return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz;
52744ad23dfSAndrii Nakryiko }
52844ad23dfSAndrii Nakryiko 
52944ad23dfSAndrii Nakryiko /* Return pointer size this BTF instance assumes. The size is heuristically
53044ad23dfSAndrii Nakryiko  * determined by looking for 'long' or 'unsigned long' integer type and
53144ad23dfSAndrii Nakryiko  * recording its size in bytes. If BTF type information doesn't have any such
53244ad23dfSAndrii Nakryiko  * type, this function returns 0. In the latter case, native architecture's
53344ad23dfSAndrii Nakryiko  * pointer size is assumed, so will be either 4 or 8, depending on
53444ad23dfSAndrii Nakryiko  * architecture that libbpf was compiled for. It's possible to override
53544ad23dfSAndrii Nakryiko  * guessed value by using btf__set_pointer_size() API.
53644ad23dfSAndrii Nakryiko  */
btf__pointer_size(const struct btf * btf)53744ad23dfSAndrii Nakryiko size_t btf__pointer_size(const struct btf *btf)
53844ad23dfSAndrii Nakryiko {
53944ad23dfSAndrii Nakryiko 	if (!btf->ptr_sz)
54044ad23dfSAndrii Nakryiko 		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
54144ad23dfSAndrii Nakryiko 
54244ad23dfSAndrii Nakryiko 	if (btf->ptr_sz < 0)
54344ad23dfSAndrii Nakryiko 		/* not enough BTF type info to guess */
54444ad23dfSAndrii Nakryiko 		return 0;
54544ad23dfSAndrii Nakryiko 
54644ad23dfSAndrii Nakryiko 	return btf->ptr_sz;
54744ad23dfSAndrii Nakryiko }
54844ad23dfSAndrii Nakryiko 
54944ad23dfSAndrii Nakryiko /* Override or set pointer size in bytes. Only values of 4 and 8 are
55044ad23dfSAndrii Nakryiko  * supported.
55144ad23dfSAndrii Nakryiko  */
btf__set_pointer_size(struct btf * btf,size_t ptr_sz)55244ad23dfSAndrii Nakryiko int btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
55344ad23dfSAndrii Nakryiko {
55444ad23dfSAndrii Nakryiko 	if (ptr_sz != 4 && ptr_sz != 8)
555e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
55644ad23dfSAndrii Nakryiko 	btf->ptr_sz = ptr_sz;
55744ad23dfSAndrii Nakryiko 	return 0;
55844ad23dfSAndrii Nakryiko }
55944ad23dfSAndrii Nakryiko 
is_host_big_endian(void)5603289959bSAndrii Nakryiko static bool is_host_big_endian(void)
5613289959bSAndrii Nakryiko {
5623930198dSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
5633289959bSAndrii Nakryiko 	return false;
5643930198dSIlya Leoshkevich #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
5653289959bSAndrii Nakryiko 	return true;
5663289959bSAndrii Nakryiko #else
5673289959bSAndrii Nakryiko # error "Unrecognized __BYTE_ORDER__"
5683289959bSAndrii Nakryiko #endif
5693289959bSAndrii Nakryiko }
5703289959bSAndrii Nakryiko 
btf__endianness(const struct btf * btf)5713289959bSAndrii Nakryiko enum btf_endianness btf__endianness(const struct btf *btf)
5723289959bSAndrii Nakryiko {
5733289959bSAndrii Nakryiko 	if (is_host_big_endian())
5743289959bSAndrii Nakryiko 		return btf->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN;
5753289959bSAndrii Nakryiko 	else
5763289959bSAndrii Nakryiko 		return btf->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
5773289959bSAndrii Nakryiko }
5783289959bSAndrii Nakryiko 
btf__set_endianness(struct btf * btf,enum btf_endianness endian)5793289959bSAndrii Nakryiko int btf__set_endianness(struct btf *btf, enum btf_endianness endian)
5803289959bSAndrii Nakryiko {
5813289959bSAndrii Nakryiko 	if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN)
582e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
5833289959bSAndrii Nakryiko 
5843289959bSAndrii Nakryiko 	btf->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN);
5853289959bSAndrii Nakryiko 	if (!btf->swapped_endian) {
5863289959bSAndrii Nakryiko 		free(btf->raw_data_swapped);
5873289959bSAndrii Nakryiko 		btf->raw_data_swapped = NULL;
5883289959bSAndrii Nakryiko 	}
5893289959bSAndrii Nakryiko 	return 0;
5903289959bSAndrii Nakryiko }
5913289959bSAndrii Nakryiko 
btf_type_is_void(const struct btf_type * t)5928a138aedSMartin KaFai Lau static bool btf_type_is_void(const struct btf_type *t)
5938a138aedSMartin KaFai Lau {
594b03bc685SAndrii Nakryiko 	return t == &btf_void || btf_is_fwd(t);
5958a138aedSMartin KaFai Lau }
5968a138aedSMartin KaFai Lau 
btf_type_is_void_or_null(const struct btf_type * t)5978a138aedSMartin KaFai Lau static bool btf_type_is_void_or_null(const struct btf_type *t)
5988a138aedSMartin KaFai Lau {
5998a138aedSMartin KaFai Lau 	return !t || btf_type_is_void(t);
6008a138aedSMartin KaFai Lau }
6018a138aedSMartin KaFai Lau 
6028a138aedSMartin KaFai Lau #define MAX_RESOLVE_DEPTH 32
6038a138aedSMartin KaFai Lau 
btf__resolve_size(const struct btf * btf,__u32 type_id)6045b891af7SMartin KaFai Lau __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
6058a138aedSMartin KaFai Lau {
6068a138aedSMartin KaFai Lau 	const struct btf_array *array;
6078a138aedSMartin KaFai Lau 	const struct btf_type *t;
6085b891af7SMartin KaFai Lau 	__u32 nelems = 1;
6095b891af7SMartin KaFai Lau 	__s64 size = -1;
6108a138aedSMartin KaFai Lau 	int i;
6118a138aedSMartin KaFai Lau 
61292b57121SOkash Khawaja 	t = btf__type_by_id(btf, type_id);
613e9fc3ce9SAndrii Nakryiko 	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); i++) {
614b03bc685SAndrii Nakryiko 		switch (btf_kind(t)) {
61569eaab04SAndrii Nakryiko 		case BTF_KIND_INT:
61669eaab04SAndrii Nakryiko 		case BTF_KIND_STRUCT:
61769eaab04SAndrii Nakryiko 		case BTF_KIND_UNION:
61869eaab04SAndrii Nakryiko 		case BTF_KIND_ENUM:
619dffbbdc2SYonghong Song 		case BTF_KIND_ENUM64:
6201713d68bSDaniel Borkmann 		case BTF_KIND_DATASEC:
62122541a9eSIlya Leoshkevich 		case BTF_KIND_FLOAT:
62269eaab04SAndrii Nakryiko 			size = t->size;
62369eaab04SAndrii Nakryiko 			goto done;
62469eaab04SAndrii Nakryiko 		case BTF_KIND_PTR:
62544ad23dfSAndrii Nakryiko 			size = btf_ptr_sz(btf);
62669eaab04SAndrii Nakryiko 			goto done;
6278a138aedSMartin KaFai Lau 		case BTF_KIND_TYPEDEF:
6288a138aedSMartin KaFai Lau 		case BTF_KIND_VOLATILE:
6298a138aedSMartin KaFai Lau 		case BTF_KIND_CONST:
6308a138aedSMartin KaFai Lau 		case BTF_KIND_RESTRICT:
6311713d68bSDaniel Borkmann 		case BTF_KIND_VAR:
632223f903eSYonghong Song 		case BTF_KIND_DECL_TAG:
63369a055d5SYonghong Song 		case BTF_KIND_TYPE_TAG:
6348a138aedSMartin KaFai Lau 			type_id = t->type;
6358a138aedSMartin KaFai Lau 			break;
6368a138aedSMartin KaFai Lau 		case BTF_KIND_ARRAY:
637b03bc685SAndrii Nakryiko 			array = btf_array(t);
6388a138aedSMartin KaFai Lau 			if (nelems && array->nelems > UINT32_MAX / nelems)
639e9fc3ce9SAndrii Nakryiko 				return libbpf_err(-E2BIG);
6408a138aedSMartin KaFai Lau 			nelems *= array->nelems;
6418a138aedSMartin KaFai Lau 			type_id = array->type;
6428a138aedSMartin KaFai Lau 			break;
6438a138aedSMartin KaFai Lau 		default:
644e9fc3ce9SAndrii Nakryiko 			return libbpf_err(-EINVAL);
6458a138aedSMartin KaFai Lau 		}
6468a138aedSMartin KaFai Lau 
64792b57121SOkash Khawaja 		t = btf__type_by_id(btf, type_id);
6488a138aedSMartin KaFai Lau 	}
6498a138aedSMartin KaFai Lau 
650994021a7SAndrii Nakryiko done:
6518a138aedSMartin KaFai Lau 	if (size < 0)
652e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
6538a138aedSMartin KaFai Lau 	if (nelems && size > UINT32_MAX / nelems)
654e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-E2BIG);
6558a138aedSMartin KaFai Lau 
6568a138aedSMartin KaFai Lau 	return nelems * size;
6578a138aedSMartin KaFai Lau }
6588a138aedSMartin KaFai Lau 
btf__align_of(const struct btf * btf,__u32 id)6593d208f4cSAndrii Nakryiko int btf__align_of(const struct btf *btf, __u32 id)
6603d208f4cSAndrii Nakryiko {
6613d208f4cSAndrii Nakryiko 	const struct btf_type *t = btf__type_by_id(btf, id);
6623d208f4cSAndrii Nakryiko 	__u16 kind = btf_kind(t);
6633d208f4cSAndrii Nakryiko 
6643d208f4cSAndrii Nakryiko 	switch (kind) {
6653d208f4cSAndrii Nakryiko 	case BTF_KIND_INT:
6663d208f4cSAndrii Nakryiko 	case BTF_KIND_ENUM:
667dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
66822541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
66944ad23dfSAndrii Nakryiko 		return min(btf_ptr_sz(btf), (size_t)t->size);
6703d208f4cSAndrii Nakryiko 	case BTF_KIND_PTR:
67144ad23dfSAndrii Nakryiko 		return btf_ptr_sz(btf);
6723d208f4cSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
6733d208f4cSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
6743d208f4cSAndrii Nakryiko 	case BTF_KIND_CONST:
6753d208f4cSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
6762dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
6773d208f4cSAndrii Nakryiko 		return btf__align_of(btf, t->type);
6783d208f4cSAndrii Nakryiko 	case BTF_KIND_ARRAY:
6793d208f4cSAndrii Nakryiko 		return btf__align_of(btf, btf_array(t)->type);
6803d208f4cSAndrii Nakryiko 	case BTF_KIND_STRUCT:
6813d208f4cSAndrii Nakryiko 	case BTF_KIND_UNION: {
6823d208f4cSAndrii Nakryiko 		const struct btf_member *m = btf_members(t);
6833d208f4cSAndrii Nakryiko 		__u16 vlen = btf_vlen(t);
684a79ac2d1SPrashant Bhole 		int i, max_align = 1, align;
6853d208f4cSAndrii Nakryiko 
6863d208f4cSAndrii Nakryiko 		for (i = 0; i < vlen; i++, m++) {
687a79ac2d1SPrashant Bhole 			align = btf__align_of(btf, m->type);
688a79ac2d1SPrashant Bhole 			if (align <= 0)
689e9fc3ce9SAndrii Nakryiko 				return libbpf_err(align);
690a79ac2d1SPrashant Bhole 			max_align = max(max_align, align);
69125a4481bSAndrii Nakryiko 
69225a4481bSAndrii Nakryiko 			/* if field offset isn't aligned according to field
69325a4481bSAndrii Nakryiko 			 * type's alignment, then struct must be packed
69425a4481bSAndrii Nakryiko 			 */
69525a4481bSAndrii Nakryiko 			if (btf_member_bitfield_size(t, i) == 0 &&
69625a4481bSAndrii Nakryiko 			    (m->offset % (8 * align)) != 0)
69725a4481bSAndrii Nakryiko 				return 1;
6983d208f4cSAndrii Nakryiko 		}
6993d208f4cSAndrii Nakryiko 
70025a4481bSAndrii Nakryiko 		/* if struct/union size isn't a multiple of its alignment,
70125a4481bSAndrii Nakryiko 		 * then struct must be packed
70225a4481bSAndrii Nakryiko 		 */
70325a4481bSAndrii Nakryiko 		if ((t->size % max_align) != 0)
70425a4481bSAndrii Nakryiko 			return 1;
70525a4481bSAndrii Nakryiko 
706a79ac2d1SPrashant Bhole 		return max_align;
7073d208f4cSAndrii Nakryiko 	}
7083d208f4cSAndrii Nakryiko 	default:
7093d208f4cSAndrii Nakryiko 		pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t));
710e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, 0;
7113d208f4cSAndrii Nakryiko 	}
7123d208f4cSAndrii Nakryiko }
7133d208f4cSAndrii Nakryiko 
btf__resolve_type(const struct btf * btf,__u32 type_id)71492b57121SOkash Khawaja int btf__resolve_type(const struct btf *btf, __u32 type_id)
71592b57121SOkash Khawaja {
71692b57121SOkash Khawaja 	const struct btf_type *t;
71792b57121SOkash Khawaja 	int depth = 0;
71892b57121SOkash Khawaja 
71992b57121SOkash Khawaja 	t = btf__type_by_id(btf, type_id);
72092b57121SOkash Khawaja 	while (depth < MAX_RESOLVE_DEPTH &&
72192b57121SOkash Khawaja 	       !btf_type_is_void_or_null(t) &&
722b03bc685SAndrii Nakryiko 	       (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
72392b57121SOkash Khawaja 		type_id = t->type;
72492b57121SOkash Khawaja 		t = btf__type_by_id(btf, type_id);
72592b57121SOkash Khawaja 		depth++;
72692b57121SOkash Khawaja 	}
72792b57121SOkash Khawaja 
72892b57121SOkash Khawaja 	if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
729e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
73092b57121SOkash Khawaja 
73192b57121SOkash Khawaja 	return type_id;
73292b57121SOkash Khawaja }
73392b57121SOkash Khawaja 
btf__find_by_name(const struct btf * btf,const char * type_name)7345b891af7SMartin KaFai Lau __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
7358a138aedSMartin KaFai Lau {
7366a886de0SHengqi Chen 	__u32 i, nr_types = btf__type_cnt(btf);
7378a138aedSMartin KaFai Lau 
7388a138aedSMartin KaFai Lau 	if (!strcmp(type_name, "void"))
7398a138aedSMartin KaFai Lau 		return 0;
7408a138aedSMartin KaFai Lau 
7416a886de0SHengqi Chen 	for (i = 1; i < nr_types; i++) {
742740e69c3SAndrii Nakryiko 		const struct btf_type *t = btf__type_by_id(btf, i);
74392b57121SOkash Khawaja 		const char *name = btf__name_by_offset(btf, t->name_off);
7448a138aedSMartin KaFai Lau 
7458a138aedSMartin KaFai Lau 		if (name && !strcmp(type_name, name))
7468a138aedSMartin KaFai Lau 			return i;
7478a138aedSMartin KaFai Lau 	}
7488a138aedSMartin KaFai Lau 
749e9fc3ce9SAndrii Nakryiko 	return libbpf_err(-ENOENT);
7508a138aedSMartin KaFai Lau }
7518a138aedSMartin KaFai Lau 
btf_find_by_name_kind(const struct btf * btf,int start_id,const char * type_name,__u32 kind)7529dbe6015SKumar Kartikeya Dwivedi static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
7539dbe6015SKumar Kartikeya Dwivedi 				   const char *type_name, __u32 kind)
7541442e287SAlexei Starovoitov {
7556a886de0SHengqi Chen 	__u32 i, nr_types = btf__type_cnt(btf);
7561442e287SAlexei Starovoitov 
7571442e287SAlexei Starovoitov 	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
7581442e287SAlexei Starovoitov 		return 0;
7591442e287SAlexei Starovoitov 
7606a886de0SHengqi Chen 	for (i = start_id; i < nr_types; i++) {
761740e69c3SAndrii Nakryiko 		const struct btf_type *t = btf__type_by_id(btf, i);
7621442e287SAlexei Starovoitov 		const char *name;
7631442e287SAlexei Starovoitov 
7641442e287SAlexei Starovoitov 		if (btf_kind(t) != kind)
7651442e287SAlexei Starovoitov 			continue;
7661442e287SAlexei Starovoitov 		name = btf__name_by_offset(btf, t->name_off);
7671442e287SAlexei Starovoitov 		if (name && !strcmp(type_name, name))
7681442e287SAlexei Starovoitov 			return i;
7691442e287SAlexei Starovoitov 	}
7701442e287SAlexei Starovoitov 
771e9fc3ce9SAndrii Nakryiko 	return libbpf_err(-ENOENT);
7721442e287SAlexei Starovoitov }
7731442e287SAlexei Starovoitov 
btf__find_by_name_kind_own(const struct btf * btf,const char * type_name,__u32 kind)7749dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
7759dbe6015SKumar Kartikeya Dwivedi 				 __u32 kind)
7769dbe6015SKumar Kartikeya Dwivedi {
7779dbe6015SKumar Kartikeya Dwivedi 	return btf_find_by_name_kind(btf, btf->start_id, type_name, kind);
7789dbe6015SKumar Kartikeya Dwivedi }
7799dbe6015SKumar Kartikeya Dwivedi 
btf__find_by_name_kind(const struct btf * btf,const char * type_name,__u32 kind)7809dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
7819dbe6015SKumar Kartikeya Dwivedi 			     __u32 kind)
7829dbe6015SKumar Kartikeya Dwivedi {
7839dbe6015SKumar Kartikeya Dwivedi 	return btf_find_by_name_kind(btf, 1, type_name, kind);
7849dbe6015SKumar Kartikeya Dwivedi }
7859dbe6015SKumar Kartikeya Dwivedi 
btf_is_modifiable(const struct btf * btf)786919d2b1dSAndrii Nakryiko static bool btf_is_modifiable(const struct btf *btf)
787919d2b1dSAndrii Nakryiko {
788919d2b1dSAndrii Nakryiko 	return (void *)btf->hdr != btf->raw_data;
789919d2b1dSAndrii Nakryiko }
790919d2b1dSAndrii Nakryiko 
btf__free(struct btf * btf)7918a138aedSMartin KaFai Lau void btf__free(struct btf *btf)
7928a138aedSMartin KaFai Lau {
79350450fc7SAndrii Nakryiko 	if (IS_ERR_OR_NULL(btf))
7948a138aedSMartin KaFai Lau 		return;
7958a138aedSMartin KaFai Lau 
79681372e12SAndrii Nakryiko 	if (btf->fd >= 0)
7978a138aedSMartin KaFai Lau 		close(btf->fd);
7988a138aedSMartin KaFai Lau 
799919d2b1dSAndrii Nakryiko 	if (btf_is_modifiable(btf)) {
800919d2b1dSAndrii Nakryiko 		/* if BTF was modified after loading, it will have a split
801919d2b1dSAndrii Nakryiko 		 * in-memory representation for header, types, and strings
802919d2b1dSAndrii Nakryiko 		 * sections, so we need to free all of them individually. It
803919d2b1dSAndrii Nakryiko 		 * might still have a cached contiguous raw data present,
804919d2b1dSAndrii Nakryiko 		 * which will be unconditionally freed below.
805919d2b1dSAndrii Nakryiko 		 */
806919d2b1dSAndrii Nakryiko 		free(btf->hdr);
807919d2b1dSAndrii Nakryiko 		free(btf->types_data);
80890d76d3eSAndrii Nakryiko 		strset__free(btf->strs_set);
809919d2b1dSAndrii Nakryiko 	}
810b8604247SAndrii Nakryiko 	free(btf->raw_data);
8113289959bSAndrii Nakryiko 	free(btf->raw_data_swapped);
812740e69c3SAndrii Nakryiko 	free(btf->type_offs);
8138a138aedSMartin KaFai Lau 	free(btf);
8148a138aedSMartin KaFai Lau }
8158a138aedSMartin KaFai Lau 
btf_new_empty(struct btf * base_btf)816ba451366SAndrii Nakryiko static struct btf *btf_new_empty(struct btf *base_btf)
817a871b043SAndrii Nakryiko {
818a871b043SAndrii Nakryiko 	struct btf *btf;
819a871b043SAndrii Nakryiko 
820a871b043SAndrii Nakryiko 	btf = calloc(1, sizeof(*btf));
821a871b043SAndrii Nakryiko 	if (!btf)
822a871b043SAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
8233289959bSAndrii Nakryiko 
824ba451366SAndrii Nakryiko 	btf->nr_types = 0;
825ba451366SAndrii Nakryiko 	btf->start_id = 1;
826ba451366SAndrii Nakryiko 	btf->start_str_off = 0;
827a871b043SAndrii Nakryiko 	btf->fd = -1;
828a871b043SAndrii Nakryiko 	btf->ptr_sz = sizeof(void *);
8293289959bSAndrii Nakryiko 	btf->swapped_endian = false;
830a871b043SAndrii Nakryiko 
831ba451366SAndrii Nakryiko 	if (base_btf) {
832ba451366SAndrii Nakryiko 		btf->base_btf = base_btf;
8336a886de0SHengqi Chen 		btf->start_id = btf__type_cnt(base_btf);
834ba451366SAndrii Nakryiko 		btf->start_str_off = base_btf->hdr->str_len;
835ba451366SAndrii Nakryiko 	}
836ba451366SAndrii Nakryiko 
837a871b043SAndrii Nakryiko 	/* +1 for empty string at offset 0 */
838ba451366SAndrii Nakryiko 	btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1);
839a871b043SAndrii Nakryiko 	btf->raw_data = calloc(1, btf->raw_size);
840a871b043SAndrii Nakryiko 	if (!btf->raw_data) {
841a871b043SAndrii Nakryiko 		free(btf);
842a871b043SAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
843a871b043SAndrii Nakryiko 	}
844a871b043SAndrii Nakryiko 
845a871b043SAndrii Nakryiko 	btf->hdr = btf->raw_data;
846a871b043SAndrii Nakryiko 	btf->hdr->hdr_len = sizeof(struct btf_header);
847a871b043SAndrii Nakryiko 	btf->hdr->magic = BTF_MAGIC;
848a871b043SAndrii Nakryiko 	btf->hdr->version = BTF_VERSION;
849a871b043SAndrii Nakryiko 
850a871b043SAndrii Nakryiko 	btf->types_data = btf->raw_data + btf->hdr->hdr_len;
851a871b043SAndrii Nakryiko 	btf->strs_data = btf->raw_data + btf->hdr->hdr_len;
852ba451366SAndrii Nakryiko 	btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
853a871b043SAndrii Nakryiko 
854a871b043SAndrii Nakryiko 	return btf;
855a871b043SAndrii Nakryiko }
856a871b043SAndrii Nakryiko 
btf__new_empty(void)857ba451366SAndrii Nakryiko struct btf *btf__new_empty(void)
858ba451366SAndrii Nakryiko {
859e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new_empty(NULL));
860ba451366SAndrii Nakryiko }
861ba451366SAndrii Nakryiko 
btf__new_empty_split(struct btf * base_btf)862ba451366SAndrii Nakryiko struct btf *btf__new_empty_split(struct btf *base_btf)
863ba451366SAndrii Nakryiko {
864e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new_empty(base_btf));
865ba451366SAndrii Nakryiko }
866ba451366SAndrii Nakryiko 
btf_new(const void * data,__u32 size,struct btf * base_btf)867ba451366SAndrii Nakryiko static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
8688a138aedSMartin KaFai Lau {
8698a138aedSMartin KaFai Lau 	struct btf *btf;
8708a138aedSMartin KaFai Lau 	int err;
8718a138aedSMartin KaFai Lau 
8728a138aedSMartin KaFai Lau 	btf = calloc(1, sizeof(struct btf));
8738a138aedSMartin KaFai Lau 	if (!btf)
8748a138aedSMartin KaFai Lau 		return ERR_PTR(-ENOMEM);
8758a138aedSMartin KaFai Lau 
876ba451366SAndrii Nakryiko 	btf->nr_types = 0;
877ba451366SAndrii Nakryiko 	btf->start_id = 1;
878ba451366SAndrii Nakryiko 	btf->start_str_off = 0;
879c34c338aSDaniel Xu 	btf->fd = -1;
880ba451366SAndrii Nakryiko 
881ba451366SAndrii Nakryiko 	if (base_btf) {
882ba451366SAndrii Nakryiko 		btf->base_btf = base_btf;
8836a886de0SHengqi Chen 		btf->start_id = btf__type_cnt(base_btf);
884ba451366SAndrii Nakryiko 		btf->start_str_off = base_btf->hdr->str_len;
885ba451366SAndrii Nakryiko 	}
886ba451366SAndrii Nakryiko 
887b8604247SAndrii Nakryiko 	btf->raw_data = malloc(size);
888b8604247SAndrii Nakryiko 	if (!btf->raw_data) {
8898a138aedSMartin KaFai Lau 		err = -ENOMEM;
8908a138aedSMartin KaFai Lau 		goto done;
8918a138aedSMartin KaFai Lau 	}
892b8604247SAndrii Nakryiko 	memcpy(btf->raw_data, data, size);
893b8604247SAndrii Nakryiko 	btf->raw_size = size;
8948a138aedSMartin KaFai Lau 
895b8604247SAndrii Nakryiko 	btf->hdr = btf->raw_data;
8968461ef8bSYonghong Song 	err = btf_parse_hdr(btf);
8978a138aedSMartin KaFai Lau 	if (err)
8988a138aedSMartin KaFai Lau 		goto done;
8998a138aedSMartin KaFai Lau 
900b8604247SAndrii Nakryiko 	btf->strs_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->str_off;
901b8604247SAndrii Nakryiko 	btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off;
9028a138aedSMartin KaFai Lau 
903b8604247SAndrii Nakryiko 	err = btf_parse_str_sec(btf);
904b8604247SAndrii Nakryiko 	err = err ?: btf_parse_type_sec(btf);
9053289959bSAndrii Nakryiko 	if (err)
9063289959bSAndrii Nakryiko 		goto done;
9073289959bSAndrii Nakryiko 
9088a138aedSMartin KaFai Lau done:
9098a138aedSMartin KaFai Lau 	if (err) {
9108a138aedSMartin KaFai Lau 		btf__free(btf);
9118a138aedSMartin KaFai Lau 		return ERR_PTR(err);
9128a138aedSMartin KaFai Lau 	}
9138a138aedSMartin KaFai Lau 
9148a138aedSMartin KaFai Lau 	return btf;
9158a138aedSMartin KaFai Lau }
9168a138aedSMartin KaFai Lau 
btf__new(const void * data,__u32 size)917ba451366SAndrii Nakryiko struct btf *btf__new(const void *data, __u32 size)
918ba451366SAndrii Nakryiko {
919e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new(data, size, NULL));
920ba451366SAndrii Nakryiko }
921ba451366SAndrii Nakryiko 
btf_parse_elf(const char * path,struct btf * base_btf,struct btf_ext ** btf_ext)922ba451366SAndrii Nakryiko static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
923ba451366SAndrii Nakryiko 				 struct btf_ext **btf_ext)
924e6c64855SAndrii Nakryiko {
925e6c64855SAndrii Nakryiko 	Elf_Data *btf_data = NULL, *btf_ext_data = NULL;
926e6c64855SAndrii Nakryiko 	int err = 0, fd = -1, idx = 0;
927e6c64855SAndrii Nakryiko 	struct btf *btf = NULL;
928e6c64855SAndrii Nakryiko 	Elf_Scn *scn = NULL;
929e6c64855SAndrii Nakryiko 	Elf *elf = NULL;
930e6c64855SAndrii Nakryiko 	GElf_Ehdr ehdr;
9316095d5a2SJiri Olsa 	size_t shstrndx;
932e6c64855SAndrii Nakryiko 
933e6c64855SAndrii Nakryiko 	if (elf_version(EV_CURRENT) == EV_NONE) {
934be18010eSKefeng Wang 		pr_warn("failed to init libelf for %s\n", path);
935e6c64855SAndrii Nakryiko 		return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
936e6c64855SAndrii Nakryiko 	}
937e6c64855SAndrii Nakryiko 
93892274e24SKumar Kartikeya Dwivedi 	fd = open(path, O_RDONLY | O_CLOEXEC);
939e6c64855SAndrii Nakryiko 	if (fd < 0) {
940e6c64855SAndrii Nakryiko 		err = -errno;
941be18010eSKefeng Wang 		pr_warn("failed to open %s: %s\n", path, strerror(errno));
942e6c64855SAndrii Nakryiko 		return ERR_PTR(err);
943e6c64855SAndrii Nakryiko 	}
944e6c64855SAndrii Nakryiko 
945e6c64855SAndrii Nakryiko 	err = -LIBBPF_ERRNO__FORMAT;
946e6c64855SAndrii Nakryiko 
947e6c64855SAndrii Nakryiko 	elf = elf_begin(fd, ELF_C_READ, NULL);
948e6c64855SAndrii Nakryiko 	if (!elf) {
949be18010eSKefeng Wang 		pr_warn("failed to open %s as ELF file\n", path);
950e6c64855SAndrii Nakryiko 		goto done;
951e6c64855SAndrii Nakryiko 	}
952e6c64855SAndrii Nakryiko 	if (!gelf_getehdr(elf, &ehdr)) {
953be18010eSKefeng Wang 		pr_warn("failed to get EHDR from %s\n", path);
954e6c64855SAndrii Nakryiko 		goto done;
955e6c64855SAndrii Nakryiko 	}
9566095d5a2SJiri Olsa 
9576095d5a2SJiri Olsa 	if (elf_getshdrstrndx(elf, &shstrndx)) {
9586095d5a2SJiri Olsa 		pr_warn("failed to get section names section index for %s\n",
9596095d5a2SJiri Olsa 			path);
9606095d5a2SJiri Olsa 		goto done;
9616095d5a2SJiri Olsa 	}
9626095d5a2SJiri Olsa 
9636095d5a2SJiri Olsa 	if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) {
964be18010eSKefeng Wang 		pr_warn("failed to get e_shstrndx from %s\n", path);
965e6c64855SAndrii Nakryiko 		goto done;
966e6c64855SAndrii Nakryiko 	}
967e6c64855SAndrii Nakryiko 
968e6c64855SAndrii Nakryiko 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
969e6c64855SAndrii Nakryiko 		GElf_Shdr sh;
970e6c64855SAndrii Nakryiko 		char *name;
971e6c64855SAndrii Nakryiko 
972e6c64855SAndrii Nakryiko 		idx++;
973e6c64855SAndrii Nakryiko 		if (gelf_getshdr(scn, &sh) != &sh) {
974be18010eSKefeng Wang 			pr_warn("failed to get section(%d) header from %s\n",
975e6c64855SAndrii Nakryiko 				idx, path);
976e6c64855SAndrii Nakryiko 			goto done;
977e6c64855SAndrii Nakryiko 		}
9786095d5a2SJiri Olsa 		name = elf_strptr(elf, shstrndx, sh.sh_name);
979e6c64855SAndrii Nakryiko 		if (!name) {
980be18010eSKefeng Wang 			pr_warn("failed to get section(%d) name from %s\n",
981e6c64855SAndrii Nakryiko 				idx, path);
982e6c64855SAndrii Nakryiko 			goto done;
983e6c64855SAndrii Nakryiko 		}
984e6c64855SAndrii Nakryiko 		if (strcmp(name, BTF_ELF_SEC) == 0) {
985e6c64855SAndrii Nakryiko 			btf_data = elf_getdata(scn, 0);
986e6c64855SAndrii Nakryiko 			if (!btf_data) {
987be18010eSKefeng Wang 				pr_warn("failed to get section(%d, %s) data from %s\n",
988e6c64855SAndrii Nakryiko 					idx, name, path);
989e6c64855SAndrii Nakryiko 				goto done;
990e6c64855SAndrii Nakryiko 			}
991e6c64855SAndrii Nakryiko 			continue;
992e6c64855SAndrii Nakryiko 		} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
993e6c64855SAndrii Nakryiko 			btf_ext_data = elf_getdata(scn, 0);
994e6c64855SAndrii Nakryiko 			if (!btf_ext_data) {
995be18010eSKefeng Wang 				pr_warn("failed to get section(%d, %s) data from %s\n",
996e6c64855SAndrii Nakryiko 					idx, name, path);
997e6c64855SAndrii Nakryiko 				goto done;
998e6c64855SAndrii Nakryiko 			}
999e6c64855SAndrii Nakryiko 			continue;
1000e6c64855SAndrii Nakryiko 		}
1001e6c64855SAndrii Nakryiko 	}
1002e6c64855SAndrii Nakryiko 
1003e6c64855SAndrii Nakryiko 	if (!btf_data) {
1004e6b4e1d7SChangbin Du 		pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path);
1005acd3b776SChangbin Du 		err = -ENODATA;
1006e6c64855SAndrii Nakryiko 		goto done;
1007e6c64855SAndrii Nakryiko 	}
1008ba451366SAndrii Nakryiko 	btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
1009e9fc3ce9SAndrii Nakryiko 	err = libbpf_get_error(btf);
1010e9fc3ce9SAndrii Nakryiko 	if (err)
1011e6c64855SAndrii Nakryiko 		goto done;
1012e6c64855SAndrii Nakryiko 
101344ad23dfSAndrii Nakryiko 	switch (gelf_getclass(elf)) {
101444ad23dfSAndrii Nakryiko 	case ELFCLASS32:
101544ad23dfSAndrii Nakryiko 		btf__set_pointer_size(btf, 4);
101644ad23dfSAndrii Nakryiko 		break;
101744ad23dfSAndrii Nakryiko 	case ELFCLASS64:
101844ad23dfSAndrii Nakryiko 		btf__set_pointer_size(btf, 8);
101944ad23dfSAndrii Nakryiko 		break;
102044ad23dfSAndrii Nakryiko 	default:
102144ad23dfSAndrii Nakryiko 		pr_warn("failed to get ELF class (bitness) for %s\n", path);
102244ad23dfSAndrii Nakryiko 		break;
102344ad23dfSAndrii Nakryiko 	}
102444ad23dfSAndrii Nakryiko 
1025e6c64855SAndrii Nakryiko 	if (btf_ext && btf_ext_data) {
1026e9fc3ce9SAndrii Nakryiko 		*btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size);
1027e9fc3ce9SAndrii Nakryiko 		err = libbpf_get_error(*btf_ext);
1028e9fc3ce9SAndrii Nakryiko 		if (err)
1029e6c64855SAndrii Nakryiko 			goto done;
1030e6c64855SAndrii Nakryiko 	} else if (btf_ext) {
1031e6c64855SAndrii Nakryiko 		*btf_ext = NULL;
1032e6c64855SAndrii Nakryiko 	}
1033e6c64855SAndrii Nakryiko done:
1034e6c64855SAndrii Nakryiko 	if (elf)
1035e6c64855SAndrii Nakryiko 		elf_end(elf);
1036e6c64855SAndrii Nakryiko 	close(fd);
1037e6c64855SAndrii Nakryiko 
1038e9fc3ce9SAndrii Nakryiko 	if (!err)
1039e6c64855SAndrii Nakryiko 		return btf;
1040e9fc3ce9SAndrii Nakryiko 
1041e9fc3ce9SAndrii Nakryiko 	if (btf_ext)
1042e9fc3ce9SAndrii Nakryiko 		btf_ext__free(*btf_ext);
1043e6c64855SAndrii Nakryiko 	btf__free(btf);
1044e9fc3ce9SAndrii Nakryiko 
1045e6c64855SAndrii Nakryiko 	return ERR_PTR(err);
1046e6c64855SAndrii Nakryiko }
1047e6c64855SAndrii Nakryiko 
btf__parse_elf(const char * path,struct btf_ext ** btf_ext)1048ba451366SAndrii Nakryiko struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
1049ba451366SAndrii Nakryiko {
1050e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext));
1051ba451366SAndrii Nakryiko }
1052ba451366SAndrii Nakryiko 
btf__parse_elf_split(const char * path,struct btf * base_btf)1053ba451366SAndrii Nakryiko struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf)
1054ba451366SAndrii Nakryiko {
1055e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_elf(path, base_btf, NULL));
1056ba451366SAndrii Nakryiko }
1057ba451366SAndrii Nakryiko 
btf_parse_raw(const char * path,struct btf * base_btf)1058ba451366SAndrii Nakryiko static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
105994a1feddSAndrii Nakryiko {
1060932ac54aSDaniel T. Lee 	struct btf *btf = NULL;
106194a1feddSAndrii Nakryiko 	void *data = NULL;
106294a1feddSAndrii Nakryiko 	FILE *f = NULL;
106394a1feddSAndrii Nakryiko 	__u16 magic;
106494a1feddSAndrii Nakryiko 	int err = 0;
106594a1feddSAndrii Nakryiko 	long sz;
106694a1feddSAndrii Nakryiko 
1067*59842c54SAndrii Nakryiko 	f = fopen(path, "rbe");
106894a1feddSAndrii Nakryiko 	if (!f) {
106994a1feddSAndrii Nakryiko 		err = -errno;
107094a1feddSAndrii Nakryiko 		goto err_out;
107194a1feddSAndrii Nakryiko 	}
107294a1feddSAndrii Nakryiko 
107394a1feddSAndrii Nakryiko 	/* check BTF magic */
107494a1feddSAndrii Nakryiko 	if (fread(&magic, 1, sizeof(magic), f) < sizeof(magic)) {
107594a1feddSAndrii Nakryiko 		err = -EIO;
107694a1feddSAndrii Nakryiko 		goto err_out;
107794a1feddSAndrii Nakryiko 	}
10783289959bSAndrii Nakryiko 	if (magic != BTF_MAGIC && magic != bswap_16(BTF_MAGIC)) {
107994a1feddSAndrii Nakryiko 		/* definitely not a raw BTF */
108094a1feddSAndrii Nakryiko 		err = -EPROTO;
108194a1feddSAndrii Nakryiko 		goto err_out;
108294a1feddSAndrii Nakryiko 	}
108394a1feddSAndrii Nakryiko 
108494a1feddSAndrii Nakryiko 	/* get file size */
108594a1feddSAndrii Nakryiko 	if (fseek(f, 0, SEEK_END)) {
108694a1feddSAndrii Nakryiko 		err = -errno;
108794a1feddSAndrii Nakryiko 		goto err_out;
108894a1feddSAndrii Nakryiko 	}
108994a1feddSAndrii Nakryiko 	sz = ftell(f);
109094a1feddSAndrii Nakryiko 	if (sz < 0) {
109194a1feddSAndrii Nakryiko 		err = -errno;
109294a1feddSAndrii Nakryiko 		goto err_out;
109394a1feddSAndrii Nakryiko 	}
109494a1feddSAndrii Nakryiko 	/* rewind to the start */
109594a1feddSAndrii Nakryiko 	if (fseek(f, 0, SEEK_SET)) {
109694a1feddSAndrii Nakryiko 		err = -errno;
109794a1feddSAndrii Nakryiko 		goto err_out;
109894a1feddSAndrii Nakryiko 	}
109994a1feddSAndrii Nakryiko 
110094a1feddSAndrii Nakryiko 	/* pre-alloc memory and read all of BTF data */
110194a1feddSAndrii Nakryiko 	data = malloc(sz);
110294a1feddSAndrii Nakryiko 	if (!data) {
110394a1feddSAndrii Nakryiko 		err = -ENOMEM;
110494a1feddSAndrii Nakryiko 		goto err_out;
110594a1feddSAndrii Nakryiko 	}
110694a1feddSAndrii Nakryiko 	if (fread(data, 1, sz, f) < sz) {
110794a1feddSAndrii Nakryiko 		err = -EIO;
110894a1feddSAndrii Nakryiko 		goto err_out;
110994a1feddSAndrii Nakryiko 	}
111094a1feddSAndrii Nakryiko 
111194a1feddSAndrii Nakryiko 	/* finally parse BTF data */
1112ba451366SAndrii Nakryiko 	btf = btf_new(data, sz, base_btf);
111394a1feddSAndrii Nakryiko 
111494a1feddSAndrii Nakryiko err_out:
111594a1feddSAndrii Nakryiko 	free(data);
111694a1feddSAndrii Nakryiko 	if (f)
111794a1feddSAndrii Nakryiko 		fclose(f);
111894a1feddSAndrii Nakryiko 	return err ? ERR_PTR(err) : btf;
111994a1feddSAndrii Nakryiko }
112094a1feddSAndrii Nakryiko 
btf__parse_raw(const char * path)1121ba451366SAndrii Nakryiko struct btf *btf__parse_raw(const char *path)
1122ba451366SAndrii Nakryiko {
1123e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_raw(path, NULL));
1124ba451366SAndrii Nakryiko }
1125ba451366SAndrii Nakryiko 
btf__parse_raw_split(const char * path,struct btf * base_btf)1126ba451366SAndrii Nakryiko struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
1127ba451366SAndrii Nakryiko {
1128e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_raw(path, base_btf));
1129ba451366SAndrii Nakryiko }
1130ba451366SAndrii Nakryiko 
btf_parse(const char * path,struct btf * base_btf,struct btf_ext ** btf_ext)1131ba451366SAndrii Nakryiko static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
113294a1feddSAndrii Nakryiko {
113394a1feddSAndrii Nakryiko 	struct btf *btf;
1134e9fc3ce9SAndrii Nakryiko 	int err;
113594a1feddSAndrii Nakryiko 
113694a1feddSAndrii Nakryiko 	if (btf_ext)
113794a1feddSAndrii Nakryiko 		*btf_ext = NULL;
113894a1feddSAndrii Nakryiko 
1139ba451366SAndrii Nakryiko 	btf = btf_parse_raw(path, base_btf);
1140e9fc3ce9SAndrii Nakryiko 	err = libbpf_get_error(btf);
1141e9fc3ce9SAndrii Nakryiko 	if (!err)
114294a1feddSAndrii Nakryiko 		return btf;
1143e9fc3ce9SAndrii Nakryiko 	if (err != -EPROTO)
1144e9fc3ce9SAndrii Nakryiko 		return ERR_PTR(err);
1145ba451366SAndrii Nakryiko 	return btf_parse_elf(path, base_btf, btf_ext);
1146ba451366SAndrii Nakryiko }
1147ba451366SAndrii Nakryiko 
btf__parse(const char * path,struct btf_ext ** btf_ext)1148ba451366SAndrii Nakryiko struct btf *btf__parse(const char *path, struct btf_ext **btf_ext)
1149ba451366SAndrii Nakryiko {
1150e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse(path, NULL, btf_ext));
1151ba451366SAndrii Nakryiko }
1152ba451366SAndrii Nakryiko 
btf__parse_split(const char * path,struct btf * base_btf)1153ba451366SAndrii Nakryiko struct btf *btf__parse_split(const char *path, struct btf *base_btf)
1154ba451366SAndrii Nakryiko {
1155e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse(path, base_btf, NULL));
115694a1feddSAndrii Nakryiko }
115794a1feddSAndrii Nakryiko 
11583289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
11593289959bSAndrii Nakryiko 
btf_load_into_kernel(struct btf * btf,char * log_buf,size_t log_sz,__u32 log_level)11601a190d1eSAndrii Nakryiko int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level)
1161d29d87f7SAndrii Nakryiko {
11621a190d1eSAndrii Nakryiko 	LIBBPF_OPTS(bpf_btf_load_opts, opts);
11631a190d1eSAndrii Nakryiko 	__u32 buf_sz = 0, raw_size;
11641a190d1eSAndrii Nakryiko 	char *buf = NULL, *tmp;
11653289959bSAndrii Nakryiko 	void *raw_data;
1166d29d87f7SAndrii Nakryiko 	int err = 0;
1167d29d87f7SAndrii Nakryiko 
1168d29d87f7SAndrii Nakryiko 	if (btf->fd >= 0)
1169e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EEXIST);
11701a190d1eSAndrii Nakryiko 	if (log_sz && !log_buf)
11711a190d1eSAndrii Nakryiko 		return libbpf_err(-EINVAL);
1172d29d87f7SAndrii Nakryiko 
11731a190d1eSAndrii Nakryiko 	/* cache native raw data representation */
11743289959bSAndrii Nakryiko 	raw_data = btf_get_raw_data(btf, &raw_size, false);
1175b8604247SAndrii Nakryiko 	if (!raw_data) {
1176b8604247SAndrii Nakryiko 		err = -ENOMEM;
1177b8604247SAndrii Nakryiko 		goto done;
1178b8604247SAndrii Nakryiko 	}
11793289959bSAndrii Nakryiko 	btf->raw_size = raw_size;
11803289959bSAndrii Nakryiko 	btf->raw_data = raw_data;
1181b8604247SAndrii Nakryiko 
11821a190d1eSAndrii Nakryiko retry_load:
11831a190d1eSAndrii Nakryiko 	/* if log_level is 0, we won't provide log_buf/log_size to the kernel,
11841a190d1eSAndrii Nakryiko 	 * initially. Only if BTF loading fails, we bump log_level to 1 and
11851a190d1eSAndrii Nakryiko 	 * retry, using either auto-allocated or custom log_buf. This way
11861a190d1eSAndrii Nakryiko 	 * non-NULL custom log_buf provides a buffer just in case, but hopes
11871a190d1eSAndrii Nakryiko 	 * for successful load and no need for log_buf.
11881a190d1eSAndrii Nakryiko 	 */
11891a190d1eSAndrii Nakryiko 	if (log_level) {
11901a190d1eSAndrii Nakryiko 		/* if caller didn't provide custom log_buf, we'll keep
11911a190d1eSAndrii Nakryiko 		 * allocating our own progressively bigger buffers for BTF
11921a190d1eSAndrii Nakryiko 		 * verification log
11931a190d1eSAndrii Nakryiko 		 */
11941a190d1eSAndrii Nakryiko 		if (!log_buf) {
11951a190d1eSAndrii Nakryiko 			buf_sz = max((__u32)BPF_LOG_BUF_SIZE, buf_sz * 2);
11961a190d1eSAndrii Nakryiko 			tmp = realloc(buf, buf_sz);
11971a190d1eSAndrii Nakryiko 			if (!tmp) {
11981a190d1eSAndrii Nakryiko 				err = -ENOMEM;
11991a190d1eSAndrii Nakryiko 				goto done;
12001a190d1eSAndrii Nakryiko 			}
12011a190d1eSAndrii Nakryiko 			buf = tmp;
12021a190d1eSAndrii Nakryiko 			buf[0] = '\0';
12038395f320SStanislav Fomichev 		}
12048395f320SStanislav Fomichev 
12051a190d1eSAndrii Nakryiko 		opts.log_buf = log_buf ? log_buf : buf;
12061a190d1eSAndrii Nakryiko 		opts.log_size = log_buf ? log_sz : buf_sz;
12071a190d1eSAndrii Nakryiko 		opts.log_level = log_level;
12081a190d1eSAndrii Nakryiko 	}
12091a190d1eSAndrii Nakryiko 
12101a190d1eSAndrii Nakryiko 	btf->fd = bpf_btf_load(raw_data, raw_size, &opts);
12111a190d1eSAndrii Nakryiko 	if (btf->fd < 0) {
12121a190d1eSAndrii Nakryiko 		/* time to turn on verbose mode and try again */
12131a190d1eSAndrii Nakryiko 		if (log_level == 0) {
12141a190d1eSAndrii Nakryiko 			log_level = 1;
12151a190d1eSAndrii Nakryiko 			goto retry_load;
12161a190d1eSAndrii Nakryiko 		}
12171a190d1eSAndrii Nakryiko 		/* only retry if caller didn't provide custom log_buf, but
12181a190d1eSAndrii Nakryiko 		 * make sure we can never overflow buf_sz
12191a190d1eSAndrii Nakryiko 		 */
12201a190d1eSAndrii Nakryiko 		if (!log_buf && errno == ENOSPC && buf_sz <= UINT_MAX / 2)
12211a190d1eSAndrii Nakryiko 			goto retry_load;
12221a190d1eSAndrii Nakryiko 
1223d29d87f7SAndrii Nakryiko 		err = -errno;
12241a190d1eSAndrii Nakryiko 		pr_warn("BTF loading error: %d\n", err);
12251a190d1eSAndrii Nakryiko 		/* don't print out contents of custom log_buf */
12261a190d1eSAndrii Nakryiko 		if (!log_buf && buf[0])
12271a190d1eSAndrii Nakryiko 			pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf);
1228d29d87f7SAndrii Nakryiko 	}
1229d29d87f7SAndrii Nakryiko 
1230d29d87f7SAndrii Nakryiko done:
12311a190d1eSAndrii Nakryiko 	free(buf);
1232e9fc3ce9SAndrii Nakryiko 	return libbpf_err(err);
1233d29d87f7SAndrii Nakryiko }
12341a190d1eSAndrii Nakryiko 
btf__load_into_kernel(struct btf * btf)12351a190d1eSAndrii Nakryiko int btf__load_into_kernel(struct btf *btf)
12361a190d1eSAndrii Nakryiko {
12371a190d1eSAndrii Nakryiko 	return btf_load_into_kernel(btf, NULL, 0, 0);
12381a190d1eSAndrii Nakryiko }
12391a190d1eSAndrii Nakryiko 
btf__fd(const struct btf * btf)12408a138aedSMartin KaFai Lau int btf__fd(const struct btf *btf)
12418a138aedSMartin KaFai Lau {
12428a138aedSMartin KaFai Lau 	return btf->fd;
12438a138aedSMartin KaFai Lau }
124492b57121SOkash Khawaja 
btf__set_fd(struct btf * btf,int fd)124581372e12SAndrii Nakryiko void btf__set_fd(struct btf *btf, int fd)
124681372e12SAndrii Nakryiko {
124781372e12SAndrii Nakryiko 	btf->fd = fd;
124881372e12SAndrii Nakryiko }
124981372e12SAndrii Nakryiko 
btf_strs_data(const struct btf * btf)125090d76d3eSAndrii Nakryiko static const void *btf_strs_data(const struct btf *btf)
125190d76d3eSAndrii Nakryiko {
125290d76d3eSAndrii Nakryiko 	return btf->strs_data ? btf->strs_data : strset__data(btf->strs_set);
125390d76d3eSAndrii Nakryiko }
125490d76d3eSAndrii Nakryiko 
btf_get_raw_data(const struct btf * btf,__u32 * size,bool swap_endian)12553289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian)
12563289959bSAndrii Nakryiko {
12573289959bSAndrii Nakryiko 	struct btf_header *hdr = btf->hdr;
12583289959bSAndrii Nakryiko 	struct btf_type *t;
12593289959bSAndrii Nakryiko 	void *data, *p;
12603289959bSAndrii Nakryiko 	__u32 data_sz;
12613289959bSAndrii Nakryiko 	int i;
12623289959bSAndrii Nakryiko 
12633289959bSAndrii Nakryiko 	data = swap_endian ? btf->raw_data_swapped : btf->raw_data;
12643289959bSAndrii Nakryiko 	if (data) {
12653289959bSAndrii Nakryiko 		*size = btf->raw_size;
12663289959bSAndrii Nakryiko 		return data;
12673289959bSAndrii Nakryiko 	}
12683289959bSAndrii Nakryiko 
12693289959bSAndrii Nakryiko 	data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len;
12703289959bSAndrii Nakryiko 	data = calloc(1, data_sz);
12713289959bSAndrii Nakryiko 	if (!data)
12723289959bSAndrii Nakryiko 		return NULL;
12733289959bSAndrii Nakryiko 	p = data;
12743289959bSAndrii Nakryiko 
12753289959bSAndrii Nakryiko 	memcpy(p, hdr, hdr->hdr_len);
12763289959bSAndrii Nakryiko 	if (swap_endian)
12773289959bSAndrii Nakryiko 		btf_bswap_hdr(p);
12783289959bSAndrii Nakryiko 	p += hdr->hdr_len;
12793289959bSAndrii Nakryiko 
12803289959bSAndrii Nakryiko 	memcpy(p, btf->types_data, hdr->type_len);
12813289959bSAndrii Nakryiko 	if (swap_endian) {
1282ba451366SAndrii Nakryiko 		for (i = 0; i < btf->nr_types; i++) {
12833289959bSAndrii Nakryiko 			t = p + btf->type_offs[i];
12843289959bSAndrii Nakryiko 			/* btf_bswap_type_rest() relies on native t->info, so
12853289959bSAndrii Nakryiko 			 * we swap base type info after we swapped all the
12863289959bSAndrii Nakryiko 			 * additional information
12873289959bSAndrii Nakryiko 			 */
12883289959bSAndrii Nakryiko 			if (btf_bswap_type_rest(t))
12893289959bSAndrii Nakryiko 				goto err_out;
12903289959bSAndrii Nakryiko 			btf_bswap_type_base(t);
12913289959bSAndrii Nakryiko 		}
12923289959bSAndrii Nakryiko 	}
12933289959bSAndrii Nakryiko 	p += hdr->type_len;
12943289959bSAndrii Nakryiko 
129590d76d3eSAndrii Nakryiko 	memcpy(p, btf_strs_data(btf), hdr->str_len);
12963289959bSAndrii Nakryiko 	p += hdr->str_len;
12973289959bSAndrii Nakryiko 
12983289959bSAndrii Nakryiko 	*size = data_sz;
12993289959bSAndrii Nakryiko 	return data;
13003289959bSAndrii Nakryiko err_out:
13013289959bSAndrii Nakryiko 	free(data);
13023289959bSAndrii Nakryiko 	return NULL;
13033289959bSAndrii Nakryiko }
13043289959bSAndrii Nakryiko 
btf__raw_data(const struct btf * btf_ro,__u32 * size)13056a886de0SHengqi Chen const void *btf__raw_data(const struct btf *btf_ro, __u32 *size)
130602c87446SAndrii Nakryiko {
1307919d2b1dSAndrii Nakryiko 	struct btf *btf = (struct btf *)btf_ro;
13083289959bSAndrii Nakryiko 	__u32 data_sz;
1309919d2b1dSAndrii Nakryiko 	void *data;
1310919d2b1dSAndrii Nakryiko 
13113289959bSAndrii Nakryiko 	data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian);
13123289959bSAndrii Nakryiko 	if (!data)
13136a886de0SHengqi Chen 		return errno = ENOMEM, NULL;
1314919d2b1dSAndrii Nakryiko 
13153289959bSAndrii Nakryiko 	btf->raw_size = data_sz;
13163289959bSAndrii Nakryiko 	if (btf->swapped_endian)
13173289959bSAndrii Nakryiko 		btf->raw_data_swapped = data;
13183289959bSAndrii Nakryiko 	else
13193289959bSAndrii Nakryiko 		btf->raw_data = data;
13203289959bSAndrii Nakryiko 	*size = data_sz;
13213289959bSAndrii Nakryiko 	return data;
132202c87446SAndrii Nakryiko }
132302c87446SAndrii Nakryiko 
13246a886de0SHengqi Chen __attribute__((alias("btf__raw_data")))
13256a886de0SHengqi Chen const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
13266a886de0SHengqi Chen 
btf__str_by_offset(const struct btf * btf,__u32 offset)1327f86ed050SAndrii Nakryiko const char *btf__str_by_offset(const struct btf *btf, __u32 offset)
132892b57121SOkash Khawaja {
1329ba451366SAndrii Nakryiko 	if (offset < btf->start_str_off)
1330ba451366SAndrii Nakryiko 		return btf__str_by_offset(btf->base_btf, offset);
1331ba451366SAndrii Nakryiko 	else if (offset - btf->start_str_off < btf->hdr->str_len)
133290d76d3eSAndrii Nakryiko 		return btf_strs_data(btf) + (offset - btf->start_str_off);
133392b57121SOkash Khawaja 	else
1334e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, NULL;
133592b57121SOkash Khawaja }
13362993e051SYonghong Song 
btf__name_by_offset(const struct btf * btf,__u32 offset)1337f86ed050SAndrii Nakryiko const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
1338f86ed050SAndrii Nakryiko {
1339f86ed050SAndrii Nakryiko 	return btf__str_by_offset(btf, offset);
1340f86ed050SAndrii Nakryiko }
1341f86ed050SAndrii Nakryiko 
btf_get_from_fd(int btf_fd,struct btf * base_btf)1342a19f93cfSAndrii Nakryiko struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
1343d7f5b5e0SYonghong Song {
1344a19f93cfSAndrii Nakryiko 	struct bpf_btf_info btf_info;
1345d7f5b5e0SYonghong Song 	__u32 len = sizeof(btf_info);
1346d7f5b5e0SYonghong Song 	__u32 last_size;
1347a19f93cfSAndrii Nakryiko 	struct btf *btf;
1348d7f5b5e0SYonghong Song 	void *ptr;
1349d7f5b5e0SYonghong Song 	int err;
1350d7f5b5e0SYonghong Song 
1351629dfc66SIlya Leoshkevich 	/* we won't know btf_size until we call bpf_btf_get_info_by_fd(). so
1352d7f5b5e0SYonghong Song 	 * let's start with a sane default - 4KiB here - and resize it only if
1353629dfc66SIlya Leoshkevich 	 * bpf_btf_get_info_by_fd() needs a bigger buffer.
1354d7f5b5e0SYonghong Song 	 */
1355a19f93cfSAndrii Nakryiko 	last_size = 4096;
1356d7f5b5e0SYonghong Song 	ptr = malloc(last_size);
1357a19f93cfSAndrii Nakryiko 	if (!ptr)
1358a19f93cfSAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
1359d7f5b5e0SYonghong Song 
1360a19f93cfSAndrii Nakryiko 	memset(&btf_info, 0, sizeof(btf_info));
1361d7f5b5e0SYonghong Song 	btf_info.btf = ptr_to_u64(ptr);
1362a19f93cfSAndrii Nakryiko 	btf_info.btf_size = last_size;
1363629dfc66SIlya Leoshkevich 	err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
1364d7f5b5e0SYonghong Song 
1365d7f5b5e0SYonghong Song 	if (!err && btf_info.btf_size > last_size) {
1366d7f5b5e0SYonghong Song 		void *temp_ptr;
1367d7f5b5e0SYonghong Song 
1368d7f5b5e0SYonghong Song 		last_size = btf_info.btf_size;
1369d7f5b5e0SYonghong Song 		temp_ptr = realloc(ptr, last_size);
1370d7f5b5e0SYonghong Song 		if (!temp_ptr) {
1371a19f93cfSAndrii Nakryiko 			btf = ERR_PTR(-ENOMEM);
1372d7f5b5e0SYonghong Song 			goto exit_free;
1373d7f5b5e0SYonghong Song 		}
1374d7f5b5e0SYonghong Song 		ptr = temp_ptr;
1375a19f93cfSAndrii Nakryiko 
1376a19f93cfSAndrii Nakryiko 		len = sizeof(btf_info);
1377a19f93cfSAndrii Nakryiko 		memset(&btf_info, 0, sizeof(btf_info));
1378d7f5b5e0SYonghong Song 		btf_info.btf = ptr_to_u64(ptr);
1379a19f93cfSAndrii Nakryiko 		btf_info.btf_size = last_size;
1380a19f93cfSAndrii Nakryiko 
1381629dfc66SIlya Leoshkevich 		err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
1382d7f5b5e0SYonghong Song 	}
1383d7f5b5e0SYonghong Song 
1384d7f5b5e0SYonghong Song 	if (err || btf_info.btf_size > last_size) {
1385a19f93cfSAndrii Nakryiko 		btf = err ? ERR_PTR(-errno) : ERR_PTR(-E2BIG);
1386d7f5b5e0SYonghong Song 		goto exit_free;
1387d7f5b5e0SYonghong Song 	}
1388d7f5b5e0SYonghong Song 
1389a19f93cfSAndrii Nakryiko 	btf = btf_new(ptr, btf_info.btf_size, base_btf);
1390d7f5b5e0SYonghong Song 
1391d7f5b5e0SYonghong Song exit_free:
1392d7f5b5e0SYonghong Song 	free(ptr);
1393a19f93cfSAndrii Nakryiko 	return btf;
1394a19f93cfSAndrii Nakryiko }
1395d7f5b5e0SYonghong Song 
btf__load_from_kernel_by_id_split(__u32 id,struct btf * base_btf)139661fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
13976cc93e2fSQuentin Monnet {
13986cc93e2fSQuentin Monnet 	struct btf *btf;
13996cc93e2fSQuentin Monnet 	int btf_fd;
14006cc93e2fSQuentin Monnet 
14016cc93e2fSQuentin Monnet 	btf_fd = bpf_btf_get_fd_by_id(id);
14026cc93e2fSQuentin Monnet 	if (btf_fd < 0)
14036cc93e2fSQuentin Monnet 		return libbpf_err_ptr(-errno);
14046cc93e2fSQuentin Monnet 
140561fc51b1SQuentin Monnet 	btf = btf_get_from_fd(btf_fd, base_btf);
14066cc93e2fSQuentin Monnet 	close(btf_fd);
14076cc93e2fSQuentin Monnet 
14086cc93e2fSQuentin Monnet 	return libbpf_ptr(btf);
14096cc93e2fSQuentin Monnet }
14106cc93e2fSQuentin Monnet 
btf__load_from_kernel_by_id(__u32 id)141161fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id(__u32 id)
141261fc51b1SQuentin Monnet {
141361fc51b1SQuentin Monnet 	return btf__load_from_kernel_by_id_split(id, NULL);
141461fc51b1SQuentin Monnet }
141561fc51b1SQuentin Monnet 
btf_invalidate_raw_data(struct btf * btf)14163289959bSAndrii Nakryiko static void btf_invalidate_raw_data(struct btf *btf)
14173289959bSAndrii Nakryiko {
14183289959bSAndrii Nakryiko 	if (btf->raw_data) {
14193289959bSAndrii Nakryiko 		free(btf->raw_data);
14203289959bSAndrii Nakryiko 		btf->raw_data = NULL;
14213289959bSAndrii Nakryiko 	}
14223289959bSAndrii Nakryiko 	if (btf->raw_data_swapped) {
14233289959bSAndrii Nakryiko 		free(btf->raw_data_swapped);
14243289959bSAndrii Nakryiko 		btf->raw_data_swapped = NULL;
14253289959bSAndrii Nakryiko 	}
14263289959bSAndrii Nakryiko }
14273289959bSAndrii Nakryiko 
1428919d2b1dSAndrii Nakryiko /* Ensure BTF is ready to be modified (by splitting into a three memory
1429919d2b1dSAndrii Nakryiko  * regions for header, types, and strings). Also invalidate cached
1430919d2b1dSAndrii Nakryiko  * raw_data, if any.
1431919d2b1dSAndrii Nakryiko  */
btf_ensure_modifiable(struct btf * btf)1432919d2b1dSAndrii Nakryiko static int btf_ensure_modifiable(struct btf *btf)
1433919d2b1dSAndrii Nakryiko {
143490d76d3eSAndrii Nakryiko 	void *hdr, *types;
143590d76d3eSAndrii Nakryiko 	struct strset *set = NULL;
143690d76d3eSAndrii Nakryiko 	int err = -ENOMEM;
1437919d2b1dSAndrii Nakryiko 
1438919d2b1dSAndrii Nakryiko 	if (btf_is_modifiable(btf)) {
1439919d2b1dSAndrii Nakryiko 		/* any BTF modification invalidates raw_data */
14403289959bSAndrii Nakryiko 		btf_invalidate_raw_data(btf);
1441919d2b1dSAndrii Nakryiko 		return 0;
1442919d2b1dSAndrii Nakryiko 	}
1443919d2b1dSAndrii Nakryiko 
1444919d2b1dSAndrii Nakryiko 	/* split raw data into three memory regions */
1445919d2b1dSAndrii Nakryiko 	hdr = malloc(btf->hdr->hdr_len);
1446919d2b1dSAndrii Nakryiko 	types = malloc(btf->hdr->type_len);
144790d76d3eSAndrii Nakryiko 	if (!hdr || !types)
1448919d2b1dSAndrii Nakryiko 		goto err_out;
1449919d2b1dSAndrii Nakryiko 
1450919d2b1dSAndrii Nakryiko 	memcpy(hdr, btf->hdr, btf->hdr->hdr_len);
1451919d2b1dSAndrii Nakryiko 	memcpy(types, btf->types_data, btf->hdr->type_len);
145288a82c2aSAndrii Nakryiko 
1453919d2b1dSAndrii Nakryiko 	/* build lookup index for all strings */
145490d76d3eSAndrii Nakryiko 	set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len);
145590d76d3eSAndrii Nakryiko 	if (IS_ERR(set)) {
145690d76d3eSAndrii Nakryiko 		err = PTR_ERR(set);
1457919d2b1dSAndrii Nakryiko 		goto err_out;
1458919d2b1dSAndrii Nakryiko 	}
1459919d2b1dSAndrii Nakryiko 
1460919d2b1dSAndrii Nakryiko 	/* only when everything was successful, update internal state */
1461919d2b1dSAndrii Nakryiko 	btf->hdr = hdr;
1462919d2b1dSAndrii Nakryiko 	btf->types_data = types;
1463919d2b1dSAndrii Nakryiko 	btf->types_data_cap = btf->hdr->type_len;
146490d76d3eSAndrii Nakryiko 	btf->strs_data = NULL;
146590d76d3eSAndrii Nakryiko 	btf->strs_set = set;
1466919d2b1dSAndrii Nakryiko 	/* if BTF was created from scratch, all strings are guaranteed to be
1467919d2b1dSAndrii Nakryiko 	 * unique and deduplicated
1468919d2b1dSAndrii Nakryiko 	 */
1469ba451366SAndrii Nakryiko 	if (btf->hdr->str_len == 0)
1470ba451366SAndrii Nakryiko 		btf->strs_deduped = true;
1471ba451366SAndrii Nakryiko 	if (!btf->base_btf && btf->hdr->str_len == 1)
1472ba451366SAndrii Nakryiko 		btf->strs_deduped = true;
1473919d2b1dSAndrii Nakryiko 
1474919d2b1dSAndrii Nakryiko 	/* invalidate raw_data representation */
14753289959bSAndrii Nakryiko 	btf_invalidate_raw_data(btf);
1476919d2b1dSAndrii Nakryiko 
1477919d2b1dSAndrii Nakryiko 	return 0;
1478919d2b1dSAndrii Nakryiko 
1479919d2b1dSAndrii Nakryiko err_out:
148090d76d3eSAndrii Nakryiko 	strset__free(set);
1481919d2b1dSAndrii Nakryiko 	free(hdr);
1482919d2b1dSAndrii Nakryiko 	free(types);
148390d76d3eSAndrii Nakryiko 	return err;
1484919d2b1dSAndrii Nakryiko }
1485919d2b1dSAndrii Nakryiko 
1486919d2b1dSAndrii Nakryiko /* Find an offset in BTF string section that corresponds to a given string *s*.
1487919d2b1dSAndrii Nakryiko  * Returns:
1488919d2b1dSAndrii Nakryiko  *   - >0 offset into string section, if string is found;
1489919d2b1dSAndrii Nakryiko  *   - -ENOENT, if string is not in the string section;
1490919d2b1dSAndrii Nakryiko  *   - <0, on any other error.
1491919d2b1dSAndrii Nakryiko  */
btf__find_str(struct btf * btf,const char * s)1492919d2b1dSAndrii Nakryiko int btf__find_str(struct btf *btf, const char *s)
1493919d2b1dSAndrii Nakryiko {
149490d76d3eSAndrii Nakryiko 	int off;
1495919d2b1dSAndrii Nakryiko 
1496ba451366SAndrii Nakryiko 	if (btf->base_btf) {
149790d76d3eSAndrii Nakryiko 		off = btf__find_str(btf->base_btf, s);
149890d76d3eSAndrii Nakryiko 		if (off != -ENOENT)
149990d76d3eSAndrii Nakryiko 			return off;
1500ba451366SAndrii Nakryiko 	}
1501ba451366SAndrii Nakryiko 
1502919d2b1dSAndrii Nakryiko 	/* BTF needs to be in a modifiable state to build string lookup index */
1503919d2b1dSAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1504e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
1505919d2b1dSAndrii Nakryiko 
150690d76d3eSAndrii Nakryiko 	off = strset__find_str(btf->strs_set, s);
150790d76d3eSAndrii Nakryiko 	if (off < 0)
1508e9fc3ce9SAndrii Nakryiko 		return libbpf_err(off);
1509919d2b1dSAndrii Nakryiko 
151090d76d3eSAndrii Nakryiko 	return btf->start_str_off + off;
1511919d2b1dSAndrii Nakryiko }
1512919d2b1dSAndrii Nakryiko 
1513919d2b1dSAndrii Nakryiko /* Add a string s to the BTF string section.
1514919d2b1dSAndrii Nakryiko  * Returns:
1515919d2b1dSAndrii Nakryiko  *   - > 0 offset into string section, on success;
1516919d2b1dSAndrii Nakryiko  *   - < 0, on error.
1517919d2b1dSAndrii Nakryiko  */
btf__add_str(struct btf * btf,const char * s)1518919d2b1dSAndrii Nakryiko int btf__add_str(struct btf *btf, const char *s)
1519919d2b1dSAndrii Nakryiko {
152090d76d3eSAndrii Nakryiko 	int off;
1521919d2b1dSAndrii Nakryiko 
1522ba451366SAndrii Nakryiko 	if (btf->base_btf) {
152390d76d3eSAndrii Nakryiko 		off = btf__find_str(btf->base_btf, s);
152490d76d3eSAndrii Nakryiko 		if (off != -ENOENT)
152590d76d3eSAndrii Nakryiko 			return off;
1526ba451366SAndrii Nakryiko 	}
1527ba451366SAndrii Nakryiko 
1528919d2b1dSAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1529e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
1530919d2b1dSAndrii Nakryiko 
153190d76d3eSAndrii Nakryiko 	off = strset__add_str(btf->strs_set, s);
153290d76d3eSAndrii Nakryiko 	if (off < 0)
1533e9fc3ce9SAndrii Nakryiko 		return libbpf_err(off);
1534919d2b1dSAndrii Nakryiko 
153590d76d3eSAndrii Nakryiko 	btf->hdr->str_len = strset__data_size(btf->strs_set);
1536919d2b1dSAndrii Nakryiko 
153790d76d3eSAndrii Nakryiko 	return btf->start_str_off + off;
1538919d2b1dSAndrii Nakryiko }
1539919d2b1dSAndrii Nakryiko 
btf_add_type_mem(struct btf * btf,size_t add_sz)15404a3b33f8SAndrii Nakryiko static void *btf_add_type_mem(struct btf *btf, size_t add_sz)
15414a3b33f8SAndrii Nakryiko {
15423b029e06SAndrii Nakryiko 	return libbpf_add_mem(&btf->types_data, &btf->types_data_cap, 1,
15434a3b33f8SAndrii Nakryiko 			      btf->hdr->type_len, UINT_MAX, add_sz);
15444a3b33f8SAndrii Nakryiko }
15454a3b33f8SAndrii Nakryiko 
btf_type_inc_vlen(struct btf_type * t)15464a3b33f8SAndrii Nakryiko static void btf_type_inc_vlen(struct btf_type *t)
15474a3b33f8SAndrii Nakryiko {
15484a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
15494a3b33f8SAndrii Nakryiko }
15504a3b33f8SAndrii Nakryiko 
btf_commit_type(struct btf * btf,int data_sz)1551c81ed6d8SAndrii Nakryiko static int btf_commit_type(struct btf *btf, int data_sz)
1552c81ed6d8SAndrii Nakryiko {
1553c81ed6d8SAndrii Nakryiko 	int err;
1554c81ed6d8SAndrii Nakryiko 
1555c81ed6d8SAndrii Nakryiko 	err = btf_add_type_idx_entry(btf, btf->hdr->type_len);
1556c81ed6d8SAndrii Nakryiko 	if (err)
1557e9fc3ce9SAndrii Nakryiko 		return libbpf_err(err);
1558c81ed6d8SAndrii Nakryiko 
1559c81ed6d8SAndrii Nakryiko 	btf->hdr->type_len += data_sz;
1560c81ed6d8SAndrii Nakryiko 	btf->hdr->str_off += data_sz;
1561c81ed6d8SAndrii Nakryiko 	btf->nr_types++;
1562ba451366SAndrii Nakryiko 	return btf->start_id + btf->nr_types - 1;
1563c81ed6d8SAndrii Nakryiko }
1564c81ed6d8SAndrii Nakryiko 
15659af44bc5SAndrii Nakryiko struct btf_pipe {
15669af44bc5SAndrii Nakryiko 	const struct btf *src;
15679af44bc5SAndrii Nakryiko 	struct btf *dst;
1568d81283d2SKui-Feng Lee 	struct hashmap *str_off_map; /* map string offsets from src to dst */
15699af44bc5SAndrii Nakryiko };
15709af44bc5SAndrii Nakryiko 
btf_rewrite_str(__u32 * str_off,void * ctx)15719af44bc5SAndrii Nakryiko static int btf_rewrite_str(__u32 *str_off, void *ctx)
15729af44bc5SAndrii Nakryiko {
15739af44bc5SAndrii Nakryiko 	struct btf_pipe *p = ctx;
1574c302378bSEduard Zingerman 	long mapped_off;
1575d81283d2SKui-Feng Lee 	int off, err;
15769af44bc5SAndrii Nakryiko 
15779af44bc5SAndrii Nakryiko 	if (!*str_off) /* nothing to do for empty strings */
15789af44bc5SAndrii Nakryiko 		return 0;
15799af44bc5SAndrii Nakryiko 
1580d81283d2SKui-Feng Lee 	if (p->str_off_map &&
1581c302378bSEduard Zingerman 	    hashmap__find(p->str_off_map, *str_off, &mapped_off)) {
1582c302378bSEduard Zingerman 		*str_off = mapped_off;
1583d81283d2SKui-Feng Lee 		return 0;
1584d81283d2SKui-Feng Lee 	}
1585d81283d2SKui-Feng Lee 
15869af44bc5SAndrii Nakryiko 	off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off));
15879af44bc5SAndrii Nakryiko 	if (off < 0)
15889af44bc5SAndrii Nakryiko 		return off;
15899af44bc5SAndrii Nakryiko 
1590d81283d2SKui-Feng Lee 	/* Remember string mapping from src to dst.  It avoids
1591d81283d2SKui-Feng Lee 	 * performing expensive string comparisons.
1592d81283d2SKui-Feng Lee 	 */
1593d81283d2SKui-Feng Lee 	if (p->str_off_map) {
1594c302378bSEduard Zingerman 		err = hashmap__append(p->str_off_map, *str_off, off);
1595d81283d2SKui-Feng Lee 		if (err)
1596d81283d2SKui-Feng Lee 			return err;
1597d81283d2SKui-Feng Lee 	}
1598d81283d2SKui-Feng Lee 
15999af44bc5SAndrii Nakryiko 	*str_off = off;
16009af44bc5SAndrii Nakryiko 	return 0;
16019af44bc5SAndrii Nakryiko }
16029af44bc5SAndrii Nakryiko 
btf__add_type(struct btf * btf,const struct btf * src_btf,const struct btf_type * src_type)16039af44bc5SAndrii Nakryiko int btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type)
16049af44bc5SAndrii Nakryiko {
16059af44bc5SAndrii Nakryiko 	struct btf_pipe p = { .src = src_btf, .dst = btf };
16069af44bc5SAndrii Nakryiko 	struct btf_type *t;
16079af44bc5SAndrii Nakryiko 	int sz, err;
16089af44bc5SAndrii Nakryiko 
16099af44bc5SAndrii Nakryiko 	sz = btf_type_size(src_type);
16109af44bc5SAndrii Nakryiko 	if (sz < 0)
1611e9fc3ce9SAndrii Nakryiko 		return libbpf_err(sz);
16129af44bc5SAndrii Nakryiko 
16139af44bc5SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
16149af44bc5SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1615e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16169af44bc5SAndrii Nakryiko 
16179af44bc5SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
16189af44bc5SAndrii Nakryiko 	if (!t)
1619e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16209af44bc5SAndrii Nakryiko 
16219af44bc5SAndrii Nakryiko 	memcpy(t, src_type, sz);
16229af44bc5SAndrii Nakryiko 
16239af44bc5SAndrii Nakryiko 	err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
16249af44bc5SAndrii Nakryiko 	if (err)
1625e9fc3ce9SAndrii Nakryiko 		return libbpf_err(err);
16269af44bc5SAndrii Nakryiko 
16279af44bc5SAndrii Nakryiko 	return btf_commit_type(btf, sz);
16289af44bc5SAndrii Nakryiko }
16299af44bc5SAndrii Nakryiko 
btf_rewrite_type_ids(__u32 * type_id,void * ctx)16307ca61121SAndrii Nakryiko static int btf_rewrite_type_ids(__u32 *type_id, void *ctx)
16317ca61121SAndrii Nakryiko {
16327ca61121SAndrii Nakryiko 	struct btf *btf = ctx;
16337ca61121SAndrii Nakryiko 
16347ca61121SAndrii Nakryiko 	if (!*type_id) /* nothing to do for VOID references */
16357ca61121SAndrii Nakryiko 		return 0;
16367ca61121SAndrii Nakryiko 
16377ca61121SAndrii Nakryiko 	/* we haven't updated btf's type count yet, so
16387ca61121SAndrii Nakryiko 	 * btf->start_id + btf->nr_types - 1 is the type ID offset we should
16397ca61121SAndrii Nakryiko 	 * add to all newly added BTF types
16407ca61121SAndrii Nakryiko 	 */
16417ca61121SAndrii Nakryiko 	*type_id += btf->start_id + btf->nr_types - 1;
16427ca61121SAndrii Nakryiko 	return 0;
16437ca61121SAndrii Nakryiko }
16447ca61121SAndrii Nakryiko 
1645c302378bSEduard Zingerman static size_t btf_dedup_identity_hash_fn(long key, void *ctx);
1646c302378bSEduard Zingerman static bool btf_dedup_equal_fn(long k1, long k2, void *ctx);
1647d81283d2SKui-Feng Lee 
btf__add_btf(struct btf * btf,const struct btf * src_btf)16487ca61121SAndrii Nakryiko int btf__add_btf(struct btf *btf, const struct btf *src_btf)
16497ca61121SAndrii Nakryiko {
16507ca61121SAndrii Nakryiko 	struct btf_pipe p = { .src = src_btf, .dst = btf };
16517ca61121SAndrii Nakryiko 	int data_sz, sz, cnt, i, err, old_strs_len;
16527ca61121SAndrii Nakryiko 	__u32 *off;
16537ca61121SAndrii Nakryiko 	void *t;
16547ca61121SAndrii Nakryiko 
16557ca61121SAndrii Nakryiko 	/* appending split BTF isn't supported yet */
16567ca61121SAndrii Nakryiko 	if (src_btf->base_btf)
16577ca61121SAndrii Nakryiko 		return libbpf_err(-ENOTSUP);
16587ca61121SAndrii Nakryiko 
16597ca61121SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
16607ca61121SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
16617ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16627ca61121SAndrii Nakryiko 
16637ca61121SAndrii Nakryiko 	/* remember original strings section size if we have to roll back
16647ca61121SAndrii Nakryiko 	 * partial strings section changes
16657ca61121SAndrii Nakryiko 	 */
16667ca61121SAndrii Nakryiko 	old_strs_len = btf->hdr->str_len;
16677ca61121SAndrii Nakryiko 
16687ca61121SAndrii Nakryiko 	data_sz = src_btf->hdr->type_len;
16696a886de0SHengqi Chen 	cnt = btf__type_cnt(src_btf) - 1;
16707ca61121SAndrii Nakryiko 
16717ca61121SAndrii Nakryiko 	/* pre-allocate enough memory for new types */
16727ca61121SAndrii Nakryiko 	t = btf_add_type_mem(btf, data_sz);
16737ca61121SAndrii Nakryiko 	if (!t)
16747ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16757ca61121SAndrii Nakryiko 
16767ca61121SAndrii Nakryiko 	/* pre-allocate enough memory for type offset index for new types */
16777ca61121SAndrii Nakryiko 	off = btf_add_type_offs_mem(btf, cnt);
16787ca61121SAndrii Nakryiko 	if (!off)
16797ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16807ca61121SAndrii Nakryiko 
1681d81283d2SKui-Feng Lee 	/* Map the string offsets from src_btf to the offsets from btf to improve performance */
1682d81283d2SKui-Feng Lee 	p.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
1683d81283d2SKui-Feng Lee 	if (IS_ERR(p.str_off_map))
1684d81283d2SKui-Feng Lee 		return libbpf_err(-ENOMEM);
1685d81283d2SKui-Feng Lee 
16867ca61121SAndrii Nakryiko 	/* bulk copy types data for all types from src_btf */
16877ca61121SAndrii Nakryiko 	memcpy(t, src_btf->types_data, data_sz);
16887ca61121SAndrii Nakryiko 
16897ca61121SAndrii Nakryiko 	for (i = 0; i < cnt; i++) {
16907ca61121SAndrii Nakryiko 		sz = btf_type_size(t);
16917ca61121SAndrii Nakryiko 		if (sz < 0) {
16927ca61121SAndrii Nakryiko 			/* unlikely, has to be corrupted src_btf */
16937ca61121SAndrii Nakryiko 			err = sz;
16947ca61121SAndrii Nakryiko 			goto err_out;
16957ca61121SAndrii Nakryiko 		}
16967ca61121SAndrii Nakryiko 
16977ca61121SAndrii Nakryiko 		/* fill out type ID to type offset mapping for lookups by type ID */
16987ca61121SAndrii Nakryiko 		*off = t - btf->types_data;
16997ca61121SAndrii Nakryiko 
17007ca61121SAndrii Nakryiko 		/* add, dedup, and remap strings referenced by this BTF type */
17017ca61121SAndrii Nakryiko 		err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
17027ca61121SAndrii Nakryiko 		if (err)
17037ca61121SAndrii Nakryiko 			goto err_out;
17047ca61121SAndrii Nakryiko 
17057ca61121SAndrii Nakryiko 		/* remap all type IDs referenced from this BTF type */
17067ca61121SAndrii Nakryiko 		err = btf_type_visit_type_ids(t, btf_rewrite_type_ids, btf);
17077ca61121SAndrii Nakryiko 		if (err)
17087ca61121SAndrii Nakryiko 			goto err_out;
17097ca61121SAndrii Nakryiko 
17107ca61121SAndrii Nakryiko 		/* go to next type data and type offset index entry */
17117ca61121SAndrii Nakryiko 		t += sz;
17127ca61121SAndrii Nakryiko 		off++;
17137ca61121SAndrii Nakryiko 	}
17147ca61121SAndrii Nakryiko 
17157ca61121SAndrii Nakryiko 	/* Up until now any of the copied type data was effectively invisible,
17167ca61121SAndrii Nakryiko 	 * so if we exited early before this point due to error, BTF would be
17177ca61121SAndrii Nakryiko 	 * effectively unmodified. There would be extra internal memory
17187ca61121SAndrii Nakryiko 	 * pre-allocated, but it would not be available for querying.  But now
17197ca61121SAndrii Nakryiko 	 * that we've copied and rewritten all the data successfully, we can
17207ca61121SAndrii Nakryiko 	 * update type count and various internal offsets and sizes to
17217ca61121SAndrii Nakryiko 	 * "commit" the changes and made them visible to the outside world.
17227ca61121SAndrii Nakryiko 	 */
17237ca61121SAndrii Nakryiko 	btf->hdr->type_len += data_sz;
17247ca61121SAndrii Nakryiko 	btf->hdr->str_off += data_sz;
17257ca61121SAndrii Nakryiko 	btf->nr_types += cnt;
17267ca61121SAndrii Nakryiko 
1727d81283d2SKui-Feng Lee 	hashmap__free(p.str_off_map);
1728d81283d2SKui-Feng Lee 
17297ca61121SAndrii Nakryiko 	/* return type ID of the first added BTF type */
17307ca61121SAndrii Nakryiko 	return btf->start_id + btf->nr_types - cnt;
17317ca61121SAndrii Nakryiko err_out:
17327ca61121SAndrii Nakryiko 	/* zero out preallocated memory as if it was just allocated with
17337ca61121SAndrii Nakryiko 	 * libbpf_add_mem()
17347ca61121SAndrii Nakryiko 	 */
17357ca61121SAndrii Nakryiko 	memset(btf->types_data + btf->hdr->type_len, 0, data_sz);
17367ca61121SAndrii Nakryiko 	memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
17377ca61121SAndrii Nakryiko 
17387ca61121SAndrii Nakryiko 	/* and now restore original strings section size; types data size
1739c7694ac3SKang Minchul 	 * wasn't modified, so doesn't need restoring, see big comment above
1740c7694ac3SKang Minchul 	 */
17417ca61121SAndrii Nakryiko 	btf->hdr->str_len = old_strs_len;
17427ca61121SAndrii Nakryiko 
1743d81283d2SKui-Feng Lee 	hashmap__free(p.str_off_map);
1744d81283d2SKui-Feng Lee 
17457ca61121SAndrii Nakryiko 	return libbpf_err(err);
17467ca61121SAndrii Nakryiko }
17477ca61121SAndrii Nakryiko 
17484a3b33f8SAndrii Nakryiko /*
17494a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_INT type with:
17504a3b33f8SAndrii Nakryiko  *   - *name* - non-empty, non-NULL type name;
17514a3b33f8SAndrii Nakryiko  *   - *sz* - power-of-2 (1, 2, 4, ..) size of the type, in bytes;
17524a3b33f8SAndrii Nakryiko  *   - encoding is a combination of BTF_INT_SIGNED, BTF_INT_CHAR, BTF_INT_BOOL.
17534a3b33f8SAndrii Nakryiko  * Returns:
17544a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
17554a3b33f8SAndrii Nakryiko  *   - <0, on error.
17564a3b33f8SAndrii Nakryiko  */
btf__add_int(struct btf * btf,const char * name,size_t byte_sz,int encoding)17574a3b33f8SAndrii Nakryiko int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding)
17584a3b33f8SAndrii Nakryiko {
17594a3b33f8SAndrii Nakryiko 	struct btf_type *t;
1760c81ed6d8SAndrii Nakryiko 	int sz, name_off;
17614a3b33f8SAndrii Nakryiko 
17624a3b33f8SAndrii Nakryiko 	/* non-empty name */
17634a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
1764e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
17654a3b33f8SAndrii Nakryiko 	/* byte_sz must be power of 2 */
17664a3b33f8SAndrii Nakryiko 	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16)
1767e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
17684a3b33f8SAndrii Nakryiko 	if (encoding & ~(BTF_INT_SIGNED | BTF_INT_CHAR | BTF_INT_BOOL))
1769e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
17704a3b33f8SAndrii Nakryiko 
17714a3b33f8SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
17724a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1773e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17744a3b33f8SAndrii Nakryiko 
17754a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(int);
17764a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
17774a3b33f8SAndrii Nakryiko 	if (!t)
1778e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17794a3b33f8SAndrii Nakryiko 
17804a3b33f8SAndrii Nakryiko 	/* if something goes wrong later, we might end up with an extra string,
17814a3b33f8SAndrii Nakryiko 	 * but that shouldn't be a problem, because BTF can't be constructed
17824a3b33f8SAndrii Nakryiko 	 * completely anyway and will most probably be just discarded
17834a3b33f8SAndrii Nakryiko 	 */
17844a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
17854a3b33f8SAndrii Nakryiko 	if (name_off < 0)
17864a3b33f8SAndrii Nakryiko 		return name_off;
17874a3b33f8SAndrii Nakryiko 
17884a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
17894a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_INT, 0, 0);
17904a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
17914a3b33f8SAndrii Nakryiko 	/* set INT info, we don't allow setting legacy bit offset/size */
17924a3b33f8SAndrii Nakryiko 	*(__u32 *)(t + 1) = (encoding << 24) | (byte_sz * 8);
17934a3b33f8SAndrii Nakryiko 
1794c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
17954a3b33f8SAndrii Nakryiko }
17964a3b33f8SAndrii Nakryiko 
179722541a9eSIlya Leoshkevich /*
179822541a9eSIlya Leoshkevich  * Append new BTF_KIND_FLOAT type with:
179922541a9eSIlya Leoshkevich  *   - *name* - non-empty, non-NULL type name;
180022541a9eSIlya Leoshkevich  *   - *sz* - size of the type, in bytes;
180122541a9eSIlya Leoshkevich  * Returns:
180222541a9eSIlya Leoshkevich  *   - >0, type ID of newly added BTF type;
180322541a9eSIlya Leoshkevich  *   - <0, on error.
180422541a9eSIlya Leoshkevich  */
btf__add_float(struct btf * btf,const char * name,size_t byte_sz)180522541a9eSIlya Leoshkevich int btf__add_float(struct btf *btf, const char *name, size_t byte_sz)
180622541a9eSIlya Leoshkevich {
180722541a9eSIlya Leoshkevich 	struct btf_type *t;
180822541a9eSIlya Leoshkevich 	int sz, name_off;
180922541a9eSIlya Leoshkevich 
181022541a9eSIlya Leoshkevich 	/* non-empty name */
181122541a9eSIlya Leoshkevich 	if (!name || !name[0])
1812e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
181322541a9eSIlya Leoshkevich 
181422541a9eSIlya Leoshkevich 	/* byte_sz must be one of the explicitly allowed values */
181522541a9eSIlya Leoshkevich 	if (byte_sz != 2 && byte_sz != 4 && byte_sz != 8 && byte_sz != 12 &&
181622541a9eSIlya Leoshkevich 	    byte_sz != 16)
1817e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
181822541a9eSIlya Leoshkevich 
181922541a9eSIlya Leoshkevich 	if (btf_ensure_modifiable(btf))
1820e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
182122541a9eSIlya Leoshkevich 
182222541a9eSIlya Leoshkevich 	sz = sizeof(struct btf_type);
182322541a9eSIlya Leoshkevich 	t = btf_add_type_mem(btf, sz);
182422541a9eSIlya Leoshkevich 	if (!t)
1825e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
182622541a9eSIlya Leoshkevich 
182722541a9eSIlya Leoshkevich 	name_off = btf__add_str(btf, name);
182822541a9eSIlya Leoshkevich 	if (name_off < 0)
182922541a9eSIlya Leoshkevich 		return name_off;
183022541a9eSIlya Leoshkevich 
183122541a9eSIlya Leoshkevich 	t->name_off = name_off;
183222541a9eSIlya Leoshkevich 	t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0);
183322541a9eSIlya Leoshkevich 	t->size = byte_sz;
183422541a9eSIlya Leoshkevich 
183522541a9eSIlya Leoshkevich 	return btf_commit_type(btf, sz);
183622541a9eSIlya Leoshkevich }
183722541a9eSIlya Leoshkevich 
18384a3b33f8SAndrii Nakryiko /* it's completely legal to append BTF types with type IDs pointing forward to
18394a3b33f8SAndrii Nakryiko  * types that haven't been appended yet, so we only make sure that id looks
18404a3b33f8SAndrii Nakryiko  * sane, we can't guarantee that ID will always be valid
18414a3b33f8SAndrii Nakryiko  */
validate_type_id(int id)18424a3b33f8SAndrii Nakryiko static int validate_type_id(int id)
18434a3b33f8SAndrii Nakryiko {
18444a3b33f8SAndrii Nakryiko 	if (id < 0 || id > BTF_MAX_NR_TYPES)
18454a3b33f8SAndrii Nakryiko 		return -EINVAL;
18464a3b33f8SAndrii Nakryiko 	return 0;
18474a3b33f8SAndrii Nakryiko }
18484a3b33f8SAndrii Nakryiko 
18494a3b33f8SAndrii Nakryiko /* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */
btf_add_ref_kind(struct btf * btf,int kind,const char * name,int ref_type_id)18504a3b33f8SAndrii Nakryiko static int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id)
18514a3b33f8SAndrii Nakryiko {
18524a3b33f8SAndrii Nakryiko 	struct btf_type *t;
1853c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
18544a3b33f8SAndrii Nakryiko 
18554a3b33f8SAndrii Nakryiko 	if (validate_type_id(ref_type_id))
1856e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
18574a3b33f8SAndrii Nakryiko 
18584a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1859e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
18604a3b33f8SAndrii Nakryiko 
18614a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
18624a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
18634a3b33f8SAndrii Nakryiko 	if (!t)
1864e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
18654a3b33f8SAndrii Nakryiko 
18664a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
18674a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
18684a3b33f8SAndrii Nakryiko 		if (name_off < 0)
18694a3b33f8SAndrii Nakryiko 			return name_off;
18704a3b33f8SAndrii Nakryiko 	}
18714a3b33f8SAndrii Nakryiko 
18724a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
18734a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(kind, 0, 0);
18744a3b33f8SAndrii Nakryiko 	t->type = ref_type_id;
18754a3b33f8SAndrii Nakryiko 
1876c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
18774a3b33f8SAndrii Nakryiko }
18784a3b33f8SAndrii Nakryiko 
18794a3b33f8SAndrii Nakryiko /*
18804a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_PTR type with:
18814a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
18824a3b33f8SAndrii Nakryiko  * Returns:
18834a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
18844a3b33f8SAndrii Nakryiko  *   - <0, on error.
18854a3b33f8SAndrii Nakryiko  */
btf__add_ptr(struct btf * btf,int ref_type_id)18864a3b33f8SAndrii Nakryiko int btf__add_ptr(struct btf *btf, int ref_type_id)
18874a3b33f8SAndrii Nakryiko {
18884a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id);
18894a3b33f8SAndrii Nakryiko }
18904a3b33f8SAndrii Nakryiko 
18914a3b33f8SAndrii Nakryiko /*
18924a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_ARRAY type with:
18934a3b33f8SAndrii Nakryiko  *   - *index_type_id* - type ID of the type describing array index;
18944a3b33f8SAndrii Nakryiko  *   - *elem_type_id* - type ID of the type describing array element;
18954a3b33f8SAndrii Nakryiko  *   - *nr_elems* - the size of the array;
18964a3b33f8SAndrii Nakryiko  * Returns:
18974a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
18984a3b33f8SAndrii Nakryiko  *   - <0, on error.
18994a3b33f8SAndrii Nakryiko  */
btf__add_array(struct btf * btf,int index_type_id,int elem_type_id,__u32 nr_elems)19004a3b33f8SAndrii Nakryiko int btf__add_array(struct btf *btf, int index_type_id, int elem_type_id, __u32 nr_elems)
19014a3b33f8SAndrii Nakryiko {
19024a3b33f8SAndrii Nakryiko 	struct btf_type *t;
19034a3b33f8SAndrii Nakryiko 	struct btf_array *a;
1904c81ed6d8SAndrii Nakryiko 	int sz;
19054a3b33f8SAndrii Nakryiko 
19064a3b33f8SAndrii Nakryiko 	if (validate_type_id(index_type_id) || validate_type_id(elem_type_id))
1907e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
19084a3b33f8SAndrii Nakryiko 
19094a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1910e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19114a3b33f8SAndrii Nakryiko 
19124a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(struct btf_array);
19134a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
19144a3b33f8SAndrii Nakryiko 	if (!t)
1915e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19164a3b33f8SAndrii Nakryiko 
19174a3b33f8SAndrii Nakryiko 	t->name_off = 0;
19184a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_ARRAY, 0, 0);
19194a3b33f8SAndrii Nakryiko 	t->size = 0;
19204a3b33f8SAndrii Nakryiko 
19214a3b33f8SAndrii Nakryiko 	a = btf_array(t);
19224a3b33f8SAndrii Nakryiko 	a->type = elem_type_id;
19234a3b33f8SAndrii Nakryiko 	a->index_type = index_type_id;
19244a3b33f8SAndrii Nakryiko 	a->nelems = nr_elems;
19254a3b33f8SAndrii Nakryiko 
1926c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
19274a3b33f8SAndrii Nakryiko }
19284a3b33f8SAndrii Nakryiko 
19294a3b33f8SAndrii Nakryiko /* generic STRUCT/UNION append function */
btf_add_composite(struct btf * btf,int kind,const char * name,__u32 bytes_sz)19304a3b33f8SAndrii Nakryiko static int btf_add_composite(struct btf *btf, int kind, const char *name, __u32 bytes_sz)
19314a3b33f8SAndrii Nakryiko {
19324a3b33f8SAndrii Nakryiko 	struct btf_type *t;
1933c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
19344a3b33f8SAndrii Nakryiko 
19354a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1936e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19374a3b33f8SAndrii Nakryiko 
19384a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
19394a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
19404a3b33f8SAndrii Nakryiko 	if (!t)
1941e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19424a3b33f8SAndrii Nakryiko 
19434a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
19444a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
19454a3b33f8SAndrii Nakryiko 		if (name_off < 0)
19464a3b33f8SAndrii Nakryiko 			return name_off;
19474a3b33f8SAndrii Nakryiko 	}
19484a3b33f8SAndrii Nakryiko 
19494a3b33f8SAndrii Nakryiko 	/* start out with vlen=0 and no kflag; this will be adjusted when
19504a3b33f8SAndrii Nakryiko 	 * adding each member
19514a3b33f8SAndrii Nakryiko 	 */
19524a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
19534a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(kind, 0, 0);
19544a3b33f8SAndrii Nakryiko 	t->size = bytes_sz;
19554a3b33f8SAndrii Nakryiko 
1956c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
19574a3b33f8SAndrii Nakryiko }
19584a3b33f8SAndrii Nakryiko 
19594a3b33f8SAndrii Nakryiko /*
19604a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_STRUCT type with:
19614a3b33f8SAndrii Nakryiko  *   - *name* - name of the struct, can be NULL or empty for anonymous structs;
19624a3b33f8SAndrii Nakryiko  *   - *byte_sz* - size of the struct, in bytes;
19634a3b33f8SAndrii Nakryiko  *
19644a3b33f8SAndrii Nakryiko  * Struct initially has no fields in it. Fields can be added by
19654a3b33f8SAndrii Nakryiko  * btf__add_field() right after btf__add_struct() succeeds.
19664a3b33f8SAndrii Nakryiko  *
19674a3b33f8SAndrii Nakryiko  * Returns:
19684a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
19694a3b33f8SAndrii Nakryiko  *   - <0, on error.
19704a3b33f8SAndrii Nakryiko  */
btf__add_struct(struct btf * btf,const char * name,__u32 byte_sz)19714a3b33f8SAndrii Nakryiko int btf__add_struct(struct btf *btf, const char *name, __u32 byte_sz)
19724a3b33f8SAndrii Nakryiko {
19734a3b33f8SAndrii Nakryiko 	return btf_add_composite(btf, BTF_KIND_STRUCT, name, byte_sz);
19744a3b33f8SAndrii Nakryiko }
19754a3b33f8SAndrii Nakryiko 
19764a3b33f8SAndrii Nakryiko /*
19774a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_UNION type with:
19784a3b33f8SAndrii Nakryiko  *   - *name* - name of the union, can be NULL or empty for anonymous union;
19794a3b33f8SAndrii Nakryiko  *   - *byte_sz* - size of the union, in bytes;
19804a3b33f8SAndrii Nakryiko  *
19814a3b33f8SAndrii Nakryiko  * Union initially has no fields in it. Fields can be added by
19824a3b33f8SAndrii Nakryiko  * btf__add_field() right after btf__add_union() succeeds. All fields
19834a3b33f8SAndrii Nakryiko  * should have *bit_offset* of 0.
19844a3b33f8SAndrii Nakryiko  *
19854a3b33f8SAndrii Nakryiko  * Returns:
19864a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
19874a3b33f8SAndrii Nakryiko  *   - <0, on error.
19884a3b33f8SAndrii Nakryiko  */
btf__add_union(struct btf * btf,const char * name,__u32 byte_sz)19894a3b33f8SAndrii Nakryiko int btf__add_union(struct btf *btf, const char *name, __u32 byte_sz)
19904a3b33f8SAndrii Nakryiko {
19914a3b33f8SAndrii Nakryiko 	return btf_add_composite(btf, BTF_KIND_UNION, name, byte_sz);
19924a3b33f8SAndrii Nakryiko }
19934a3b33f8SAndrii Nakryiko 
btf_last_type(struct btf * btf)1994c81ed6d8SAndrii Nakryiko static struct btf_type *btf_last_type(struct btf *btf)
1995c81ed6d8SAndrii Nakryiko {
19966a886de0SHengqi Chen 	return btf_type_by_id(btf, btf__type_cnt(btf) - 1);
1997c81ed6d8SAndrii Nakryiko }
1998c81ed6d8SAndrii Nakryiko 
19994a3b33f8SAndrii Nakryiko /*
20004a3b33f8SAndrii Nakryiko  * Append new field for the current STRUCT/UNION type with:
20014a3b33f8SAndrii Nakryiko  *   - *name* - name of the field, can be NULL or empty for anonymous field;
20024a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID for the type describing field type;
20034a3b33f8SAndrii Nakryiko  *   - *bit_offset* - bit offset of the start of the field within struct/union;
20044a3b33f8SAndrii Nakryiko  *   - *bit_size* - bit size of a bitfield, 0 for non-bitfield fields;
20054a3b33f8SAndrii Nakryiko  * Returns:
20064a3b33f8SAndrii Nakryiko  *   -  0, on success;
20074a3b33f8SAndrii Nakryiko  *   - <0, on error.
20084a3b33f8SAndrii Nakryiko  */
btf__add_field(struct btf * btf,const char * name,int type_id,__u32 bit_offset,__u32 bit_size)20094a3b33f8SAndrii Nakryiko int btf__add_field(struct btf *btf, const char *name, int type_id,
20104a3b33f8SAndrii Nakryiko 		   __u32 bit_offset, __u32 bit_size)
20114a3b33f8SAndrii Nakryiko {
20124a3b33f8SAndrii Nakryiko 	struct btf_type *t;
20134a3b33f8SAndrii Nakryiko 	struct btf_member *m;
20144a3b33f8SAndrii Nakryiko 	bool is_bitfield;
20154a3b33f8SAndrii Nakryiko 	int sz, name_off = 0;
20164a3b33f8SAndrii Nakryiko 
20174a3b33f8SAndrii Nakryiko 	/* last type should be union/struct */
20184a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2019e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2020c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
20214a3b33f8SAndrii Nakryiko 	if (!btf_is_composite(t))
2022e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
20234a3b33f8SAndrii Nakryiko 
20244a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2025e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
20264a3b33f8SAndrii Nakryiko 	/* best-effort bit field offset/size enforcement */
20274a3b33f8SAndrii Nakryiko 	is_bitfield = bit_size || (bit_offset % 8 != 0);
20284a3b33f8SAndrii Nakryiko 	if (is_bitfield && (bit_size == 0 || bit_size > 255 || bit_offset > 0xffffff))
2029e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
20304a3b33f8SAndrii Nakryiko 
20314a3b33f8SAndrii Nakryiko 	/* only offset 0 is allowed for unions */
20324a3b33f8SAndrii Nakryiko 	if (btf_is_union(t) && bit_offset)
2033e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
20344a3b33f8SAndrii Nakryiko 
20354a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
20364a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2037e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20384a3b33f8SAndrii Nakryiko 
20394a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_member);
20404a3b33f8SAndrii Nakryiko 	m = btf_add_type_mem(btf, sz);
20414a3b33f8SAndrii Nakryiko 	if (!m)
2042e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20434a3b33f8SAndrii Nakryiko 
20444a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
20454a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
20464a3b33f8SAndrii Nakryiko 		if (name_off < 0)
20474a3b33f8SAndrii Nakryiko 			return name_off;
20484a3b33f8SAndrii Nakryiko 	}
20494a3b33f8SAndrii Nakryiko 
20504a3b33f8SAndrii Nakryiko 	m->name_off = name_off;
20514a3b33f8SAndrii Nakryiko 	m->type = type_id;
20524a3b33f8SAndrii Nakryiko 	m->offset = bit_offset | (bit_size << 24);
20534a3b33f8SAndrii Nakryiko 
20544a3b33f8SAndrii Nakryiko 	/* btf_add_type_mem can invalidate t pointer */
2055c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
20564a3b33f8SAndrii Nakryiko 	/* update parent type's vlen and kflag */
20574a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
20584a3b33f8SAndrii Nakryiko 
20594a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
20604a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
20614a3b33f8SAndrii Nakryiko 	return 0;
20624a3b33f8SAndrii Nakryiko }
20634a3b33f8SAndrii Nakryiko 
btf_add_enum_common(struct btf * btf,const char * name,__u32 byte_sz,bool is_signed,__u8 kind)20648479aa75SYonghong Song static int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
20658479aa75SYonghong Song 			       bool is_signed, __u8 kind)
20664a3b33f8SAndrii Nakryiko {
20674a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2068c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
20694a3b33f8SAndrii Nakryiko 
20704a3b33f8SAndrii Nakryiko 	/* byte_sz must be power of 2 */
20714a3b33f8SAndrii Nakryiko 	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 8)
2072e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
20734a3b33f8SAndrii Nakryiko 
20744a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2075e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20764a3b33f8SAndrii Nakryiko 
20774a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
20784a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
20794a3b33f8SAndrii Nakryiko 	if (!t)
2080e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20814a3b33f8SAndrii Nakryiko 
20824a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
20834a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
20844a3b33f8SAndrii Nakryiko 		if (name_off < 0)
20854a3b33f8SAndrii Nakryiko 			return name_off;
20864a3b33f8SAndrii Nakryiko 	}
20874a3b33f8SAndrii Nakryiko 
20884a3b33f8SAndrii Nakryiko 	/* start out with vlen=0; it will be adjusted when adding enum values */
20894a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
20908479aa75SYonghong Song 	t->info = btf_type_info(kind, 0, is_signed);
20914a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
20924a3b33f8SAndrii Nakryiko 
2093c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
20944a3b33f8SAndrii Nakryiko }
20954a3b33f8SAndrii Nakryiko 
20964a3b33f8SAndrii Nakryiko /*
20978479aa75SYonghong Song  * Append new BTF_KIND_ENUM type with:
20988479aa75SYonghong Song  *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
20998479aa75SYonghong Song  *   - *byte_sz* - size of the enum, in bytes.
21008479aa75SYonghong Song  *
21018479aa75SYonghong Song  * Enum initially has no enum values in it (and corresponds to enum forward
21028479aa75SYonghong Song  * declaration). Enumerator values can be added by btf__add_enum_value()
21038479aa75SYonghong Song  * immediately after btf__add_enum() succeeds.
21048479aa75SYonghong Song  *
21058479aa75SYonghong Song  * Returns:
21068479aa75SYonghong Song  *   - >0, type ID of newly added BTF type;
21078479aa75SYonghong Song  *   - <0, on error.
21088479aa75SYonghong Song  */
btf__add_enum(struct btf * btf,const char * name,__u32 byte_sz)21098479aa75SYonghong Song int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
21108479aa75SYonghong Song {
2111dffbbdc2SYonghong Song 	/*
2112dffbbdc2SYonghong Song 	 * set the signedness to be unsigned, it will change to signed
2113dffbbdc2SYonghong Song 	 * if any later enumerator is negative.
2114dffbbdc2SYonghong Song 	 */
21158479aa75SYonghong Song 	return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
21168479aa75SYonghong Song }
21178479aa75SYonghong Song 
21188479aa75SYonghong Song /*
21194a3b33f8SAndrii Nakryiko  * Append new enum value for the current ENUM type with:
21204a3b33f8SAndrii Nakryiko  *   - *name* - name of the enumerator value, can't be NULL or empty;
21214a3b33f8SAndrii Nakryiko  *   - *value* - integer value corresponding to enum value *name*;
21224a3b33f8SAndrii Nakryiko  * Returns:
21234a3b33f8SAndrii Nakryiko  *   -  0, on success;
21244a3b33f8SAndrii Nakryiko  *   - <0, on error.
21254a3b33f8SAndrii Nakryiko  */
btf__add_enum_value(struct btf * btf,const char * name,__s64 value)21264a3b33f8SAndrii Nakryiko int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
21274a3b33f8SAndrii Nakryiko {
21284a3b33f8SAndrii Nakryiko 	struct btf_type *t;
21294a3b33f8SAndrii Nakryiko 	struct btf_enum *v;
21304a3b33f8SAndrii Nakryiko 	int sz, name_off;
21314a3b33f8SAndrii Nakryiko 
21324a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_ENUM */
21334a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2134e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2135c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
21364a3b33f8SAndrii Nakryiko 	if (!btf_is_enum(t))
2137e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21384a3b33f8SAndrii Nakryiko 
21394a3b33f8SAndrii Nakryiko 	/* non-empty name */
21404a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2141e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21424a3b33f8SAndrii Nakryiko 	if (value < INT_MIN || value > UINT_MAX)
2143e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-E2BIG);
21444a3b33f8SAndrii Nakryiko 
21454a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
21464a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2147e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21484a3b33f8SAndrii Nakryiko 
21494a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_enum);
21504a3b33f8SAndrii Nakryiko 	v = btf_add_type_mem(btf, sz);
21514a3b33f8SAndrii Nakryiko 	if (!v)
2152e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21534a3b33f8SAndrii Nakryiko 
21544a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
21554a3b33f8SAndrii Nakryiko 	if (name_off < 0)
21564a3b33f8SAndrii Nakryiko 		return name_off;
21574a3b33f8SAndrii Nakryiko 
21584a3b33f8SAndrii Nakryiko 	v->name_off = name_off;
21594a3b33f8SAndrii Nakryiko 	v->val = value;
21604a3b33f8SAndrii Nakryiko 
21614a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2162c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
21634a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
21644a3b33f8SAndrii Nakryiko 
2165dffbbdc2SYonghong Song 	/* if negative value, set signedness to signed */
2166dffbbdc2SYonghong Song 	if (value < 0)
2167dffbbdc2SYonghong Song 		t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
2168dffbbdc2SYonghong Song 
2169dffbbdc2SYonghong Song 	btf->hdr->type_len += sz;
2170dffbbdc2SYonghong Song 	btf->hdr->str_off += sz;
2171dffbbdc2SYonghong Song 	return 0;
2172dffbbdc2SYonghong Song }
2173dffbbdc2SYonghong Song 
2174dffbbdc2SYonghong Song /*
2175dffbbdc2SYonghong Song  * Append new BTF_KIND_ENUM64 type with:
2176dffbbdc2SYonghong Song  *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
2177dffbbdc2SYonghong Song  *   - *byte_sz* - size of the enum, in bytes.
2178dffbbdc2SYonghong Song  *   - *is_signed* - whether the enum values are signed or not;
2179dffbbdc2SYonghong Song  *
2180dffbbdc2SYonghong Song  * Enum initially has no enum values in it (and corresponds to enum forward
2181dffbbdc2SYonghong Song  * declaration). Enumerator values can be added by btf__add_enum64_value()
2182dffbbdc2SYonghong Song  * immediately after btf__add_enum64() succeeds.
2183dffbbdc2SYonghong Song  *
2184dffbbdc2SYonghong Song  * Returns:
2185dffbbdc2SYonghong Song  *   - >0, type ID of newly added BTF type;
2186dffbbdc2SYonghong Song  *   - <0, on error.
2187dffbbdc2SYonghong Song  */
btf__add_enum64(struct btf * btf,const char * name,__u32 byte_sz,bool is_signed)2188dffbbdc2SYonghong Song int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
2189dffbbdc2SYonghong Song 		    bool is_signed)
2190dffbbdc2SYonghong Song {
2191dffbbdc2SYonghong Song 	return btf_add_enum_common(btf, name, byte_sz, is_signed,
2192dffbbdc2SYonghong Song 				   BTF_KIND_ENUM64);
2193dffbbdc2SYonghong Song }
2194dffbbdc2SYonghong Song 
2195dffbbdc2SYonghong Song /*
2196dffbbdc2SYonghong Song  * Append new enum value for the current ENUM64 type with:
2197dffbbdc2SYonghong Song  *   - *name* - name of the enumerator value, can't be NULL or empty;
2198dffbbdc2SYonghong Song  *   - *value* - integer value corresponding to enum value *name*;
2199dffbbdc2SYonghong Song  * Returns:
2200dffbbdc2SYonghong Song  *   -  0, on success;
2201dffbbdc2SYonghong Song  *   - <0, on error.
2202dffbbdc2SYonghong Song  */
btf__add_enum64_value(struct btf * btf,const char * name,__u64 value)2203dffbbdc2SYonghong Song int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
2204dffbbdc2SYonghong Song {
2205dffbbdc2SYonghong Song 	struct btf_enum64 *v;
2206dffbbdc2SYonghong Song 	struct btf_type *t;
2207dffbbdc2SYonghong Song 	int sz, name_off;
2208dffbbdc2SYonghong Song 
2209dffbbdc2SYonghong Song 	/* last type should be BTF_KIND_ENUM64 */
2210dffbbdc2SYonghong Song 	if (btf->nr_types == 0)
2211dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2212dffbbdc2SYonghong Song 	t = btf_last_type(btf);
2213dffbbdc2SYonghong Song 	if (!btf_is_enum64(t))
2214dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2215dffbbdc2SYonghong Song 
2216dffbbdc2SYonghong Song 	/* non-empty name */
2217dffbbdc2SYonghong Song 	if (!name || !name[0])
2218dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2219dffbbdc2SYonghong Song 
2220dffbbdc2SYonghong Song 	/* decompose and invalidate raw data */
2221dffbbdc2SYonghong Song 	if (btf_ensure_modifiable(btf))
2222dffbbdc2SYonghong Song 		return libbpf_err(-ENOMEM);
2223dffbbdc2SYonghong Song 
2224dffbbdc2SYonghong Song 	sz = sizeof(struct btf_enum64);
2225dffbbdc2SYonghong Song 	v = btf_add_type_mem(btf, sz);
2226dffbbdc2SYonghong Song 	if (!v)
2227dffbbdc2SYonghong Song 		return libbpf_err(-ENOMEM);
2228dffbbdc2SYonghong Song 
2229dffbbdc2SYonghong Song 	name_off = btf__add_str(btf, name);
2230dffbbdc2SYonghong Song 	if (name_off < 0)
2231dffbbdc2SYonghong Song 		return name_off;
2232dffbbdc2SYonghong Song 
2233dffbbdc2SYonghong Song 	v->name_off = name_off;
2234dffbbdc2SYonghong Song 	v->val_lo32 = (__u32)value;
2235dffbbdc2SYonghong Song 	v->val_hi32 = value >> 32;
2236dffbbdc2SYonghong Song 
2237dffbbdc2SYonghong Song 	/* update parent type's vlen */
2238dffbbdc2SYonghong Song 	t = btf_last_type(btf);
2239dffbbdc2SYonghong Song 	btf_type_inc_vlen(t);
2240dffbbdc2SYonghong Song 
22414a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
22424a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
22434a3b33f8SAndrii Nakryiko 	return 0;
22444a3b33f8SAndrii Nakryiko }
22454a3b33f8SAndrii Nakryiko 
22464a3b33f8SAndrii Nakryiko /*
22474a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FWD type with:
22484a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
22494a3b33f8SAndrii Nakryiko  *   - *fwd_kind*, kind of forward declaration, one of BTF_FWD_STRUCT,
22504a3b33f8SAndrii Nakryiko  *     BTF_FWD_UNION, or BTF_FWD_ENUM;
22514a3b33f8SAndrii Nakryiko  * Returns:
22524a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
22534a3b33f8SAndrii Nakryiko  *   - <0, on error.
22544a3b33f8SAndrii Nakryiko  */
btf__add_fwd(struct btf * btf,const char * name,enum btf_fwd_kind fwd_kind)22554a3b33f8SAndrii Nakryiko int btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind)
22564a3b33f8SAndrii Nakryiko {
22574a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2258e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
22594a3b33f8SAndrii Nakryiko 
22604a3b33f8SAndrii Nakryiko 	switch (fwd_kind) {
22614a3b33f8SAndrii Nakryiko 	case BTF_FWD_STRUCT:
22624a3b33f8SAndrii Nakryiko 	case BTF_FWD_UNION: {
22634a3b33f8SAndrii Nakryiko 		struct btf_type *t;
22644a3b33f8SAndrii Nakryiko 		int id;
22654a3b33f8SAndrii Nakryiko 
22664a3b33f8SAndrii Nakryiko 		id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0);
22674a3b33f8SAndrii Nakryiko 		if (id <= 0)
22684a3b33f8SAndrii Nakryiko 			return id;
22694a3b33f8SAndrii Nakryiko 		t = btf_type_by_id(btf, id);
22704a3b33f8SAndrii Nakryiko 		t->info = btf_type_info(BTF_KIND_FWD, 0, fwd_kind == BTF_FWD_UNION);
22714a3b33f8SAndrii Nakryiko 		return id;
22724a3b33f8SAndrii Nakryiko 	}
22734a3b33f8SAndrii Nakryiko 	case BTF_FWD_ENUM:
22744a3b33f8SAndrii Nakryiko 		/* enum forward in BTF currently is just an enum with no enum
22754a3b33f8SAndrii Nakryiko 		 * values; we also assume a standard 4-byte size for it
22764a3b33f8SAndrii Nakryiko 		 */
22774a3b33f8SAndrii Nakryiko 		return btf__add_enum(btf, name, sizeof(int));
22784a3b33f8SAndrii Nakryiko 	default:
2279e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
22804a3b33f8SAndrii Nakryiko 	}
22814a3b33f8SAndrii Nakryiko }
22824a3b33f8SAndrii Nakryiko 
22834a3b33f8SAndrii Nakryiko /*
22844a3b33f8SAndrii Nakryiko  * Append new BTF_KING_TYPEDEF type with:
22854a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
22864a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
22874a3b33f8SAndrii Nakryiko  * Returns:
22884a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
22894a3b33f8SAndrii Nakryiko  *   - <0, on error.
22904a3b33f8SAndrii Nakryiko  */
btf__add_typedef(struct btf * btf,const char * name,int ref_type_id)22914a3b33f8SAndrii Nakryiko int btf__add_typedef(struct btf *btf, const char *name, int ref_type_id)
22924a3b33f8SAndrii Nakryiko {
22934a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2294e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
22954a3b33f8SAndrii Nakryiko 
22964a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id);
22974a3b33f8SAndrii Nakryiko }
22984a3b33f8SAndrii Nakryiko 
22994a3b33f8SAndrii Nakryiko /*
23004a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_VOLATILE type with:
23014a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23024a3b33f8SAndrii Nakryiko  * Returns:
23034a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23044a3b33f8SAndrii Nakryiko  *   - <0, on error.
23054a3b33f8SAndrii Nakryiko  */
btf__add_volatile(struct btf * btf,int ref_type_id)23064a3b33f8SAndrii Nakryiko int btf__add_volatile(struct btf *btf, int ref_type_id)
23074a3b33f8SAndrii Nakryiko {
23084a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id);
23094a3b33f8SAndrii Nakryiko }
23104a3b33f8SAndrii Nakryiko 
23114a3b33f8SAndrii Nakryiko /*
23124a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_CONST type with:
23134a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23144a3b33f8SAndrii Nakryiko  * Returns:
23154a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23164a3b33f8SAndrii Nakryiko  *   - <0, on error.
23174a3b33f8SAndrii Nakryiko  */
btf__add_const(struct btf * btf,int ref_type_id)23184a3b33f8SAndrii Nakryiko int btf__add_const(struct btf *btf, int ref_type_id)
23194a3b33f8SAndrii Nakryiko {
23204a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id);
23214a3b33f8SAndrii Nakryiko }
23224a3b33f8SAndrii Nakryiko 
23234a3b33f8SAndrii Nakryiko /*
23244a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_RESTRICT type with:
23254a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23264a3b33f8SAndrii Nakryiko  * Returns:
23274a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23284a3b33f8SAndrii Nakryiko  *   - <0, on error.
23294a3b33f8SAndrii Nakryiko  */
btf__add_restrict(struct btf * btf,int ref_type_id)23304a3b33f8SAndrii Nakryiko int btf__add_restrict(struct btf *btf, int ref_type_id)
23314a3b33f8SAndrii Nakryiko {
23324a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id);
23334a3b33f8SAndrii Nakryiko }
23344a3b33f8SAndrii Nakryiko 
23354a3b33f8SAndrii Nakryiko /*
23362dc1e488SYonghong Song  * Append new BTF_KIND_TYPE_TAG type with:
23372dc1e488SYonghong Song  *   - *value*, non-empty/non-NULL tag value;
23382dc1e488SYonghong Song  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23392dc1e488SYonghong Song  * Returns:
23402dc1e488SYonghong Song  *   - >0, type ID of newly added BTF type;
23412dc1e488SYonghong Song  *   - <0, on error.
23422dc1e488SYonghong Song  */
btf__add_type_tag(struct btf * btf,const char * value,int ref_type_id)23432dc1e488SYonghong Song int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
23442dc1e488SYonghong Song {
23452dc1e488SYonghong Song 	if (!value || !value[0])
23462dc1e488SYonghong Song 		return libbpf_err(-EINVAL);
23472dc1e488SYonghong Song 
23482dc1e488SYonghong Song 	return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
23492dc1e488SYonghong Song }
23502dc1e488SYonghong Song 
23512dc1e488SYonghong Song /*
23524a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FUNC type with:
23534a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
23544a3b33f8SAndrii Nakryiko  *   - *proto_type_id* - FUNC_PROTO's type ID, it might not exist yet;
23554a3b33f8SAndrii Nakryiko  * Returns:
23564a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23574a3b33f8SAndrii Nakryiko  *   - <0, on error.
23584a3b33f8SAndrii Nakryiko  */
btf__add_func(struct btf * btf,const char * name,enum btf_func_linkage linkage,int proto_type_id)23594a3b33f8SAndrii Nakryiko int btf__add_func(struct btf *btf, const char *name,
23604a3b33f8SAndrii Nakryiko 		  enum btf_func_linkage linkage, int proto_type_id)
23614a3b33f8SAndrii Nakryiko {
23624a3b33f8SAndrii Nakryiko 	int id;
23634a3b33f8SAndrii Nakryiko 
23644a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2365e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23664a3b33f8SAndrii Nakryiko 	if (linkage != BTF_FUNC_STATIC && linkage != BTF_FUNC_GLOBAL &&
23674a3b33f8SAndrii Nakryiko 	    linkage != BTF_FUNC_EXTERN)
2368e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23694a3b33f8SAndrii Nakryiko 
23704a3b33f8SAndrii Nakryiko 	id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id);
23714a3b33f8SAndrii Nakryiko 	if (id > 0) {
23724a3b33f8SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(btf, id);
23734a3b33f8SAndrii Nakryiko 
23744a3b33f8SAndrii Nakryiko 		t->info = btf_type_info(BTF_KIND_FUNC, linkage, 0);
23754a3b33f8SAndrii Nakryiko 	}
2376e9fc3ce9SAndrii Nakryiko 	return libbpf_err(id);
23774a3b33f8SAndrii Nakryiko }
23784a3b33f8SAndrii Nakryiko 
23794a3b33f8SAndrii Nakryiko /*
23804a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FUNC_PROTO with:
23814a3b33f8SAndrii Nakryiko  *   - *ret_type_id* - type ID for return result of a function.
23824a3b33f8SAndrii Nakryiko  *
23834a3b33f8SAndrii Nakryiko  * Function prototype initially has no arguments, but they can be added by
23844a3b33f8SAndrii Nakryiko  * btf__add_func_param() one by one, immediately after
23854a3b33f8SAndrii Nakryiko  * btf__add_func_proto() succeeded.
23864a3b33f8SAndrii Nakryiko  *
23874a3b33f8SAndrii Nakryiko  * Returns:
23884a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23894a3b33f8SAndrii Nakryiko  *   - <0, on error.
23904a3b33f8SAndrii Nakryiko  */
btf__add_func_proto(struct btf * btf,int ret_type_id)23914a3b33f8SAndrii Nakryiko int btf__add_func_proto(struct btf *btf, int ret_type_id)
23924a3b33f8SAndrii Nakryiko {
23934a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2394c81ed6d8SAndrii Nakryiko 	int sz;
23954a3b33f8SAndrii Nakryiko 
23964a3b33f8SAndrii Nakryiko 	if (validate_type_id(ret_type_id))
2397e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23984a3b33f8SAndrii Nakryiko 
23994a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2400e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24014a3b33f8SAndrii Nakryiko 
24024a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
24034a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
24044a3b33f8SAndrii Nakryiko 	if (!t)
2405e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24064a3b33f8SAndrii Nakryiko 
24074a3b33f8SAndrii Nakryiko 	/* start out with vlen=0; this will be adjusted when adding enum
24084a3b33f8SAndrii Nakryiko 	 * values, if necessary
24094a3b33f8SAndrii Nakryiko 	 */
24104a3b33f8SAndrii Nakryiko 	t->name_off = 0;
24114a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_FUNC_PROTO, 0, 0);
24124a3b33f8SAndrii Nakryiko 	t->type = ret_type_id;
24134a3b33f8SAndrii Nakryiko 
2414c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
24154a3b33f8SAndrii Nakryiko }
24164a3b33f8SAndrii Nakryiko 
24174a3b33f8SAndrii Nakryiko /*
24184a3b33f8SAndrii Nakryiko  * Append new function parameter for current FUNC_PROTO type with:
24194a3b33f8SAndrii Nakryiko  *   - *name* - parameter name, can be NULL or empty;
24204a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID describing the type of the parameter.
24214a3b33f8SAndrii Nakryiko  * Returns:
24224a3b33f8SAndrii Nakryiko  *   -  0, on success;
24234a3b33f8SAndrii Nakryiko  *   - <0, on error.
24244a3b33f8SAndrii Nakryiko  */
btf__add_func_param(struct btf * btf,const char * name,int type_id)24254a3b33f8SAndrii Nakryiko int btf__add_func_param(struct btf *btf, const char *name, int type_id)
24264a3b33f8SAndrii Nakryiko {
24274a3b33f8SAndrii Nakryiko 	struct btf_type *t;
24284a3b33f8SAndrii Nakryiko 	struct btf_param *p;
24294a3b33f8SAndrii Nakryiko 	int sz, name_off = 0;
24304a3b33f8SAndrii Nakryiko 
24314a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2432e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24334a3b33f8SAndrii Nakryiko 
24344a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_FUNC_PROTO */
24354a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2436e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2437c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
24384a3b33f8SAndrii Nakryiko 	if (!btf_is_func_proto(t))
2439e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24404a3b33f8SAndrii Nakryiko 
24414a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
24424a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2443e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24444a3b33f8SAndrii Nakryiko 
24454a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_param);
24464a3b33f8SAndrii Nakryiko 	p = btf_add_type_mem(btf, sz);
24474a3b33f8SAndrii Nakryiko 	if (!p)
2448e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24494a3b33f8SAndrii Nakryiko 
24504a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
24514a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
24524a3b33f8SAndrii Nakryiko 		if (name_off < 0)
24534a3b33f8SAndrii Nakryiko 			return name_off;
24544a3b33f8SAndrii Nakryiko 	}
24554a3b33f8SAndrii Nakryiko 
24564a3b33f8SAndrii Nakryiko 	p->name_off = name_off;
24574a3b33f8SAndrii Nakryiko 	p->type = type_id;
24584a3b33f8SAndrii Nakryiko 
24594a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2460c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
24614a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
24624a3b33f8SAndrii Nakryiko 
24634a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
24644a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
24654a3b33f8SAndrii Nakryiko 	return 0;
24664a3b33f8SAndrii Nakryiko }
24674a3b33f8SAndrii Nakryiko 
24684a3b33f8SAndrii Nakryiko /*
24694a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_VAR type with:
24704a3b33f8SAndrii Nakryiko  *   - *name* - non-empty/non-NULL name;
24714a3b33f8SAndrii Nakryiko  *   - *linkage* - variable linkage, one of BTF_VAR_STATIC,
24724a3b33f8SAndrii Nakryiko  *     BTF_VAR_GLOBAL_ALLOCATED, or BTF_VAR_GLOBAL_EXTERN;
24734a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID of the type describing the type of the variable.
24744a3b33f8SAndrii Nakryiko  * Returns:
24754a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
24764a3b33f8SAndrii Nakryiko  *   - <0, on error.
24774a3b33f8SAndrii Nakryiko  */
btf__add_var(struct btf * btf,const char * name,int linkage,int type_id)24784a3b33f8SAndrii Nakryiko int btf__add_var(struct btf *btf, const char *name, int linkage, int type_id)
24794a3b33f8SAndrii Nakryiko {
24804a3b33f8SAndrii Nakryiko 	struct btf_type *t;
24814a3b33f8SAndrii Nakryiko 	struct btf_var *v;
2482c81ed6d8SAndrii Nakryiko 	int sz, name_off;
24834a3b33f8SAndrii Nakryiko 
24844a3b33f8SAndrii Nakryiko 	/* non-empty name */
24854a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2486e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24874a3b33f8SAndrii Nakryiko 	if (linkage != BTF_VAR_STATIC && linkage != BTF_VAR_GLOBAL_ALLOCATED &&
24884a3b33f8SAndrii Nakryiko 	    linkage != BTF_VAR_GLOBAL_EXTERN)
2489e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24904a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2491e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24924a3b33f8SAndrii Nakryiko 
24934a3b33f8SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
24944a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2495e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24964a3b33f8SAndrii Nakryiko 
24974a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(struct btf_var);
24984a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
24994a3b33f8SAndrii Nakryiko 	if (!t)
2500e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25014a3b33f8SAndrii Nakryiko 
25024a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
25034a3b33f8SAndrii Nakryiko 	if (name_off < 0)
25044a3b33f8SAndrii Nakryiko 		return name_off;
25054a3b33f8SAndrii Nakryiko 
25064a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
25074a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_VAR, 0, 0);
25084a3b33f8SAndrii Nakryiko 	t->type = type_id;
25094a3b33f8SAndrii Nakryiko 
25104a3b33f8SAndrii Nakryiko 	v = btf_var(t);
25114a3b33f8SAndrii Nakryiko 	v->linkage = linkage;
25124a3b33f8SAndrii Nakryiko 
2513c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
25144a3b33f8SAndrii Nakryiko }
25154a3b33f8SAndrii Nakryiko 
25164a3b33f8SAndrii Nakryiko /*
25174a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_DATASEC type with:
25184a3b33f8SAndrii Nakryiko  *   - *name* - non-empty/non-NULL name;
25194a3b33f8SAndrii Nakryiko  *   - *byte_sz* - data section size, in bytes.
25204a3b33f8SAndrii Nakryiko  *
25214a3b33f8SAndrii Nakryiko  * Data section is initially empty. Variables info can be added with
25224a3b33f8SAndrii Nakryiko  * btf__add_datasec_var_info() calls, after btf__add_datasec() succeeds.
25234a3b33f8SAndrii Nakryiko  *
25244a3b33f8SAndrii Nakryiko  * Returns:
25254a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
25264a3b33f8SAndrii Nakryiko  *   - <0, on error.
25274a3b33f8SAndrii Nakryiko  */
btf__add_datasec(struct btf * btf,const char * name,__u32 byte_sz)25284a3b33f8SAndrii Nakryiko int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz)
25294a3b33f8SAndrii Nakryiko {
25304a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2531c81ed6d8SAndrii Nakryiko 	int sz, name_off;
25324a3b33f8SAndrii Nakryiko 
25334a3b33f8SAndrii Nakryiko 	/* non-empty name */
25344a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2535e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25364a3b33f8SAndrii Nakryiko 
25374a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2538e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25394a3b33f8SAndrii Nakryiko 
25404a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
25414a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
25424a3b33f8SAndrii Nakryiko 	if (!t)
2543e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25444a3b33f8SAndrii Nakryiko 
25454a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
25464a3b33f8SAndrii Nakryiko 	if (name_off < 0)
25474a3b33f8SAndrii Nakryiko 		return name_off;
25484a3b33f8SAndrii Nakryiko 
25494a3b33f8SAndrii Nakryiko 	/* start with vlen=0, which will be update as var_secinfos are added */
25504a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
25514a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_DATASEC, 0, 0);
25524a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
25534a3b33f8SAndrii Nakryiko 
2554c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
25554a3b33f8SAndrii Nakryiko }
25564a3b33f8SAndrii Nakryiko 
25574a3b33f8SAndrii Nakryiko /*
25584a3b33f8SAndrii Nakryiko  * Append new data section variable information entry for current DATASEC type:
25594a3b33f8SAndrii Nakryiko  *   - *var_type_id* - type ID, describing type of the variable;
25604a3b33f8SAndrii Nakryiko  *   - *offset* - variable offset within data section, in bytes;
25614a3b33f8SAndrii Nakryiko  *   - *byte_sz* - variable size, in bytes.
25624a3b33f8SAndrii Nakryiko  *
25634a3b33f8SAndrii Nakryiko  * Returns:
25644a3b33f8SAndrii Nakryiko  *   -  0, on success;
25654a3b33f8SAndrii Nakryiko  *   - <0, on error.
25664a3b33f8SAndrii Nakryiko  */
btf__add_datasec_var_info(struct btf * btf,int var_type_id,__u32 offset,__u32 byte_sz)25674a3b33f8SAndrii Nakryiko int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz)
25684a3b33f8SAndrii Nakryiko {
25694a3b33f8SAndrii Nakryiko 	struct btf_type *t;
25704a3b33f8SAndrii Nakryiko 	struct btf_var_secinfo *v;
25714a3b33f8SAndrii Nakryiko 	int sz;
25724a3b33f8SAndrii Nakryiko 
25734a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_DATASEC */
25744a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2575e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2576c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
25774a3b33f8SAndrii Nakryiko 	if (!btf_is_datasec(t))
2578e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25794a3b33f8SAndrii Nakryiko 
25804a3b33f8SAndrii Nakryiko 	if (validate_type_id(var_type_id))
2581e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25824a3b33f8SAndrii Nakryiko 
25834a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
25844a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2585e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25864a3b33f8SAndrii Nakryiko 
25874a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_var_secinfo);
25884a3b33f8SAndrii Nakryiko 	v = btf_add_type_mem(btf, sz);
25894a3b33f8SAndrii Nakryiko 	if (!v)
2590e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25914a3b33f8SAndrii Nakryiko 
25924a3b33f8SAndrii Nakryiko 	v->type = var_type_id;
25934a3b33f8SAndrii Nakryiko 	v->offset = offset;
25944a3b33f8SAndrii Nakryiko 	v->size = byte_sz;
25954a3b33f8SAndrii Nakryiko 
25964a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2597c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
25984a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
25994a3b33f8SAndrii Nakryiko 
26004a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
26014a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
26024a3b33f8SAndrii Nakryiko 	return 0;
26034a3b33f8SAndrii Nakryiko }
26044a3b33f8SAndrii Nakryiko 
26055b84bd10SYonghong Song /*
2606223f903eSYonghong Song  * Append new BTF_KIND_DECL_TAG type with:
26075b84bd10SYonghong Song  *   - *value* - non-empty/non-NULL string;
26085b84bd10SYonghong Song  *   - *ref_type_id* - referenced type ID, it might not exist yet;
26095b84bd10SYonghong Song  *   - *component_idx* - -1 for tagging reference type, otherwise struct/union
26105b84bd10SYonghong Song  *     member or function argument index;
26115b84bd10SYonghong Song  * Returns:
26125b84bd10SYonghong Song  *   - >0, type ID of newly added BTF type;
26135b84bd10SYonghong Song  *   - <0, on error.
26145b84bd10SYonghong Song  */
btf__add_decl_tag(struct btf * btf,const char * value,int ref_type_id,int component_idx)2615223f903eSYonghong Song int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
26165b84bd10SYonghong Song 		 int component_idx)
26175b84bd10SYonghong Song {
26185b84bd10SYonghong Song 	struct btf_type *t;
26195b84bd10SYonghong Song 	int sz, value_off;
26205b84bd10SYonghong Song 
26215b84bd10SYonghong Song 	if (!value || !value[0] || component_idx < -1)
26225b84bd10SYonghong Song 		return libbpf_err(-EINVAL);
26235b84bd10SYonghong Song 
26245b84bd10SYonghong Song 	if (validate_type_id(ref_type_id))
26255b84bd10SYonghong Song 		return libbpf_err(-EINVAL);
26265b84bd10SYonghong Song 
26275b84bd10SYonghong Song 	if (btf_ensure_modifiable(btf))
26285b84bd10SYonghong Song 		return libbpf_err(-ENOMEM);
26295b84bd10SYonghong Song 
2630223f903eSYonghong Song 	sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag);
26315b84bd10SYonghong Song 	t = btf_add_type_mem(btf, sz);
26325b84bd10SYonghong Song 	if (!t)
26335b84bd10SYonghong Song 		return libbpf_err(-ENOMEM);
26345b84bd10SYonghong Song 
26355b84bd10SYonghong Song 	value_off = btf__add_str(btf, value);
26365b84bd10SYonghong Song 	if (value_off < 0)
26375b84bd10SYonghong Song 		return value_off;
26385b84bd10SYonghong Song 
26395b84bd10SYonghong Song 	t->name_off = value_off;
2640223f903eSYonghong Song 	t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false);
26415b84bd10SYonghong Song 	t->type = ref_type_id;
2642223f903eSYonghong Song 	btf_decl_tag(t)->component_idx = component_idx;
26435b84bd10SYonghong Song 
26445b84bd10SYonghong Song 	return btf_commit_type(btf, sz);
26455b84bd10SYonghong Song }
26465b84bd10SYonghong Song 
2647ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param {
26483d650141SMartin KaFai Lau 	__u32 off;
26493d650141SMartin KaFai Lau 	__u32 len;
26503d650141SMartin KaFai Lau 	__u32 min_rec_size;
26513d650141SMartin KaFai Lau 	struct btf_ext_info *ext_info;
26523d650141SMartin KaFai Lau 	const char *desc;
26533d650141SMartin KaFai Lau };
26543d650141SMartin KaFai Lau 
btf_ext_setup_info(struct btf_ext * btf_ext,struct btf_ext_sec_setup_param * ext_sec)2655ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_info(struct btf_ext *btf_ext,
2656ae4ab4b4SAndrii Nakryiko 			      struct btf_ext_sec_setup_param *ext_sec)
26572993e051SYonghong Song {
26583d650141SMartin KaFai Lau 	const struct btf_ext_info_sec *sinfo;
26593d650141SMartin KaFai Lau 	struct btf_ext_info *ext_info;
2660f0187f0bSMartin KaFai Lau 	__u32 info_left, record_size;
266111d5daa8SAndrii Nakryiko 	size_t sec_cnt = 0;
2662f0187f0bSMartin KaFai Lau 	/* The start of the info sec (including the __u32 record_size). */
2663ae4ab4b4SAndrii Nakryiko 	void *info;
2664f0187f0bSMartin KaFai Lau 
26654cedc0daSAndrii Nakryiko 	if (ext_sec->len == 0)
26664cedc0daSAndrii Nakryiko 		return 0;
26674cedc0daSAndrii Nakryiko 
26683d650141SMartin KaFai Lau 	if (ext_sec->off & 0x03) {
26698461ef8bSYonghong Song 		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
26703d650141SMartin KaFai Lau 		     ext_sec->desc);
2671f0187f0bSMartin KaFai Lau 		return -EINVAL;
2672f0187f0bSMartin KaFai Lau 	}
2673f0187f0bSMartin KaFai Lau 
2674ae4ab4b4SAndrii Nakryiko 	info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off;
2675ae4ab4b4SAndrii Nakryiko 	info_left = ext_sec->len;
2676ae4ab4b4SAndrii Nakryiko 
2677ae4ab4b4SAndrii Nakryiko 	if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) {
26788461ef8bSYonghong Song 		pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
26793d650141SMartin KaFai Lau 			 ext_sec->desc, ext_sec->off, ext_sec->len);
2680f0187f0bSMartin KaFai Lau 		return -EINVAL;
2681f0187f0bSMartin KaFai Lau 	}
2682f0187f0bSMartin KaFai Lau 
26833d650141SMartin KaFai Lau 	/* At least a record size */
2684f0187f0bSMartin KaFai Lau 	if (info_left < sizeof(__u32)) {
26858461ef8bSYonghong Song 		pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);
26862993e051SYonghong Song 		return -EINVAL;
26872993e051SYonghong Song 	}
26882993e051SYonghong Song 
2689f0187f0bSMartin KaFai Lau 	/* The record size needs to meet the minimum standard */
2690f0187f0bSMartin KaFai Lau 	record_size = *(__u32 *)info;
26913d650141SMartin KaFai Lau 	if (record_size < ext_sec->min_rec_size ||
2692f0187f0bSMartin KaFai Lau 	    record_size & 0x03) {
26938461ef8bSYonghong Song 		pr_debug("%s section in .BTF.ext has invalid record size %u\n",
26943d650141SMartin KaFai Lau 			 ext_sec->desc, record_size);
26952993e051SYonghong Song 		return -EINVAL;
26962993e051SYonghong Song 	}
26972993e051SYonghong Song 
2698f0187f0bSMartin KaFai Lau 	sinfo = info + sizeof(__u32);
2699f0187f0bSMartin KaFai Lau 	info_left -= sizeof(__u32);
27002993e051SYonghong Song 
27013d650141SMartin KaFai Lau 	/* If no records, return failure now so .BTF.ext won't be used. */
2702f0187f0bSMartin KaFai Lau 	if (!info_left) {
27038461ef8bSYonghong Song 		pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);
27042993e051SYonghong Song 		return -EINVAL;
27052993e051SYonghong Song 	}
27062993e051SYonghong Song 
2707f0187f0bSMartin KaFai Lau 	while (info_left) {
27083d650141SMartin KaFai Lau 		unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
2709f0187f0bSMartin KaFai Lau 		__u64 total_record_size;
2710f0187f0bSMartin KaFai Lau 		__u32 num_records;
2711f0187f0bSMartin KaFai Lau 
2712f0187f0bSMartin KaFai Lau 		if (info_left < sec_hdrlen) {
27138461ef8bSYonghong Song 			pr_debug("%s section header is not found in .BTF.ext\n",
27143d650141SMartin KaFai Lau 			     ext_sec->desc);
27152993e051SYonghong Song 			return -EINVAL;
27162993e051SYonghong Song 		}
27172993e051SYonghong Song 
27183d650141SMartin KaFai Lau 		num_records = sinfo->num_info;
27192993e051SYonghong Song 		if (num_records == 0) {
27208461ef8bSYonghong Song 			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
27213d650141SMartin KaFai Lau 			     ext_sec->desc);
27222993e051SYonghong Song 			return -EINVAL;
27232993e051SYonghong Song 		}
27242993e051SYonghong Song 
272511d5daa8SAndrii Nakryiko 		total_record_size = sec_hdrlen + (__u64)num_records * record_size;
2726f0187f0bSMartin KaFai Lau 		if (info_left < total_record_size) {
27278461ef8bSYonghong Song 			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
27283d650141SMartin KaFai Lau 			     ext_sec->desc);
27292993e051SYonghong Song 			return -EINVAL;
27302993e051SYonghong Song 		}
27312993e051SYonghong Song 
2732f0187f0bSMartin KaFai Lau 		info_left -= total_record_size;
27332993e051SYonghong Song 		sinfo = (void *)sinfo + total_record_size;
273411d5daa8SAndrii Nakryiko 		sec_cnt++;
27352993e051SYonghong Song 	}
27362993e051SYonghong Song 
27373d650141SMartin KaFai Lau 	ext_info = ext_sec->ext_info;
27383d650141SMartin KaFai Lau 	ext_info->len = ext_sec->len - sizeof(__u32);
27393d650141SMartin KaFai Lau 	ext_info->rec_size = record_size;
2740ae4ab4b4SAndrii Nakryiko 	ext_info->info = info + sizeof(__u32);
274111d5daa8SAndrii Nakryiko 	ext_info->sec_cnt = sec_cnt;
2742f0187f0bSMartin KaFai Lau 
27432993e051SYonghong Song 	return 0;
27442993e051SYonghong Song }
27452993e051SYonghong Song 
btf_ext_setup_func_info(struct btf_ext * btf_ext)2746ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_func_info(struct btf_ext *btf_ext)
27473d650141SMartin KaFai Lau {
2748ae4ab4b4SAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
2749ae4ab4b4SAndrii Nakryiko 		.off = btf_ext->hdr->func_info_off,
2750ae4ab4b4SAndrii Nakryiko 		.len = btf_ext->hdr->func_info_len,
27513d650141SMartin KaFai Lau 		.min_rec_size = sizeof(struct bpf_func_info_min),
27523d650141SMartin KaFai Lau 		.ext_info = &btf_ext->func_info,
27533d650141SMartin KaFai Lau 		.desc = "func_info"
27543d650141SMartin KaFai Lau 	};
27553d650141SMartin KaFai Lau 
2756ae4ab4b4SAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
27573d650141SMartin KaFai Lau }
27583d650141SMartin KaFai Lau 
btf_ext_setup_line_info(struct btf_ext * btf_ext)2759ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
27603d650141SMartin KaFai Lau {
2761ae4ab4b4SAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
2762ae4ab4b4SAndrii Nakryiko 		.off = btf_ext->hdr->line_info_off,
2763ae4ab4b4SAndrii Nakryiko 		.len = btf_ext->hdr->line_info_len,
27643d650141SMartin KaFai Lau 		.min_rec_size = sizeof(struct bpf_line_info_min),
27653d650141SMartin KaFai Lau 		.ext_info = &btf_ext->line_info,
27663d650141SMartin KaFai Lau 		.desc = "line_info",
27673d650141SMartin KaFai Lau 	};
27683d650141SMartin KaFai Lau 
2769ae4ab4b4SAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
27703d650141SMartin KaFai Lau }
27713d650141SMartin KaFai Lau 
btf_ext_setup_core_relos(struct btf_ext * btf_ext)277228b93c64SAndrii Nakryiko static int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
27734cedc0daSAndrii Nakryiko {
27744cedc0daSAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
277528b93c64SAndrii Nakryiko 		.off = btf_ext->hdr->core_relo_off,
277628b93c64SAndrii Nakryiko 		.len = btf_ext->hdr->core_relo_len,
277728b93c64SAndrii Nakryiko 		.min_rec_size = sizeof(struct bpf_core_relo),
277828b93c64SAndrii Nakryiko 		.ext_info = &btf_ext->core_relo_info,
277928b93c64SAndrii Nakryiko 		.desc = "core_relo",
27804cedc0daSAndrii Nakryiko 	};
27814cedc0daSAndrii Nakryiko 
27824cedc0daSAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
27834cedc0daSAndrii Nakryiko }
27844cedc0daSAndrii Nakryiko 
btf_ext_parse_hdr(__u8 * data,__u32 data_size)27858461ef8bSYonghong Song static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
27862993e051SYonghong Song {
27872993e051SYonghong Song 	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
27882993e051SYonghong Song 
27894cedc0daSAndrii Nakryiko 	if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
27902993e051SYonghong Song 	    data_size < hdr->hdr_len) {
27918461ef8bSYonghong Song 		pr_debug("BTF.ext header not found");
27922993e051SYonghong Song 		return -EINVAL;
27932993e051SYonghong Song 	}
27942993e051SYonghong Song 
27953289959bSAndrii Nakryiko 	if (hdr->magic == bswap_16(BTF_MAGIC)) {
27963289959bSAndrii Nakryiko 		pr_warn("BTF.ext in non-native endianness is not supported\n");
27973289959bSAndrii Nakryiko 		return -ENOTSUP;
27983289959bSAndrii Nakryiko 	} else if (hdr->magic != BTF_MAGIC) {
27998461ef8bSYonghong Song 		pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
28002993e051SYonghong Song 		return -EINVAL;
28012993e051SYonghong Song 	}
28022993e051SYonghong Song 
28032993e051SYonghong Song 	if (hdr->version != BTF_VERSION) {
28048461ef8bSYonghong Song 		pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
28052993e051SYonghong Song 		return -ENOTSUP;
28062993e051SYonghong Song 	}
28072993e051SYonghong Song 
28082993e051SYonghong Song 	if (hdr->flags) {
28098461ef8bSYonghong Song 		pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
28102993e051SYonghong Song 		return -ENOTSUP;
28112993e051SYonghong Song 	}
28122993e051SYonghong Song 
2813f0187f0bSMartin KaFai Lau 	if (data_size == hdr->hdr_len) {
28148461ef8bSYonghong Song 		pr_debug("BTF.ext has no data\n");
28152993e051SYonghong Song 		return -EINVAL;
28162993e051SYonghong Song 	}
28172993e051SYonghong Song 
2818f0187f0bSMartin KaFai Lau 	return 0;
28192993e051SYonghong Song }
28202993e051SYonghong Song 
btf_ext__free(struct btf_ext * btf_ext)28212993e051SYonghong Song void btf_ext__free(struct btf_ext *btf_ext)
28222993e051SYonghong Song {
282350450fc7SAndrii Nakryiko 	if (IS_ERR_OR_NULL(btf_ext))
28242993e051SYonghong Song 		return;
282511d5daa8SAndrii Nakryiko 	free(btf_ext->func_info.sec_idxs);
282611d5daa8SAndrii Nakryiko 	free(btf_ext->line_info.sec_idxs);
282711d5daa8SAndrii Nakryiko 	free(btf_ext->core_relo_info.sec_idxs);
2828ae4ab4b4SAndrii Nakryiko 	free(btf_ext->data);
28292993e051SYonghong Song 	free(btf_ext);
28302993e051SYonghong Song }
28312993e051SYonghong Song 
btf_ext__new(const __u8 * data,__u32 size)2832401891a9SAndrii Nakryiko struct btf_ext *btf_ext__new(const __u8 *data, __u32 size)
28332993e051SYonghong Song {
28342993e051SYonghong Song 	struct btf_ext *btf_ext;
28352993e051SYonghong Song 	int err;
28362993e051SYonghong Song 
28372993e051SYonghong Song 	btf_ext = calloc(1, sizeof(struct btf_ext));
28382993e051SYonghong Song 	if (!btf_ext)
2839e9fc3ce9SAndrii Nakryiko 		return libbpf_err_ptr(-ENOMEM);
28402993e051SYonghong Song 
2841ae4ab4b4SAndrii Nakryiko 	btf_ext->data_size = size;
2842ae4ab4b4SAndrii Nakryiko 	btf_ext->data = malloc(size);
2843ae4ab4b4SAndrii Nakryiko 	if (!btf_ext->data) {
2844ae4ab4b4SAndrii Nakryiko 		err = -ENOMEM;
2845ae4ab4b4SAndrii Nakryiko 		goto done;
28462993e051SYonghong Song 	}
2847ae4ab4b4SAndrii Nakryiko 	memcpy(btf_ext->data, data, size);
28482993e051SYonghong Song 
2849401891a9SAndrii Nakryiko 	err = btf_ext_parse_hdr(btf_ext->data, size);
2850401891a9SAndrii Nakryiko 	if (err)
2851401891a9SAndrii Nakryiko 		goto done;
2852401891a9SAndrii Nakryiko 
2853e9fc3ce9SAndrii Nakryiko 	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
2854e9fc3ce9SAndrii Nakryiko 		err = -EINVAL;
28554cedc0daSAndrii Nakryiko 		goto done;
2856e9fc3ce9SAndrii Nakryiko 	}
2857e9fc3ce9SAndrii Nakryiko 
2858ae4ab4b4SAndrii Nakryiko 	err = btf_ext_setup_func_info(btf_ext);
2859ae4ab4b4SAndrii Nakryiko 	if (err)
2860ae4ab4b4SAndrii Nakryiko 		goto done;
2861ae4ab4b4SAndrii Nakryiko 
2862ae4ab4b4SAndrii Nakryiko 	err = btf_ext_setup_line_info(btf_ext);
2863ae4ab4b4SAndrii Nakryiko 	if (err)
2864ae4ab4b4SAndrii Nakryiko 		goto done;
2865ae4ab4b4SAndrii Nakryiko 
2866e93f3999SYuntao Wang 	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len))
2867e93f3999SYuntao Wang 		goto done; /* skip core relos parsing */
2868e9fc3ce9SAndrii Nakryiko 
286928b93c64SAndrii Nakryiko 	err = btf_ext_setup_core_relos(btf_ext);
28704cedc0daSAndrii Nakryiko 	if (err)
28714cedc0daSAndrii Nakryiko 		goto done;
28724cedc0daSAndrii Nakryiko 
2873ae4ab4b4SAndrii Nakryiko done:
28743d650141SMartin KaFai Lau 	if (err) {
28753d650141SMartin KaFai Lau 		btf_ext__free(btf_ext);
2876e9fc3ce9SAndrii Nakryiko 		return libbpf_err_ptr(err);
28773d650141SMartin KaFai Lau 	}
28783d650141SMartin KaFai Lau 
28792993e051SYonghong Song 	return btf_ext;
28802993e051SYonghong Song }
28812993e051SYonghong Song 
btf_ext__get_raw_data(const struct btf_ext * btf_ext,__u32 * size)2882ae4ab4b4SAndrii Nakryiko const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)
2883ae4ab4b4SAndrii Nakryiko {
2884ae4ab4b4SAndrii Nakryiko 	*size = btf_ext->data_size;
2885ae4ab4b4SAndrii Nakryiko 	return btf_ext->data;
2886ae4ab4b4SAndrii Nakryiko }
2887ae4ab4b4SAndrii Nakryiko 
2888d5caef5bSAndrii Nakryiko struct btf_dedup;
2889d5caef5bSAndrii Nakryiko 
2890957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
2891d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d);
2892f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d);
2893d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d);
2894d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d);
2895d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d);
2896d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d);
2897082108fdSEduard Zingerman static int btf_dedup_resolve_fwds(struct btf_dedup *d);
2898d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d);
2899d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d);
2900d5caef5bSAndrii Nakryiko 
2901d5caef5bSAndrii Nakryiko /*
2902d5caef5bSAndrii Nakryiko  * Deduplicate BTF types and strings.
2903d5caef5bSAndrii Nakryiko  *
2904d5caef5bSAndrii Nakryiko  * BTF dedup algorithm takes as an input `struct btf` representing `.BTF` ELF
2905d5caef5bSAndrii Nakryiko  * section with all BTF type descriptors and string data. It overwrites that
2906d5caef5bSAndrii Nakryiko  * memory in-place with deduplicated types and strings without any loss of
2907d5caef5bSAndrii Nakryiko  * information. If optional `struct btf_ext` representing '.BTF.ext' ELF section
2908d5caef5bSAndrii Nakryiko  * is provided, all the strings referenced from .BTF.ext section are honored
2909d5caef5bSAndrii Nakryiko  * and updated to point to the right offsets after deduplication.
2910d5caef5bSAndrii Nakryiko  *
2911d5caef5bSAndrii Nakryiko  * If function returns with error, type/string data might be garbled and should
2912d5caef5bSAndrii Nakryiko  * be discarded.
2913d5caef5bSAndrii Nakryiko  *
2914d5caef5bSAndrii Nakryiko  * More verbose and detailed description of both problem btf_dedup is solving,
2915d5caef5bSAndrii Nakryiko  * as well as solution could be found at:
2916d5caef5bSAndrii Nakryiko  * https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html
2917d5caef5bSAndrii Nakryiko  *
2918d5caef5bSAndrii Nakryiko  * Problem description and justification
2919d5caef5bSAndrii Nakryiko  * =====================================
2920d5caef5bSAndrii Nakryiko  *
2921d5caef5bSAndrii Nakryiko  * BTF type information is typically emitted either as a result of conversion
2922d5caef5bSAndrii Nakryiko  * from DWARF to BTF or directly by compiler. In both cases, each compilation
2923d5caef5bSAndrii Nakryiko  * unit contains information about a subset of all the types that are used
2924d5caef5bSAndrii Nakryiko  * in an application. These subsets are frequently overlapping and contain a lot
2925d5caef5bSAndrii Nakryiko  * of duplicated information when later concatenated together into a single
2926d5caef5bSAndrii Nakryiko  * binary. This algorithm ensures that each unique type is represented by single
2927d5caef5bSAndrii Nakryiko  * BTF type descriptor, greatly reducing resulting size of BTF data.
2928d5caef5bSAndrii Nakryiko  *
2929d5caef5bSAndrii Nakryiko  * Compilation unit isolation and subsequent duplication of data is not the only
2930d5caef5bSAndrii Nakryiko  * problem. The same type hierarchy (e.g., struct and all the type that struct
2931d5caef5bSAndrii Nakryiko  * references) in different compilation units can be represented in BTF to
2932d5caef5bSAndrii Nakryiko  * various degrees of completeness (or, rather, incompleteness) due to
2933d5caef5bSAndrii Nakryiko  * struct/union forward declarations.
2934d5caef5bSAndrii Nakryiko  *
2935d5caef5bSAndrii Nakryiko  * Let's take a look at an example, that we'll use to better understand the
2936d5caef5bSAndrii Nakryiko  * problem (and solution). Suppose we have two compilation units, each using
2937d5caef5bSAndrii Nakryiko  * same `struct S`, but each of them having incomplete type information about
2938d5caef5bSAndrii Nakryiko  * struct's fields:
2939d5caef5bSAndrii Nakryiko  *
2940d5caef5bSAndrii Nakryiko  * // CU #1:
2941d5caef5bSAndrii Nakryiko  * struct S;
2942d5caef5bSAndrii Nakryiko  * struct A {
2943d5caef5bSAndrii Nakryiko  *	int a;
2944d5caef5bSAndrii Nakryiko  *	struct A* self;
2945d5caef5bSAndrii Nakryiko  *	struct S* parent;
2946d5caef5bSAndrii Nakryiko  * };
2947d5caef5bSAndrii Nakryiko  * struct B;
2948d5caef5bSAndrii Nakryiko  * struct S {
2949d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
2950d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
2951d5caef5bSAndrii Nakryiko  * };
2952d5caef5bSAndrii Nakryiko  *
2953d5caef5bSAndrii Nakryiko  * // CU #2:
2954d5caef5bSAndrii Nakryiko  * struct S;
2955d5caef5bSAndrii Nakryiko  * struct A;
2956d5caef5bSAndrii Nakryiko  * struct B {
2957d5caef5bSAndrii Nakryiko  *	int b;
2958d5caef5bSAndrii Nakryiko  *	struct B* self;
2959d5caef5bSAndrii Nakryiko  *	struct S* parent;
2960d5caef5bSAndrii Nakryiko  * };
2961d5caef5bSAndrii Nakryiko  * struct S {
2962d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
2963d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
2964d5caef5bSAndrii Nakryiko  * };
2965d5caef5bSAndrii Nakryiko  *
2966d5caef5bSAndrii Nakryiko  * In case of CU #1, BTF data will know only that `struct B` exist (but no
2967d5caef5bSAndrii Nakryiko  * more), but will know the complete type information about `struct A`. While
2968d5caef5bSAndrii Nakryiko  * for CU #2, it will know full type information about `struct B`, but will
2969d5caef5bSAndrii Nakryiko  * only know about forward declaration of `struct A` (in BTF terms, it will
2970d5caef5bSAndrii Nakryiko  * have `BTF_KIND_FWD` type descriptor with name `B`).
2971d5caef5bSAndrii Nakryiko  *
2972d5caef5bSAndrii Nakryiko  * This compilation unit isolation means that it's possible that there is no
2973d5caef5bSAndrii Nakryiko  * single CU with complete type information describing structs `S`, `A`, and
2974d5caef5bSAndrii Nakryiko  * `B`. Also, we might get tons of duplicated and redundant type information.
2975d5caef5bSAndrii Nakryiko  *
2976d5caef5bSAndrii Nakryiko  * Additional complication we need to keep in mind comes from the fact that
2977d5caef5bSAndrii Nakryiko  * types, in general, can form graphs containing cycles, not just DAGs.
2978d5caef5bSAndrii Nakryiko  *
2979d5caef5bSAndrii Nakryiko  * While algorithm does deduplication, it also merges and resolves type
2980d5caef5bSAndrii Nakryiko  * information (unless disabled throught `struct btf_opts`), whenever possible.
2981d5caef5bSAndrii Nakryiko  * E.g., in the example above with two compilation units having partial type
2982d5caef5bSAndrii Nakryiko  * information for structs `A` and `B`, the output of algorithm will emit
2983d5caef5bSAndrii Nakryiko  * a single copy of each BTF type that describes structs `A`, `B`, and `S`
2984d5caef5bSAndrii Nakryiko  * (as well as type information for `int` and pointers), as if they were defined
2985d5caef5bSAndrii Nakryiko  * in a single compilation unit as:
2986d5caef5bSAndrii Nakryiko  *
2987d5caef5bSAndrii Nakryiko  * struct A {
2988d5caef5bSAndrii Nakryiko  *	int a;
2989d5caef5bSAndrii Nakryiko  *	struct A* self;
2990d5caef5bSAndrii Nakryiko  *	struct S* parent;
2991d5caef5bSAndrii Nakryiko  * };
2992d5caef5bSAndrii Nakryiko  * struct B {
2993d5caef5bSAndrii Nakryiko  *	int b;
2994d5caef5bSAndrii Nakryiko  *	struct B* self;
2995d5caef5bSAndrii Nakryiko  *	struct S* parent;
2996d5caef5bSAndrii Nakryiko  * };
2997d5caef5bSAndrii Nakryiko  * struct S {
2998d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
2999d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
3000d5caef5bSAndrii Nakryiko  * };
3001d5caef5bSAndrii Nakryiko  *
3002d5caef5bSAndrii Nakryiko  * Algorithm summary
3003d5caef5bSAndrii Nakryiko  * =================
3004d5caef5bSAndrii Nakryiko  *
3005082108fdSEduard Zingerman  * Algorithm completes its work in 7 separate passes:
3006d5caef5bSAndrii Nakryiko  *
3007d5caef5bSAndrii Nakryiko  * 1. Strings deduplication.
3008d5caef5bSAndrii Nakryiko  * 2. Primitive types deduplication (int, enum, fwd).
3009d5caef5bSAndrii Nakryiko  * 3. Struct/union types deduplication.
3010082108fdSEduard Zingerman  * 4. Resolve unambiguous forward declarations.
3011082108fdSEduard Zingerman  * 5. Reference types deduplication (pointers, typedefs, arrays, funcs, func
3012d5caef5bSAndrii Nakryiko  *    protos, and const/volatile/restrict modifiers).
3013082108fdSEduard Zingerman  * 6. Types compaction.
3014082108fdSEduard Zingerman  * 7. Types remapping.
3015d5caef5bSAndrii Nakryiko  *
3016d5caef5bSAndrii Nakryiko  * Algorithm determines canonical type descriptor, which is a single
3017d5caef5bSAndrii Nakryiko  * representative type for each truly unique type. This canonical type is the
3018d5caef5bSAndrii Nakryiko  * one that will go into final deduplicated BTF type information. For
3019d5caef5bSAndrii Nakryiko  * struct/unions, it is also the type that algorithm will merge additional type
3020d5caef5bSAndrii Nakryiko  * information into (while resolving FWDs), as it discovers it from data in
3021d5caef5bSAndrii Nakryiko  * other CUs. Each input BTF type eventually gets either mapped to itself, if
3022d5caef5bSAndrii Nakryiko  * that type is canonical, or to some other type, if that type is equivalent
3023d5caef5bSAndrii Nakryiko  * and was chosen as canonical representative. This mapping is stored in
3024d5caef5bSAndrii Nakryiko  * `btf_dedup->map` array. This map is also used to record STRUCT/UNION that
3025d5caef5bSAndrii Nakryiko  * FWD type got resolved to.
3026d5caef5bSAndrii Nakryiko  *
3027d5caef5bSAndrii Nakryiko  * To facilitate fast discovery of canonical types, we also maintain canonical
3028d5caef5bSAndrii Nakryiko  * index (`btf_dedup->dedup_table`), which maps type descriptor's signature hash
3029d5caef5bSAndrii Nakryiko  * (i.e., hashed kind, name, size, fields, etc) into a list of canonical types
3030d5caef5bSAndrii Nakryiko  * that match that signature. With sufficiently good choice of type signature
3031d5caef5bSAndrii Nakryiko  * hashing function, we can limit number of canonical types for each unique type
3032d5caef5bSAndrii Nakryiko  * signature to a very small number, allowing to find canonical type for any
3033d5caef5bSAndrii Nakryiko  * duplicated type very quickly.
3034d5caef5bSAndrii Nakryiko  *
3035d5caef5bSAndrii Nakryiko  * Struct/union deduplication is the most critical part and algorithm for
3036d5caef5bSAndrii Nakryiko  * deduplicating structs/unions is described in greater details in comments for
3037d5caef5bSAndrii Nakryiko  * `btf_dedup_is_equiv` function.
3038d5caef5bSAndrii Nakryiko  */
btf__dedup(struct btf * btf,const struct btf_dedup_opts * opts)3039aaf6886dSAndrii Nakryiko int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)
3040d5caef5bSAndrii Nakryiko {
3041957d350aSAndrii Nakryiko 	struct btf_dedup *d;
3042d5caef5bSAndrii Nakryiko 	int err;
3043d5caef5bSAndrii Nakryiko 
3044957d350aSAndrii Nakryiko 	if (!OPTS_VALID(opts, btf_dedup_opts))
3045957d350aSAndrii Nakryiko 		return libbpf_err(-EINVAL);
3046957d350aSAndrii Nakryiko 
3047957d350aSAndrii Nakryiko 	d = btf_dedup_new(btf, opts);
3048d5caef5bSAndrii Nakryiko 	if (IS_ERR(d)) {
3049d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d));
3050e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
3051d5caef5bSAndrii Nakryiko 	}
3052d5caef5bSAndrii Nakryiko 
30531000298cSMauricio Vásquez 	if (btf_ensure_modifiable(btf)) {
30541000298cSMauricio Vásquez 		err = -ENOMEM;
30551000298cSMauricio Vásquez 		goto done;
30561000298cSMauricio Vásquez 	}
3057919d2b1dSAndrii Nakryiko 
3058f86524efSAndrii Nakryiko 	err = btf_dedup_prep(d);
3059f86524efSAndrii Nakryiko 	if (err) {
3060f86524efSAndrii Nakryiko 		pr_debug("btf_dedup_prep failed:%d\n", err);
3061f86524efSAndrii Nakryiko 		goto done;
3062f86524efSAndrii Nakryiko 	}
3063d5caef5bSAndrii Nakryiko 	err = btf_dedup_strings(d);
3064d5caef5bSAndrii Nakryiko 	if (err < 0) {
3065d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_strings failed:%d\n", err);
3066d5caef5bSAndrii Nakryiko 		goto done;
3067d5caef5bSAndrii Nakryiko 	}
3068d5caef5bSAndrii Nakryiko 	err = btf_dedup_prim_types(d);
3069d5caef5bSAndrii Nakryiko 	if (err < 0) {
3070d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_prim_types failed:%d\n", err);
3071d5caef5bSAndrii Nakryiko 		goto done;
3072d5caef5bSAndrii Nakryiko 	}
3073d5caef5bSAndrii Nakryiko 	err = btf_dedup_struct_types(d);
3074d5caef5bSAndrii Nakryiko 	if (err < 0) {
3075d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_struct_types failed:%d\n", err);
3076d5caef5bSAndrii Nakryiko 		goto done;
3077d5caef5bSAndrii Nakryiko 	}
3078082108fdSEduard Zingerman 	err = btf_dedup_resolve_fwds(d);
3079082108fdSEduard Zingerman 	if (err < 0) {
3080082108fdSEduard Zingerman 		pr_debug("btf_dedup_resolve_fwds failed:%d\n", err);
3081082108fdSEduard Zingerman 		goto done;
3082082108fdSEduard Zingerman 	}
3083d5caef5bSAndrii Nakryiko 	err = btf_dedup_ref_types(d);
3084d5caef5bSAndrii Nakryiko 	if (err < 0) {
3085d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_ref_types failed:%d\n", err);
3086d5caef5bSAndrii Nakryiko 		goto done;
3087d5caef5bSAndrii Nakryiko 	}
3088d5caef5bSAndrii Nakryiko 	err = btf_dedup_compact_types(d);
3089d5caef5bSAndrii Nakryiko 	if (err < 0) {
3090d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_compact_types failed:%d\n", err);
3091d5caef5bSAndrii Nakryiko 		goto done;
3092d5caef5bSAndrii Nakryiko 	}
3093d5caef5bSAndrii Nakryiko 	err = btf_dedup_remap_types(d);
3094d5caef5bSAndrii Nakryiko 	if (err < 0) {
3095d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_remap_types failed:%d\n", err);
3096d5caef5bSAndrii Nakryiko 		goto done;
3097d5caef5bSAndrii Nakryiko 	}
3098d5caef5bSAndrii Nakryiko 
3099d5caef5bSAndrii Nakryiko done:
3100d5caef5bSAndrii Nakryiko 	btf_dedup_free(d);
3101e9fc3ce9SAndrii Nakryiko 	return libbpf_err(err);
3102d5caef5bSAndrii Nakryiko }
3103d5caef5bSAndrii Nakryiko 
3104d5caef5bSAndrii Nakryiko #define BTF_UNPROCESSED_ID ((__u32)-1)
3105d5caef5bSAndrii Nakryiko #define BTF_IN_PROGRESS_ID ((__u32)-2)
3106d5caef5bSAndrii Nakryiko 
3107d5caef5bSAndrii Nakryiko struct btf_dedup {
3108d5caef5bSAndrii Nakryiko 	/* .BTF section to be deduped in-place */
3109d5caef5bSAndrii Nakryiko 	struct btf *btf;
3110d5caef5bSAndrii Nakryiko 	/*
3111d5caef5bSAndrii Nakryiko 	 * Optional .BTF.ext section. When provided, any strings referenced
3112d5caef5bSAndrii Nakryiko 	 * from it will be taken into account when deduping strings
3113d5caef5bSAndrii Nakryiko 	 */
3114d5caef5bSAndrii Nakryiko 	struct btf_ext *btf_ext;
3115d5caef5bSAndrii Nakryiko 	/*
3116d5caef5bSAndrii Nakryiko 	 * This is a map from any type's signature hash to a list of possible
3117d5caef5bSAndrii Nakryiko 	 * canonical representative type candidates. Hash collisions are
3118d5caef5bSAndrii Nakryiko 	 * ignored, so even types of various kinds can share same list of
3119d5caef5bSAndrii Nakryiko 	 * candidates, which is fine because we rely on subsequent
3120d5caef5bSAndrii Nakryiko 	 * btf_xxx_equal() checks to authoritatively verify type equality.
3121d5caef5bSAndrii Nakryiko 	 */
31222fc3fc0bSAndrii Nakryiko 	struct hashmap *dedup_table;
3123d5caef5bSAndrii Nakryiko 	/* Canonical types map */
3124d5caef5bSAndrii Nakryiko 	__u32 *map;
3125d5caef5bSAndrii Nakryiko 	/* Hypothetical mapping, used during type graph equivalence checks */
3126d5caef5bSAndrii Nakryiko 	__u32 *hypot_map;
3127d5caef5bSAndrii Nakryiko 	__u32 *hypot_list;
3128d5caef5bSAndrii Nakryiko 	size_t hypot_cnt;
3129d5caef5bSAndrii Nakryiko 	size_t hypot_cap;
3130f86524efSAndrii Nakryiko 	/* Whether hypothetical mapping, if successful, would need to adjust
3131f86524efSAndrii Nakryiko 	 * already canonicalized types (due to a new forward declaration to
3132f86524efSAndrii Nakryiko 	 * concrete type resolution). In such case, during split BTF dedup
3133f86524efSAndrii Nakryiko 	 * candidate type would still be considered as different, because base
3134f86524efSAndrii Nakryiko 	 * BTF is considered to be immutable.
3135f86524efSAndrii Nakryiko 	 */
3136f86524efSAndrii Nakryiko 	bool hypot_adjust_canon;
3137d5caef5bSAndrii Nakryiko 	/* Various option modifying behavior of algorithm */
3138d5caef5bSAndrii Nakryiko 	struct btf_dedup_opts opts;
313988a82c2aSAndrii Nakryiko 	/* temporary strings deduplication state */
314090d76d3eSAndrii Nakryiko 	struct strset *strs_set;
3141d5caef5bSAndrii Nakryiko };
3142d5caef5bSAndrii Nakryiko 
hash_combine(long h,long value)31432fc3fc0bSAndrii Nakryiko static long hash_combine(long h, long value)
3144d5caef5bSAndrii Nakryiko {
31452fc3fc0bSAndrii Nakryiko 	return h * 31 + value;
3146d5caef5bSAndrii Nakryiko }
3147d5caef5bSAndrii Nakryiko 
31482fc3fc0bSAndrii Nakryiko #define for_each_dedup_cand(d, node, hash) \
3149c302378bSEduard Zingerman 	hashmap__for_each_key_entry(d->dedup_table, node, hash)
3150d5caef5bSAndrii Nakryiko 
btf_dedup_table_add(struct btf_dedup * d,long hash,__u32 type_id)31512fc3fc0bSAndrii Nakryiko static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
3152d5caef5bSAndrii Nakryiko {
3153c302378bSEduard Zingerman 	return hashmap__append(d->dedup_table, hash, type_id);
3154d5caef5bSAndrii Nakryiko }
3155d5caef5bSAndrii Nakryiko 
btf_dedup_hypot_map_add(struct btf_dedup * d,__u32 from_id,__u32 to_id)3156d5caef5bSAndrii Nakryiko static int btf_dedup_hypot_map_add(struct btf_dedup *d,
3157d5caef5bSAndrii Nakryiko 				   __u32 from_id, __u32 to_id)
3158d5caef5bSAndrii Nakryiko {
3159d5caef5bSAndrii Nakryiko 	if (d->hypot_cnt == d->hypot_cap) {
3160d5caef5bSAndrii Nakryiko 		__u32 *new_list;
3161d5caef5bSAndrii Nakryiko 
3162fb2426adSMartin KaFai Lau 		d->hypot_cap += max((size_t)16, d->hypot_cap / 2);
3163029258d7SAndrii Nakryiko 		new_list = libbpf_reallocarray(d->hypot_list, d->hypot_cap, sizeof(__u32));
3164d5caef5bSAndrii Nakryiko 		if (!new_list)
3165d5caef5bSAndrii Nakryiko 			return -ENOMEM;
3166d5caef5bSAndrii Nakryiko 		d->hypot_list = new_list;
3167d5caef5bSAndrii Nakryiko 	}
3168d5caef5bSAndrii Nakryiko 	d->hypot_list[d->hypot_cnt++] = from_id;
3169d5caef5bSAndrii Nakryiko 	d->hypot_map[from_id] = to_id;
3170d5caef5bSAndrii Nakryiko 	return 0;
3171d5caef5bSAndrii Nakryiko }
3172d5caef5bSAndrii Nakryiko 
btf_dedup_clear_hypot_map(struct btf_dedup * d)3173d5caef5bSAndrii Nakryiko static void btf_dedup_clear_hypot_map(struct btf_dedup *d)
3174d5caef5bSAndrii Nakryiko {
3175d5caef5bSAndrii Nakryiko 	int i;
3176d5caef5bSAndrii Nakryiko 
3177d5caef5bSAndrii Nakryiko 	for (i = 0; i < d->hypot_cnt; i++)
3178d5caef5bSAndrii Nakryiko 		d->hypot_map[d->hypot_list[i]] = BTF_UNPROCESSED_ID;
3179d5caef5bSAndrii Nakryiko 	d->hypot_cnt = 0;
3180f86524efSAndrii Nakryiko 	d->hypot_adjust_canon = false;
3181d5caef5bSAndrii Nakryiko }
3182d5caef5bSAndrii Nakryiko 
btf_dedup_free(struct btf_dedup * d)3183d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d)
3184d5caef5bSAndrii Nakryiko {
31852fc3fc0bSAndrii Nakryiko 	hashmap__free(d->dedup_table);
31862fc3fc0bSAndrii Nakryiko 	d->dedup_table = NULL;
3187d5caef5bSAndrii Nakryiko 
3188d5caef5bSAndrii Nakryiko 	free(d->map);
3189d5caef5bSAndrii Nakryiko 	d->map = NULL;
3190d5caef5bSAndrii Nakryiko 
3191d5caef5bSAndrii Nakryiko 	free(d->hypot_map);
3192d5caef5bSAndrii Nakryiko 	d->hypot_map = NULL;
3193d5caef5bSAndrii Nakryiko 
3194d5caef5bSAndrii Nakryiko 	free(d->hypot_list);
3195d5caef5bSAndrii Nakryiko 	d->hypot_list = NULL;
3196d5caef5bSAndrii Nakryiko 
3197d5caef5bSAndrii Nakryiko 	free(d);
3198d5caef5bSAndrii Nakryiko }
3199d5caef5bSAndrii Nakryiko 
btf_dedup_identity_hash_fn(long key,void * ctx)3200c302378bSEduard Zingerman static size_t btf_dedup_identity_hash_fn(long key, void *ctx)
320151edf5f6SAndrii Nakryiko {
3202c302378bSEduard Zingerman 	return key;
320351edf5f6SAndrii Nakryiko }
320451edf5f6SAndrii Nakryiko 
btf_dedup_collision_hash_fn(long key,void * ctx)3205c302378bSEduard Zingerman static size_t btf_dedup_collision_hash_fn(long key, void *ctx)
32062fc3fc0bSAndrii Nakryiko {
32072fc3fc0bSAndrii Nakryiko 	return 0;
32082fc3fc0bSAndrii Nakryiko }
32092fc3fc0bSAndrii Nakryiko 
btf_dedup_equal_fn(long k1,long k2,void * ctx)3210c302378bSEduard Zingerman static bool btf_dedup_equal_fn(long k1, long k2, void *ctx)
32112fc3fc0bSAndrii Nakryiko {
32122fc3fc0bSAndrii Nakryiko 	return k1 == k2;
32132fc3fc0bSAndrii Nakryiko }
321451edf5f6SAndrii Nakryiko 
btf_dedup_new(struct btf * btf,const struct btf_dedup_opts * opts)3215957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts)
3216d5caef5bSAndrii Nakryiko {
3217d5caef5bSAndrii Nakryiko 	struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup));
32182fc3fc0bSAndrii Nakryiko 	hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn;
3219f86524efSAndrii Nakryiko 	int i, err = 0, type_cnt;
3220d5caef5bSAndrii Nakryiko 
3221d5caef5bSAndrii Nakryiko 	if (!d)
3222d5caef5bSAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
3223d5caef5bSAndrii Nakryiko 
3224957d350aSAndrii Nakryiko 	if (OPTS_GET(opts, force_collisions, false))
32252fc3fc0bSAndrii Nakryiko 		hash_fn = btf_dedup_collision_hash_fn;
322651edf5f6SAndrii Nakryiko 
3227d5caef5bSAndrii Nakryiko 	d->btf = btf;
3228957d350aSAndrii Nakryiko 	d->btf_ext = OPTS_GET(opts, btf_ext, NULL);
3229d5caef5bSAndrii Nakryiko 
32302fc3fc0bSAndrii Nakryiko 	d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL);
32312fc3fc0bSAndrii Nakryiko 	if (IS_ERR(d->dedup_table)) {
32322fc3fc0bSAndrii Nakryiko 		err = PTR_ERR(d->dedup_table);
32332fc3fc0bSAndrii Nakryiko 		d->dedup_table = NULL;
3234d5caef5bSAndrii Nakryiko 		goto done;
3235d5caef5bSAndrii Nakryiko 	}
3236d5caef5bSAndrii Nakryiko 
32376a886de0SHengqi Chen 	type_cnt = btf__type_cnt(btf);
3238f86524efSAndrii Nakryiko 	d->map = malloc(sizeof(__u32) * type_cnt);
3239d5caef5bSAndrii Nakryiko 	if (!d->map) {
3240d5caef5bSAndrii Nakryiko 		err = -ENOMEM;
3241d5caef5bSAndrii Nakryiko 		goto done;
3242d5caef5bSAndrii Nakryiko 	}
3243d5caef5bSAndrii Nakryiko 	/* special BTF "void" type is made canonical immediately */
3244d5caef5bSAndrii Nakryiko 	d->map[0] = 0;
3245f86524efSAndrii Nakryiko 	for (i = 1; i < type_cnt; i++) {
3246740e69c3SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, i);
3247189cf5a4SAndrii Nakryiko 
3248189cf5a4SAndrii Nakryiko 		/* VAR and DATASEC are never deduped and are self-canonical */
3249b03bc685SAndrii Nakryiko 		if (btf_is_var(t) || btf_is_datasec(t))
3250189cf5a4SAndrii Nakryiko 			d->map[i] = i;
3251189cf5a4SAndrii Nakryiko 		else
3252d5caef5bSAndrii Nakryiko 			d->map[i] = BTF_UNPROCESSED_ID;
3253189cf5a4SAndrii Nakryiko 	}
3254d5caef5bSAndrii Nakryiko 
3255f86524efSAndrii Nakryiko 	d->hypot_map = malloc(sizeof(__u32) * type_cnt);
3256d5caef5bSAndrii Nakryiko 	if (!d->hypot_map) {
3257d5caef5bSAndrii Nakryiko 		err = -ENOMEM;
3258d5caef5bSAndrii Nakryiko 		goto done;
3259d5caef5bSAndrii Nakryiko 	}
3260f86524efSAndrii Nakryiko 	for (i = 0; i < type_cnt; i++)
3261d5caef5bSAndrii Nakryiko 		d->hypot_map[i] = BTF_UNPROCESSED_ID;
3262d5caef5bSAndrii Nakryiko 
3263d5caef5bSAndrii Nakryiko done:
3264d5caef5bSAndrii Nakryiko 	if (err) {
3265d5caef5bSAndrii Nakryiko 		btf_dedup_free(d);
3266d5caef5bSAndrii Nakryiko 		return ERR_PTR(err);
3267d5caef5bSAndrii Nakryiko 	}
3268d5caef5bSAndrii Nakryiko 
3269d5caef5bSAndrii Nakryiko 	return d;
3270d5caef5bSAndrii Nakryiko }
3271d5caef5bSAndrii Nakryiko 
3272d5caef5bSAndrii Nakryiko /*
3273d5caef5bSAndrii Nakryiko  * Iterate over all possible places in .BTF and .BTF.ext that can reference
3274d5caef5bSAndrii Nakryiko  * string and pass pointer to it to a provided callback `fn`.
3275d5caef5bSAndrii Nakryiko  */
btf_for_each_str_off(struct btf_dedup * d,str_off_visit_fn fn,void * ctx)3276f36e99a4SAndrii Nakryiko static int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx)
3277d5caef5bSAndrii Nakryiko {
3278f36e99a4SAndrii Nakryiko 	int i, r;
3279d5caef5bSAndrii Nakryiko 
3280f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
3281f36e99a4SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
3282f36e99a4SAndrii Nakryiko 
3283f36e99a4SAndrii Nakryiko 		r = btf_type_visit_str_offs(t, fn, ctx);
3284d5caef5bSAndrii Nakryiko 		if (r)
3285d5caef5bSAndrii Nakryiko 			return r;
3286d5caef5bSAndrii Nakryiko 	}
3287d5caef5bSAndrii Nakryiko 
3288d5caef5bSAndrii Nakryiko 	if (!d->btf_ext)
3289d5caef5bSAndrii Nakryiko 		return 0;
3290d5caef5bSAndrii Nakryiko 
3291f36e99a4SAndrii Nakryiko 	r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx);
3292d5caef5bSAndrii Nakryiko 	if (r)
3293d5caef5bSAndrii Nakryiko 		return r;
3294d5caef5bSAndrii Nakryiko 
3295d5caef5bSAndrii Nakryiko 	return 0;
3296d5caef5bSAndrii Nakryiko }
3297d5caef5bSAndrii Nakryiko 
strs_dedup_remap_str_off(__u32 * str_off_ptr,void * ctx)329888a82c2aSAndrii Nakryiko static int strs_dedup_remap_str_off(__u32 *str_off_ptr, void *ctx)
3299d5caef5bSAndrii Nakryiko {
330088a82c2aSAndrii Nakryiko 	struct btf_dedup *d = ctx;
3301f86524efSAndrii Nakryiko 	__u32 str_off = *str_off_ptr;
330288a82c2aSAndrii Nakryiko 	const char *s;
330390d76d3eSAndrii Nakryiko 	int off, err;
3304d5caef5bSAndrii Nakryiko 
3305f86524efSAndrii Nakryiko 	/* don't touch empty string or string in main BTF */
3306f86524efSAndrii Nakryiko 	if (str_off == 0 || str_off < d->btf->start_str_off)
3307d5caef5bSAndrii Nakryiko 		return 0;
3308d5caef5bSAndrii Nakryiko 
3309f86524efSAndrii Nakryiko 	s = btf__str_by_offset(d->btf, str_off);
3310f86524efSAndrii Nakryiko 	if (d->btf->base_btf) {
3311f86524efSAndrii Nakryiko 		err = btf__find_str(d->btf->base_btf, s);
3312f86524efSAndrii Nakryiko 		if (err >= 0) {
3313f86524efSAndrii Nakryiko 			*str_off_ptr = err;
3314f86524efSAndrii Nakryiko 			return 0;
3315f86524efSAndrii Nakryiko 		}
3316f86524efSAndrii Nakryiko 		if (err != -ENOENT)
3317f86524efSAndrii Nakryiko 			return err;
3318f86524efSAndrii Nakryiko 	}
3319f86524efSAndrii Nakryiko 
332090d76d3eSAndrii Nakryiko 	off = strset__add_str(d->strs_set, s);
332190d76d3eSAndrii Nakryiko 	if (off < 0)
332290d76d3eSAndrii Nakryiko 		return off;
332388a82c2aSAndrii Nakryiko 
332490d76d3eSAndrii Nakryiko 	*str_off_ptr = d->btf->start_str_off + off;
3325d5caef5bSAndrii Nakryiko 	return 0;
3326d5caef5bSAndrii Nakryiko }
3327d5caef5bSAndrii Nakryiko 
3328d5caef5bSAndrii Nakryiko /*
3329d5caef5bSAndrii Nakryiko  * Dedup string and filter out those that are not referenced from either .BTF
3330d5caef5bSAndrii Nakryiko  * or .BTF.ext (if provided) sections.
3331d5caef5bSAndrii Nakryiko  *
3332d5caef5bSAndrii Nakryiko  * This is done by building index of all strings in BTF's string section,
3333d5caef5bSAndrii Nakryiko  * then iterating over all entities that can reference strings (e.g., type
3334d5caef5bSAndrii Nakryiko  * names, struct field names, .BTF.ext line info, etc) and marking corresponding
3335d5caef5bSAndrii Nakryiko  * strings as used. After that all used strings are deduped and compacted into
3336d5caef5bSAndrii Nakryiko  * sequential blob of memory and new offsets are calculated. Then all the string
3337d5caef5bSAndrii Nakryiko  * references are iterated again and rewritten using new offsets.
3338d5caef5bSAndrii Nakryiko  */
btf_dedup_strings(struct btf_dedup * d)3339d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d)
3340d5caef5bSAndrii Nakryiko {
334188a82c2aSAndrii Nakryiko 	int err;
3342d5caef5bSAndrii Nakryiko 
3343919d2b1dSAndrii Nakryiko 	if (d->btf->strs_deduped)
3344919d2b1dSAndrii Nakryiko 		return 0;
3345919d2b1dSAndrii Nakryiko 
334690d76d3eSAndrii Nakryiko 	d->strs_set = strset__new(BTF_MAX_STR_OFFSET, NULL, 0);
334790d76d3eSAndrii Nakryiko 	if (IS_ERR(d->strs_set)) {
334890d76d3eSAndrii Nakryiko 		err = PTR_ERR(d->strs_set);
334988a82c2aSAndrii Nakryiko 		goto err_out;
3350d5caef5bSAndrii Nakryiko 	}
3351d5caef5bSAndrii Nakryiko 
3352f86524efSAndrii Nakryiko 	if (!d->btf->base_btf) {
335388a82c2aSAndrii Nakryiko 		/* insert empty string; we won't be looking it up during strings
335488a82c2aSAndrii Nakryiko 		 * dedup, but it's good to have it for generic BTF string lookups
335588a82c2aSAndrii Nakryiko 		 */
335690d76d3eSAndrii Nakryiko 		err = strset__add_str(d->strs_set, "");
335790d76d3eSAndrii Nakryiko 		if (err < 0)
335888a82c2aSAndrii Nakryiko 			goto err_out;
3359f86524efSAndrii Nakryiko 	}
3360d5caef5bSAndrii Nakryiko 
3361d5caef5bSAndrii Nakryiko 	/* remap string offsets */
336288a82c2aSAndrii Nakryiko 	err = btf_for_each_str_off(d, strs_dedup_remap_str_off, d);
3363d5caef5bSAndrii Nakryiko 	if (err)
336488a82c2aSAndrii Nakryiko 		goto err_out;
3365d5caef5bSAndrii Nakryiko 
336688a82c2aSAndrii Nakryiko 	/* replace BTF string data and hash with deduped ones */
336790d76d3eSAndrii Nakryiko 	strset__free(d->btf->strs_set);
336890d76d3eSAndrii Nakryiko 	d->btf->hdr->str_len = strset__data_size(d->strs_set);
336990d76d3eSAndrii Nakryiko 	d->btf->strs_set = d->strs_set;
337090d76d3eSAndrii Nakryiko 	d->strs_set = NULL;
3371919d2b1dSAndrii Nakryiko 	d->btf->strs_deduped = true;
337288a82c2aSAndrii Nakryiko 	return 0;
3373d5caef5bSAndrii Nakryiko 
337488a82c2aSAndrii Nakryiko err_out:
337590d76d3eSAndrii Nakryiko 	strset__free(d->strs_set);
337690d76d3eSAndrii Nakryiko 	d->strs_set = NULL;
337788a82c2aSAndrii Nakryiko 
3378d5caef5bSAndrii Nakryiko 	return err;
3379d5caef5bSAndrii Nakryiko }
3380d5caef5bSAndrii Nakryiko 
btf_hash_common(struct btf_type * t)33812fc3fc0bSAndrii Nakryiko static long btf_hash_common(struct btf_type *t)
3382d5caef5bSAndrii Nakryiko {
33832fc3fc0bSAndrii Nakryiko 	long h;
3384d5caef5bSAndrii Nakryiko 
3385d5caef5bSAndrii Nakryiko 	h = hash_combine(0, t->name_off);
3386d5caef5bSAndrii Nakryiko 	h = hash_combine(h, t->info);
3387d5caef5bSAndrii Nakryiko 	h = hash_combine(h, t->size);
3388d5caef5bSAndrii Nakryiko 	return h;
3389d5caef5bSAndrii Nakryiko }
3390d5caef5bSAndrii Nakryiko 
btf_equal_common(struct btf_type * t1,struct btf_type * t2)3391d5caef5bSAndrii Nakryiko static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2)
3392d5caef5bSAndrii Nakryiko {
3393d5caef5bSAndrii Nakryiko 	return t1->name_off == t2->name_off &&
3394d5caef5bSAndrii Nakryiko 	       t1->info == t2->info &&
3395d5caef5bSAndrii Nakryiko 	       t1->size == t2->size;
3396d5caef5bSAndrii Nakryiko }
3397d5caef5bSAndrii Nakryiko 
339830025e8bSYonghong Song /* Calculate type signature hash of INT or TAG. */
btf_hash_int_decl_tag(struct btf_type * t)3399223f903eSYonghong Song static long btf_hash_int_decl_tag(struct btf_type *t)
3400d5caef5bSAndrii Nakryiko {
3401d5caef5bSAndrii Nakryiko 	__u32 info = *(__u32 *)(t + 1);
34022fc3fc0bSAndrii Nakryiko 	long h;
3403d5caef5bSAndrii Nakryiko 
3404d5caef5bSAndrii Nakryiko 	h = btf_hash_common(t);
3405d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info);
3406d5caef5bSAndrii Nakryiko 	return h;
3407d5caef5bSAndrii Nakryiko }
3408d5caef5bSAndrii Nakryiko 
340930025e8bSYonghong Song /* Check structural equality of two INTs or TAGs. */
btf_equal_int_tag(struct btf_type * t1,struct btf_type * t2)341030025e8bSYonghong Song static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
3411d5caef5bSAndrii Nakryiko {
3412d5caef5bSAndrii Nakryiko 	__u32 info1, info2;
3413d5caef5bSAndrii Nakryiko 
3414d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3415d5caef5bSAndrii Nakryiko 		return false;
3416d5caef5bSAndrii Nakryiko 	info1 = *(__u32 *)(t1 + 1);
3417d5caef5bSAndrii Nakryiko 	info2 = *(__u32 *)(t2 + 1);
3418d5caef5bSAndrii Nakryiko 	return info1 == info2;
3419d5caef5bSAndrii Nakryiko }
3420d5caef5bSAndrii Nakryiko 
34212ef20263SYonghong Song /* Calculate type signature hash of ENUM/ENUM64. */
btf_hash_enum(struct btf_type * t)34222fc3fc0bSAndrii Nakryiko static long btf_hash_enum(struct btf_type *t)
3423d5caef5bSAndrii Nakryiko {
34242fc3fc0bSAndrii Nakryiko 	long h;
3425d5caef5bSAndrii Nakryiko 
3426de048b6eSEduard Zingerman 	/* don't hash vlen, enum members and size to support enum fwd resolving */
34279768095bSAndrii Nakryiko 	h = hash_combine(0, t->name_off);
3428d5caef5bSAndrii Nakryiko 	return h;
3429d5caef5bSAndrii Nakryiko }
3430d5caef5bSAndrii Nakryiko 
btf_equal_enum_members(struct btf_type * t1,struct btf_type * t2)3431de048b6eSEduard Zingerman static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
3432d5caef5bSAndrii Nakryiko {
3433b03bc685SAndrii Nakryiko 	const struct btf_enum *m1, *m2;
3434d5caef5bSAndrii Nakryiko 	__u16 vlen;
3435d5caef5bSAndrii Nakryiko 	int i;
3436d5caef5bSAndrii Nakryiko 
3437b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3438b03bc685SAndrii Nakryiko 	m1 = btf_enum(t1);
3439b03bc685SAndrii Nakryiko 	m2 = btf_enum(t2);
3440d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3441d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->val != m2->val)
3442d5caef5bSAndrii Nakryiko 			return false;
3443d5caef5bSAndrii Nakryiko 		m1++;
3444d5caef5bSAndrii Nakryiko 		m2++;
3445d5caef5bSAndrii Nakryiko 	}
3446d5caef5bSAndrii Nakryiko 	return true;
3447d5caef5bSAndrii Nakryiko }
3448d5caef5bSAndrii Nakryiko 
btf_equal_enum64_members(struct btf_type * t1,struct btf_type * t2)3449de048b6eSEduard Zingerman static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
34502ef20263SYonghong Song {
34512ef20263SYonghong Song 	const struct btf_enum64 *m1, *m2;
34522ef20263SYonghong Song 	__u16 vlen;
34532ef20263SYonghong Song 	int i;
34542ef20263SYonghong Song 
34552ef20263SYonghong Song 	vlen = btf_vlen(t1);
34562ef20263SYonghong Song 	m1 = btf_enum64(t1);
34572ef20263SYonghong Song 	m2 = btf_enum64(t2);
34582ef20263SYonghong Song 	for (i = 0; i < vlen; i++) {
34592ef20263SYonghong Song 		if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
34602ef20263SYonghong Song 		    m1->val_hi32 != m2->val_hi32)
34612ef20263SYonghong Song 			return false;
34622ef20263SYonghong Song 		m1++;
34632ef20263SYonghong Song 		m2++;
34642ef20263SYonghong Song 	}
34652ef20263SYonghong Song 	return true;
34662ef20263SYonghong Song }
34672ef20263SYonghong Song 
3468de048b6eSEduard Zingerman /* Check structural equality of two ENUMs or ENUM64s. */
btf_equal_enum(struct btf_type * t1,struct btf_type * t2)3469de048b6eSEduard Zingerman static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
3470de048b6eSEduard Zingerman {
3471de048b6eSEduard Zingerman 	if (!btf_equal_common(t1, t2))
3472de048b6eSEduard Zingerman 		return false;
3473de048b6eSEduard Zingerman 
3474de048b6eSEduard Zingerman 	/* t1 & t2 kinds are identical because of btf_equal_common */
3475de048b6eSEduard Zingerman 	if (btf_kind(t1) == BTF_KIND_ENUM)
3476de048b6eSEduard Zingerman 		return btf_equal_enum_members(t1, t2);
3477de048b6eSEduard Zingerman 	else
3478de048b6eSEduard Zingerman 		return btf_equal_enum64_members(t1, t2);
3479de048b6eSEduard Zingerman }
3480de048b6eSEduard Zingerman 
btf_is_enum_fwd(struct btf_type * t)34819768095bSAndrii Nakryiko static inline bool btf_is_enum_fwd(struct btf_type *t)
34829768095bSAndrii Nakryiko {
34832ef20263SYonghong Song 	return btf_is_any_enum(t) && btf_vlen(t) == 0;
34849768095bSAndrii Nakryiko }
34859768095bSAndrii Nakryiko 
btf_compat_enum(struct btf_type * t1,struct btf_type * t2)34869768095bSAndrii Nakryiko static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
34879768095bSAndrii Nakryiko {
34889768095bSAndrii Nakryiko 	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
34899768095bSAndrii Nakryiko 		return btf_equal_enum(t1, t2);
3490de048b6eSEduard Zingerman 	/* At this point either t1 or t2 or both are forward declarations, thus:
3491de048b6eSEduard Zingerman 	 * - skip comparing vlen because it is zero for forward declarations;
3492de048b6eSEduard Zingerman 	 * - skip comparing size to allow enum forward declarations
3493de048b6eSEduard Zingerman 	 *   to be compatible with enum64 full declarations;
3494de048b6eSEduard Zingerman 	 * - skip comparing kind for the same reason.
3495de048b6eSEduard Zingerman 	 */
34969768095bSAndrii Nakryiko 	return t1->name_off == t2->name_off &&
3497de048b6eSEduard Zingerman 	       btf_is_any_enum(t1) && btf_is_any_enum(t2);
34982ef20263SYonghong Song }
34992ef20263SYonghong Song 
3500d5caef5bSAndrii Nakryiko /*
3501d5caef5bSAndrii Nakryiko  * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
3502d5caef5bSAndrii Nakryiko  * as referenced type IDs equivalence is established separately during type
3503d5caef5bSAndrii Nakryiko  * graph equivalence check algorithm.
3504d5caef5bSAndrii Nakryiko  */
btf_hash_struct(struct btf_type * t)35052fc3fc0bSAndrii Nakryiko static long btf_hash_struct(struct btf_type *t)
3506d5caef5bSAndrii Nakryiko {
3507b03bc685SAndrii Nakryiko 	const struct btf_member *member = btf_members(t);
3508b03bc685SAndrii Nakryiko 	__u32 vlen = btf_vlen(t);
35092fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3510d5caef5bSAndrii Nakryiko 	int i;
3511d5caef5bSAndrii Nakryiko 
3512d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3513d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->name_off);
3514d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->offset);
3515d5caef5bSAndrii Nakryiko 		/* no hashing of referenced type ID, it can be unresolved yet */
3516d5caef5bSAndrii Nakryiko 		member++;
3517d5caef5bSAndrii Nakryiko 	}
3518d5caef5bSAndrii Nakryiko 	return h;
3519d5caef5bSAndrii Nakryiko }
3520d5caef5bSAndrii Nakryiko 
3521d5caef5bSAndrii Nakryiko /*
3522efdd3eb8SAndrii Nakryiko  * Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced
3523efdd3eb8SAndrii Nakryiko  * type IDs. This check is performed during type graph equivalence check and
3524d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3525d5caef5bSAndrii Nakryiko  */
btf_shallow_equal_struct(struct btf_type * t1,struct btf_type * t2)352691097fbeSAndrii Nakryiko static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
3527d5caef5bSAndrii Nakryiko {
3528b03bc685SAndrii Nakryiko 	const struct btf_member *m1, *m2;
3529d5caef5bSAndrii Nakryiko 	__u16 vlen;
3530d5caef5bSAndrii Nakryiko 	int i;
3531d5caef5bSAndrii Nakryiko 
3532d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3533d5caef5bSAndrii Nakryiko 		return false;
3534d5caef5bSAndrii Nakryiko 
3535b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3536b03bc685SAndrii Nakryiko 	m1 = btf_members(t1);
3537b03bc685SAndrii Nakryiko 	m2 = btf_members(t2);
3538d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3539d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
3540d5caef5bSAndrii Nakryiko 			return false;
3541d5caef5bSAndrii Nakryiko 		m1++;
3542d5caef5bSAndrii Nakryiko 		m2++;
3543d5caef5bSAndrii Nakryiko 	}
3544d5caef5bSAndrii Nakryiko 	return true;
3545d5caef5bSAndrii Nakryiko }
3546d5caef5bSAndrii Nakryiko 
3547d5caef5bSAndrii Nakryiko /*
3548d5caef5bSAndrii Nakryiko  * Calculate type signature hash of ARRAY, including referenced type IDs,
3549d5caef5bSAndrii Nakryiko  * under assumption that they were already resolved to canonical type IDs and
3550d5caef5bSAndrii Nakryiko  * are not going to change.
3551d5caef5bSAndrii Nakryiko  */
btf_hash_array(struct btf_type * t)35522fc3fc0bSAndrii Nakryiko static long btf_hash_array(struct btf_type *t)
3553d5caef5bSAndrii Nakryiko {
3554b03bc685SAndrii Nakryiko 	const struct btf_array *info = btf_array(t);
35552fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3556d5caef5bSAndrii Nakryiko 
3557d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->type);
3558d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->index_type);
3559d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->nelems);
3560d5caef5bSAndrii Nakryiko 	return h;
3561d5caef5bSAndrii Nakryiko }
3562d5caef5bSAndrii Nakryiko 
3563d5caef5bSAndrii Nakryiko /*
3564d5caef5bSAndrii Nakryiko  * Check exact equality of two ARRAYs, taking into account referenced
3565d5caef5bSAndrii Nakryiko  * type IDs, under assumption that they were already resolved to canonical
3566d5caef5bSAndrii Nakryiko  * type IDs and are not going to change.
3567d5caef5bSAndrii Nakryiko  * This function is called during reference types deduplication to compare
3568d5caef5bSAndrii Nakryiko  * ARRAY to potential canonical representative.
3569d5caef5bSAndrii Nakryiko  */
btf_equal_array(struct btf_type * t1,struct btf_type * t2)3570d5caef5bSAndrii Nakryiko static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
3571d5caef5bSAndrii Nakryiko {
3572b03bc685SAndrii Nakryiko 	const struct btf_array *info1, *info2;
3573d5caef5bSAndrii Nakryiko 
3574d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3575d5caef5bSAndrii Nakryiko 		return false;
3576d5caef5bSAndrii Nakryiko 
3577b03bc685SAndrii Nakryiko 	info1 = btf_array(t1);
3578b03bc685SAndrii Nakryiko 	info2 = btf_array(t2);
3579d5caef5bSAndrii Nakryiko 	return info1->type == info2->type &&
3580d5caef5bSAndrii Nakryiko 	       info1->index_type == info2->index_type &&
3581d5caef5bSAndrii Nakryiko 	       info1->nelems == info2->nelems;
3582d5caef5bSAndrii Nakryiko }
3583d5caef5bSAndrii Nakryiko 
3584d5caef5bSAndrii Nakryiko /*
3585d5caef5bSAndrii Nakryiko  * Check structural compatibility of two ARRAYs, ignoring referenced type
3586d5caef5bSAndrii Nakryiko  * IDs. This check is performed during type graph equivalence check and
3587d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3588d5caef5bSAndrii Nakryiko  */
btf_compat_array(struct btf_type * t1,struct btf_type * t2)3589d5caef5bSAndrii Nakryiko static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
3590d5caef5bSAndrii Nakryiko {
3591d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3592d5caef5bSAndrii Nakryiko 		return false;
3593d5caef5bSAndrii Nakryiko 
3594b03bc685SAndrii Nakryiko 	return btf_array(t1)->nelems == btf_array(t2)->nelems;
3595d5caef5bSAndrii Nakryiko }
3596d5caef5bSAndrii Nakryiko 
3597d5caef5bSAndrii Nakryiko /*
3598d5caef5bSAndrii Nakryiko  * Calculate type signature hash of FUNC_PROTO, including referenced type IDs,
3599d5caef5bSAndrii Nakryiko  * under assumption that they were already resolved to canonical type IDs and
3600d5caef5bSAndrii Nakryiko  * are not going to change.
3601d5caef5bSAndrii Nakryiko  */
btf_hash_fnproto(struct btf_type * t)36022fc3fc0bSAndrii Nakryiko static long btf_hash_fnproto(struct btf_type *t)
3603d5caef5bSAndrii Nakryiko {
3604b03bc685SAndrii Nakryiko 	const struct btf_param *member = btf_params(t);
3605b03bc685SAndrii Nakryiko 	__u16 vlen = btf_vlen(t);
36062fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3607d5caef5bSAndrii Nakryiko 	int i;
3608d5caef5bSAndrii Nakryiko 
3609d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3610d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->name_off);
3611d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->type);
3612d5caef5bSAndrii Nakryiko 		member++;
3613d5caef5bSAndrii Nakryiko 	}
3614d5caef5bSAndrii Nakryiko 	return h;
3615d5caef5bSAndrii Nakryiko }
3616d5caef5bSAndrii Nakryiko 
3617d5caef5bSAndrii Nakryiko /*
3618d5caef5bSAndrii Nakryiko  * Check exact equality of two FUNC_PROTOs, taking into account referenced
3619d5caef5bSAndrii Nakryiko  * type IDs, under assumption that they were already resolved to canonical
3620d5caef5bSAndrii Nakryiko  * type IDs and are not going to change.
3621d5caef5bSAndrii Nakryiko  * This function is called during reference types deduplication to compare
3622d5caef5bSAndrii Nakryiko  * FUNC_PROTO to potential canonical representative.
3623d5caef5bSAndrii Nakryiko  */
btf_equal_fnproto(struct btf_type * t1,struct btf_type * t2)36242fc3fc0bSAndrii Nakryiko static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
3625d5caef5bSAndrii Nakryiko {
3626b03bc685SAndrii Nakryiko 	const struct btf_param *m1, *m2;
3627d5caef5bSAndrii Nakryiko 	__u16 vlen;
3628d5caef5bSAndrii Nakryiko 	int i;
3629d5caef5bSAndrii Nakryiko 
3630d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3631d5caef5bSAndrii Nakryiko 		return false;
3632d5caef5bSAndrii Nakryiko 
3633b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3634b03bc685SAndrii Nakryiko 	m1 = btf_params(t1);
3635b03bc685SAndrii Nakryiko 	m2 = btf_params(t2);
3636d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3637d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->type != m2->type)
3638d5caef5bSAndrii Nakryiko 			return false;
3639d5caef5bSAndrii Nakryiko 		m1++;
3640d5caef5bSAndrii Nakryiko 		m2++;
3641d5caef5bSAndrii Nakryiko 	}
3642d5caef5bSAndrii Nakryiko 	return true;
3643d5caef5bSAndrii Nakryiko }
3644d5caef5bSAndrii Nakryiko 
3645d5caef5bSAndrii Nakryiko /*
3646d5caef5bSAndrii Nakryiko  * Check structural compatibility of two FUNC_PROTOs, ignoring referenced type
3647d5caef5bSAndrii Nakryiko  * IDs. This check is performed during type graph equivalence check and
3648d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3649d5caef5bSAndrii Nakryiko  */
btf_compat_fnproto(struct btf_type * t1,struct btf_type * t2)36502fc3fc0bSAndrii Nakryiko static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
3651d5caef5bSAndrii Nakryiko {
3652b03bc685SAndrii Nakryiko 	const struct btf_param *m1, *m2;
3653d5caef5bSAndrii Nakryiko 	__u16 vlen;
3654d5caef5bSAndrii Nakryiko 	int i;
3655d5caef5bSAndrii Nakryiko 
3656d5caef5bSAndrii Nakryiko 	/* skip return type ID */
3657d5caef5bSAndrii Nakryiko 	if (t1->name_off != t2->name_off || t1->info != t2->info)
3658d5caef5bSAndrii Nakryiko 		return false;
3659d5caef5bSAndrii Nakryiko 
3660b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3661b03bc685SAndrii Nakryiko 	m1 = btf_params(t1);
3662b03bc685SAndrii Nakryiko 	m2 = btf_params(t2);
3663d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3664d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off)
3665d5caef5bSAndrii Nakryiko 			return false;
3666d5caef5bSAndrii Nakryiko 		m1++;
3667d5caef5bSAndrii Nakryiko 		m2++;
3668d5caef5bSAndrii Nakryiko 	}
3669d5caef5bSAndrii Nakryiko 	return true;
3670d5caef5bSAndrii Nakryiko }
3671d5caef5bSAndrii Nakryiko 
3672f86524efSAndrii Nakryiko /* Prepare split BTF for deduplication by calculating hashes of base BTF's
3673f86524efSAndrii Nakryiko  * types and initializing the rest of the state (canonical type mapping) for
3674f86524efSAndrii Nakryiko  * the fixed base BTF part.
3675f86524efSAndrii Nakryiko  */
btf_dedup_prep(struct btf_dedup * d)3676f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d)
3677f86524efSAndrii Nakryiko {
3678f86524efSAndrii Nakryiko 	struct btf_type *t;
3679f86524efSAndrii Nakryiko 	int type_id;
3680f86524efSAndrii Nakryiko 	long h;
3681f86524efSAndrii Nakryiko 
3682f86524efSAndrii Nakryiko 	if (!d->btf->base_btf)
3683f86524efSAndrii Nakryiko 		return 0;
3684f86524efSAndrii Nakryiko 
3685f86524efSAndrii Nakryiko 	for (type_id = 1; type_id < d->btf->start_id; type_id++) {
3686f86524efSAndrii Nakryiko 		t = btf_type_by_id(d->btf, type_id);
3687f86524efSAndrii Nakryiko 
3688f86524efSAndrii Nakryiko 		/* all base BTF types are self-canonical by definition */
3689f86524efSAndrii Nakryiko 		d->map[type_id] = type_id;
3690f86524efSAndrii Nakryiko 
3691f86524efSAndrii Nakryiko 		switch (btf_kind(t)) {
3692f86524efSAndrii Nakryiko 		case BTF_KIND_VAR:
3693f86524efSAndrii Nakryiko 		case BTF_KIND_DATASEC:
3694f86524efSAndrii Nakryiko 			/* VAR and DATASEC are never hash/deduplicated */
3695f86524efSAndrii Nakryiko 			continue;
3696f86524efSAndrii Nakryiko 		case BTF_KIND_CONST:
3697f86524efSAndrii Nakryiko 		case BTF_KIND_VOLATILE:
3698f86524efSAndrii Nakryiko 		case BTF_KIND_RESTRICT:
3699f86524efSAndrii Nakryiko 		case BTF_KIND_PTR:
3700f86524efSAndrii Nakryiko 		case BTF_KIND_FWD:
3701f86524efSAndrii Nakryiko 		case BTF_KIND_TYPEDEF:
3702f86524efSAndrii Nakryiko 		case BTF_KIND_FUNC:
370322541a9eSIlya Leoshkevich 		case BTF_KIND_FLOAT:
37042dc1e488SYonghong Song 		case BTF_KIND_TYPE_TAG:
3705f86524efSAndrii Nakryiko 			h = btf_hash_common(t);
3706f86524efSAndrii Nakryiko 			break;
3707f86524efSAndrii Nakryiko 		case BTF_KIND_INT:
3708223f903eSYonghong Song 		case BTF_KIND_DECL_TAG:
3709223f903eSYonghong Song 			h = btf_hash_int_decl_tag(t);
3710f86524efSAndrii Nakryiko 			break;
3711f86524efSAndrii Nakryiko 		case BTF_KIND_ENUM:
37122ef20263SYonghong Song 		case BTF_KIND_ENUM64:
3713f86524efSAndrii Nakryiko 			h = btf_hash_enum(t);
3714f86524efSAndrii Nakryiko 			break;
3715f86524efSAndrii Nakryiko 		case BTF_KIND_STRUCT:
3716f86524efSAndrii Nakryiko 		case BTF_KIND_UNION:
3717f86524efSAndrii Nakryiko 			h = btf_hash_struct(t);
3718f86524efSAndrii Nakryiko 			break;
3719f86524efSAndrii Nakryiko 		case BTF_KIND_ARRAY:
3720f86524efSAndrii Nakryiko 			h = btf_hash_array(t);
3721f86524efSAndrii Nakryiko 			break;
3722f86524efSAndrii Nakryiko 		case BTF_KIND_FUNC_PROTO:
3723f86524efSAndrii Nakryiko 			h = btf_hash_fnproto(t);
3724f86524efSAndrii Nakryiko 			break;
3725f86524efSAndrii Nakryiko 		default:
3726f86524efSAndrii Nakryiko 			pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id);
3727f86524efSAndrii Nakryiko 			return -EINVAL;
3728f86524efSAndrii Nakryiko 		}
3729f86524efSAndrii Nakryiko 		if (btf_dedup_table_add(d, h, type_id))
3730f86524efSAndrii Nakryiko 			return -ENOMEM;
3731f86524efSAndrii Nakryiko 	}
3732f86524efSAndrii Nakryiko 
3733f86524efSAndrii Nakryiko 	return 0;
3734f86524efSAndrii Nakryiko }
3735f86524efSAndrii Nakryiko 
3736d5caef5bSAndrii Nakryiko /*
3737d5caef5bSAndrii Nakryiko  * Deduplicate primitive types, that can't reference other types, by calculating
3738d5caef5bSAndrii Nakryiko  * their type signature hash and comparing them with any possible canonical
3739d5caef5bSAndrii Nakryiko  * candidate. If no canonical candidate matches, type itself is marked as
3740d5caef5bSAndrii Nakryiko  * canonical and is added into `btf_dedup->dedup_table` as another candidate.
3741d5caef5bSAndrii Nakryiko  */
btf_dedup_prim_type(struct btf_dedup * d,__u32 type_id)3742d5caef5bSAndrii Nakryiko static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
3743d5caef5bSAndrii Nakryiko {
3744740e69c3SAndrii Nakryiko 	struct btf_type *t = btf_type_by_id(d->btf, type_id);
37452fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
3746d5caef5bSAndrii Nakryiko 	struct btf_type *cand;
3747d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are canonical */
3748d5caef5bSAndrii Nakryiko 	__u32 new_id = type_id;
37492fc3fc0bSAndrii Nakryiko 	__u32 cand_id;
37502fc3fc0bSAndrii Nakryiko 	long h;
3751d5caef5bSAndrii Nakryiko 
3752b03bc685SAndrii Nakryiko 	switch (btf_kind(t)) {
3753d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
3754d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
3755d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
3756d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
3757d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
3758d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY:
3759d5caef5bSAndrii Nakryiko 	case BTF_KIND_STRUCT:
3760d5caef5bSAndrii Nakryiko 	case BTF_KIND_UNION:
3761d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
3762d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO:
3763189cf5a4SAndrii Nakryiko 	case BTF_KIND_VAR:
3764189cf5a4SAndrii Nakryiko 	case BTF_KIND_DATASEC:
3765223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
37662dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
3767d5caef5bSAndrii Nakryiko 		return 0;
3768d5caef5bSAndrii Nakryiko 
3769d5caef5bSAndrii Nakryiko 	case BTF_KIND_INT:
3770223f903eSYonghong Song 		h = btf_hash_int_decl_tag(t);
37712fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
3772c302378bSEduard Zingerman 			cand_id = hash_entry->value;
3773740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
377430025e8bSYonghong Song 			if (btf_equal_int_tag(t, cand)) {
37752fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3776d5caef5bSAndrii Nakryiko 				break;
3777d5caef5bSAndrii Nakryiko 			}
3778d5caef5bSAndrii Nakryiko 		}
3779d5caef5bSAndrii Nakryiko 		break;
3780d5caef5bSAndrii Nakryiko 
3781d5caef5bSAndrii Nakryiko 	case BTF_KIND_ENUM:
3782de048b6eSEduard Zingerman 	case BTF_KIND_ENUM64:
3783d5caef5bSAndrii Nakryiko 		h = btf_hash_enum(t);
37842fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
3785c302378bSEduard Zingerman 			cand_id = hash_entry->value;
3786740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
3787d5caef5bSAndrii Nakryiko 			if (btf_equal_enum(t, cand)) {
37882fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3789d5caef5bSAndrii Nakryiko 				break;
3790d5caef5bSAndrii Nakryiko 			}
37919768095bSAndrii Nakryiko 			if (btf_compat_enum(t, cand)) {
37929768095bSAndrii Nakryiko 				if (btf_is_enum_fwd(t)) {
37939768095bSAndrii Nakryiko 					/* resolve fwd to full enum */
37942fc3fc0bSAndrii Nakryiko 					new_id = cand_id;
37959768095bSAndrii Nakryiko 					break;
37969768095bSAndrii Nakryiko 				}
37979768095bSAndrii Nakryiko 				/* resolve canonical enum fwd to full enum */
37982fc3fc0bSAndrii Nakryiko 				d->map[cand_id] = type_id;
37999768095bSAndrii Nakryiko 			}
3800d5caef5bSAndrii Nakryiko 		}
3801d5caef5bSAndrii Nakryiko 		break;
3802d5caef5bSAndrii Nakryiko 
3803d5caef5bSAndrii Nakryiko 	case BTF_KIND_FWD:
380422541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
3805d5caef5bSAndrii Nakryiko 		h = btf_hash_common(t);
38062fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
3807c302378bSEduard Zingerman 			cand_id = hash_entry->value;
3808740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
3809d5caef5bSAndrii Nakryiko 			if (btf_equal_common(t, cand)) {
38102fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3811d5caef5bSAndrii Nakryiko 				break;
3812d5caef5bSAndrii Nakryiko 			}
3813d5caef5bSAndrii Nakryiko 		}
3814d5caef5bSAndrii Nakryiko 		break;
3815d5caef5bSAndrii Nakryiko 
3816d5caef5bSAndrii Nakryiko 	default:
3817d5caef5bSAndrii Nakryiko 		return -EINVAL;
3818d5caef5bSAndrii Nakryiko 	}
3819d5caef5bSAndrii Nakryiko 
3820d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
3821d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
3822d5caef5bSAndrii Nakryiko 		return -ENOMEM;
3823d5caef5bSAndrii Nakryiko 
3824d5caef5bSAndrii Nakryiko 	return 0;
3825d5caef5bSAndrii Nakryiko }
3826d5caef5bSAndrii Nakryiko 
btf_dedup_prim_types(struct btf_dedup * d)3827d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d)
3828d5caef5bSAndrii Nakryiko {
3829d5caef5bSAndrii Nakryiko 	int i, err;
3830d5caef5bSAndrii Nakryiko 
3831f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
3832f86524efSAndrii Nakryiko 		err = btf_dedup_prim_type(d, d->btf->start_id + i);
3833d5caef5bSAndrii Nakryiko 		if (err)
3834d5caef5bSAndrii Nakryiko 			return err;
3835d5caef5bSAndrii Nakryiko 	}
3836d5caef5bSAndrii Nakryiko 	return 0;
3837d5caef5bSAndrii Nakryiko }
3838d5caef5bSAndrii Nakryiko 
3839d5caef5bSAndrii Nakryiko /*
3840d5caef5bSAndrii Nakryiko  * Check whether type is already mapped into canonical one (could be to itself).
3841d5caef5bSAndrii Nakryiko  */
is_type_mapped(struct btf_dedup * d,uint32_t type_id)3842d5caef5bSAndrii Nakryiko static inline bool is_type_mapped(struct btf_dedup *d, uint32_t type_id)
3843d5caef5bSAndrii Nakryiko {
38445aab392cSAndrii Nakryiko 	return d->map[type_id] <= BTF_MAX_NR_TYPES;
3845d5caef5bSAndrii Nakryiko }
3846d5caef5bSAndrii Nakryiko 
3847d5caef5bSAndrii Nakryiko /*
3848d5caef5bSAndrii Nakryiko  * Resolve type ID into its canonical type ID, if any; otherwise return original
3849d5caef5bSAndrii Nakryiko  * type ID. If type is FWD and is resolved into STRUCT/UNION already, follow
3850d5caef5bSAndrii Nakryiko  * STRUCT/UNION link and resolve it into canonical type ID as well.
3851d5caef5bSAndrii Nakryiko  */
resolve_type_id(struct btf_dedup * d,__u32 type_id)3852d5caef5bSAndrii Nakryiko static inline __u32 resolve_type_id(struct btf_dedup *d, __u32 type_id)
3853d5caef5bSAndrii Nakryiko {
3854d5caef5bSAndrii Nakryiko 	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
3855d5caef5bSAndrii Nakryiko 		type_id = d->map[type_id];
3856d5caef5bSAndrii Nakryiko 	return type_id;
3857d5caef5bSAndrii Nakryiko }
3858d5caef5bSAndrii Nakryiko 
3859d5caef5bSAndrii Nakryiko /*
3860d5caef5bSAndrii Nakryiko  * Resolve FWD to underlying STRUCT/UNION, if any; otherwise return original
3861d5caef5bSAndrii Nakryiko  * type ID.
3862d5caef5bSAndrii Nakryiko  */
resolve_fwd_id(struct btf_dedup * d,uint32_t type_id)3863d5caef5bSAndrii Nakryiko static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
3864d5caef5bSAndrii Nakryiko {
3865d5caef5bSAndrii Nakryiko 	__u32 orig_type_id = type_id;
3866d5caef5bSAndrii Nakryiko 
3867740e69c3SAndrii Nakryiko 	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
3868d5caef5bSAndrii Nakryiko 		return type_id;
3869d5caef5bSAndrii Nakryiko 
3870d5caef5bSAndrii Nakryiko 	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
3871d5caef5bSAndrii Nakryiko 		type_id = d->map[type_id];
3872d5caef5bSAndrii Nakryiko 
3873740e69c3SAndrii Nakryiko 	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
3874d5caef5bSAndrii Nakryiko 		return type_id;
3875d5caef5bSAndrii Nakryiko 
3876d5caef5bSAndrii Nakryiko 	return orig_type_id;
3877d5caef5bSAndrii Nakryiko }
3878d5caef5bSAndrii Nakryiko 
3879d5caef5bSAndrii Nakryiko 
btf_fwd_kind(struct btf_type * t)3880d5caef5bSAndrii Nakryiko static inline __u16 btf_fwd_kind(struct btf_type *t)
3881d5caef5bSAndrii Nakryiko {
3882b03bc685SAndrii Nakryiko 	return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
3883d5caef5bSAndrii Nakryiko }
3884d5caef5bSAndrii Nakryiko 
38856b6e6b1dSAndrii Nakryiko /* Check if given two types are identical ARRAY definitions */
btf_dedup_identical_arrays(struct btf_dedup * d,__u32 id1,__u32 id2)3886f3c51fe0SAlan Maguire static bool btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
38876b6e6b1dSAndrii Nakryiko {
38886b6e6b1dSAndrii Nakryiko 	struct btf_type *t1, *t2;
38896b6e6b1dSAndrii Nakryiko 
38906b6e6b1dSAndrii Nakryiko 	t1 = btf_type_by_id(d->btf, id1);
38916b6e6b1dSAndrii Nakryiko 	t2 = btf_type_by_id(d->btf, id2);
38926b6e6b1dSAndrii Nakryiko 	if (!btf_is_array(t1) || !btf_is_array(t2))
3893f3c51fe0SAlan Maguire 		return false;
38946b6e6b1dSAndrii Nakryiko 
38956b6e6b1dSAndrii Nakryiko 	return btf_equal_array(t1, t2);
38966b6e6b1dSAndrii Nakryiko }
38976b6e6b1dSAndrii Nakryiko 
3898efdd3eb8SAndrii Nakryiko /* Check if given two types are identical STRUCT/UNION definitions */
btf_dedup_identical_structs(struct btf_dedup * d,__u32 id1,__u32 id2)3899efdd3eb8SAndrii Nakryiko static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2)
3900efdd3eb8SAndrii Nakryiko {
3901efdd3eb8SAndrii Nakryiko 	const struct btf_member *m1, *m2;
3902efdd3eb8SAndrii Nakryiko 	struct btf_type *t1, *t2;
3903efdd3eb8SAndrii Nakryiko 	int n, i;
3904efdd3eb8SAndrii Nakryiko 
3905efdd3eb8SAndrii Nakryiko 	t1 = btf_type_by_id(d->btf, id1);
3906efdd3eb8SAndrii Nakryiko 	t2 = btf_type_by_id(d->btf, id2);
3907efdd3eb8SAndrii Nakryiko 
3908efdd3eb8SAndrii Nakryiko 	if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2))
3909efdd3eb8SAndrii Nakryiko 		return false;
3910efdd3eb8SAndrii Nakryiko 
3911efdd3eb8SAndrii Nakryiko 	if (!btf_shallow_equal_struct(t1, t2))
3912efdd3eb8SAndrii Nakryiko 		return false;
3913efdd3eb8SAndrii Nakryiko 
3914efdd3eb8SAndrii Nakryiko 	m1 = btf_members(t1);
3915efdd3eb8SAndrii Nakryiko 	m2 = btf_members(t2);
3916efdd3eb8SAndrii Nakryiko 	for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
3917f3c51fe0SAlan Maguire 		if (m1->type != m2->type &&
3918f3c51fe0SAlan Maguire 		    !btf_dedup_identical_arrays(d, m1->type, m2->type) &&
3919f3c51fe0SAlan Maguire 		    !btf_dedup_identical_structs(d, m1->type, m2->type))
3920efdd3eb8SAndrii Nakryiko 			return false;
3921efdd3eb8SAndrii Nakryiko 	}
3922efdd3eb8SAndrii Nakryiko 	return true;
3923efdd3eb8SAndrii Nakryiko }
3924efdd3eb8SAndrii Nakryiko 
3925d5caef5bSAndrii Nakryiko /*
3926d5caef5bSAndrii Nakryiko  * Check equivalence of BTF type graph formed by candidate struct/union (we'll
3927d5caef5bSAndrii Nakryiko  * call it "candidate graph" in this description for brevity) to a type graph
3928d5caef5bSAndrii Nakryiko  * formed by (potential) canonical struct/union ("canonical graph" for brevity
3929d5caef5bSAndrii Nakryiko  * here, though keep in mind that not all types in canonical graph are
3930d5caef5bSAndrii Nakryiko  * necessarily canonical representatives themselves, some of them might be
3931d5caef5bSAndrii Nakryiko  * duplicates or its uniqueness might not have been established yet).
3932d5caef5bSAndrii Nakryiko  * Returns:
3933d5caef5bSAndrii Nakryiko  *  - >0, if type graphs are equivalent;
3934d5caef5bSAndrii Nakryiko  *  -  0, if not equivalent;
3935d5caef5bSAndrii Nakryiko  *  - <0, on error.
3936d5caef5bSAndrii Nakryiko  *
3937d5caef5bSAndrii Nakryiko  * Algorithm performs side-by-side DFS traversal of both type graphs and checks
3938d5caef5bSAndrii Nakryiko  * equivalence of BTF types at each step. If at any point BTF types in candidate
3939d5caef5bSAndrii Nakryiko  * and canonical graphs are not compatible structurally, whole graphs are
3940d5caef5bSAndrii Nakryiko  * incompatible. If types are structurally equivalent (i.e., all information
3941d5caef5bSAndrii Nakryiko  * except referenced type IDs is exactly the same), a mapping from `canon_id` to
3942d5caef5bSAndrii Nakryiko  * a `cand_id` is recored in hypothetical mapping (`btf_dedup->hypot_map`).
3943d5caef5bSAndrii Nakryiko  * If a type references other types, then those referenced types are checked
3944d5caef5bSAndrii Nakryiko  * for equivalence recursively.
3945d5caef5bSAndrii Nakryiko  *
3946d5caef5bSAndrii Nakryiko  * During DFS traversal, if we find that for current `canon_id` type we
3947d5caef5bSAndrii Nakryiko  * already have some mapping in hypothetical map, we check for two possible
3948d5caef5bSAndrii Nakryiko  * situations:
3949d5caef5bSAndrii Nakryiko  *   - `canon_id` is mapped to exactly the same type as `cand_id`. This will
3950d5caef5bSAndrii Nakryiko  *     happen when type graphs have cycles. In this case we assume those two
3951d5caef5bSAndrii Nakryiko  *     types are equivalent.
3952d5caef5bSAndrii Nakryiko  *   - `canon_id` is mapped to different type. This is contradiction in our
3953d5caef5bSAndrii Nakryiko  *     hypothetical mapping, because same graph in canonical graph corresponds
3954d5caef5bSAndrii Nakryiko  *     to two different types in candidate graph, which for equivalent type
3955d5caef5bSAndrii Nakryiko  *     graphs shouldn't happen. This condition terminates equivalence check
3956d5caef5bSAndrii Nakryiko  *     with negative result.
3957d5caef5bSAndrii Nakryiko  *
3958d5caef5bSAndrii Nakryiko  * If type graphs traversal exhausts types to check and find no contradiction,
3959d5caef5bSAndrii Nakryiko  * then type graphs are equivalent.
3960d5caef5bSAndrii Nakryiko  *
3961d5caef5bSAndrii Nakryiko  * When checking types for equivalence, there is one special case: FWD types.
3962d5caef5bSAndrii Nakryiko  * If FWD type resolution is allowed and one of the types (either from canonical
3963d5caef5bSAndrii Nakryiko  * or candidate graph) is FWD and other is STRUCT/UNION (depending on FWD's kind
3964d5caef5bSAndrii Nakryiko  * flag) and their names match, hypothetical mapping is updated to point from
3965d5caef5bSAndrii Nakryiko  * FWD to STRUCT/UNION. If graphs will be determined as equivalent successfully,
3966d5caef5bSAndrii Nakryiko  * this mapping will be used to record FWD -> STRUCT/UNION mapping permanently.
3967d5caef5bSAndrii Nakryiko  *
3968d5caef5bSAndrii Nakryiko  * Technically, this could lead to incorrect FWD to STRUCT/UNION resolution,
3969d5caef5bSAndrii Nakryiko  * if there are two exactly named (or anonymous) structs/unions that are
3970d5caef5bSAndrii Nakryiko  * compatible structurally, one of which has FWD field, while other is concrete
3971d5caef5bSAndrii Nakryiko  * STRUCT/UNION, but according to C sources they are different structs/unions
3972d5caef5bSAndrii Nakryiko  * that are referencing different types with the same name. This is extremely
3973d5caef5bSAndrii Nakryiko  * unlikely to happen, but btf_dedup API allows to disable FWD resolution if
3974d5caef5bSAndrii Nakryiko  * this logic is causing problems.
3975d5caef5bSAndrii Nakryiko  *
3976d5caef5bSAndrii Nakryiko  * Doing FWD resolution means that both candidate and/or canonical graphs can
3977d5caef5bSAndrii Nakryiko  * consists of portions of the graph that come from multiple compilation units.
3978d5caef5bSAndrii Nakryiko  * This is due to the fact that types within single compilation unit are always
3979d5caef5bSAndrii Nakryiko  * deduplicated and FWDs are already resolved, if referenced struct/union
3980d5caef5bSAndrii Nakryiko  * definiton is available. So, if we had unresolved FWD and found corresponding
3981d5caef5bSAndrii Nakryiko  * STRUCT/UNION, they will be from different compilation units. This
3982d5caef5bSAndrii Nakryiko  * consequently means that when we "link" FWD to corresponding STRUCT/UNION,
3983d5caef5bSAndrii Nakryiko  * type graph will likely have at least two different BTF types that describe
3984d5caef5bSAndrii Nakryiko  * same type (e.g., most probably there will be two different BTF types for the
3985d5caef5bSAndrii Nakryiko  * same 'int' primitive type) and could even have "overlapping" parts of type
3986d5caef5bSAndrii Nakryiko  * graph that describe same subset of types.
3987d5caef5bSAndrii Nakryiko  *
3988d5caef5bSAndrii Nakryiko  * This in turn means that our assumption that each type in canonical graph
3989d5caef5bSAndrii Nakryiko  * must correspond to exactly one type in candidate graph might not hold
3990d5caef5bSAndrii Nakryiko  * anymore and will make it harder to detect contradictions using hypothetical
3991d5caef5bSAndrii Nakryiko  * map. To handle this problem, we allow to follow FWD -> STRUCT/UNION
3992d5caef5bSAndrii Nakryiko  * resolution only in canonical graph. FWDs in candidate graphs are never
3993d5caef5bSAndrii Nakryiko  * resolved. To see why it's OK, let's check all possible situations w.r.t. FWDs
3994d5caef5bSAndrii Nakryiko  * that can occur:
3995d5caef5bSAndrii Nakryiko  *   - Both types in canonical and candidate graphs are FWDs. If they are
3996d5caef5bSAndrii Nakryiko  *     structurally equivalent, then they can either be both resolved to the
3997d5caef5bSAndrii Nakryiko  *     same STRUCT/UNION or not resolved at all. In both cases they are
3998d5caef5bSAndrii Nakryiko  *     equivalent and there is no need to resolve FWD on candidate side.
3999d5caef5bSAndrii Nakryiko  *   - Both types in canonical and candidate graphs are concrete STRUCT/UNION,
4000d5caef5bSAndrii Nakryiko  *     so nothing to resolve as well, algorithm will check equivalence anyway.
4001d5caef5bSAndrii Nakryiko  *   - Type in canonical graph is FWD, while type in candidate is concrete
4002d5caef5bSAndrii Nakryiko  *     STRUCT/UNION. In this case candidate graph comes from single compilation
4003d5caef5bSAndrii Nakryiko  *     unit, so there is exactly one BTF type for each unique C type. After
4004d5caef5bSAndrii Nakryiko  *     resolving FWD into STRUCT/UNION, there might be more than one BTF type
4005d5caef5bSAndrii Nakryiko  *     in canonical graph mapping to single BTF type in candidate graph, but
4006d5caef5bSAndrii Nakryiko  *     because hypothetical mapping maps from canonical to candidate types, it's
4007d5caef5bSAndrii Nakryiko  *     alright, and we still maintain the property of having single `canon_id`
4008d5caef5bSAndrii Nakryiko  *     mapping to single `cand_id` (there could be two different `canon_id`
4009d5caef5bSAndrii Nakryiko  *     mapped to the same `cand_id`, but it's not contradictory).
4010d5caef5bSAndrii Nakryiko  *   - Type in canonical graph is concrete STRUCT/UNION, while type in candidate
4011d5caef5bSAndrii Nakryiko  *     graph is FWD. In this case we are just going to check compatibility of
4012d5caef5bSAndrii Nakryiko  *     STRUCT/UNION and corresponding FWD, and if they are compatible, we'll
4013d5caef5bSAndrii Nakryiko  *     assume that whatever STRUCT/UNION FWD resolves to must be equivalent to
4014d5caef5bSAndrii Nakryiko  *     a concrete STRUCT/UNION from canonical graph. If the rest of type graphs
4015d5caef5bSAndrii Nakryiko  *     turn out equivalent, we'll re-resolve FWD to concrete STRUCT/UNION from
4016d5caef5bSAndrii Nakryiko  *     canonical graph.
4017d5caef5bSAndrii Nakryiko  */
btf_dedup_is_equiv(struct btf_dedup * d,__u32 cand_id,__u32 canon_id)4018d5caef5bSAndrii Nakryiko static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
4019d5caef5bSAndrii Nakryiko 			      __u32 canon_id)
4020d5caef5bSAndrii Nakryiko {
4021d5caef5bSAndrii Nakryiko 	struct btf_type *cand_type;
4022d5caef5bSAndrii Nakryiko 	struct btf_type *canon_type;
4023d5caef5bSAndrii Nakryiko 	__u32 hypot_type_id;
4024d5caef5bSAndrii Nakryiko 	__u16 cand_kind;
4025d5caef5bSAndrii Nakryiko 	__u16 canon_kind;
4026d5caef5bSAndrii Nakryiko 	int i, eq;
4027d5caef5bSAndrii Nakryiko 
4028d5caef5bSAndrii Nakryiko 	/* if both resolve to the same canonical, they must be equivalent */
4029d5caef5bSAndrii Nakryiko 	if (resolve_type_id(d, cand_id) == resolve_type_id(d, canon_id))
4030d5caef5bSAndrii Nakryiko 		return 1;
4031d5caef5bSAndrii Nakryiko 
4032d5caef5bSAndrii Nakryiko 	canon_id = resolve_fwd_id(d, canon_id);
4033d5caef5bSAndrii Nakryiko 
4034d5caef5bSAndrii Nakryiko 	hypot_type_id = d->hypot_map[canon_id];
40356b6e6b1dSAndrii Nakryiko 	if (hypot_type_id <= BTF_MAX_NR_TYPES) {
4036efdd3eb8SAndrii Nakryiko 		if (hypot_type_id == cand_id)
4037efdd3eb8SAndrii Nakryiko 			return 1;
40386b6e6b1dSAndrii Nakryiko 		/* In some cases compiler will generate different DWARF types
40396b6e6b1dSAndrii Nakryiko 		 * for *identical* array type definitions and use them for
40406b6e6b1dSAndrii Nakryiko 		 * different fields within the *same* struct. This breaks type
40416b6e6b1dSAndrii Nakryiko 		 * equivalence check, which makes an assumption that candidate
40426b6e6b1dSAndrii Nakryiko 		 * types sub-graph has a consistent and deduped-by-compiler
40436b6e6b1dSAndrii Nakryiko 		 * types within a single CU. So work around that by explicitly
40446b6e6b1dSAndrii Nakryiko 		 * allowing identical array types here.
40456b6e6b1dSAndrii Nakryiko 		 */
4046efdd3eb8SAndrii Nakryiko 		if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id))
4047efdd3eb8SAndrii Nakryiko 			return 1;
4048efdd3eb8SAndrii Nakryiko 		/* It turns out that similar situation can happen with
4049efdd3eb8SAndrii Nakryiko 		 * struct/union sometimes, sigh... Handle the case where
4050efdd3eb8SAndrii Nakryiko 		 * structs/unions are exactly the same, down to the referenced
4051efdd3eb8SAndrii Nakryiko 		 * type IDs. Anything more complicated (e.g., if referenced
4052efdd3eb8SAndrii Nakryiko 		 * types are different, but equivalent) is *way more*
4053efdd3eb8SAndrii Nakryiko 		 * complicated and requires a many-to-many equivalence mapping.
4054efdd3eb8SAndrii Nakryiko 		 */
4055efdd3eb8SAndrii Nakryiko 		if (btf_dedup_identical_structs(d, hypot_type_id, cand_id))
4056efdd3eb8SAndrii Nakryiko 			return 1;
4057efdd3eb8SAndrii Nakryiko 		return 0;
40586b6e6b1dSAndrii Nakryiko 	}
4059d5caef5bSAndrii Nakryiko 
4060d5caef5bSAndrii Nakryiko 	if (btf_dedup_hypot_map_add(d, canon_id, cand_id))
4061d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4062d5caef5bSAndrii Nakryiko 
4063740e69c3SAndrii Nakryiko 	cand_type = btf_type_by_id(d->btf, cand_id);
4064740e69c3SAndrii Nakryiko 	canon_type = btf_type_by_id(d->btf, canon_id);
4065b03bc685SAndrii Nakryiko 	cand_kind = btf_kind(cand_type);
4066b03bc685SAndrii Nakryiko 	canon_kind = btf_kind(canon_type);
4067d5caef5bSAndrii Nakryiko 
4068d5caef5bSAndrii Nakryiko 	if (cand_type->name_off != canon_type->name_off)
4069d5caef5bSAndrii Nakryiko 		return 0;
4070d5caef5bSAndrii Nakryiko 
4071d5caef5bSAndrii Nakryiko 	/* FWD <--> STRUCT/UNION equivalence check, if enabled */
4072957d350aSAndrii Nakryiko 	if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
4073d5caef5bSAndrii Nakryiko 	    && cand_kind != canon_kind) {
4074d5caef5bSAndrii Nakryiko 		__u16 real_kind;
4075d5caef5bSAndrii Nakryiko 		__u16 fwd_kind;
4076d5caef5bSAndrii Nakryiko 
4077d5caef5bSAndrii Nakryiko 		if (cand_kind == BTF_KIND_FWD) {
4078d5caef5bSAndrii Nakryiko 			real_kind = canon_kind;
4079d5caef5bSAndrii Nakryiko 			fwd_kind = btf_fwd_kind(cand_type);
4080d5caef5bSAndrii Nakryiko 		} else {
4081d5caef5bSAndrii Nakryiko 			real_kind = cand_kind;
4082d5caef5bSAndrii Nakryiko 			fwd_kind = btf_fwd_kind(canon_type);
4083f86524efSAndrii Nakryiko 			/* we'd need to resolve base FWD to STRUCT/UNION */
4084f86524efSAndrii Nakryiko 			if (fwd_kind == real_kind && canon_id < d->btf->start_id)
4085f86524efSAndrii Nakryiko 				d->hypot_adjust_canon = true;
4086d5caef5bSAndrii Nakryiko 		}
4087d5caef5bSAndrii Nakryiko 		return fwd_kind == real_kind;
4088d5caef5bSAndrii Nakryiko 	}
4089d5caef5bSAndrii Nakryiko 
40909ec71c1cSAndrii Nakryiko 	if (cand_kind != canon_kind)
40919ec71c1cSAndrii Nakryiko 		return 0;
40929ec71c1cSAndrii Nakryiko 
4093d5caef5bSAndrii Nakryiko 	switch (cand_kind) {
4094d5caef5bSAndrii Nakryiko 	case BTF_KIND_INT:
409530025e8bSYonghong Song 		return btf_equal_int_tag(cand_type, canon_type);
4096d5caef5bSAndrii Nakryiko 
4097d5caef5bSAndrii Nakryiko 	case BTF_KIND_ENUM:
40982ef20263SYonghong Song 	case BTF_KIND_ENUM64:
4099de048b6eSEduard Zingerman 		return btf_compat_enum(cand_type, canon_type);
41002ef20263SYonghong Song 
4101d5caef5bSAndrii Nakryiko 	case BTF_KIND_FWD:
410222541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
4103d5caef5bSAndrii Nakryiko 		return btf_equal_common(cand_type, canon_type);
4104d5caef5bSAndrii Nakryiko 
4105d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
4106d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4107d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4108d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
4109d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4110d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
411169a055d5SYonghong Song 	case BTF_KIND_TYPE_TAG:
41129768095bSAndrii Nakryiko 		if (cand_type->info != canon_type->info)
41139768095bSAndrii Nakryiko 			return 0;
4114d5caef5bSAndrii Nakryiko 		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
4115d5caef5bSAndrii Nakryiko 
4116d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4117b03bc685SAndrii Nakryiko 		const struct btf_array *cand_arr, *canon_arr;
4118d5caef5bSAndrii Nakryiko 
4119d5caef5bSAndrii Nakryiko 		if (!btf_compat_array(cand_type, canon_type))
4120d5caef5bSAndrii Nakryiko 			return 0;
4121b03bc685SAndrii Nakryiko 		cand_arr = btf_array(cand_type);
4122b03bc685SAndrii Nakryiko 		canon_arr = btf_array(canon_type);
4123f86524efSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, cand_arr->index_type, canon_arr->index_type);
4124d5caef5bSAndrii Nakryiko 		if (eq <= 0)
4125d5caef5bSAndrii Nakryiko 			return eq;
4126d5caef5bSAndrii Nakryiko 		return btf_dedup_is_equiv(d, cand_arr->type, canon_arr->type);
4127d5caef5bSAndrii Nakryiko 	}
4128d5caef5bSAndrii Nakryiko 
4129d5caef5bSAndrii Nakryiko 	case BTF_KIND_STRUCT:
4130d5caef5bSAndrii Nakryiko 	case BTF_KIND_UNION: {
4131b03bc685SAndrii Nakryiko 		const struct btf_member *cand_m, *canon_m;
4132d5caef5bSAndrii Nakryiko 		__u16 vlen;
4133d5caef5bSAndrii Nakryiko 
413491097fbeSAndrii Nakryiko 		if (!btf_shallow_equal_struct(cand_type, canon_type))
4135d5caef5bSAndrii Nakryiko 			return 0;
4136b03bc685SAndrii Nakryiko 		vlen = btf_vlen(cand_type);
4137b03bc685SAndrii Nakryiko 		cand_m = btf_members(cand_type);
4138b03bc685SAndrii Nakryiko 		canon_m = btf_members(canon_type);
4139d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4140d5caef5bSAndrii Nakryiko 			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
4141d5caef5bSAndrii Nakryiko 			if (eq <= 0)
4142d5caef5bSAndrii Nakryiko 				return eq;
4143d5caef5bSAndrii Nakryiko 			cand_m++;
4144d5caef5bSAndrii Nakryiko 			canon_m++;
4145d5caef5bSAndrii Nakryiko 		}
4146d5caef5bSAndrii Nakryiko 
4147d5caef5bSAndrii Nakryiko 		return 1;
4148d5caef5bSAndrii Nakryiko 	}
4149d5caef5bSAndrii Nakryiko 
4150d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4151b03bc685SAndrii Nakryiko 		const struct btf_param *cand_p, *canon_p;
4152d5caef5bSAndrii Nakryiko 		__u16 vlen;
4153d5caef5bSAndrii Nakryiko 
4154d5caef5bSAndrii Nakryiko 		if (!btf_compat_fnproto(cand_type, canon_type))
4155d5caef5bSAndrii Nakryiko 			return 0;
4156d5caef5bSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
4157d5caef5bSAndrii Nakryiko 		if (eq <= 0)
4158d5caef5bSAndrii Nakryiko 			return eq;
4159b03bc685SAndrii Nakryiko 		vlen = btf_vlen(cand_type);
4160b03bc685SAndrii Nakryiko 		cand_p = btf_params(cand_type);
4161b03bc685SAndrii Nakryiko 		canon_p = btf_params(canon_type);
4162d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4163d5caef5bSAndrii Nakryiko 			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
4164d5caef5bSAndrii Nakryiko 			if (eq <= 0)
4165d5caef5bSAndrii Nakryiko 				return eq;
4166d5caef5bSAndrii Nakryiko 			cand_p++;
4167d5caef5bSAndrii Nakryiko 			canon_p++;
4168d5caef5bSAndrii Nakryiko 		}
4169d5caef5bSAndrii Nakryiko 		return 1;
4170d5caef5bSAndrii Nakryiko 	}
4171d5caef5bSAndrii Nakryiko 
4172d5caef5bSAndrii Nakryiko 	default:
4173d5caef5bSAndrii Nakryiko 		return -EINVAL;
4174d5caef5bSAndrii Nakryiko 	}
4175d5caef5bSAndrii Nakryiko 	return 0;
4176d5caef5bSAndrii Nakryiko }
4177d5caef5bSAndrii Nakryiko 
4178d5caef5bSAndrii Nakryiko /*
4179d5caef5bSAndrii Nakryiko  * Use hypothetical mapping, produced by successful type graph equivalence
4180d5caef5bSAndrii Nakryiko  * check, to augment existing struct/union canonical mapping, where possible.
4181d5caef5bSAndrii Nakryiko  *
4182d5caef5bSAndrii Nakryiko  * If BTF_KIND_FWD resolution is allowed, this mapping is also used to record
4183d5caef5bSAndrii Nakryiko  * FWD -> STRUCT/UNION correspondence as well. FWD resolution is bidirectional:
4184d5caef5bSAndrii Nakryiko  * it doesn't matter if FWD type was part of canonical graph or candidate one,
4185d5caef5bSAndrii Nakryiko  * we are recording the mapping anyway. As opposed to carefulness required
4186d5caef5bSAndrii Nakryiko  * for struct/union correspondence mapping (described below), for FWD resolution
4187d5caef5bSAndrii Nakryiko  * it's not important, as by the time that FWD type (reference type) will be
4188d5caef5bSAndrii Nakryiko  * deduplicated all structs/unions will be deduped already anyway.
4189d5caef5bSAndrii Nakryiko  *
4190d5caef5bSAndrii Nakryiko  * Recording STRUCT/UNION mapping is purely a performance optimization and is
4191d5caef5bSAndrii Nakryiko  * not required for correctness. It needs to be done carefully to ensure that
4192d5caef5bSAndrii Nakryiko  * struct/union from candidate's type graph is not mapped into corresponding
4193d5caef5bSAndrii Nakryiko  * struct/union from canonical type graph that itself hasn't been resolved into
4194d5caef5bSAndrii Nakryiko  * canonical representative. The only guarantee we have is that canonical
4195d5caef5bSAndrii Nakryiko  * struct/union was determined as canonical and that won't change. But any
4196d5caef5bSAndrii Nakryiko  * types referenced through that struct/union fields could have been not yet
4197d5caef5bSAndrii Nakryiko  * resolved, so in case like that it's too early to establish any kind of
4198d5caef5bSAndrii Nakryiko  * correspondence between structs/unions.
4199d5caef5bSAndrii Nakryiko  *
4200d5caef5bSAndrii Nakryiko  * No canonical correspondence is derived for primitive types (they are already
4201d5caef5bSAndrii Nakryiko  * deduplicated completely already anyway) or reference types (they rely on
4202d5caef5bSAndrii Nakryiko  * stability of struct/union canonical relationship for equivalence checks).
4203d5caef5bSAndrii Nakryiko  */
btf_dedup_merge_hypot_map(struct btf_dedup * d)4204d5caef5bSAndrii Nakryiko static void btf_dedup_merge_hypot_map(struct btf_dedup *d)
4205d5caef5bSAndrii Nakryiko {
4206f86524efSAndrii Nakryiko 	__u32 canon_type_id, targ_type_id;
4207d5caef5bSAndrii Nakryiko 	__u16 t_kind, c_kind;
4208d5caef5bSAndrii Nakryiko 	__u32 t_id, c_id;
4209d5caef5bSAndrii Nakryiko 	int i;
4210d5caef5bSAndrii Nakryiko 
4211d5caef5bSAndrii Nakryiko 	for (i = 0; i < d->hypot_cnt; i++) {
4212f86524efSAndrii Nakryiko 		canon_type_id = d->hypot_list[i];
4213f86524efSAndrii Nakryiko 		targ_type_id = d->hypot_map[canon_type_id];
4214d5caef5bSAndrii Nakryiko 		t_id = resolve_type_id(d, targ_type_id);
4215f86524efSAndrii Nakryiko 		c_id = resolve_type_id(d, canon_type_id);
4216740e69c3SAndrii Nakryiko 		t_kind = btf_kind(btf__type_by_id(d->btf, t_id));
4217740e69c3SAndrii Nakryiko 		c_kind = btf_kind(btf__type_by_id(d->btf, c_id));
4218d5caef5bSAndrii Nakryiko 		/*
4219d5caef5bSAndrii Nakryiko 		 * Resolve FWD into STRUCT/UNION.
4220d5caef5bSAndrii Nakryiko 		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
4221d5caef5bSAndrii Nakryiko 		 * mapped to canonical representative (as opposed to
4222d5caef5bSAndrii Nakryiko 		 * STRUCT/UNION <--> STRUCT/UNION mapping logic below), because
4223d5caef5bSAndrii Nakryiko 		 * eventually that struct is going to be mapped and all resolved
4224d5caef5bSAndrii Nakryiko 		 * FWDs will automatically resolve to correct canonical
4225d5caef5bSAndrii Nakryiko 		 * representative. This will happen before ref type deduping,
4226d5caef5bSAndrii Nakryiko 		 * which critically depends on stability of these mapping. This
4227d5caef5bSAndrii Nakryiko 		 * stability is not a requirement for STRUCT/UNION equivalence
4228d5caef5bSAndrii Nakryiko 		 * checks, though.
4229d5caef5bSAndrii Nakryiko 		 */
4230f86524efSAndrii Nakryiko 
4231f86524efSAndrii Nakryiko 		/* if it's the split BTF case, we still need to point base FWD
4232f86524efSAndrii Nakryiko 		 * to STRUCT/UNION in a split BTF, because FWDs from split BTF
4233f86524efSAndrii Nakryiko 		 * will be resolved against base FWD. If we don't point base
4234f86524efSAndrii Nakryiko 		 * canonical FWD to the resolved STRUCT/UNION, then all the
4235f86524efSAndrii Nakryiko 		 * FWDs in split BTF won't be correctly resolved to a proper
4236f86524efSAndrii Nakryiko 		 * STRUCT/UNION.
4237f86524efSAndrii Nakryiko 		 */
4238d5caef5bSAndrii Nakryiko 		if (t_kind != BTF_KIND_FWD && c_kind == BTF_KIND_FWD)
4239d5caef5bSAndrii Nakryiko 			d->map[c_id] = t_id;
4240f86524efSAndrii Nakryiko 
4241f86524efSAndrii Nakryiko 		/* if graph equivalence determined that we'd need to adjust
4242f86524efSAndrii Nakryiko 		 * base canonical types, then we need to only point base FWDs
4243f86524efSAndrii Nakryiko 		 * to STRUCTs/UNIONs and do no more modifications. For all
4244f86524efSAndrii Nakryiko 		 * other purposes the type graphs were not equivalent.
4245f86524efSAndrii Nakryiko 		 */
4246f86524efSAndrii Nakryiko 		if (d->hypot_adjust_canon)
4247f86524efSAndrii Nakryiko 			continue;
4248f86524efSAndrii Nakryiko 
4249f86524efSAndrii Nakryiko 		if (t_kind == BTF_KIND_FWD && c_kind != BTF_KIND_FWD)
4250d5caef5bSAndrii Nakryiko 			d->map[t_id] = c_id;
4251d5caef5bSAndrii Nakryiko 
4252d5caef5bSAndrii Nakryiko 		if ((t_kind == BTF_KIND_STRUCT || t_kind == BTF_KIND_UNION) &&
4253d5caef5bSAndrii Nakryiko 		    c_kind != BTF_KIND_FWD &&
4254d5caef5bSAndrii Nakryiko 		    is_type_mapped(d, c_id) &&
4255d5caef5bSAndrii Nakryiko 		    !is_type_mapped(d, t_id)) {
4256d5caef5bSAndrii Nakryiko 			/*
4257d5caef5bSAndrii Nakryiko 			 * as a perf optimization, we can map struct/union
4258d5caef5bSAndrii Nakryiko 			 * that's part of type graph we just verified for
4259d5caef5bSAndrii Nakryiko 			 * equivalence. We can do that for struct/union that has
4260d5caef5bSAndrii Nakryiko 			 * canonical representative only, though.
4261d5caef5bSAndrii Nakryiko 			 */
4262d5caef5bSAndrii Nakryiko 			d->map[t_id] = c_id;
4263d5caef5bSAndrii Nakryiko 		}
4264d5caef5bSAndrii Nakryiko 	}
4265d5caef5bSAndrii Nakryiko }
4266d5caef5bSAndrii Nakryiko 
4267d5caef5bSAndrii Nakryiko /*
4268d5caef5bSAndrii Nakryiko  * Deduplicate struct/union types.
4269d5caef5bSAndrii Nakryiko  *
4270d5caef5bSAndrii Nakryiko  * For each struct/union type its type signature hash is calculated, taking
4271d5caef5bSAndrii Nakryiko  * into account type's name, size, number, order and names of fields, but
4272d5caef5bSAndrii Nakryiko  * ignoring type ID's referenced from fields, because they might not be deduped
4273d5caef5bSAndrii Nakryiko  * completely until after reference types deduplication phase. This type hash
4274d5caef5bSAndrii Nakryiko  * is used to iterate over all potential canonical types, sharing same hash.
4275d5caef5bSAndrii Nakryiko  * For each canonical candidate we check whether type graphs that they form
4276d5caef5bSAndrii Nakryiko  * (through referenced types in fields and so on) are equivalent using algorithm
4277d5caef5bSAndrii Nakryiko  * implemented in `btf_dedup_is_equiv`. If such equivalence is found and
4278d5caef5bSAndrii Nakryiko  * BTF_KIND_FWD resolution is allowed, then hypothetical mapping
4279d5caef5bSAndrii Nakryiko  * (btf_dedup->hypot_map) produced by aforementioned type graph equivalence
4280d5caef5bSAndrii Nakryiko  * algorithm is used to record FWD -> STRUCT/UNION mapping. It's also used to
4281d5caef5bSAndrii Nakryiko  * potentially map other structs/unions to their canonical representatives,
4282d5caef5bSAndrii Nakryiko  * if such relationship hasn't yet been established. This speeds up algorithm
4283d5caef5bSAndrii Nakryiko  * by eliminating some of the duplicate work.
4284d5caef5bSAndrii Nakryiko  *
4285d5caef5bSAndrii Nakryiko  * If no matching canonical representative was found, struct/union is marked
4286d5caef5bSAndrii Nakryiko  * as canonical for itself and is added into btf_dedup->dedup_table hash map
4287d5caef5bSAndrii Nakryiko  * for further look ups.
4288d5caef5bSAndrii Nakryiko  */
btf_dedup_struct_type(struct btf_dedup * d,__u32 type_id)4289d5caef5bSAndrii Nakryiko static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
4290d5caef5bSAndrii Nakryiko {
429191097fbeSAndrii Nakryiko 	struct btf_type *cand_type, *t;
42922fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
4293d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are canonical */
4294d5caef5bSAndrii Nakryiko 	__u32 new_id = type_id;
4295d5caef5bSAndrii Nakryiko 	__u16 kind;
42962fc3fc0bSAndrii Nakryiko 	long h;
4297d5caef5bSAndrii Nakryiko 
4298d5caef5bSAndrii Nakryiko 	/* already deduped or is in process of deduping (loop detected) */
42995aab392cSAndrii Nakryiko 	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
4300d5caef5bSAndrii Nakryiko 		return 0;
4301d5caef5bSAndrii Nakryiko 
4302740e69c3SAndrii Nakryiko 	t = btf_type_by_id(d->btf, type_id);
4303b03bc685SAndrii Nakryiko 	kind = btf_kind(t);
4304d5caef5bSAndrii Nakryiko 
4305d5caef5bSAndrii Nakryiko 	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
4306d5caef5bSAndrii Nakryiko 		return 0;
4307d5caef5bSAndrii Nakryiko 
4308d5caef5bSAndrii Nakryiko 	h = btf_hash_struct(t);
43092fc3fc0bSAndrii Nakryiko 	for_each_dedup_cand(d, hash_entry, h) {
4310c302378bSEduard Zingerman 		__u32 cand_id = hash_entry->value;
4311d5caef5bSAndrii Nakryiko 		int eq;
4312d5caef5bSAndrii Nakryiko 
431391097fbeSAndrii Nakryiko 		/*
431491097fbeSAndrii Nakryiko 		 * Even though btf_dedup_is_equiv() checks for
431591097fbeSAndrii Nakryiko 		 * btf_shallow_equal_struct() internally when checking two
431691097fbeSAndrii Nakryiko 		 * structs (unions) for equivalence, we need to guard here
431791097fbeSAndrii Nakryiko 		 * from picking matching FWD type as a dedup candidate.
431891097fbeSAndrii Nakryiko 		 * This can happen due to hash collision. In such case just
431991097fbeSAndrii Nakryiko 		 * relying on btf_dedup_is_equiv() would lead to potentially
432091097fbeSAndrii Nakryiko 		 * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because
432191097fbeSAndrii Nakryiko 		 * FWD and compatible STRUCT/UNION are considered equivalent.
432291097fbeSAndrii Nakryiko 		 */
4323740e69c3SAndrii Nakryiko 		cand_type = btf_type_by_id(d->btf, cand_id);
432491097fbeSAndrii Nakryiko 		if (!btf_shallow_equal_struct(t, cand_type))
432591097fbeSAndrii Nakryiko 			continue;
432691097fbeSAndrii Nakryiko 
4327d5caef5bSAndrii Nakryiko 		btf_dedup_clear_hypot_map(d);
43282fc3fc0bSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, type_id, cand_id);
4329d5caef5bSAndrii Nakryiko 		if (eq < 0)
4330d5caef5bSAndrii Nakryiko 			return eq;
4331d5caef5bSAndrii Nakryiko 		if (!eq)
4332d5caef5bSAndrii Nakryiko 			continue;
4333d5caef5bSAndrii Nakryiko 		btf_dedup_merge_hypot_map(d);
4334f86524efSAndrii Nakryiko 		if (d->hypot_adjust_canon) /* not really equivalent */
4335f86524efSAndrii Nakryiko 			continue;
4336f86524efSAndrii Nakryiko 		new_id = cand_id;
4337d5caef5bSAndrii Nakryiko 		break;
4338d5caef5bSAndrii Nakryiko 	}
4339d5caef5bSAndrii Nakryiko 
4340d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
4341d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
4342d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4343d5caef5bSAndrii Nakryiko 
4344d5caef5bSAndrii Nakryiko 	return 0;
4345d5caef5bSAndrii Nakryiko }
4346d5caef5bSAndrii Nakryiko 
btf_dedup_struct_types(struct btf_dedup * d)4347d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d)
4348d5caef5bSAndrii Nakryiko {
4349d5caef5bSAndrii Nakryiko 	int i, err;
4350d5caef5bSAndrii Nakryiko 
4351f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4352f86524efSAndrii Nakryiko 		err = btf_dedup_struct_type(d, d->btf->start_id + i);
4353d5caef5bSAndrii Nakryiko 		if (err)
4354d5caef5bSAndrii Nakryiko 			return err;
4355d5caef5bSAndrii Nakryiko 	}
4356d5caef5bSAndrii Nakryiko 	return 0;
4357d5caef5bSAndrii Nakryiko }
4358d5caef5bSAndrii Nakryiko 
4359d5caef5bSAndrii Nakryiko /*
4360d5caef5bSAndrii Nakryiko  * Deduplicate reference type.
4361d5caef5bSAndrii Nakryiko  *
4362d5caef5bSAndrii Nakryiko  * Once all primitive and struct/union types got deduplicated, we can easily
4363d5caef5bSAndrii Nakryiko  * deduplicate all other (reference) BTF types. This is done in two steps:
4364d5caef5bSAndrii Nakryiko  *
4365d5caef5bSAndrii Nakryiko  * 1. Resolve all referenced type IDs into their canonical type IDs. This
4366d5caef5bSAndrii Nakryiko  * resolution can be done either immediately for primitive or struct/union types
4367d5caef5bSAndrii Nakryiko  * (because they were deduped in previous two phases) or recursively for
4368d5caef5bSAndrii Nakryiko  * reference types. Recursion will always terminate at either primitive or
4369d5caef5bSAndrii Nakryiko  * struct/union type, at which point we can "unwind" chain of reference types
4370d5caef5bSAndrii Nakryiko  * one by one. There is no danger of encountering cycles because in C type
4371d5caef5bSAndrii Nakryiko  * system the only way to form type cycle is through struct/union, so any chain
4372d5caef5bSAndrii Nakryiko  * of reference types, even those taking part in a type cycle, will inevitably
4373d5caef5bSAndrii Nakryiko  * reach struct/union at some point.
4374d5caef5bSAndrii Nakryiko  *
4375d5caef5bSAndrii Nakryiko  * 2. Once all referenced type IDs are resolved into canonical ones, BTF type
4376d5caef5bSAndrii Nakryiko  * becomes "stable", in the sense that no further deduplication will cause
4377d5caef5bSAndrii Nakryiko  * any changes to it. With that, it's now possible to calculate type's signature
4378d5caef5bSAndrii Nakryiko  * hash (this time taking into account referenced type IDs) and loop over all
4379d5caef5bSAndrii Nakryiko  * potential canonical representatives. If no match was found, current type
4380d5caef5bSAndrii Nakryiko  * will become canonical representative of itself and will be added into
4381d5caef5bSAndrii Nakryiko  * btf_dedup->dedup_table as another possible canonical representative.
4382d5caef5bSAndrii Nakryiko  */
btf_dedup_ref_type(struct btf_dedup * d,__u32 type_id)4383d5caef5bSAndrii Nakryiko static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
4384d5caef5bSAndrii Nakryiko {
43852fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
43862fc3fc0bSAndrii Nakryiko 	__u32 new_id = type_id, cand_id;
4387d5caef5bSAndrii Nakryiko 	struct btf_type *t, *cand;
4388d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are representative type */
43893d8669e6SDan Carpenter 	int ref_type_id;
43902fc3fc0bSAndrii Nakryiko 	long h;
4391d5caef5bSAndrii Nakryiko 
4392d5caef5bSAndrii Nakryiko 	if (d->map[type_id] == BTF_IN_PROGRESS_ID)
4393d5caef5bSAndrii Nakryiko 		return -ELOOP;
43945aab392cSAndrii Nakryiko 	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
4395d5caef5bSAndrii Nakryiko 		return resolve_type_id(d, type_id);
4396d5caef5bSAndrii Nakryiko 
4397740e69c3SAndrii Nakryiko 	t = btf_type_by_id(d->btf, type_id);
4398d5caef5bSAndrii Nakryiko 	d->map[type_id] = BTF_IN_PROGRESS_ID;
4399d5caef5bSAndrii Nakryiko 
4400b03bc685SAndrii Nakryiko 	switch (btf_kind(t)) {
4401d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
4402d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4403d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4404d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
4405d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4406d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
44072dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
4408d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, t->type);
4409d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4410d5caef5bSAndrii Nakryiko 			return ref_type_id;
4411d5caef5bSAndrii Nakryiko 		t->type = ref_type_id;
4412d5caef5bSAndrii Nakryiko 
4413d5caef5bSAndrii Nakryiko 		h = btf_hash_common(t);
44142fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
4415c302378bSEduard Zingerman 			cand_id = hash_entry->value;
4416740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4417d5caef5bSAndrii Nakryiko 			if (btf_equal_common(t, cand)) {
44182fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4419d5caef5bSAndrii Nakryiko 				break;
4420d5caef5bSAndrii Nakryiko 			}
4421d5caef5bSAndrii Nakryiko 		}
4422d5caef5bSAndrii Nakryiko 		break;
4423d5caef5bSAndrii Nakryiko 
4424223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
44255b84bd10SYonghong Song 		ref_type_id = btf_dedup_ref_type(d, t->type);
44265b84bd10SYonghong Song 		if (ref_type_id < 0)
44275b84bd10SYonghong Song 			return ref_type_id;
44285b84bd10SYonghong Song 		t->type = ref_type_id;
44295b84bd10SYonghong Song 
4430223f903eSYonghong Song 		h = btf_hash_int_decl_tag(t);
44315b84bd10SYonghong Song 		for_each_dedup_cand(d, hash_entry, h) {
4432c302378bSEduard Zingerman 			cand_id = hash_entry->value;
44335b84bd10SYonghong Song 			cand = btf_type_by_id(d->btf, cand_id);
44345b84bd10SYonghong Song 			if (btf_equal_int_tag(t, cand)) {
44355b84bd10SYonghong Song 				new_id = cand_id;
44365b84bd10SYonghong Song 				break;
44375b84bd10SYonghong Song 			}
44385b84bd10SYonghong Song 		}
44395b84bd10SYonghong Song 		break;
44405b84bd10SYonghong Song 
4441d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4442b03bc685SAndrii Nakryiko 		struct btf_array *info = btf_array(t);
4443d5caef5bSAndrii Nakryiko 
4444d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, info->type);
4445d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4446d5caef5bSAndrii Nakryiko 			return ref_type_id;
4447d5caef5bSAndrii Nakryiko 		info->type = ref_type_id;
4448d5caef5bSAndrii Nakryiko 
4449d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, info->index_type);
4450d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4451d5caef5bSAndrii Nakryiko 			return ref_type_id;
4452d5caef5bSAndrii Nakryiko 		info->index_type = ref_type_id;
4453d5caef5bSAndrii Nakryiko 
4454d5caef5bSAndrii Nakryiko 		h = btf_hash_array(t);
44552fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
4456c302378bSEduard Zingerman 			cand_id = hash_entry->value;
4457740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4458d5caef5bSAndrii Nakryiko 			if (btf_equal_array(t, cand)) {
44592fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4460d5caef5bSAndrii Nakryiko 				break;
4461d5caef5bSAndrii Nakryiko 			}
4462d5caef5bSAndrii Nakryiko 		}
4463d5caef5bSAndrii Nakryiko 		break;
4464d5caef5bSAndrii Nakryiko 	}
4465d5caef5bSAndrii Nakryiko 
4466d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4467d5caef5bSAndrii Nakryiko 		struct btf_param *param;
4468d5caef5bSAndrii Nakryiko 		__u16 vlen;
4469d5caef5bSAndrii Nakryiko 		int i;
4470d5caef5bSAndrii Nakryiko 
4471d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, t->type);
4472d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4473d5caef5bSAndrii Nakryiko 			return ref_type_id;
4474d5caef5bSAndrii Nakryiko 		t->type = ref_type_id;
4475d5caef5bSAndrii Nakryiko 
4476b03bc685SAndrii Nakryiko 		vlen = btf_vlen(t);
4477b03bc685SAndrii Nakryiko 		param = btf_params(t);
4478d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4479d5caef5bSAndrii Nakryiko 			ref_type_id = btf_dedup_ref_type(d, param->type);
4480d5caef5bSAndrii Nakryiko 			if (ref_type_id < 0)
4481d5caef5bSAndrii Nakryiko 				return ref_type_id;
4482d5caef5bSAndrii Nakryiko 			param->type = ref_type_id;
4483d5caef5bSAndrii Nakryiko 			param++;
4484d5caef5bSAndrii Nakryiko 		}
4485d5caef5bSAndrii Nakryiko 
4486d5caef5bSAndrii Nakryiko 		h = btf_hash_fnproto(t);
44872fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
4488c302378bSEduard Zingerman 			cand_id = hash_entry->value;
4489740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4490d5caef5bSAndrii Nakryiko 			if (btf_equal_fnproto(t, cand)) {
44912fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4492d5caef5bSAndrii Nakryiko 				break;
4493d5caef5bSAndrii Nakryiko 			}
4494d5caef5bSAndrii Nakryiko 		}
4495d5caef5bSAndrii Nakryiko 		break;
4496d5caef5bSAndrii Nakryiko 	}
4497d5caef5bSAndrii Nakryiko 
4498d5caef5bSAndrii Nakryiko 	default:
4499d5caef5bSAndrii Nakryiko 		return -EINVAL;
4500d5caef5bSAndrii Nakryiko 	}
4501d5caef5bSAndrii Nakryiko 
4502d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
4503d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
4504d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4505d5caef5bSAndrii Nakryiko 
4506d5caef5bSAndrii Nakryiko 	return new_id;
4507d5caef5bSAndrii Nakryiko }
4508d5caef5bSAndrii Nakryiko 
btf_dedup_ref_types(struct btf_dedup * d)4509d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d)
4510d5caef5bSAndrii Nakryiko {
4511d5caef5bSAndrii Nakryiko 	int i, err;
4512d5caef5bSAndrii Nakryiko 
4513f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4514f86524efSAndrii Nakryiko 		err = btf_dedup_ref_type(d, d->btf->start_id + i);
4515d5caef5bSAndrii Nakryiko 		if (err < 0)
4516d5caef5bSAndrii Nakryiko 			return err;
4517d5caef5bSAndrii Nakryiko 	}
45182fc3fc0bSAndrii Nakryiko 	/* we won't need d->dedup_table anymore */
45192fc3fc0bSAndrii Nakryiko 	hashmap__free(d->dedup_table);
45202fc3fc0bSAndrii Nakryiko 	d->dedup_table = NULL;
4521d5caef5bSAndrii Nakryiko 	return 0;
4522d5caef5bSAndrii Nakryiko }
4523d5caef5bSAndrii Nakryiko 
4524d5caef5bSAndrii Nakryiko /*
4525082108fdSEduard Zingerman  * Collect a map from type names to type ids for all canonical structs
4526082108fdSEduard Zingerman  * and unions. If the same name is shared by several canonical types
4527082108fdSEduard Zingerman  * use a special value 0 to indicate this fact.
4528082108fdSEduard Zingerman  */
btf_dedup_fill_unique_names_map(struct btf_dedup * d,struct hashmap * names_map)4529082108fdSEduard Zingerman static int btf_dedup_fill_unique_names_map(struct btf_dedup *d, struct hashmap *names_map)
4530082108fdSEduard Zingerman {
4531082108fdSEduard Zingerman 	__u32 nr_types = btf__type_cnt(d->btf);
4532082108fdSEduard Zingerman 	struct btf_type *t;
4533082108fdSEduard Zingerman 	__u32 type_id;
4534082108fdSEduard Zingerman 	__u16 kind;
4535082108fdSEduard Zingerman 	int err;
4536082108fdSEduard Zingerman 
4537082108fdSEduard Zingerman 	/*
4538082108fdSEduard Zingerman 	 * Iterate over base and split module ids in order to get all
4539082108fdSEduard Zingerman 	 * available structs in the map.
4540082108fdSEduard Zingerman 	 */
4541082108fdSEduard Zingerman 	for (type_id = 1; type_id < nr_types; ++type_id) {
4542082108fdSEduard Zingerman 		t = btf_type_by_id(d->btf, type_id);
4543082108fdSEduard Zingerman 		kind = btf_kind(t);
4544082108fdSEduard Zingerman 
4545082108fdSEduard Zingerman 		if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
4546082108fdSEduard Zingerman 			continue;
4547082108fdSEduard Zingerman 
4548082108fdSEduard Zingerman 		/* Skip non-canonical types */
4549082108fdSEduard Zingerman 		if (type_id != d->map[type_id])
4550082108fdSEduard Zingerman 			continue;
4551082108fdSEduard Zingerman 
4552082108fdSEduard Zingerman 		err = hashmap__add(names_map, t->name_off, type_id);
4553082108fdSEduard Zingerman 		if (err == -EEXIST)
4554082108fdSEduard Zingerman 			err = hashmap__set(names_map, t->name_off, 0, NULL, NULL);
4555082108fdSEduard Zingerman 
4556082108fdSEduard Zingerman 		if (err)
4557082108fdSEduard Zingerman 			return err;
4558082108fdSEduard Zingerman 	}
4559082108fdSEduard Zingerman 
4560082108fdSEduard Zingerman 	return 0;
4561082108fdSEduard Zingerman }
4562082108fdSEduard Zingerman 
btf_dedup_resolve_fwd(struct btf_dedup * d,struct hashmap * names_map,__u32 type_id)4563082108fdSEduard Zingerman static int btf_dedup_resolve_fwd(struct btf_dedup *d, struct hashmap *names_map, __u32 type_id)
4564082108fdSEduard Zingerman {
4565082108fdSEduard Zingerman 	struct btf_type *t = btf_type_by_id(d->btf, type_id);
4566082108fdSEduard Zingerman 	enum btf_fwd_kind fwd_kind = btf_kflag(t);
4567082108fdSEduard Zingerman 	__u16 cand_kind, kind = btf_kind(t);
4568082108fdSEduard Zingerman 	struct btf_type *cand_t;
4569082108fdSEduard Zingerman 	uintptr_t cand_id;
4570082108fdSEduard Zingerman 
4571082108fdSEduard Zingerman 	if (kind != BTF_KIND_FWD)
4572082108fdSEduard Zingerman 		return 0;
4573082108fdSEduard Zingerman 
4574082108fdSEduard Zingerman 	/* Skip if this FWD already has a mapping */
4575082108fdSEduard Zingerman 	if (type_id != d->map[type_id])
4576082108fdSEduard Zingerman 		return 0;
4577082108fdSEduard Zingerman 
4578082108fdSEduard Zingerman 	if (!hashmap__find(names_map, t->name_off, &cand_id))
4579082108fdSEduard Zingerman 		return 0;
4580082108fdSEduard Zingerman 
4581082108fdSEduard Zingerman 	/* Zero is a special value indicating that name is not unique */
4582082108fdSEduard Zingerman 	if (!cand_id)
4583082108fdSEduard Zingerman 		return 0;
4584082108fdSEduard Zingerman 
4585082108fdSEduard Zingerman 	cand_t = btf_type_by_id(d->btf, cand_id);
4586082108fdSEduard Zingerman 	cand_kind = btf_kind(cand_t);
4587082108fdSEduard Zingerman 	if ((cand_kind == BTF_KIND_STRUCT && fwd_kind != BTF_FWD_STRUCT) ||
4588082108fdSEduard Zingerman 	    (cand_kind == BTF_KIND_UNION && fwd_kind != BTF_FWD_UNION))
4589082108fdSEduard Zingerman 		return 0;
4590082108fdSEduard Zingerman 
4591082108fdSEduard Zingerman 	d->map[type_id] = cand_id;
4592082108fdSEduard Zingerman 
4593082108fdSEduard Zingerman 	return 0;
4594082108fdSEduard Zingerman }
4595082108fdSEduard Zingerman 
4596082108fdSEduard Zingerman /*
4597082108fdSEduard Zingerman  * Resolve unambiguous forward declarations.
4598082108fdSEduard Zingerman  *
4599082108fdSEduard Zingerman  * The lion's share of all FWD declarations is resolved during
4600082108fdSEduard Zingerman  * `btf_dedup_struct_types` phase when different type graphs are
4601082108fdSEduard Zingerman  * compared against each other. However, if in some compilation unit a
4602082108fdSEduard Zingerman  * FWD declaration is not a part of a type graph compared against
4603082108fdSEduard Zingerman  * another type graph that declaration's canonical type would not be
4604082108fdSEduard Zingerman  * changed. Example:
4605082108fdSEduard Zingerman  *
4606082108fdSEduard Zingerman  * CU #1:
4607082108fdSEduard Zingerman  *
4608082108fdSEduard Zingerman  * struct foo;
4609082108fdSEduard Zingerman  * struct foo *some_global;
4610082108fdSEduard Zingerman  *
4611082108fdSEduard Zingerman  * CU #2:
4612082108fdSEduard Zingerman  *
4613082108fdSEduard Zingerman  * struct foo { int u; };
4614082108fdSEduard Zingerman  * struct foo *another_global;
4615082108fdSEduard Zingerman  *
4616082108fdSEduard Zingerman  * After `btf_dedup_struct_types` the BTF looks as follows:
4617082108fdSEduard Zingerman  *
4618082108fdSEduard Zingerman  * [1] STRUCT 'foo' size=4 vlen=1 ...
4619082108fdSEduard Zingerman  * [2] INT 'int' size=4 ...
4620082108fdSEduard Zingerman  * [3] PTR '(anon)' type_id=1
4621082108fdSEduard Zingerman  * [4] FWD 'foo' fwd_kind=struct
4622082108fdSEduard Zingerman  * [5] PTR '(anon)' type_id=4
4623082108fdSEduard Zingerman  *
4624082108fdSEduard Zingerman  * This pass assumes that such FWD declarations should be mapped to
4625082108fdSEduard Zingerman  * structs or unions with identical name in case if the name is not
4626082108fdSEduard Zingerman  * ambiguous.
4627082108fdSEduard Zingerman  */
btf_dedup_resolve_fwds(struct btf_dedup * d)4628082108fdSEduard Zingerman static int btf_dedup_resolve_fwds(struct btf_dedup *d)
4629082108fdSEduard Zingerman {
4630082108fdSEduard Zingerman 	int i, err;
4631082108fdSEduard Zingerman 	struct hashmap *names_map;
4632082108fdSEduard Zingerman 
4633082108fdSEduard Zingerman 	names_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
4634082108fdSEduard Zingerman 	if (IS_ERR(names_map))
4635082108fdSEduard Zingerman 		return PTR_ERR(names_map);
4636082108fdSEduard Zingerman 
4637082108fdSEduard Zingerman 	err = btf_dedup_fill_unique_names_map(d, names_map);
4638082108fdSEduard Zingerman 	if (err < 0)
4639082108fdSEduard Zingerman 		goto exit;
4640082108fdSEduard Zingerman 
4641082108fdSEduard Zingerman 	for (i = 0; i < d->btf->nr_types; i++) {
4642082108fdSEduard Zingerman 		err = btf_dedup_resolve_fwd(d, names_map, d->btf->start_id + i);
4643082108fdSEduard Zingerman 		if (err < 0)
4644082108fdSEduard Zingerman 			break;
4645082108fdSEduard Zingerman 	}
4646082108fdSEduard Zingerman 
4647082108fdSEduard Zingerman exit:
4648082108fdSEduard Zingerman 	hashmap__free(names_map);
4649082108fdSEduard Zingerman 	return err;
4650082108fdSEduard Zingerman }
4651082108fdSEduard Zingerman 
4652082108fdSEduard Zingerman /*
4653d5caef5bSAndrii Nakryiko  * Compact types.
4654d5caef5bSAndrii Nakryiko  *
4655d5caef5bSAndrii Nakryiko  * After we established for each type its corresponding canonical representative
4656d5caef5bSAndrii Nakryiko  * type, we now can eliminate types that are not canonical and leave only
4657d5caef5bSAndrii Nakryiko  * canonical ones layed out sequentially in memory by copying them over
4658d5caef5bSAndrii Nakryiko  * duplicates. During compaction btf_dedup->hypot_map array is reused to store
4659d5caef5bSAndrii Nakryiko  * a map from original type ID to a new compacted type ID, which will be used
4660d5caef5bSAndrii Nakryiko  * during next phase to "fix up" type IDs, referenced from struct/union and
4661d5caef5bSAndrii Nakryiko  * reference types.
4662d5caef5bSAndrii Nakryiko  */
btf_dedup_compact_types(struct btf_dedup * d)4663d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d)
4664d5caef5bSAndrii Nakryiko {
4665740e69c3SAndrii Nakryiko 	__u32 *new_offs;
4666f86524efSAndrii Nakryiko 	__u32 next_type_id = d->btf->start_id;
4667f86524efSAndrii Nakryiko 	const struct btf_type *t;
4668740e69c3SAndrii Nakryiko 	void *p;
4669f86524efSAndrii Nakryiko 	int i, id, len;
4670d5caef5bSAndrii Nakryiko 
4671d5caef5bSAndrii Nakryiko 	/* we are going to reuse hypot_map to store compaction remapping */
4672d5caef5bSAndrii Nakryiko 	d->hypot_map[0] = 0;
4673f86524efSAndrii Nakryiko 	/* base BTF types are not renumbered */
4674f86524efSAndrii Nakryiko 	for (id = 1; id < d->btf->start_id; id++)
4675f86524efSAndrii Nakryiko 		d->hypot_map[id] = id;
4676f86524efSAndrii Nakryiko 	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++)
4677f86524efSAndrii Nakryiko 		d->hypot_map[id] = BTF_UNPROCESSED_ID;
4678d5caef5bSAndrii Nakryiko 
4679740e69c3SAndrii Nakryiko 	p = d->btf->types_data;
4680d5caef5bSAndrii Nakryiko 
4681f86524efSAndrii Nakryiko 	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) {
4682f86524efSAndrii Nakryiko 		if (d->map[id] != id)
4683d5caef5bSAndrii Nakryiko 			continue;
4684d5caef5bSAndrii Nakryiko 
4685f86524efSAndrii Nakryiko 		t = btf__type_by_id(d->btf, id);
4686f86524efSAndrii Nakryiko 		len = btf_type_size(t);
4687d5caef5bSAndrii Nakryiko 		if (len < 0)
4688d5caef5bSAndrii Nakryiko 			return len;
4689d5caef5bSAndrii Nakryiko 
4690f86524efSAndrii Nakryiko 		memmove(p, t, len);
4691f86524efSAndrii Nakryiko 		d->hypot_map[id] = next_type_id;
4692f86524efSAndrii Nakryiko 		d->btf->type_offs[next_type_id - d->btf->start_id] = p - d->btf->types_data;
4693d5caef5bSAndrii Nakryiko 		p += len;
4694d5caef5bSAndrii Nakryiko 		next_type_id++;
4695d5caef5bSAndrii Nakryiko 	}
4696d5caef5bSAndrii Nakryiko 
4697d5caef5bSAndrii Nakryiko 	/* shrink struct btf's internal types index and update btf_header */
4698f86524efSAndrii Nakryiko 	d->btf->nr_types = next_type_id - d->btf->start_id;
4699ba451366SAndrii Nakryiko 	d->btf->type_offs_cap = d->btf->nr_types;
4700740e69c3SAndrii Nakryiko 	d->btf->hdr->type_len = p - d->btf->types_data;
4701740e69c3SAndrii Nakryiko 	new_offs = libbpf_reallocarray(d->btf->type_offs, d->btf->type_offs_cap,
4702740e69c3SAndrii Nakryiko 				       sizeof(*new_offs));
4703f86524efSAndrii Nakryiko 	if (d->btf->type_offs_cap && !new_offs)
4704d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4705740e69c3SAndrii Nakryiko 	d->btf->type_offs = new_offs;
4706919d2b1dSAndrii Nakryiko 	d->btf->hdr->str_off = d->btf->hdr->type_len;
4707b8604247SAndrii Nakryiko 	d->btf->raw_size = d->btf->hdr->hdr_len + d->btf->hdr->type_len + d->btf->hdr->str_len;
4708d5caef5bSAndrii Nakryiko 	return 0;
4709d5caef5bSAndrii Nakryiko }
4710d5caef5bSAndrii Nakryiko 
4711d5caef5bSAndrii Nakryiko /*
4712d5caef5bSAndrii Nakryiko  * Figure out final (deduplicated and compacted) type ID for provided original
4713d5caef5bSAndrii Nakryiko  * `type_id` by first resolving it into corresponding canonical type ID and
4714d5caef5bSAndrii Nakryiko  * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map,
4715d5caef5bSAndrii Nakryiko  * which is populated during compaction phase.
4716d5caef5bSAndrii Nakryiko  */
btf_dedup_remap_type_id(__u32 * type_id,void * ctx)4717f36e99a4SAndrii Nakryiko static int btf_dedup_remap_type_id(__u32 *type_id, void *ctx)
4718d5caef5bSAndrii Nakryiko {
4719f36e99a4SAndrii Nakryiko 	struct btf_dedup *d = ctx;
4720d5caef5bSAndrii Nakryiko 	__u32 resolved_type_id, new_type_id;
4721d5caef5bSAndrii Nakryiko 
4722f36e99a4SAndrii Nakryiko 	resolved_type_id = resolve_type_id(d, *type_id);
4723d5caef5bSAndrii Nakryiko 	new_type_id = d->hypot_map[resolved_type_id];
47245aab392cSAndrii Nakryiko 	if (new_type_id > BTF_MAX_NR_TYPES)
4725d5caef5bSAndrii Nakryiko 		return -EINVAL;
4726f36e99a4SAndrii Nakryiko 
4727f36e99a4SAndrii Nakryiko 	*type_id = new_type_id;
4728f36e99a4SAndrii Nakryiko 	return 0;
4729d5caef5bSAndrii Nakryiko }
4730d5caef5bSAndrii Nakryiko 
4731d5caef5bSAndrii Nakryiko /*
4732d5caef5bSAndrii Nakryiko  * Remap referenced type IDs into deduped type IDs.
4733d5caef5bSAndrii Nakryiko  *
4734d5caef5bSAndrii Nakryiko  * After BTF types are deduplicated and compacted, their final type IDs may
4735d5caef5bSAndrii Nakryiko  * differ from original ones. The map from original to a corresponding
4736d5caef5bSAndrii Nakryiko  * deduped type ID is stored in btf_dedup->hypot_map and is populated during
4737d5caef5bSAndrii Nakryiko  * compaction phase. During remapping phase we are rewriting all type IDs
4738d5caef5bSAndrii Nakryiko  * referenced from any BTF type (e.g., struct fields, func proto args, etc) to
4739d5caef5bSAndrii Nakryiko  * their final deduped type IDs.
4740d5caef5bSAndrii Nakryiko  */
btf_dedup_remap_types(struct btf_dedup * d)4741d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d)
4742d5caef5bSAndrii Nakryiko {
4743d5caef5bSAndrii Nakryiko 	int i, r;
4744d5caef5bSAndrii Nakryiko 
4745f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4746f36e99a4SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
4747f36e99a4SAndrii Nakryiko 
4748f36e99a4SAndrii Nakryiko 		r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d);
4749f36e99a4SAndrii Nakryiko 		if (r)
4750d5caef5bSAndrii Nakryiko 			return r;
4751d5caef5bSAndrii Nakryiko 	}
4752f36e99a4SAndrii Nakryiko 
4753f36e99a4SAndrii Nakryiko 	if (!d->btf_ext)
4754f36e99a4SAndrii Nakryiko 		return 0;
4755f36e99a4SAndrii Nakryiko 
4756f36e99a4SAndrii Nakryiko 	r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d);
4757f36e99a4SAndrii Nakryiko 	if (r)
4758f36e99a4SAndrii Nakryiko 		return r;
4759f36e99a4SAndrii Nakryiko 
4760d5caef5bSAndrii Nakryiko 	return 0;
4761d5caef5bSAndrii Nakryiko }
4762fb2426adSMartin KaFai Lau 
4763fb2426adSMartin KaFai Lau /*
4764fb2426adSMartin KaFai Lau  * Probe few well-known locations for vmlinux kernel image and try to load BTF
4765fb2426adSMartin KaFai Lau  * data out of it to use for target BTF.
4766fb2426adSMartin KaFai Lau  */
btf__load_vmlinux_btf(void)4767a710eed3SHengqi Chen struct btf *btf__load_vmlinux_btf(void)
4768fb2426adSMartin KaFai Lau {
476901f2e36cSTao Chen 	const char *locations[] = {
4770fb2426adSMartin KaFai Lau 		/* try canonical vmlinux BTF through sysfs first */
477101f2e36cSTao Chen 		"/sys/kernel/btf/vmlinux",
477201f2e36cSTao Chen 		/* fall back to trying to find vmlinux on disk otherwise */
477301f2e36cSTao Chen 		"/boot/vmlinux-%1$s",
477401f2e36cSTao Chen 		"/lib/modules/%1$s/vmlinux-%1$s",
477501f2e36cSTao Chen 		"/lib/modules/%1$s/build/vmlinux",
477601f2e36cSTao Chen 		"/usr/lib/modules/%1$s/kernel/vmlinux",
477701f2e36cSTao Chen 		"/usr/lib/debug/boot/vmlinux-%1$s",
477801f2e36cSTao Chen 		"/usr/lib/debug/boot/vmlinux-%1$s.debug",
477901f2e36cSTao Chen 		"/usr/lib/debug/lib/modules/%1$s/vmlinux",
4780fb2426adSMartin KaFai Lau 	};
4781fb2426adSMartin KaFai Lau 	char path[PATH_MAX + 1];
4782fb2426adSMartin KaFai Lau 	struct utsname buf;
4783fb2426adSMartin KaFai Lau 	struct btf *btf;
4784e9fc3ce9SAndrii Nakryiko 	int i, err;
4785fb2426adSMartin KaFai Lau 
4786fb2426adSMartin KaFai Lau 	uname(&buf);
4787fb2426adSMartin KaFai Lau 
4788fb2426adSMartin KaFai Lau 	for (i = 0; i < ARRAY_SIZE(locations); i++) {
478901f2e36cSTao Chen 		snprintf(path, PATH_MAX, locations[i], buf.release);
4790fb2426adSMartin KaFai Lau 
47916a4ab886SJon Doron 		if (faccessat(AT_FDCWD, path, R_OK, AT_EACCESS))
4792fb2426adSMartin KaFai Lau 			continue;
4793fb2426adSMartin KaFai Lau 
479401f2e36cSTao Chen 		btf = btf__parse(path, NULL);
4795e9fc3ce9SAndrii Nakryiko 		err = libbpf_get_error(btf);
4796e9fc3ce9SAndrii Nakryiko 		pr_debug("loading kernel BTF '%s': %d\n", path, err);
4797e9fc3ce9SAndrii Nakryiko 		if (err)
4798fb2426adSMartin KaFai Lau 			continue;
4799fb2426adSMartin KaFai Lau 
4800fb2426adSMartin KaFai Lau 		return btf;
4801fb2426adSMartin KaFai Lau 	}
4802fb2426adSMartin KaFai Lau 
4803fb2426adSMartin KaFai Lau 	pr_warn("failed to find valid kernel BTF\n");
4804e9fc3ce9SAndrii Nakryiko 	return libbpf_err_ptr(-ESRCH);
4805fb2426adSMartin KaFai Lau }
4806f36e99a4SAndrii Nakryiko 
4807a710eed3SHengqi Chen struct btf *libbpf_find_kernel_btf(void) __attribute__((alias("btf__load_vmlinux_btf")));
4808a710eed3SHengqi Chen 
btf__load_module_btf(const char * module_name,struct btf * vmlinux_btf)4809a710eed3SHengqi Chen struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf)
4810a710eed3SHengqi Chen {
4811a710eed3SHengqi Chen 	char path[80];
4812a710eed3SHengqi Chen 
4813a710eed3SHengqi Chen 	snprintf(path, sizeof(path), "/sys/kernel/btf/%s", module_name);
4814a710eed3SHengqi Chen 	return btf__parse_split(path, vmlinux_btf);
4815a710eed3SHengqi Chen }
4816a710eed3SHengqi Chen 
btf_type_visit_type_ids(struct btf_type * t,type_id_visit_fn visit,void * ctx)4817f36e99a4SAndrii Nakryiko int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx)
4818f36e99a4SAndrii Nakryiko {
4819f36e99a4SAndrii Nakryiko 	int i, n, err;
4820f36e99a4SAndrii Nakryiko 
4821f36e99a4SAndrii Nakryiko 	switch (btf_kind(t)) {
4822f36e99a4SAndrii Nakryiko 	case BTF_KIND_INT:
4823f36e99a4SAndrii Nakryiko 	case BTF_KIND_FLOAT:
4824f36e99a4SAndrii Nakryiko 	case BTF_KIND_ENUM:
4825dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
4826f36e99a4SAndrii Nakryiko 		return 0;
4827f36e99a4SAndrii Nakryiko 
4828f36e99a4SAndrii Nakryiko 	case BTF_KIND_FWD:
4829f36e99a4SAndrii Nakryiko 	case BTF_KIND_CONST:
4830f36e99a4SAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4831f36e99a4SAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4832f36e99a4SAndrii Nakryiko 	case BTF_KIND_PTR:
4833f36e99a4SAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4834f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC:
4835f36e99a4SAndrii Nakryiko 	case BTF_KIND_VAR:
4836223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
48372dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
4838f36e99a4SAndrii Nakryiko 		return visit(&t->type, ctx);
4839f36e99a4SAndrii Nakryiko 
4840f36e99a4SAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4841f36e99a4SAndrii Nakryiko 		struct btf_array *a = btf_array(t);
4842f36e99a4SAndrii Nakryiko 
4843f36e99a4SAndrii Nakryiko 		err = visit(&a->type, ctx);
4844f36e99a4SAndrii Nakryiko 		err = err ?: visit(&a->index_type, ctx);
4845f36e99a4SAndrii Nakryiko 		return err;
4846f36e99a4SAndrii Nakryiko 	}
4847f36e99a4SAndrii Nakryiko 
4848f36e99a4SAndrii Nakryiko 	case BTF_KIND_STRUCT:
4849f36e99a4SAndrii Nakryiko 	case BTF_KIND_UNION: {
4850f36e99a4SAndrii Nakryiko 		struct btf_member *m = btf_members(t);
4851f36e99a4SAndrii Nakryiko 
4852f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4853f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4854f36e99a4SAndrii Nakryiko 			if (err)
4855f36e99a4SAndrii Nakryiko 				return err;
4856f36e99a4SAndrii Nakryiko 		}
4857f36e99a4SAndrii Nakryiko 		return 0;
4858f36e99a4SAndrii Nakryiko 	}
4859f36e99a4SAndrii Nakryiko 
4860f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4861f36e99a4SAndrii Nakryiko 		struct btf_param *m = btf_params(t);
4862f36e99a4SAndrii Nakryiko 
4863f36e99a4SAndrii Nakryiko 		err = visit(&t->type, ctx);
4864f36e99a4SAndrii Nakryiko 		if (err)
4865f36e99a4SAndrii Nakryiko 			return err;
4866f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4867f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4868f36e99a4SAndrii Nakryiko 			if (err)
4869f36e99a4SAndrii Nakryiko 				return err;
4870f36e99a4SAndrii Nakryiko 		}
4871f36e99a4SAndrii Nakryiko 		return 0;
4872f36e99a4SAndrii Nakryiko 	}
4873f36e99a4SAndrii Nakryiko 
4874f36e99a4SAndrii Nakryiko 	case BTF_KIND_DATASEC: {
4875f36e99a4SAndrii Nakryiko 		struct btf_var_secinfo *m = btf_var_secinfos(t);
4876f36e99a4SAndrii Nakryiko 
4877f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4878f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4879f36e99a4SAndrii Nakryiko 			if (err)
4880f36e99a4SAndrii Nakryiko 				return err;
4881f36e99a4SAndrii Nakryiko 		}
4882f36e99a4SAndrii Nakryiko 		return 0;
4883f36e99a4SAndrii Nakryiko 	}
4884f36e99a4SAndrii Nakryiko 
4885f36e99a4SAndrii Nakryiko 	default:
4886f36e99a4SAndrii Nakryiko 		return -EINVAL;
4887f36e99a4SAndrii Nakryiko 	}
4888f36e99a4SAndrii Nakryiko }
4889f36e99a4SAndrii Nakryiko 
btf_type_visit_str_offs(struct btf_type * t,str_off_visit_fn visit,void * ctx)4890f36e99a4SAndrii Nakryiko int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx)
4891f36e99a4SAndrii Nakryiko {
4892f36e99a4SAndrii Nakryiko 	int i, n, err;
4893f36e99a4SAndrii Nakryiko 
4894f36e99a4SAndrii Nakryiko 	err = visit(&t->name_off, ctx);
4895f36e99a4SAndrii Nakryiko 	if (err)
4896f36e99a4SAndrii Nakryiko 		return err;
4897f36e99a4SAndrii Nakryiko 
4898f36e99a4SAndrii Nakryiko 	switch (btf_kind(t)) {
4899f36e99a4SAndrii Nakryiko 	case BTF_KIND_STRUCT:
4900f36e99a4SAndrii Nakryiko 	case BTF_KIND_UNION: {
4901f36e99a4SAndrii Nakryiko 		struct btf_member *m = btf_members(t);
4902f36e99a4SAndrii Nakryiko 
4903f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4904f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
4905f36e99a4SAndrii Nakryiko 			if (err)
4906f36e99a4SAndrii Nakryiko 				return err;
4907f36e99a4SAndrii Nakryiko 		}
4908f36e99a4SAndrii Nakryiko 		break;
4909f36e99a4SAndrii Nakryiko 	}
4910f36e99a4SAndrii Nakryiko 	case BTF_KIND_ENUM: {
4911f36e99a4SAndrii Nakryiko 		struct btf_enum *m = btf_enum(t);
4912f36e99a4SAndrii Nakryiko 
4913f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4914f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
4915f36e99a4SAndrii Nakryiko 			if (err)
4916f36e99a4SAndrii Nakryiko 				return err;
4917f36e99a4SAndrii Nakryiko 		}
4918f36e99a4SAndrii Nakryiko 		break;
4919f36e99a4SAndrii Nakryiko 	}
4920dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64: {
4921dffbbdc2SYonghong Song 		struct btf_enum64 *m = btf_enum64(t);
4922dffbbdc2SYonghong Song 
4923dffbbdc2SYonghong Song 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4924dffbbdc2SYonghong Song 			err = visit(&m->name_off, ctx);
4925dffbbdc2SYonghong Song 			if (err)
4926dffbbdc2SYonghong Song 				return err;
4927dffbbdc2SYonghong Song 		}
4928dffbbdc2SYonghong Song 		break;
4929dffbbdc2SYonghong Song 	}
4930f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4931f36e99a4SAndrii Nakryiko 		struct btf_param *m = btf_params(t);
4932f36e99a4SAndrii Nakryiko 
4933f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4934f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
4935f36e99a4SAndrii Nakryiko 			if (err)
4936f36e99a4SAndrii Nakryiko 				return err;
4937f36e99a4SAndrii Nakryiko 		}
4938f36e99a4SAndrii Nakryiko 		break;
4939f36e99a4SAndrii Nakryiko 	}
4940f36e99a4SAndrii Nakryiko 	default:
4941f36e99a4SAndrii Nakryiko 		break;
4942f36e99a4SAndrii Nakryiko 	}
4943f36e99a4SAndrii Nakryiko 
4944f36e99a4SAndrii Nakryiko 	return 0;
4945f36e99a4SAndrii Nakryiko }
4946f36e99a4SAndrii Nakryiko 
btf_ext_visit_type_ids(struct btf_ext * btf_ext,type_id_visit_fn visit,void * ctx)4947f36e99a4SAndrii Nakryiko int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx)
4948f36e99a4SAndrii Nakryiko {
4949f36e99a4SAndrii Nakryiko 	const struct btf_ext_info *seg;
4950f36e99a4SAndrii Nakryiko 	struct btf_ext_info_sec *sec;
4951f36e99a4SAndrii Nakryiko 	int i, err;
4952f36e99a4SAndrii Nakryiko 
4953f36e99a4SAndrii Nakryiko 	seg = &btf_ext->func_info;
4954f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
4955f36e99a4SAndrii Nakryiko 		struct bpf_func_info_min *rec;
4956f36e99a4SAndrii Nakryiko 
4957f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
4958f36e99a4SAndrii Nakryiko 			err = visit(&rec->type_id, ctx);
4959f36e99a4SAndrii Nakryiko 			if (err < 0)
4960f36e99a4SAndrii Nakryiko 				return err;
4961f36e99a4SAndrii Nakryiko 		}
4962f36e99a4SAndrii Nakryiko 	}
4963f36e99a4SAndrii Nakryiko 
4964f36e99a4SAndrii Nakryiko 	seg = &btf_ext->core_relo_info;
4965f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
4966f36e99a4SAndrii Nakryiko 		struct bpf_core_relo *rec;
4967f36e99a4SAndrii Nakryiko 
4968f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
4969f36e99a4SAndrii Nakryiko 			err = visit(&rec->type_id, ctx);
4970f36e99a4SAndrii Nakryiko 			if (err < 0)
4971f36e99a4SAndrii Nakryiko 				return err;
4972f36e99a4SAndrii Nakryiko 		}
4973f36e99a4SAndrii Nakryiko 	}
4974f36e99a4SAndrii Nakryiko 
4975f36e99a4SAndrii Nakryiko 	return 0;
4976f36e99a4SAndrii Nakryiko }
4977f36e99a4SAndrii Nakryiko 
btf_ext_visit_str_offs(struct btf_ext * btf_ext,str_off_visit_fn visit,void * ctx)4978f36e99a4SAndrii Nakryiko int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx)
4979f36e99a4SAndrii Nakryiko {
4980f36e99a4SAndrii Nakryiko 	const struct btf_ext_info *seg;
4981f36e99a4SAndrii Nakryiko 	struct btf_ext_info_sec *sec;
4982f36e99a4SAndrii Nakryiko 	int i, err;
4983f36e99a4SAndrii Nakryiko 
4984f36e99a4SAndrii Nakryiko 	seg = &btf_ext->func_info;
4985f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
4986f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
4987f36e99a4SAndrii Nakryiko 		if (err)
4988f36e99a4SAndrii Nakryiko 			return err;
4989f36e99a4SAndrii Nakryiko 	}
4990f36e99a4SAndrii Nakryiko 
4991f36e99a4SAndrii Nakryiko 	seg = &btf_ext->line_info;
4992f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
4993f36e99a4SAndrii Nakryiko 		struct bpf_line_info_min *rec;
4994f36e99a4SAndrii Nakryiko 
4995f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
4996f36e99a4SAndrii Nakryiko 		if (err)
4997f36e99a4SAndrii Nakryiko 			return err;
4998f36e99a4SAndrii Nakryiko 
4999f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5000f36e99a4SAndrii Nakryiko 			err = visit(&rec->file_name_off, ctx);
5001f36e99a4SAndrii Nakryiko 			if (err)
5002f36e99a4SAndrii Nakryiko 				return err;
5003f36e99a4SAndrii Nakryiko 			err = visit(&rec->line_off, ctx);
5004f36e99a4SAndrii Nakryiko 			if (err)
5005f36e99a4SAndrii Nakryiko 				return err;
5006f36e99a4SAndrii Nakryiko 		}
5007f36e99a4SAndrii Nakryiko 	}
5008f36e99a4SAndrii Nakryiko 
5009f36e99a4SAndrii Nakryiko 	seg = &btf_ext->core_relo_info;
5010f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5011f36e99a4SAndrii Nakryiko 		struct bpf_core_relo *rec;
5012f36e99a4SAndrii Nakryiko 
5013f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
5014f36e99a4SAndrii Nakryiko 		if (err)
5015f36e99a4SAndrii Nakryiko 			return err;
5016f36e99a4SAndrii Nakryiko 
5017f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5018f36e99a4SAndrii Nakryiko 			err = visit(&rec->access_str_off, ctx);
5019f36e99a4SAndrii Nakryiko 			if (err)
5020f36e99a4SAndrii Nakryiko 				return err;
5021f36e99a4SAndrii Nakryiko 		}
5022f36e99a4SAndrii Nakryiko 	}
5023f36e99a4SAndrii Nakryiko 
5024f36e99a4SAndrii Nakryiko 	return 0;
5025f36e99a4SAndrii Nakryiko }
5026