xref: /openbmc/linux/tools/lib/bpf/btf.c (revision 2ef20263)
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 
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  */
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
4519c651127SAndrii Nakryiko __u32 btf__get_nr_types(const struct btf *btf)
4529c651127SAndrii Nakryiko {
453ba451366SAndrii Nakryiko 	return btf->start_id + btf->nr_types - 1;
4549c651127SAndrii Nakryiko }
4559c651127SAndrii Nakryiko 
4566a886de0SHengqi Chen __u32 btf__type_cnt(const struct btf *btf)
4576a886de0SHengqi Chen {
4586a886de0SHengqi Chen 	return btf->start_id + btf->nr_types;
4596a886de0SHengqi Chen }
4606a886de0SHengqi Chen 
4610cfdcd63SAndrii Nakryiko const struct btf *btf__base_btf(const struct btf *btf)
4620cfdcd63SAndrii Nakryiko {
4630cfdcd63SAndrii Nakryiko 	return btf->base_btf;
4640cfdcd63SAndrii Nakryiko }
4650cfdcd63SAndrii Nakryiko 
466740e69c3SAndrii Nakryiko /* internal helper returning non-const pointer to a type */
46774753e14SAlexei Starovoitov struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id)
468740e69c3SAndrii Nakryiko {
469740e69c3SAndrii Nakryiko 	if (type_id == 0)
470740e69c3SAndrii Nakryiko 		return &btf_void;
471ba451366SAndrii Nakryiko 	if (type_id < btf->start_id)
472ba451366SAndrii Nakryiko 		return btf_type_by_id(btf->base_btf, type_id);
473ba451366SAndrii Nakryiko 	return btf->types_data + btf->type_offs[type_id - btf->start_id];
474740e69c3SAndrii Nakryiko }
475740e69c3SAndrii Nakryiko 
47638d5d3b3SMartin KaFai Lau const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
4778a138aedSMartin KaFai Lau {
478ba451366SAndrii Nakryiko 	if (type_id >= btf->start_id + btf->nr_types)
479e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, NULL;
480740e69c3SAndrii Nakryiko 	return btf_type_by_id((struct btf *)btf, type_id);
4818a138aedSMartin KaFai Lau }
4828a138aedSMartin KaFai Lau 
48344ad23dfSAndrii Nakryiko static int determine_ptr_size(const struct btf *btf)
48444ad23dfSAndrii Nakryiko {
485610cd93bSDouglas Raillard 	static const char * const long_aliases[] = {
486610cd93bSDouglas Raillard 		"long",
487610cd93bSDouglas Raillard 		"long int",
488610cd93bSDouglas Raillard 		"int long",
489610cd93bSDouglas Raillard 		"unsigned long",
490610cd93bSDouglas Raillard 		"long unsigned",
491610cd93bSDouglas Raillard 		"unsigned long int",
492610cd93bSDouglas Raillard 		"unsigned int long",
493610cd93bSDouglas Raillard 		"long unsigned int",
494610cd93bSDouglas Raillard 		"long int unsigned",
495610cd93bSDouglas Raillard 		"int unsigned long",
496610cd93bSDouglas Raillard 		"int long unsigned",
497610cd93bSDouglas Raillard 	};
49844ad23dfSAndrii Nakryiko 	const struct btf_type *t;
49944ad23dfSAndrii Nakryiko 	const char *name;
500610cd93bSDouglas Raillard 	int i, j, n;
50144ad23dfSAndrii Nakryiko 
502ba451366SAndrii Nakryiko 	if (btf->base_btf && btf->base_btf->ptr_sz > 0)
503ba451366SAndrii Nakryiko 		return btf->base_btf->ptr_sz;
504ba451366SAndrii Nakryiko 
5056a886de0SHengqi Chen 	n = btf__type_cnt(btf);
5066a886de0SHengqi Chen 	for (i = 1; i < n; i++) {
50744ad23dfSAndrii Nakryiko 		t = btf__type_by_id(btf, i);
50844ad23dfSAndrii Nakryiko 		if (!btf_is_int(t))
50944ad23dfSAndrii Nakryiko 			continue;
51044ad23dfSAndrii Nakryiko 
511610cd93bSDouglas Raillard 		if (t->size != 4 && t->size != 8)
512610cd93bSDouglas Raillard 			continue;
513610cd93bSDouglas Raillard 
51444ad23dfSAndrii Nakryiko 		name = btf__name_by_offset(btf, t->name_off);
51544ad23dfSAndrii Nakryiko 		if (!name)
51644ad23dfSAndrii Nakryiko 			continue;
51744ad23dfSAndrii Nakryiko 
518610cd93bSDouglas Raillard 		for (j = 0; j < ARRAY_SIZE(long_aliases); j++) {
519610cd93bSDouglas Raillard 			if (strcmp(name, long_aliases[j]) == 0)
52044ad23dfSAndrii Nakryiko 				return t->size;
52144ad23dfSAndrii Nakryiko 		}
52244ad23dfSAndrii Nakryiko 	}
52344ad23dfSAndrii Nakryiko 
52444ad23dfSAndrii Nakryiko 	return -1;
52544ad23dfSAndrii Nakryiko }
52644ad23dfSAndrii Nakryiko 
52744ad23dfSAndrii Nakryiko static size_t btf_ptr_sz(const struct btf *btf)
52844ad23dfSAndrii Nakryiko {
52944ad23dfSAndrii Nakryiko 	if (!btf->ptr_sz)
53044ad23dfSAndrii Nakryiko 		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
53144ad23dfSAndrii Nakryiko 	return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz;
53244ad23dfSAndrii Nakryiko }
53344ad23dfSAndrii Nakryiko 
53444ad23dfSAndrii Nakryiko /* Return pointer size this BTF instance assumes. The size is heuristically
53544ad23dfSAndrii Nakryiko  * determined by looking for 'long' or 'unsigned long' integer type and
53644ad23dfSAndrii Nakryiko  * recording its size in bytes. If BTF type information doesn't have any such
53744ad23dfSAndrii Nakryiko  * type, this function returns 0. In the latter case, native architecture's
53844ad23dfSAndrii Nakryiko  * pointer size is assumed, so will be either 4 or 8, depending on
53944ad23dfSAndrii Nakryiko  * architecture that libbpf was compiled for. It's possible to override
54044ad23dfSAndrii Nakryiko  * guessed value by using btf__set_pointer_size() API.
54144ad23dfSAndrii Nakryiko  */
54244ad23dfSAndrii Nakryiko size_t btf__pointer_size(const struct btf *btf)
54344ad23dfSAndrii Nakryiko {
54444ad23dfSAndrii Nakryiko 	if (!btf->ptr_sz)
54544ad23dfSAndrii Nakryiko 		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
54644ad23dfSAndrii Nakryiko 
54744ad23dfSAndrii Nakryiko 	if (btf->ptr_sz < 0)
54844ad23dfSAndrii Nakryiko 		/* not enough BTF type info to guess */
54944ad23dfSAndrii Nakryiko 		return 0;
55044ad23dfSAndrii Nakryiko 
55144ad23dfSAndrii Nakryiko 	return btf->ptr_sz;
55244ad23dfSAndrii Nakryiko }
55344ad23dfSAndrii Nakryiko 
55444ad23dfSAndrii Nakryiko /* Override or set pointer size in bytes. Only values of 4 and 8 are
55544ad23dfSAndrii Nakryiko  * supported.
55644ad23dfSAndrii Nakryiko  */
55744ad23dfSAndrii Nakryiko int btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
55844ad23dfSAndrii Nakryiko {
55944ad23dfSAndrii Nakryiko 	if (ptr_sz != 4 && ptr_sz != 8)
560e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
56144ad23dfSAndrii Nakryiko 	btf->ptr_sz = ptr_sz;
56244ad23dfSAndrii Nakryiko 	return 0;
56344ad23dfSAndrii Nakryiko }
56444ad23dfSAndrii Nakryiko 
5653289959bSAndrii Nakryiko static bool is_host_big_endian(void)
5663289959bSAndrii Nakryiko {
5673930198dSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
5683289959bSAndrii Nakryiko 	return false;
5693930198dSIlya Leoshkevich #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
5703289959bSAndrii Nakryiko 	return true;
5713289959bSAndrii Nakryiko #else
5723289959bSAndrii Nakryiko # error "Unrecognized __BYTE_ORDER__"
5733289959bSAndrii Nakryiko #endif
5743289959bSAndrii Nakryiko }
5753289959bSAndrii Nakryiko 
5763289959bSAndrii Nakryiko enum btf_endianness btf__endianness(const struct btf *btf)
5773289959bSAndrii Nakryiko {
5783289959bSAndrii Nakryiko 	if (is_host_big_endian())
5793289959bSAndrii Nakryiko 		return btf->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN;
5803289959bSAndrii Nakryiko 	else
5813289959bSAndrii Nakryiko 		return btf->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
5823289959bSAndrii Nakryiko }
5833289959bSAndrii Nakryiko 
5843289959bSAndrii Nakryiko int btf__set_endianness(struct btf *btf, enum btf_endianness endian)
5853289959bSAndrii Nakryiko {
5863289959bSAndrii Nakryiko 	if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN)
587e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
5883289959bSAndrii Nakryiko 
5893289959bSAndrii Nakryiko 	btf->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN);
5903289959bSAndrii Nakryiko 	if (!btf->swapped_endian) {
5913289959bSAndrii Nakryiko 		free(btf->raw_data_swapped);
5923289959bSAndrii Nakryiko 		btf->raw_data_swapped = NULL;
5933289959bSAndrii Nakryiko 	}
5943289959bSAndrii Nakryiko 	return 0;
5953289959bSAndrii Nakryiko }
5963289959bSAndrii Nakryiko 
5978a138aedSMartin KaFai Lau static bool btf_type_is_void(const struct btf_type *t)
5988a138aedSMartin KaFai Lau {
599b03bc685SAndrii Nakryiko 	return t == &btf_void || btf_is_fwd(t);
6008a138aedSMartin KaFai Lau }
6018a138aedSMartin KaFai Lau 
6028a138aedSMartin KaFai Lau static bool btf_type_is_void_or_null(const struct btf_type *t)
6038a138aedSMartin KaFai Lau {
6048a138aedSMartin KaFai Lau 	return !t || btf_type_is_void(t);
6058a138aedSMartin KaFai Lau }
6068a138aedSMartin KaFai Lau 
6078a138aedSMartin KaFai Lau #define MAX_RESOLVE_DEPTH 32
6088a138aedSMartin KaFai Lau 
6095b891af7SMartin KaFai Lau __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
6108a138aedSMartin KaFai Lau {
6118a138aedSMartin KaFai Lau 	const struct btf_array *array;
6128a138aedSMartin KaFai Lau 	const struct btf_type *t;
6135b891af7SMartin KaFai Lau 	__u32 nelems = 1;
6145b891af7SMartin KaFai Lau 	__s64 size = -1;
6158a138aedSMartin KaFai Lau 	int i;
6168a138aedSMartin KaFai Lau 
61792b57121SOkash Khawaja 	t = btf__type_by_id(btf, type_id);
618e9fc3ce9SAndrii Nakryiko 	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); i++) {
619b03bc685SAndrii Nakryiko 		switch (btf_kind(t)) {
62069eaab04SAndrii Nakryiko 		case BTF_KIND_INT:
62169eaab04SAndrii Nakryiko 		case BTF_KIND_STRUCT:
62269eaab04SAndrii Nakryiko 		case BTF_KIND_UNION:
62369eaab04SAndrii Nakryiko 		case BTF_KIND_ENUM:
624dffbbdc2SYonghong Song 		case BTF_KIND_ENUM64:
6251713d68bSDaniel Borkmann 		case BTF_KIND_DATASEC:
62622541a9eSIlya Leoshkevich 		case BTF_KIND_FLOAT:
62769eaab04SAndrii Nakryiko 			size = t->size;
62869eaab04SAndrii Nakryiko 			goto done;
62969eaab04SAndrii Nakryiko 		case BTF_KIND_PTR:
63044ad23dfSAndrii Nakryiko 			size = btf_ptr_sz(btf);
63169eaab04SAndrii Nakryiko 			goto done;
6328a138aedSMartin KaFai Lau 		case BTF_KIND_TYPEDEF:
6338a138aedSMartin KaFai Lau 		case BTF_KIND_VOLATILE:
6348a138aedSMartin KaFai Lau 		case BTF_KIND_CONST:
6358a138aedSMartin KaFai Lau 		case BTF_KIND_RESTRICT:
6361713d68bSDaniel Borkmann 		case BTF_KIND_VAR:
637223f903eSYonghong Song 		case BTF_KIND_DECL_TAG:
63869a055d5SYonghong Song 		case BTF_KIND_TYPE_TAG:
6398a138aedSMartin KaFai Lau 			type_id = t->type;
6408a138aedSMartin KaFai Lau 			break;
6418a138aedSMartin KaFai Lau 		case BTF_KIND_ARRAY:
642b03bc685SAndrii Nakryiko 			array = btf_array(t);
6438a138aedSMartin KaFai Lau 			if (nelems && array->nelems > UINT32_MAX / nelems)
644e9fc3ce9SAndrii Nakryiko 				return libbpf_err(-E2BIG);
6458a138aedSMartin KaFai Lau 			nelems *= array->nelems;
6468a138aedSMartin KaFai Lau 			type_id = array->type;
6478a138aedSMartin KaFai Lau 			break;
6488a138aedSMartin KaFai Lau 		default:
649e9fc3ce9SAndrii Nakryiko 			return libbpf_err(-EINVAL);
6508a138aedSMartin KaFai Lau 		}
6518a138aedSMartin KaFai Lau 
65292b57121SOkash Khawaja 		t = btf__type_by_id(btf, type_id);
6538a138aedSMartin KaFai Lau 	}
6548a138aedSMartin KaFai Lau 
655994021a7SAndrii Nakryiko done:
6568a138aedSMartin KaFai Lau 	if (size < 0)
657e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
6588a138aedSMartin KaFai Lau 	if (nelems && size > UINT32_MAX / nelems)
659e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-E2BIG);
6608a138aedSMartin KaFai Lau 
6618a138aedSMartin KaFai Lau 	return nelems * size;
6628a138aedSMartin KaFai Lau }
6638a138aedSMartin KaFai Lau 
6643d208f4cSAndrii Nakryiko int btf__align_of(const struct btf *btf, __u32 id)
6653d208f4cSAndrii Nakryiko {
6663d208f4cSAndrii Nakryiko 	const struct btf_type *t = btf__type_by_id(btf, id);
6673d208f4cSAndrii Nakryiko 	__u16 kind = btf_kind(t);
6683d208f4cSAndrii Nakryiko 
6693d208f4cSAndrii Nakryiko 	switch (kind) {
6703d208f4cSAndrii Nakryiko 	case BTF_KIND_INT:
6713d208f4cSAndrii Nakryiko 	case BTF_KIND_ENUM:
672dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
67322541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
67444ad23dfSAndrii Nakryiko 		return min(btf_ptr_sz(btf), (size_t)t->size);
6753d208f4cSAndrii Nakryiko 	case BTF_KIND_PTR:
67644ad23dfSAndrii Nakryiko 		return btf_ptr_sz(btf);
6773d208f4cSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
6783d208f4cSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
6793d208f4cSAndrii Nakryiko 	case BTF_KIND_CONST:
6803d208f4cSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
6812dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
6823d208f4cSAndrii Nakryiko 		return btf__align_of(btf, t->type);
6833d208f4cSAndrii Nakryiko 	case BTF_KIND_ARRAY:
6843d208f4cSAndrii Nakryiko 		return btf__align_of(btf, btf_array(t)->type);
6853d208f4cSAndrii Nakryiko 	case BTF_KIND_STRUCT:
6863d208f4cSAndrii Nakryiko 	case BTF_KIND_UNION: {
6873d208f4cSAndrii Nakryiko 		const struct btf_member *m = btf_members(t);
6883d208f4cSAndrii Nakryiko 		__u16 vlen = btf_vlen(t);
689a79ac2d1SPrashant Bhole 		int i, max_align = 1, align;
6903d208f4cSAndrii Nakryiko 
6913d208f4cSAndrii Nakryiko 		for (i = 0; i < vlen; i++, m++) {
692a79ac2d1SPrashant Bhole 			align = btf__align_of(btf, m->type);
693a79ac2d1SPrashant Bhole 			if (align <= 0)
694e9fc3ce9SAndrii Nakryiko 				return libbpf_err(align);
695a79ac2d1SPrashant Bhole 			max_align = max(max_align, align);
6963d208f4cSAndrii Nakryiko 		}
6973d208f4cSAndrii Nakryiko 
698a79ac2d1SPrashant Bhole 		return max_align;
6993d208f4cSAndrii Nakryiko 	}
7003d208f4cSAndrii Nakryiko 	default:
7013d208f4cSAndrii Nakryiko 		pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t));
702e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, 0;
7033d208f4cSAndrii Nakryiko 	}
7043d208f4cSAndrii Nakryiko }
7053d208f4cSAndrii Nakryiko 
70692b57121SOkash Khawaja int btf__resolve_type(const struct btf *btf, __u32 type_id)
70792b57121SOkash Khawaja {
70892b57121SOkash Khawaja 	const struct btf_type *t;
70992b57121SOkash Khawaja 	int depth = 0;
71092b57121SOkash Khawaja 
71192b57121SOkash Khawaja 	t = btf__type_by_id(btf, type_id);
71292b57121SOkash Khawaja 	while (depth < MAX_RESOLVE_DEPTH &&
71392b57121SOkash Khawaja 	       !btf_type_is_void_or_null(t) &&
714b03bc685SAndrii Nakryiko 	       (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
71592b57121SOkash Khawaja 		type_id = t->type;
71692b57121SOkash Khawaja 		t = btf__type_by_id(btf, type_id);
71792b57121SOkash Khawaja 		depth++;
71892b57121SOkash Khawaja 	}
71992b57121SOkash Khawaja 
72092b57121SOkash Khawaja 	if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
721e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
72292b57121SOkash Khawaja 
72392b57121SOkash Khawaja 	return type_id;
72492b57121SOkash Khawaja }
72592b57121SOkash Khawaja 
7265b891af7SMartin KaFai Lau __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
7278a138aedSMartin KaFai Lau {
7286a886de0SHengqi Chen 	__u32 i, nr_types = btf__type_cnt(btf);
7298a138aedSMartin KaFai Lau 
7308a138aedSMartin KaFai Lau 	if (!strcmp(type_name, "void"))
7318a138aedSMartin KaFai Lau 		return 0;
7328a138aedSMartin KaFai Lau 
7336a886de0SHengqi Chen 	for (i = 1; i < nr_types; i++) {
734740e69c3SAndrii Nakryiko 		const struct btf_type *t = btf__type_by_id(btf, i);
73592b57121SOkash Khawaja 		const char *name = btf__name_by_offset(btf, t->name_off);
7368a138aedSMartin KaFai Lau 
7378a138aedSMartin KaFai Lau 		if (name && !strcmp(type_name, name))
7388a138aedSMartin KaFai Lau 			return i;
7398a138aedSMartin KaFai Lau 	}
7408a138aedSMartin KaFai Lau 
741e9fc3ce9SAndrii Nakryiko 	return libbpf_err(-ENOENT);
7428a138aedSMartin KaFai Lau }
7438a138aedSMartin KaFai Lau 
7449dbe6015SKumar Kartikeya Dwivedi static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
7459dbe6015SKumar Kartikeya Dwivedi 				   const char *type_name, __u32 kind)
7461442e287SAlexei Starovoitov {
7476a886de0SHengqi Chen 	__u32 i, nr_types = btf__type_cnt(btf);
7481442e287SAlexei Starovoitov 
7491442e287SAlexei Starovoitov 	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
7501442e287SAlexei Starovoitov 		return 0;
7511442e287SAlexei Starovoitov 
7526a886de0SHengqi Chen 	for (i = start_id; i < nr_types; i++) {
753740e69c3SAndrii Nakryiko 		const struct btf_type *t = btf__type_by_id(btf, i);
7541442e287SAlexei Starovoitov 		const char *name;
7551442e287SAlexei Starovoitov 
7561442e287SAlexei Starovoitov 		if (btf_kind(t) != kind)
7571442e287SAlexei Starovoitov 			continue;
7581442e287SAlexei Starovoitov 		name = btf__name_by_offset(btf, t->name_off);
7591442e287SAlexei Starovoitov 		if (name && !strcmp(type_name, name))
7601442e287SAlexei Starovoitov 			return i;
7611442e287SAlexei Starovoitov 	}
7621442e287SAlexei Starovoitov 
763e9fc3ce9SAndrii Nakryiko 	return libbpf_err(-ENOENT);
7641442e287SAlexei Starovoitov }
7651442e287SAlexei Starovoitov 
7669dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
7679dbe6015SKumar Kartikeya Dwivedi 				 __u32 kind)
7689dbe6015SKumar Kartikeya Dwivedi {
7699dbe6015SKumar Kartikeya Dwivedi 	return btf_find_by_name_kind(btf, btf->start_id, type_name, kind);
7709dbe6015SKumar Kartikeya Dwivedi }
7719dbe6015SKumar Kartikeya Dwivedi 
7729dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
7739dbe6015SKumar Kartikeya Dwivedi 			     __u32 kind)
7749dbe6015SKumar Kartikeya Dwivedi {
7759dbe6015SKumar Kartikeya Dwivedi 	return btf_find_by_name_kind(btf, 1, type_name, kind);
7769dbe6015SKumar Kartikeya Dwivedi }
7779dbe6015SKumar Kartikeya Dwivedi 
778919d2b1dSAndrii Nakryiko static bool btf_is_modifiable(const struct btf *btf)
779919d2b1dSAndrii Nakryiko {
780919d2b1dSAndrii Nakryiko 	return (void *)btf->hdr != btf->raw_data;
781919d2b1dSAndrii Nakryiko }
782919d2b1dSAndrii Nakryiko 
7838a138aedSMartin KaFai Lau void btf__free(struct btf *btf)
7848a138aedSMartin KaFai Lau {
78550450fc7SAndrii Nakryiko 	if (IS_ERR_OR_NULL(btf))
7868a138aedSMartin KaFai Lau 		return;
7878a138aedSMartin KaFai Lau 
78881372e12SAndrii Nakryiko 	if (btf->fd >= 0)
7898a138aedSMartin KaFai Lau 		close(btf->fd);
7908a138aedSMartin KaFai Lau 
791919d2b1dSAndrii Nakryiko 	if (btf_is_modifiable(btf)) {
792919d2b1dSAndrii Nakryiko 		/* if BTF was modified after loading, it will have a split
793919d2b1dSAndrii Nakryiko 		 * in-memory representation for header, types, and strings
794919d2b1dSAndrii Nakryiko 		 * sections, so we need to free all of them individually. It
795919d2b1dSAndrii Nakryiko 		 * might still have a cached contiguous raw data present,
796919d2b1dSAndrii Nakryiko 		 * which will be unconditionally freed below.
797919d2b1dSAndrii Nakryiko 		 */
798919d2b1dSAndrii Nakryiko 		free(btf->hdr);
799919d2b1dSAndrii Nakryiko 		free(btf->types_data);
80090d76d3eSAndrii Nakryiko 		strset__free(btf->strs_set);
801919d2b1dSAndrii Nakryiko 	}
802b8604247SAndrii Nakryiko 	free(btf->raw_data);
8033289959bSAndrii Nakryiko 	free(btf->raw_data_swapped);
804740e69c3SAndrii Nakryiko 	free(btf->type_offs);
8058a138aedSMartin KaFai Lau 	free(btf);
8068a138aedSMartin KaFai Lau }
8078a138aedSMartin KaFai Lau 
808ba451366SAndrii Nakryiko static struct btf *btf_new_empty(struct btf *base_btf)
809a871b043SAndrii Nakryiko {
810a871b043SAndrii Nakryiko 	struct btf *btf;
811a871b043SAndrii Nakryiko 
812a871b043SAndrii Nakryiko 	btf = calloc(1, sizeof(*btf));
813a871b043SAndrii Nakryiko 	if (!btf)
814a871b043SAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
8153289959bSAndrii Nakryiko 
816ba451366SAndrii Nakryiko 	btf->nr_types = 0;
817ba451366SAndrii Nakryiko 	btf->start_id = 1;
818ba451366SAndrii Nakryiko 	btf->start_str_off = 0;
819a871b043SAndrii Nakryiko 	btf->fd = -1;
820a871b043SAndrii Nakryiko 	btf->ptr_sz = sizeof(void *);
8213289959bSAndrii Nakryiko 	btf->swapped_endian = false;
822a871b043SAndrii Nakryiko 
823ba451366SAndrii Nakryiko 	if (base_btf) {
824ba451366SAndrii Nakryiko 		btf->base_btf = base_btf;
8256a886de0SHengqi Chen 		btf->start_id = btf__type_cnt(base_btf);
826ba451366SAndrii Nakryiko 		btf->start_str_off = base_btf->hdr->str_len;
827ba451366SAndrii Nakryiko 	}
828ba451366SAndrii Nakryiko 
829a871b043SAndrii Nakryiko 	/* +1 for empty string at offset 0 */
830ba451366SAndrii Nakryiko 	btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1);
831a871b043SAndrii Nakryiko 	btf->raw_data = calloc(1, btf->raw_size);
832a871b043SAndrii Nakryiko 	if (!btf->raw_data) {
833a871b043SAndrii Nakryiko 		free(btf);
834a871b043SAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
835a871b043SAndrii Nakryiko 	}
836a871b043SAndrii Nakryiko 
837a871b043SAndrii Nakryiko 	btf->hdr = btf->raw_data;
838a871b043SAndrii Nakryiko 	btf->hdr->hdr_len = sizeof(struct btf_header);
839a871b043SAndrii Nakryiko 	btf->hdr->magic = BTF_MAGIC;
840a871b043SAndrii Nakryiko 	btf->hdr->version = BTF_VERSION;
841a871b043SAndrii Nakryiko 
842a871b043SAndrii Nakryiko 	btf->types_data = btf->raw_data + btf->hdr->hdr_len;
843a871b043SAndrii Nakryiko 	btf->strs_data = btf->raw_data + btf->hdr->hdr_len;
844ba451366SAndrii Nakryiko 	btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
845a871b043SAndrii Nakryiko 
846a871b043SAndrii Nakryiko 	return btf;
847a871b043SAndrii Nakryiko }
848a871b043SAndrii Nakryiko 
849ba451366SAndrii Nakryiko struct btf *btf__new_empty(void)
850ba451366SAndrii Nakryiko {
851e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new_empty(NULL));
852ba451366SAndrii Nakryiko }
853ba451366SAndrii Nakryiko 
854ba451366SAndrii Nakryiko struct btf *btf__new_empty_split(struct btf *base_btf)
855ba451366SAndrii Nakryiko {
856e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new_empty(base_btf));
857ba451366SAndrii Nakryiko }
858ba451366SAndrii Nakryiko 
859ba451366SAndrii Nakryiko static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
8608a138aedSMartin KaFai Lau {
8618a138aedSMartin KaFai Lau 	struct btf *btf;
8628a138aedSMartin KaFai Lau 	int err;
8638a138aedSMartin KaFai Lau 
8648a138aedSMartin KaFai Lau 	btf = calloc(1, sizeof(struct btf));
8658a138aedSMartin KaFai Lau 	if (!btf)
8668a138aedSMartin KaFai Lau 		return ERR_PTR(-ENOMEM);
8678a138aedSMartin KaFai Lau 
868ba451366SAndrii Nakryiko 	btf->nr_types = 0;
869ba451366SAndrii Nakryiko 	btf->start_id = 1;
870ba451366SAndrii Nakryiko 	btf->start_str_off = 0;
871c34c338aSDaniel Xu 	btf->fd = -1;
872ba451366SAndrii Nakryiko 
873ba451366SAndrii Nakryiko 	if (base_btf) {
874ba451366SAndrii Nakryiko 		btf->base_btf = base_btf;
8756a886de0SHengqi Chen 		btf->start_id = btf__type_cnt(base_btf);
876ba451366SAndrii Nakryiko 		btf->start_str_off = base_btf->hdr->str_len;
877ba451366SAndrii Nakryiko 	}
878ba451366SAndrii Nakryiko 
879b8604247SAndrii Nakryiko 	btf->raw_data = malloc(size);
880b8604247SAndrii Nakryiko 	if (!btf->raw_data) {
8818a138aedSMartin KaFai Lau 		err = -ENOMEM;
8828a138aedSMartin KaFai Lau 		goto done;
8838a138aedSMartin KaFai Lau 	}
884b8604247SAndrii Nakryiko 	memcpy(btf->raw_data, data, size);
885b8604247SAndrii Nakryiko 	btf->raw_size = size;
8868a138aedSMartin KaFai Lau 
887b8604247SAndrii Nakryiko 	btf->hdr = btf->raw_data;
8888461ef8bSYonghong Song 	err = btf_parse_hdr(btf);
8898a138aedSMartin KaFai Lau 	if (err)
8908a138aedSMartin KaFai Lau 		goto done;
8918a138aedSMartin KaFai Lau 
892b8604247SAndrii Nakryiko 	btf->strs_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->str_off;
893b8604247SAndrii Nakryiko 	btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off;
8948a138aedSMartin KaFai Lau 
895b8604247SAndrii Nakryiko 	err = btf_parse_str_sec(btf);
896b8604247SAndrii Nakryiko 	err = err ?: btf_parse_type_sec(btf);
8973289959bSAndrii Nakryiko 	if (err)
8983289959bSAndrii Nakryiko 		goto done;
8993289959bSAndrii Nakryiko 
9008a138aedSMartin KaFai Lau done:
9018a138aedSMartin KaFai Lau 	if (err) {
9028a138aedSMartin KaFai Lau 		btf__free(btf);
9038a138aedSMartin KaFai Lau 		return ERR_PTR(err);
9048a138aedSMartin KaFai Lau 	}
9058a138aedSMartin KaFai Lau 
9068a138aedSMartin KaFai Lau 	return btf;
9078a138aedSMartin KaFai Lau }
9088a138aedSMartin KaFai Lau 
909ba451366SAndrii Nakryiko struct btf *btf__new(const void *data, __u32 size)
910ba451366SAndrii Nakryiko {
911e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_new(data, size, NULL));
912ba451366SAndrii Nakryiko }
913ba451366SAndrii Nakryiko 
914ba451366SAndrii Nakryiko static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
915ba451366SAndrii Nakryiko 				 struct btf_ext **btf_ext)
916e6c64855SAndrii Nakryiko {
917e6c64855SAndrii Nakryiko 	Elf_Data *btf_data = NULL, *btf_ext_data = NULL;
918e6c64855SAndrii Nakryiko 	int err = 0, fd = -1, idx = 0;
919e6c64855SAndrii Nakryiko 	struct btf *btf = NULL;
920e6c64855SAndrii Nakryiko 	Elf_Scn *scn = NULL;
921e6c64855SAndrii Nakryiko 	Elf *elf = NULL;
922e6c64855SAndrii Nakryiko 	GElf_Ehdr ehdr;
9236095d5a2SJiri Olsa 	size_t shstrndx;
924e6c64855SAndrii Nakryiko 
925e6c64855SAndrii Nakryiko 	if (elf_version(EV_CURRENT) == EV_NONE) {
926be18010eSKefeng Wang 		pr_warn("failed to init libelf for %s\n", path);
927e6c64855SAndrii Nakryiko 		return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
928e6c64855SAndrii Nakryiko 	}
929e6c64855SAndrii Nakryiko 
93092274e24SKumar Kartikeya Dwivedi 	fd = open(path, O_RDONLY | O_CLOEXEC);
931e6c64855SAndrii Nakryiko 	if (fd < 0) {
932e6c64855SAndrii Nakryiko 		err = -errno;
933be18010eSKefeng Wang 		pr_warn("failed to open %s: %s\n", path, strerror(errno));
934e6c64855SAndrii Nakryiko 		return ERR_PTR(err);
935e6c64855SAndrii Nakryiko 	}
936e6c64855SAndrii Nakryiko 
937e6c64855SAndrii Nakryiko 	err = -LIBBPF_ERRNO__FORMAT;
938e6c64855SAndrii Nakryiko 
939e6c64855SAndrii Nakryiko 	elf = elf_begin(fd, ELF_C_READ, NULL);
940e6c64855SAndrii Nakryiko 	if (!elf) {
941be18010eSKefeng Wang 		pr_warn("failed to open %s as ELF file\n", path);
942e6c64855SAndrii Nakryiko 		goto done;
943e6c64855SAndrii Nakryiko 	}
944e6c64855SAndrii Nakryiko 	if (!gelf_getehdr(elf, &ehdr)) {
945be18010eSKefeng Wang 		pr_warn("failed to get EHDR from %s\n", path);
946e6c64855SAndrii Nakryiko 		goto done;
947e6c64855SAndrii Nakryiko 	}
9486095d5a2SJiri Olsa 
9496095d5a2SJiri Olsa 	if (elf_getshdrstrndx(elf, &shstrndx)) {
9506095d5a2SJiri Olsa 		pr_warn("failed to get section names section index for %s\n",
9516095d5a2SJiri Olsa 			path);
9526095d5a2SJiri Olsa 		goto done;
9536095d5a2SJiri Olsa 	}
9546095d5a2SJiri Olsa 
9556095d5a2SJiri Olsa 	if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) {
956be18010eSKefeng Wang 		pr_warn("failed to get e_shstrndx from %s\n", path);
957e6c64855SAndrii Nakryiko 		goto done;
958e6c64855SAndrii Nakryiko 	}
959e6c64855SAndrii Nakryiko 
960e6c64855SAndrii Nakryiko 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
961e6c64855SAndrii Nakryiko 		GElf_Shdr sh;
962e6c64855SAndrii Nakryiko 		char *name;
963e6c64855SAndrii Nakryiko 
964e6c64855SAndrii Nakryiko 		idx++;
965e6c64855SAndrii Nakryiko 		if (gelf_getshdr(scn, &sh) != &sh) {
966be18010eSKefeng Wang 			pr_warn("failed to get section(%d) header from %s\n",
967e6c64855SAndrii Nakryiko 				idx, path);
968e6c64855SAndrii Nakryiko 			goto done;
969e6c64855SAndrii Nakryiko 		}
9706095d5a2SJiri Olsa 		name = elf_strptr(elf, shstrndx, sh.sh_name);
971e6c64855SAndrii Nakryiko 		if (!name) {
972be18010eSKefeng Wang 			pr_warn("failed to get section(%d) name from %s\n",
973e6c64855SAndrii Nakryiko 				idx, path);
974e6c64855SAndrii Nakryiko 			goto done;
975e6c64855SAndrii Nakryiko 		}
976e6c64855SAndrii Nakryiko 		if (strcmp(name, BTF_ELF_SEC) == 0) {
977e6c64855SAndrii Nakryiko 			btf_data = elf_getdata(scn, 0);
978e6c64855SAndrii Nakryiko 			if (!btf_data) {
979be18010eSKefeng Wang 				pr_warn("failed to get section(%d, %s) data from %s\n",
980e6c64855SAndrii Nakryiko 					idx, name, path);
981e6c64855SAndrii Nakryiko 				goto done;
982e6c64855SAndrii Nakryiko 			}
983e6c64855SAndrii Nakryiko 			continue;
984e6c64855SAndrii Nakryiko 		} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
985e6c64855SAndrii Nakryiko 			btf_ext_data = elf_getdata(scn, 0);
986e6c64855SAndrii Nakryiko 			if (!btf_ext_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 		}
993e6c64855SAndrii Nakryiko 	}
994e6c64855SAndrii Nakryiko 
995e6c64855SAndrii Nakryiko 	err = 0;
996e6c64855SAndrii Nakryiko 
997e6c64855SAndrii Nakryiko 	if (!btf_data) {
998e6c64855SAndrii Nakryiko 		err = -ENOENT;
999e6c64855SAndrii Nakryiko 		goto done;
1000e6c64855SAndrii Nakryiko 	}
1001ba451366SAndrii Nakryiko 	btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
1002e9fc3ce9SAndrii Nakryiko 	err = libbpf_get_error(btf);
1003e9fc3ce9SAndrii Nakryiko 	if (err)
1004e6c64855SAndrii Nakryiko 		goto done;
1005e6c64855SAndrii Nakryiko 
100644ad23dfSAndrii Nakryiko 	switch (gelf_getclass(elf)) {
100744ad23dfSAndrii Nakryiko 	case ELFCLASS32:
100844ad23dfSAndrii Nakryiko 		btf__set_pointer_size(btf, 4);
100944ad23dfSAndrii Nakryiko 		break;
101044ad23dfSAndrii Nakryiko 	case ELFCLASS64:
101144ad23dfSAndrii Nakryiko 		btf__set_pointer_size(btf, 8);
101244ad23dfSAndrii Nakryiko 		break;
101344ad23dfSAndrii Nakryiko 	default:
101444ad23dfSAndrii Nakryiko 		pr_warn("failed to get ELF class (bitness) for %s\n", path);
101544ad23dfSAndrii Nakryiko 		break;
101644ad23dfSAndrii Nakryiko 	}
101744ad23dfSAndrii Nakryiko 
1018e6c64855SAndrii Nakryiko 	if (btf_ext && btf_ext_data) {
1019e9fc3ce9SAndrii Nakryiko 		*btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size);
1020e9fc3ce9SAndrii Nakryiko 		err = libbpf_get_error(*btf_ext);
1021e9fc3ce9SAndrii Nakryiko 		if (err)
1022e6c64855SAndrii Nakryiko 			goto done;
1023e6c64855SAndrii Nakryiko 	} else if (btf_ext) {
1024e6c64855SAndrii Nakryiko 		*btf_ext = NULL;
1025e6c64855SAndrii Nakryiko 	}
1026e6c64855SAndrii Nakryiko done:
1027e6c64855SAndrii Nakryiko 	if (elf)
1028e6c64855SAndrii Nakryiko 		elf_end(elf);
1029e6c64855SAndrii Nakryiko 	close(fd);
1030e6c64855SAndrii Nakryiko 
1031e9fc3ce9SAndrii Nakryiko 	if (!err)
1032e6c64855SAndrii Nakryiko 		return btf;
1033e9fc3ce9SAndrii Nakryiko 
1034e9fc3ce9SAndrii Nakryiko 	if (btf_ext)
1035e9fc3ce9SAndrii Nakryiko 		btf_ext__free(*btf_ext);
1036e6c64855SAndrii Nakryiko 	btf__free(btf);
1037e9fc3ce9SAndrii Nakryiko 
1038e6c64855SAndrii Nakryiko 	return ERR_PTR(err);
1039e6c64855SAndrii Nakryiko }
1040e6c64855SAndrii Nakryiko 
1041ba451366SAndrii Nakryiko struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
1042ba451366SAndrii Nakryiko {
1043e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext));
1044ba451366SAndrii Nakryiko }
1045ba451366SAndrii Nakryiko 
1046ba451366SAndrii Nakryiko struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf)
1047ba451366SAndrii Nakryiko {
1048e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_elf(path, base_btf, NULL));
1049ba451366SAndrii Nakryiko }
1050ba451366SAndrii Nakryiko 
1051ba451366SAndrii Nakryiko static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
105294a1feddSAndrii Nakryiko {
1053932ac54aSDaniel T. Lee 	struct btf *btf = NULL;
105494a1feddSAndrii Nakryiko 	void *data = NULL;
105594a1feddSAndrii Nakryiko 	FILE *f = NULL;
105694a1feddSAndrii Nakryiko 	__u16 magic;
105794a1feddSAndrii Nakryiko 	int err = 0;
105894a1feddSAndrii Nakryiko 	long sz;
105994a1feddSAndrii Nakryiko 
106094a1feddSAndrii Nakryiko 	f = fopen(path, "rb");
106194a1feddSAndrii Nakryiko 	if (!f) {
106294a1feddSAndrii Nakryiko 		err = -errno;
106394a1feddSAndrii Nakryiko 		goto err_out;
106494a1feddSAndrii Nakryiko 	}
106594a1feddSAndrii Nakryiko 
106694a1feddSAndrii Nakryiko 	/* check BTF magic */
106794a1feddSAndrii Nakryiko 	if (fread(&magic, 1, sizeof(magic), f) < sizeof(magic)) {
106894a1feddSAndrii Nakryiko 		err = -EIO;
106994a1feddSAndrii Nakryiko 		goto err_out;
107094a1feddSAndrii Nakryiko 	}
10713289959bSAndrii Nakryiko 	if (magic != BTF_MAGIC && magic != bswap_16(BTF_MAGIC)) {
107294a1feddSAndrii Nakryiko 		/* definitely not a raw BTF */
107394a1feddSAndrii Nakryiko 		err = -EPROTO;
107494a1feddSAndrii Nakryiko 		goto err_out;
107594a1feddSAndrii Nakryiko 	}
107694a1feddSAndrii Nakryiko 
107794a1feddSAndrii Nakryiko 	/* get file size */
107894a1feddSAndrii Nakryiko 	if (fseek(f, 0, SEEK_END)) {
107994a1feddSAndrii Nakryiko 		err = -errno;
108094a1feddSAndrii Nakryiko 		goto err_out;
108194a1feddSAndrii Nakryiko 	}
108294a1feddSAndrii Nakryiko 	sz = ftell(f);
108394a1feddSAndrii Nakryiko 	if (sz < 0) {
108494a1feddSAndrii Nakryiko 		err = -errno;
108594a1feddSAndrii Nakryiko 		goto err_out;
108694a1feddSAndrii Nakryiko 	}
108794a1feddSAndrii Nakryiko 	/* rewind to the start */
108894a1feddSAndrii Nakryiko 	if (fseek(f, 0, SEEK_SET)) {
108994a1feddSAndrii Nakryiko 		err = -errno;
109094a1feddSAndrii Nakryiko 		goto err_out;
109194a1feddSAndrii Nakryiko 	}
109294a1feddSAndrii Nakryiko 
109394a1feddSAndrii Nakryiko 	/* pre-alloc memory and read all of BTF data */
109494a1feddSAndrii Nakryiko 	data = malloc(sz);
109594a1feddSAndrii Nakryiko 	if (!data) {
109694a1feddSAndrii Nakryiko 		err = -ENOMEM;
109794a1feddSAndrii Nakryiko 		goto err_out;
109894a1feddSAndrii Nakryiko 	}
109994a1feddSAndrii Nakryiko 	if (fread(data, 1, sz, f) < sz) {
110094a1feddSAndrii Nakryiko 		err = -EIO;
110194a1feddSAndrii Nakryiko 		goto err_out;
110294a1feddSAndrii Nakryiko 	}
110394a1feddSAndrii Nakryiko 
110494a1feddSAndrii Nakryiko 	/* finally parse BTF data */
1105ba451366SAndrii Nakryiko 	btf = btf_new(data, sz, base_btf);
110694a1feddSAndrii Nakryiko 
110794a1feddSAndrii Nakryiko err_out:
110894a1feddSAndrii Nakryiko 	free(data);
110994a1feddSAndrii Nakryiko 	if (f)
111094a1feddSAndrii Nakryiko 		fclose(f);
111194a1feddSAndrii Nakryiko 	return err ? ERR_PTR(err) : btf;
111294a1feddSAndrii Nakryiko }
111394a1feddSAndrii Nakryiko 
1114ba451366SAndrii Nakryiko struct btf *btf__parse_raw(const char *path)
1115ba451366SAndrii Nakryiko {
1116e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_raw(path, NULL));
1117ba451366SAndrii Nakryiko }
1118ba451366SAndrii Nakryiko 
1119ba451366SAndrii Nakryiko struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
1120ba451366SAndrii Nakryiko {
1121e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse_raw(path, base_btf));
1122ba451366SAndrii Nakryiko }
1123ba451366SAndrii Nakryiko 
1124ba451366SAndrii Nakryiko static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
112594a1feddSAndrii Nakryiko {
112694a1feddSAndrii Nakryiko 	struct btf *btf;
1127e9fc3ce9SAndrii Nakryiko 	int err;
112894a1feddSAndrii Nakryiko 
112994a1feddSAndrii Nakryiko 	if (btf_ext)
113094a1feddSAndrii Nakryiko 		*btf_ext = NULL;
113194a1feddSAndrii Nakryiko 
1132ba451366SAndrii Nakryiko 	btf = btf_parse_raw(path, base_btf);
1133e9fc3ce9SAndrii Nakryiko 	err = libbpf_get_error(btf);
1134e9fc3ce9SAndrii Nakryiko 	if (!err)
113594a1feddSAndrii Nakryiko 		return btf;
1136e9fc3ce9SAndrii Nakryiko 	if (err != -EPROTO)
1137e9fc3ce9SAndrii Nakryiko 		return ERR_PTR(err);
1138ba451366SAndrii Nakryiko 	return btf_parse_elf(path, base_btf, btf_ext);
1139ba451366SAndrii Nakryiko }
1140ba451366SAndrii Nakryiko 
1141ba451366SAndrii Nakryiko struct btf *btf__parse(const char *path, struct btf_ext **btf_ext)
1142ba451366SAndrii Nakryiko {
1143e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse(path, NULL, btf_ext));
1144ba451366SAndrii Nakryiko }
1145ba451366SAndrii Nakryiko 
1146ba451366SAndrii Nakryiko struct btf *btf__parse_split(const char *path, struct btf *base_btf)
1147ba451366SAndrii Nakryiko {
1148e9fc3ce9SAndrii Nakryiko 	return libbpf_ptr(btf_parse(path, base_btf, NULL));
114994a1feddSAndrii Nakryiko }
115094a1feddSAndrii Nakryiko 
11513289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
11523289959bSAndrii Nakryiko 
11531a190d1eSAndrii Nakryiko int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level)
1154d29d87f7SAndrii Nakryiko {
11551a190d1eSAndrii Nakryiko 	LIBBPF_OPTS(bpf_btf_load_opts, opts);
11561a190d1eSAndrii Nakryiko 	__u32 buf_sz = 0, raw_size;
11571a190d1eSAndrii Nakryiko 	char *buf = NULL, *tmp;
11583289959bSAndrii Nakryiko 	void *raw_data;
1159d29d87f7SAndrii Nakryiko 	int err = 0;
1160d29d87f7SAndrii Nakryiko 
1161d29d87f7SAndrii Nakryiko 	if (btf->fd >= 0)
1162e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EEXIST);
11631a190d1eSAndrii Nakryiko 	if (log_sz && !log_buf)
11641a190d1eSAndrii Nakryiko 		return libbpf_err(-EINVAL);
1165d29d87f7SAndrii Nakryiko 
11661a190d1eSAndrii Nakryiko 	/* cache native raw data representation */
11673289959bSAndrii Nakryiko 	raw_data = btf_get_raw_data(btf, &raw_size, false);
1168b8604247SAndrii Nakryiko 	if (!raw_data) {
1169b8604247SAndrii Nakryiko 		err = -ENOMEM;
1170b8604247SAndrii Nakryiko 		goto done;
1171b8604247SAndrii Nakryiko 	}
11723289959bSAndrii Nakryiko 	btf->raw_size = raw_size;
11733289959bSAndrii Nakryiko 	btf->raw_data = raw_data;
1174b8604247SAndrii Nakryiko 
11751a190d1eSAndrii Nakryiko retry_load:
11761a190d1eSAndrii Nakryiko 	/* if log_level is 0, we won't provide log_buf/log_size to the kernel,
11771a190d1eSAndrii Nakryiko 	 * initially. Only if BTF loading fails, we bump log_level to 1 and
11781a190d1eSAndrii Nakryiko 	 * retry, using either auto-allocated or custom log_buf. This way
11791a190d1eSAndrii Nakryiko 	 * non-NULL custom log_buf provides a buffer just in case, but hopes
11801a190d1eSAndrii Nakryiko 	 * for successful load and no need for log_buf.
11811a190d1eSAndrii Nakryiko 	 */
11821a190d1eSAndrii Nakryiko 	if (log_level) {
11831a190d1eSAndrii Nakryiko 		/* if caller didn't provide custom log_buf, we'll keep
11841a190d1eSAndrii Nakryiko 		 * allocating our own progressively bigger buffers for BTF
11851a190d1eSAndrii Nakryiko 		 * verification log
11861a190d1eSAndrii Nakryiko 		 */
11871a190d1eSAndrii Nakryiko 		if (!log_buf) {
11881a190d1eSAndrii Nakryiko 			buf_sz = max((__u32)BPF_LOG_BUF_SIZE, buf_sz * 2);
11891a190d1eSAndrii Nakryiko 			tmp = realloc(buf, buf_sz);
11901a190d1eSAndrii Nakryiko 			if (!tmp) {
11911a190d1eSAndrii Nakryiko 				err = -ENOMEM;
11921a190d1eSAndrii Nakryiko 				goto done;
11931a190d1eSAndrii Nakryiko 			}
11941a190d1eSAndrii Nakryiko 			buf = tmp;
11951a190d1eSAndrii Nakryiko 			buf[0] = '\0';
11968395f320SStanislav Fomichev 		}
11978395f320SStanislav Fomichev 
11981a190d1eSAndrii Nakryiko 		opts.log_buf = log_buf ? log_buf : buf;
11991a190d1eSAndrii Nakryiko 		opts.log_size = log_buf ? log_sz : buf_sz;
12001a190d1eSAndrii Nakryiko 		opts.log_level = log_level;
12011a190d1eSAndrii Nakryiko 	}
12021a190d1eSAndrii Nakryiko 
12031a190d1eSAndrii Nakryiko 	btf->fd = bpf_btf_load(raw_data, raw_size, &opts);
12041a190d1eSAndrii Nakryiko 	if (btf->fd < 0) {
12051a190d1eSAndrii Nakryiko 		/* time to turn on verbose mode and try again */
12061a190d1eSAndrii Nakryiko 		if (log_level == 0) {
12071a190d1eSAndrii Nakryiko 			log_level = 1;
12081a190d1eSAndrii Nakryiko 			goto retry_load;
12091a190d1eSAndrii Nakryiko 		}
12101a190d1eSAndrii Nakryiko 		/* only retry if caller didn't provide custom log_buf, but
12111a190d1eSAndrii Nakryiko 		 * make sure we can never overflow buf_sz
12121a190d1eSAndrii Nakryiko 		 */
12131a190d1eSAndrii Nakryiko 		if (!log_buf && errno == ENOSPC && buf_sz <= UINT_MAX / 2)
12141a190d1eSAndrii Nakryiko 			goto retry_load;
12151a190d1eSAndrii Nakryiko 
1216d29d87f7SAndrii Nakryiko 		err = -errno;
12171a190d1eSAndrii Nakryiko 		pr_warn("BTF loading error: %d\n", err);
12181a190d1eSAndrii Nakryiko 		/* don't print out contents of custom log_buf */
12191a190d1eSAndrii Nakryiko 		if (!log_buf && buf[0])
12201a190d1eSAndrii Nakryiko 			pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf);
1221d29d87f7SAndrii Nakryiko 	}
1222d29d87f7SAndrii Nakryiko 
1223d29d87f7SAndrii Nakryiko done:
12241a190d1eSAndrii Nakryiko 	free(buf);
1225e9fc3ce9SAndrii Nakryiko 	return libbpf_err(err);
1226d29d87f7SAndrii Nakryiko }
12271a190d1eSAndrii Nakryiko 
12281a190d1eSAndrii Nakryiko int btf__load_into_kernel(struct btf *btf)
12291a190d1eSAndrii Nakryiko {
12301a190d1eSAndrii Nakryiko 	return btf_load_into_kernel(btf, NULL, 0, 0);
12311a190d1eSAndrii Nakryiko }
12321a190d1eSAndrii Nakryiko 
12333c7e5859SQuentin Monnet int btf__load(struct btf *) __attribute__((alias("btf__load_into_kernel")));
1234d29d87f7SAndrii Nakryiko 
12358a138aedSMartin KaFai Lau int btf__fd(const struct btf *btf)
12368a138aedSMartin KaFai Lau {
12378a138aedSMartin KaFai Lau 	return btf->fd;
12388a138aedSMartin KaFai Lau }
123992b57121SOkash Khawaja 
124081372e12SAndrii Nakryiko void btf__set_fd(struct btf *btf, int fd)
124181372e12SAndrii Nakryiko {
124281372e12SAndrii Nakryiko 	btf->fd = fd;
124381372e12SAndrii Nakryiko }
124481372e12SAndrii Nakryiko 
124590d76d3eSAndrii Nakryiko static const void *btf_strs_data(const struct btf *btf)
124690d76d3eSAndrii Nakryiko {
124790d76d3eSAndrii Nakryiko 	return btf->strs_data ? btf->strs_data : strset__data(btf->strs_set);
124890d76d3eSAndrii Nakryiko }
124990d76d3eSAndrii Nakryiko 
12503289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian)
12513289959bSAndrii Nakryiko {
12523289959bSAndrii Nakryiko 	struct btf_header *hdr = btf->hdr;
12533289959bSAndrii Nakryiko 	struct btf_type *t;
12543289959bSAndrii Nakryiko 	void *data, *p;
12553289959bSAndrii Nakryiko 	__u32 data_sz;
12563289959bSAndrii Nakryiko 	int i;
12573289959bSAndrii Nakryiko 
12583289959bSAndrii Nakryiko 	data = swap_endian ? btf->raw_data_swapped : btf->raw_data;
12593289959bSAndrii Nakryiko 	if (data) {
12603289959bSAndrii Nakryiko 		*size = btf->raw_size;
12613289959bSAndrii Nakryiko 		return data;
12623289959bSAndrii Nakryiko 	}
12633289959bSAndrii Nakryiko 
12643289959bSAndrii Nakryiko 	data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len;
12653289959bSAndrii Nakryiko 	data = calloc(1, data_sz);
12663289959bSAndrii Nakryiko 	if (!data)
12673289959bSAndrii Nakryiko 		return NULL;
12683289959bSAndrii Nakryiko 	p = data;
12693289959bSAndrii Nakryiko 
12703289959bSAndrii Nakryiko 	memcpy(p, hdr, hdr->hdr_len);
12713289959bSAndrii Nakryiko 	if (swap_endian)
12723289959bSAndrii Nakryiko 		btf_bswap_hdr(p);
12733289959bSAndrii Nakryiko 	p += hdr->hdr_len;
12743289959bSAndrii Nakryiko 
12753289959bSAndrii Nakryiko 	memcpy(p, btf->types_data, hdr->type_len);
12763289959bSAndrii Nakryiko 	if (swap_endian) {
1277ba451366SAndrii Nakryiko 		for (i = 0; i < btf->nr_types; i++) {
12783289959bSAndrii Nakryiko 			t = p + btf->type_offs[i];
12793289959bSAndrii Nakryiko 			/* btf_bswap_type_rest() relies on native t->info, so
12803289959bSAndrii Nakryiko 			 * we swap base type info after we swapped all the
12813289959bSAndrii Nakryiko 			 * additional information
12823289959bSAndrii Nakryiko 			 */
12833289959bSAndrii Nakryiko 			if (btf_bswap_type_rest(t))
12843289959bSAndrii Nakryiko 				goto err_out;
12853289959bSAndrii Nakryiko 			btf_bswap_type_base(t);
12863289959bSAndrii Nakryiko 		}
12873289959bSAndrii Nakryiko 	}
12883289959bSAndrii Nakryiko 	p += hdr->type_len;
12893289959bSAndrii Nakryiko 
129090d76d3eSAndrii Nakryiko 	memcpy(p, btf_strs_data(btf), hdr->str_len);
12913289959bSAndrii Nakryiko 	p += hdr->str_len;
12923289959bSAndrii Nakryiko 
12933289959bSAndrii Nakryiko 	*size = data_sz;
12943289959bSAndrii Nakryiko 	return data;
12953289959bSAndrii Nakryiko err_out:
12963289959bSAndrii Nakryiko 	free(data);
12973289959bSAndrii Nakryiko 	return NULL;
12983289959bSAndrii Nakryiko }
12993289959bSAndrii Nakryiko 
13006a886de0SHengqi Chen const void *btf__raw_data(const struct btf *btf_ro, __u32 *size)
130102c87446SAndrii Nakryiko {
1302919d2b1dSAndrii Nakryiko 	struct btf *btf = (struct btf *)btf_ro;
13033289959bSAndrii Nakryiko 	__u32 data_sz;
1304919d2b1dSAndrii Nakryiko 	void *data;
1305919d2b1dSAndrii Nakryiko 
13063289959bSAndrii Nakryiko 	data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian);
13073289959bSAndrii Nakryiko 	if (!data)
13086a886de0SHengqi Chen 		return errno = ENOMEM, NULL;
1309919d2b1dSAndrii Nakryiko 
13103289959bSAndrii Nakryiko 	btf->raw_size = data_sz;
13113289959bSAndrii Nakryiko 	if (btf->swapped_endian)
13123289959bSAndrii Nakryiko 		btf->raw_data_swapped = data;
13133289959bSAndrii Nakryiko 	else
13143289959bSAndrii Nakryiko 		btf->raw_data = data;
13153289959bSAndrii Nakryiko 	*size = data_sz;
13163289959bSAndrii Nakryiko 	return data;
131702c87446SAndrii Nakryiko }
131802c87446SAndrii Nakryiko 
13196a886de0SHengqi Chen __attribute__((alias("btf__raw_data")))
13206a886de0SHengqi Chen const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
13216a886de0SHengqi Chen 
1322f86ed050SAndrii Nakryiko const char *btf__str_by_offset(const struct btf *btf, __u32 offset)
132392b57121SOkash Khawaja {
1324ba451366SAndrii Nakryiko 	if (offset < btf->start_str_off)
1325ba451366SAndrii Nakryiko 		return btf__str_by_offset(btf->base_btf, offset);
1326ba451366SAndrii Nakryiko 	else if (offset - btf->start_str_off < btf->hdr->str_len)
132790d76d3eSAndrii Nakryiko 		return btf_strs_data(btf) + (offset - btf->start_str_off);
132892b57121SOkash Khawaja 	else
1329e9fc3ce9SAndrii Nakryiko 		return errno = EINVAL, NULL;
133092b57121SOkash Khawaja }
13312993e051SYonghong Song 
1332f86ed050SAndrii Nakryiko const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
1333f86ed050SAndrii Nakryiko {
1334f86ed050SAndrii Nakryiko 	return btf__str_by_offset(btf, offset);
1335f86ed050SAndrii Nakryiko }
1336f86ed050SAndrii Nakryiko 
1337a19f93cfSAndrii Nakryiko struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
1338d7f5b5e0SYonghong Song {
1339a19f93cfSAndrii Nakryiko 	struct bpf_btf_info btf_info;
1340d7f5b5e0SYonghong Song 	__u32 len = sizeof(btf_info);
1341d7f5b5e0SYonghong Song 	__u32 last_size;
1342a19f93cfSAndrii Nakryiko 	struct btf *btf;
1343d7f5b5e0SYonghong Song 	void *ptr;
1344d7f5b5e0SYonghong Song 	int err;
1345d7f5b5e0SYonghong Song 
1346d7f5b5e0SYonghong Song 	/* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
1347d7f5b5e0SYonghong Song 	 * let's start with a sane default - 4KiB here - and resize it only if
1348d7f5b5e0SYonghong Song 	 * bpf_obj_get_info_by_fd() needs a bigger buffer.
1349d7f5b5e0SYonghong Song 	 */
1350a19f93cfSAndrii Nakryiko 	last_size = 4096;
1351d7f5b5e0SYonghong Song 	ptr = malloc(last_size);
1352a19f93cfSAndrii Nakryiko 	if (!ptr)
1353a19f93cfSAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
1354d7f5b5e0SYonghong Song 
1355a19f93cfSAndrii Nakryiko 	memset(&btf_info, 0, sizeof(btf_info));
1356d7f5b5e0SYonghong Song 	btf_info.btf = ptr_to_u64(ptr);
1357a19f93cfSAndrii Nakryiko 	btf_info.btf_size = last_size;
1358d7f5b5e0SYonghong Song 	err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
1359d7f5b5e0SYonghong Song 
1360d7f5b5e0SYonghong Song 	if (!err && btf_info.btf_size > last_size) {
1361d7f5b5e0SYonghong Song 		void *temp_ptr;
1362d7f5b5e0SYonghong Song 
1363d7f5b5e0SYonghong Song 		last_size = btf_info.btf_size;
1364d7f5b5e0SYonghong Song 		temp_ptr = realloc(ptr, last_size);
1365d7f5b5e0SYonghong Song 		if (!temp_ptr) {
1366a19f93cfSAndrii Nakryiko 			btf = ERR_PTR(-ENOMEM);
1367d7f5b5e0SYonghong Song 			goto exit_free;
1368d7f5b5e0SYonghong Song 		}
1369d7f5b5e0SYonghong Song 		ptr = temp_ptr;
1370a19f93cfSAndrii Nakryiko 
1371a19f93cfSAndrii Nakryiko 		len = sizeof(btf_info);
1372a19f93cfSAndrii Nakryiko 		memset(&btf_info, 0, sizeof(btf_info));
1373d7f5b5e0SYonghong Song 		btf_info.btf = ptr_to_u64(ptr);
1374a19f93cfSAndrii Nakryiko 		btf_info.btf_size = last_size;
1375a19f93cfSAndrii Nakryiko 
1376d7f5b5e0SYonghong Song 		err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
1377d7f5b5e0SYonghong Song 	}
1378d7f5b5e0SYonghong Song 
1379d7f5b5e0SYonghong Song 	if (err || btf_info.btf_size > last_size) {
1380a19f93cfSAndrii Nakryiko 		btf = err ? ERR_PTR(-errno) : ERR_PTR(-E2BIG);
1381d7f5b5e0SYonghong Song 		goto exit_free;
1382d7f5b5e0SYonghong Song 	}
1383d7f5b5e0SYonghong Song 
1384a19f93cfSAndrii Nakryiko 	btf = btf_new(ptr, btf_info.btf_size, base_btf);
1385d7f5b5e0SYonghong Song 
1386d7f5b5e0SYonghong Song exit_free:
1387d7f5b5e0SYonghong Song 	free(ptr);
1388a19f93cfSAndrii Nakryiko 	return btf;
1389a19f93cfSAndrii Nakryiko }
1390d7f5b5e0SYonghong Song 
139161fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
13926cc93e2fSQuentin Monnet {
13936cc93e2fSQuentin Monnet 	struct btf *btf;
13946cc93e2fSQuentin Monnet 	int btf_fd;
13956cc93e2fSQuentin Monnet 
13966cc93e2fSQuentin Monnet 	btf_fd = bpf_btf_get_fd_by_id(id);
13976cc93e2fSQuentin Monnet 	if (btf_fd < 0)
13986cc93e2fSQuentin Monnet 		return libbpf_err_ptr(-errno);
13996cc93e2fSQuentin Monnet 
140061fc51b1SQuentin Monnet 	btf = btf_get_from_fd(btf_fd, base_btf);
14016cc93e2fSQuentin Monnet 	close(btf_fd);
14026cc93e2fSQuentin Monnet 
14036cc93e2fSQuentin Monnet 	return libbpf_ptr(btf);
14046cc93e2fSQuentin Monnet }
14056cc93e2fSQuentin Monnet 
140661fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id(__u32 id)
140761fc51b1SQuentin Monnet {
140861fc51b1SQuentin Monnet 	return btf__load_from_kernel_by_id_split(id, NULL);
140961fc51b1SQuentin Monnet }
141061fc51b1SQuentin Monnet 
1411a19f93cfSAndrii Nakryiko int btf__get_from_id(__u32 id, struct btf **btf)
1412a19f93cfSAndrii Nakryiko {
1413a19f93cfSAndrii Nakryiko 	struct btf *res;
14146cc93e2fSQuentin Monnet 	int err;
1415a19f93cfSAndrii Nakryiko 
1416a19f93cfSAndrii Nakryiko 	*btf = NULL;
14176cc93e2fSQuentin Monnet 	res = btf__load_from_kernel_by_id(id);
1418e9fc3ce9SAndrii Nakryiko 	err = libbpf_get_error(res);
1419e9fc3ce9SAndrii Nakryiko 
1420e9fc3ce9SAndrii Nakryiko 	if (err)
1421e9fc3ce9SAndrii Nakryiko 		return libbpf_err(err);
1422a19f93cfSAndrii Nakryiko 
1423a19f93cfSAndrii Nakryiko 	*btf = res;
1424a19f93cfSAndrii Nakryiko 	return 0;
1425d7f5b5e0SYonghong Song }
1426d7f5b5e0SYonghong Song 
1427a6c109a6SYonghong Song int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
142896408c43SYonghong Song 			 __u32 expected_key_size, __u32 expected_value_size,
142996408c43SYonghong Song 			 __u32 *key_type_id, __u32 *value_type_id)
143096408c43SYonghong Song {
143196408c43SYonghong Song 	const struct btf_type *container_type;
143296408c43SYonghong Song 	const struct btf_member *key, *value;
143396408c43SYonghong Song 	const size_t max_name = 256;
143496408c43SYonghong Song 	char container_name[max_name];
143596408c43SYonghong Song 	__s64 key_size, value_size;
143696408c43SYonghong Song 	__s32 container_id;
143796408c43SYonghong Song 
1438e9fc3ce9SAndrii Nakryiko 	if (snprintf(container_name, max_name, "____btf_map_%s", map_name) == max_name) {
1439be18010eSKefeng Wang 		pr_warn("map:%s length of '____btf_map_%s' is too long\n",
144096408c43SYonghong Song 			map_name, map_name);
1441e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
144296408c43SYonghong Song 	}
144396408c43SYonghong Song 
144496408c43SYonghong Song 	container_id = btf__find_by_name(btf, container_name);
144596408c43SYonghong Song 	if (container_id < 0) {
1446f7748e29SYonghong Song 		pr_debug("map:%s container_name:%s cannot be found in BTF. Missing BPF_ANNOTATE_KV_PAIR?\n",
144796408c43SYonghong Song 			 map_name, container_name);
1448e9fc3ce9SAndrii Nakryiko 		return libbpf_err(container_id);
144996408c43SYonghong Song 	}
145096408c43SYonghong Song 
145196408c43SYonghong Song 	container_type = btf__type_by_id(btf, container_id);
145296408c43SYonghong Song 	if (!container_type) {
1453be18010eSKefeng Wang 		pr_warn("map:%s cannot find BTF type for container_id:%u\n",
145496408c43SYonghong Song 			map_name, container_id);
1455e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
145696408c43SYonghong Song 	}
145796408c43SYonghong Song 
1458b03bc685SAndrii Nakryiko 	if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) {
1459be18010eSKefeng Wang 		pr_warn("map:%s container_name:%s is an invalid container struct\n",
146096408c43SYonghong Song 			map_name, container_name);
1461e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
146296408c43SYonghong Song 	}
146396408c43SYonghong Song 
1464b03bc685SAndrii Nakryiko 	key = btf_members(container_type);
146596408c43SYonghong Song 	value = key + 1;
146696408c43SYonghong Song 
146796408c43SYonghong Song 	key_size = btf__resolve_size(btf, key->type);
146896408c43SYonghong Song 	if (key_size < 0) {
1469be18010eSKefeng Wang 		pr_warn("map:%s invalid BTF key_type_size\n", map_name);
1470e9fc3ce9SAndrii Nakryiko 		return libbpf_err(key_size);
147196408c43SYonghong Song 	}
147296408c43SYonghong Song 
147396408c43SYonghong Song 	if (expected_key_size != key_size) {
1474be18010eSKefeng Wang 		pr_warn("map:%s btf_key_type_size:%u != map_def_key_size:%u\n",
147596408c43SYonghong Song 			map_name, (__u32)key_size, expected_key_size);
1476e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
147796408c43SYonghong Song 	}
147896408c43SYonghong Song 
147996408c43SYonghong Song 	value_size = btf__resolve_size(btf, value->type);
148096408c43SYonghong Song 	if (value_size < 0) {
1481be18010eSKefeng Wang 		pr_warn("map:%s invalid BTF value_type_size\n", map_name);
1482e9fc3ce9SAndrii Nakryiko 		return libbpf_err(value_size);
148396408c43SYonghong Song 	}
148496408c43SYonghong Song 
148596408c43SYonghong Song 	if (expected_value_size != value_size) {
1486be18010eSKefeng Wang 		pr_warn("map:%s btf_value_type_size:%u != map_def_value_size:%u\n",
148796408c43SYonghong Song 			map_name, (__u32)value_size, expected_value_size);
1488e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
148996408c43SYonghong Song 	}
149096408c43SYonghong Song 
149196408c43SYonghong Song 	*key_type_id = key->type;
149296408c43SYonghong Song 	*value_type_id = value->type;
149396408c43SYonghong Song 
149496408c43SYonghong Song 	return 0;
149596408c43SYonghong Song }
149696408c43SYonghong Song 
14973289959bSAndrii Nakryiko static void btf_invalidate_raw_data(struct btf *btf)
14983289959bSAndrii Nakryiko {
14993289959bSAndrii Nakryiko 	if (btf->raw_data) {
15003289959bSAndrii Nakryiko 		free(btf->raw_data);
15013289959bSAndrii Nakryiko 		btf->raw_data = NULL;
15023289959bSAndrii Nakryiko 	}
15033289959bSAndrii Nakryiko 	if (btf->raw_data_swapped) {
15043289959bSAndrii Nakryiko 		free(btf->raw_data_swapped);
15053289959bSAndrii Nakryiko 		btf->raw_data_swapped = NULL;
15063289959bSAndrii Nakryiko 	}
15073289959bSAndrii Nakryiko }
15083289959bSAndrii Nakryiko 
1509919d2b1dSAndrii Nakryiko /* Ensure BTF is ready to be modified (by splitting into a three memory
1510919d2b1dSAndrii Nakryiko  * regions for header, types, and strings). Also invalidate cached
1511919d2b1dSAndrii Nakryiko  * raw_data, if any.
1512919d2b1dSAndrii Nakryiko  */
1513919d2b1dSAndrii Nakryiko static int btf_ensure_modifiable(struct btf *btf)
1514919d2b1dSAndrii Nakryiko {
151590d76d3eSAndrii Nakryiko 	void *hdr, *types;
151690d76d3eSAndrii Nakryiko 	struct strset *set = NULL;
151790d76d3eSAndrii Nakryiko 	int err = -ENOMEM;
1518919d2b1dSAndrii Nakryiko 
1519919d2b1dSAndrii Nakryiko 	if (btf_is_modifiable(btf)) {
1520919d2b1dSAndrii Nakryiko 		/* any BTF modification invalidates raw_data */
15213289959bSAndrii Nakryiko 		btf_invalidate_raw_data(btf);
1522919d2b1dSAndrii Nakryiko 		return 0;
1523919d2b1dSAndrii Nakryiko 	}
1524919d2b1dSAndrii Nakryiko 
1525919d2b1dSAndrii Nakryiko 	/* split raw data into three memory regions */
1526919d2b1dSAndrii Nakryiko 	hdr = malloc(btf->hdr->hdr_len);
1527919d2b1dSAndrii Nakryiko 	types = malloc(btf->hdr->type_len);
152890d76d3eSAndrii Nakryiko 	if (!hdr || !types)
1529919d2b1dSAndrii Nakryiko 		goto err_out;
1530919d2b1dSAndrii Nakryiko 
1531919d2b1dSAndrii Nakryiko 	memcpy(hdr, btf->hdr, btf->hdr->hdr_len);
1532919d2b1dSAndrii Nakryiko 	memcpy(types, btf->types_data, btf->hdr->type_len);
153388a82c2aSAndrii Nakryiko 
1534919d2b1dSAndrii Nakryiko 	/* build lookup index for all strings */
153590d76d3eSAndrii Nakryiko 	set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len);
153690d76d3eSAndrii Nakryiko 	if (IS_ERR(set)) {
153790d76d3eSAndrii Nakryiko 		err = PTR_ERR(set);
1538919d2b1dSAndrii Nakryiko 		goto err_out;
1539919d2b1dSAndrii Nakryiko 	}
1540919d2b1dSAndrii Nakryiko 
1541919d2b1dSAndrii Nakryiko 	/* only when everything was successful, update internal state */
1542919d2b1dSAndrii Nakryiko 	btf->hdr = hdr;
1543919d2b1dSAndrii Nakryiko 	btf->types_data = types;
1544919d2b1dSAndrii Nakryiko 	btf->types_data_cap = btf->hdr->type_len;
154590d76d3eSAndrii Nakryiko 	btf->strs_data = NULL;
154690d76d3eSAndrii Nakryiko 	btf->strs_set = set;
1547919d2b1dSAndrii Nakryiko 	/* if BTF was created from scratch, all strings are guaranteed to be
1548919d2b1dSAndrii Nakryiko 	 * unique and deduplicated
1549919d2b1dSAndrii Nakryiko 	 */
1550ba451366SAndrii Nakryiko 	if (btf->hdr->str_len == 0)
1551ba451366SAndrii Nakryiko 		btf->strs_deduped = true;
1552ba451366SAndrii Nakryiko 	if (!btf->base_btf && btf->hdr->str_len == 1)
1553ba451366SAndrii Nakryiko 		btf->strs_deduped = true;
1554919d2b1dSAndrii Nakryiko 
1555919d2b1dSAndrii Nakryiko 	/* invalidate raw_data representation */
15563289959bSAndrii Nakryiko 	btf_invalidate_raw_data(btf);
1557919d2b1dSAndrii Nakryiko 
1558919d2b1dSAndrii Nakryiko 	return 0;
1559919d2b1dSAndrii Nakryiko 
1560919d2b1dSAndrii Nakryiko err_out:
156190d76d3eSAndrii Nakryiko 	strset__free(set);
1562919d2b1dSAndrii Nakryiko 	free(hdr);
1563919d2b1dSAndrii Nakryiko 	free(types);
156490d76d3eSAndrii Nakryiko 	return err;
1565919d2b1dSAndrii Nakryiko }
1566919d2b1dSAndrii Nakryiko 
1567919d2b1dSAndrii Nakryiko /* Find an offset in BTF string section that corresponds to a given string *s*.
1568919d2b1dSAndrii Nakryiko  * Returns:
1569919d2b1dSAndrii Nakryiko  *   - >0 offset into string section, if string is found;
1570919d2b1dSAndrii Nakryiko  *   - -ENOENT, if string is not in the string section;
1571919d2b1dSAndrii Nakryiko  *   - <0, on any other error.
1572919d2b1dSAndrii Nakryiko  */
1573919d2b1dSAndrii Nakryiko int btf__find_str(struct btf *btf, const char *s)
1574919d2b1dSAndrii Nakryiko {
157590d76d3eSAndrii Nakryiko 	int off;
1576919d2b1dSAndrii Nakryiko 
1577ba451366SAndrii Nakryiko 	if (btf->base_btf) {
157890d76d3eSAndrii Nakryiko 		off = btf__find_str(btf->base_btf, s);
157990d76d3eSAndrii Nakryiko 		if (off != -ENOENT)
158090d76d3eSAndrii Nakryiko 			return off;
1581ba451366SAndrii Nakryiko 	}
1582ba451366SAndrii Nakryiko 
1583919d2b1dSAndrii Nakryiko 	/* BTF needs to be in a modifiable state to build string lookup index */
1584919d2b1dSAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1585e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
1586919d2b1dSAndrii Nakryiko 
158790d76d3eSAndrii Nakryiko 	off = strset__find_str(btf->strs_set, s);
158890d76d3eSAndrii Nakryiko 	if (off < 0)
1589e9fc3ce9SAndrii Nakryiko 		return libbpf_err(off);
1590919d2b1dSAndrii Nakryiko 
159190d76d3eSAndrii Nakryiko 	return btf->start_str_off + off;
1592919d2b1dSAndrii Nakryiko }
1593919d2b1dSAndrii Nakryiko 
1594919d2b1dSAndrii Nakryiko /* Add a string s to the BTF string section.
1595919d2b1dSAndrii Nakryiko  * Returns:
1596919d2b1dSAndrii Nakryiko  *   - > 0 offset into string section, on success;
1597919d2b1dSAndrii Nakryiko  *   - < 0, on error.
1598919d2b1dSAndrii Nakryiko  */
1599919d2b1dSAndrii Nakryiko int btf__add_str(struct btf *btf, const char *s)
1600919d2b1dSAndrii Nakryiko {
160190d76d3eSAndrii Nakryiko 	int off;
1602919d2b1dSAndrii Nakryiko 
1603ba451366SAndrii Nakryiko 	if (btf->base_btf) {
160490d76d3eSAndrii Nakryiko 		off = btf__find_str(btf->base_btf, s);
160590d76d3eSAndrii Nakryiko 		if (off != -ENOENT)
160690d76d3eSAndrii Nakryiko 			return off;
1607ba451366SAndrii Nakryiko 	}
1608ba451366SAndrii Nakryiko 
1609919d2b1dSAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1610e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
1611919d2b1dSAndrii Nakryiko 
161290d76d3eSAndrii Nakryiko 	off = strset__add_str(btf->strs_set, s);
161390d76d3eSAndrii Nakryiko 	if (off < 0)
1614e9fc3ce9SAndrii Nakryiko 		return libbpf_err(off);
1615919d2b1dSAndrii Nakryiko 
161690d76d3eSAndrii Nakryiko 	btf->hdr->str_len = strset__data_size(btf->strs_set);
1617919d2b1dSAndrii Nakryiko 
161890d76d3eSAndrii Nakryiko 	return btf->start_str_off + off;
1619919d2b1dSAndrii Nakryiko }
1620919d2b1dSAndrii Nakryiko 
16214a3b33f8SAndrii Nakryiko static void *btf_add_type_mem(struct btf *btf, size_t add_sz)
16224a3b33f8SAndrii Nakryiko {
16233b029e06SAndrii Nakryiko 	return libbpf_add_mem(&btf->types_data, &btf->types_data_cap, 1,
16244a3b33f8SAndrii Nakryiko 			      btf->hdr->type_len, UINT_MAX, add_sz);
16254a3b33f8SAndrii Nakryiko }
16264a3b33f8SAndrii Nakryiko 
16274a3b33f8SAndrii Nakryiko static void btf_type_inc_vlen(struct btf_type *t)
16284a3b33f8SAndrii Nakryiko {
16294a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
16304a3b33f8SAndrii Nakryiko }
16314a3b33f8SAndrii Nakryiko 
1632c81ed6d8SAndrii Nakryiko static int btf_commit_type(struct btf *btf, int data_sz)
1633c81ed6d8SAndrii Nakryiko {
1634c81ed6d8SAndrii Nakryiko 	int err;
1635c81ed6d8SAndrii Nakryiko 
1636c81ed6d8SAndrii Nakryiko 	err = btf_add_type_idx_entry(btf, btf->hdr->type_len);
1637c81ed6d8SAndrii Nakryiko 	if (err)
1638e9fc3ce9SAndrii Nakryiko 		return libbpf_err(err);
1639c81ed6d8SAndrii Nakryiko 
1640c81ed6d8SAndrii Nakryiko 	btf->hdr->type_len += data_sz;
1641c81ed6d8SAndrii Nakryiko 	btf->hdr->str_off += data_sz;
1642c81ed6d8SAndrii Nakryiko 	btf->nr_types++;
1643ba451366SAndrii Nakryiko 	return btf->start_id + btf->nr_types - 1;
1644c81ed6d8SAndrii Nakryiko }
1645c81ed6d8SAndrii Nakryiko 
16469af44bc5SAndrii Nakryiko struct btf_pipe {
16479af44bc5SAndrii Nakryiko 	const struct btf *src;
16489af44bc5SAndrii Nakryiko 	struct btf *dst;
1649d81283d2SKui-Feng Lee 	struct hashmap *str_off_map; /* map string offsets from src to dst */
16509af44bc5SAndrii Nakryiko };
16519af44bc5SAndrii Nakryiko 
16529af44bc5SAndrii Nakryiko static int btf_rewrite_str(__u32 *str_off, void *ctx)
16539af44bc5SAndrii Nakryiko {
16549af44bc5SAndrii Nakryiko 	struct btf_pipe *p = ctx;
1655d81283d2SKui-Feng Lee 	void *mapped_off;
1656d81283d2SKui-Feng Lee 	int off, err;
16579af44bc5SAndrii Nakryiko 
16589af44bc5SAndrii Nakryiko 	if (!*str_off) /* nothing to do for empty strings */
16599af44bc5SAndrii Nakryiko 		return 0;
16609af44bc5SAndrii Nakryiko 
1661d81283d2SKui-Feng Lee 	if (p->str_off_map &&
1662d81283d2SKui-Feng Lee 	    hashmap__find(p->str_off_map, (void *)(long)*str_off, &mapped_off)) {
1663d81283d2SKui-Feng Lee 		*str_off = (__u32)(long)mapped_off;
1664d81283d2SKui-Feng Lee 		return 0;
1665d81283d2SKui-Feng Lee 	}
1666d81283d2SKui-Feng Lee 
16679af44bc5SAndrii Nakryiko 	off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off));
16689af44bc5SAndrii Nakryiko 	if (off < 0)
16699af44bc5SAndrii Nakryiko 		return off;
16709af44bc5SAndrii Nakryiko 
1671d81283d2SKui-Feng Lee 	/* Remember string mapping from src to dst.  It avoids
1672d81283d2SKui-Feng Lee 	 * performing expensive string comparisons.
1673d81283d2SKui-Feng Lee 	 */
1674d81283d2SKui-Feng Lee 	if (p->str_off_map) {
1675d81283d2SKui-Feng Lee 		err = hashmap__append(p->str_off_map, (void *)(long)*str_off, (void *)(long)off);
1676d81283d2SKui-Feng Lee 		if (err)
1677d81283d2SKui-Feng Lee 			return err;
1678d81283d2SKui-Feng Lee 	}
1679d81283d2SKui-Feng Lee 
16809af44bc5SAndrii Nakryiko 	*str_off = off;
16819af44bc5SAndrii Nakryiko 	return 0;
16829af44bc5SAndrii Nakryiko }
16839af44bc5SAndrii Nakryiko 
16849af44bc5SAndrii Nakryiko int btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type)
16859af44bc5SAndrii Nakryiko {
16869af44bc5SAndrii Nakryiko 	struct btf_pipe p = { .src = src_btf, .dst = btf };
16879af44bc5SAndrii Nakryiko 	struct btf_type *t;
16889af44bc5SAndrii Nakryiko 	int sz, err;
16899af44bc5SAndrii Nakryiko 
16909af44bc5SAndrii Nakryiko 	sz = btf_type_size(src_type);
16919af44bc5SAndrii Nakryiko 	if (sz < 0)
1692e9fc3ce9SAndrii Nakryiko 		return libbpf_err(sz);
16939af44bc5SAndrii Nakryiko 
16949af44bc5SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
16959af44bc5SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1696e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
16979af44bc5SAndrii Nakryiko 
16989af44bc5SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
16999af44bc5SAndrii Nakryiko 	if (!t)
1700e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17019af44bc5SAndrii Nakryiko 
17029af44bc5SAndrii Nakryiko 	memcpy(t, src_type, sz);
17039af44bc5SAndrii Nakryiko 
17049af44bc5SAndrii Nakryiko 	err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
17059af44bc5SAndrii Nakryiko 	if (err)
1706e9fc3ce9SAndrii Nakryiko 		return libbpf_err(err);
17079af44bc5SAndrii Nakryiko 
17089af44bc5SAndrii Nakryiko 	return btf_commit_type(btf, sz);
17099af44bc5SAndrii Nakryiko }
17109af44bc5SAndrii Nakryiko 
17117ca61121SAndrii Nakryiko static int btf_rewrite_type_ids(__u32 *type_id, void *ctx)
17127ca61121SAndrii Nakryiko {
17137ca61121SAndrii Nakryiko 	struct btf *btf = ctx;
17147ca61121SAndrii Nakryiko 
17157ca61121SAndrii Nakryiko 	if (!*type_id) /* nothing to do for VOID references */
17167ca61121SAndrii Nakryiko 		return 0;
17177ca61121SAndrii Nakryiko 
17187ca61121SAndrii Nakryiko 	/* we haven't updated btf's type count yet, so
17197ca61121SAndrii Nakryiko 	 * btf->start_id + btf->nr_types - 1 is the type ID offset we should
17207ca61121SAndrii Nakryiko 	 * add to all newly added BTF types
17217ca61121SAndrii Nakryiko 	 */
17227ca61121SAndrii Nakryiko 	*type_id += btf->start_id + btf->nr_types - 1;
17237ca61121SAndrii Nakryiko 	return 0;
17247ca61121SAndrii Nakryiko }
17257ca61121SAndrii Nakryiko 
1726d81283d2SKui-Feng Lee static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx);
1727d81283d2SKui-Feng Lee static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx);
1728d81283d2SKui-Feng Lee 
17297ca61121SAndrii Nakryiko int btf__add_btf(struct btf *btf, const struct btf *src_btf)
17307ca61121SAndrii Nakryiko {
17317ca61121SAndrii Nakryiko 	struct btf_pipe p = { .src = src_btf, .dst = btf };
17327ca61121SAndrii Nakryiko 	int data_sz, sz, cnt, i, err, old_strs_len;
17337ca61121SAndrii Nakryiko 	__u32 *off;
17347ca61121SAndrii Nakryiko 	void *t;
17357ca61121SAndrii Nakryiko 
17367ca61121SAndrii Nakryiko 	/* appending split BTF isn't supported yet */
17377ca61121SAndrii Nakryiko 	if (src_btf->base_btf)
17387ca61121SAndrii Nakryiko 		return libbpf_err(-ENOTSUP);
17397ca61121SAndrii Nakryiko 
17407ca61121SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
17417ca61121SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
17427ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17437ca61121SAndrii Nakryiko 
17447ca61121SAndrii Nakryiko 	/* remember original strings section size if we have to roll back
17457ca61121SAndrii Nakryiko 	 * partial strings section changes
17467ca61121SAndrii Nakryiko 	 */
17477ca61121SAndrii Nakryiko 	old_strs_len = btf->hdr->str_len;
17487ca61121SAndrii Nakryiko 
17497ca61121SAndrii Nakryiko 	data_sz = src_btf->hdr->type_len;
17506a886de0SHengqi Chen 	cnt = btf__type_cnt(src_btf) - 1;
17517ca61121SAndrii Nakryiko 
17527ca61121SAndrii Nakryiko 	/* pre-allocate enough memory for new types */
17537ca61121SAndrii Nakryiko 	t = btf_add_type_mem(btf, data_sz);
17547ca61121SAndrii Nakryiko 	if (!t)
17557ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17567ca61121SAndrii Nakryiko 
17577ca61121SAndrii Nakryiko 	/* pre-allocate enough memory for type offset index for new types */
17587ca61121SAndrii Nakryiko 	off = btf_add_type_offs_mem(btf, cnt);
17597ca61121SAndrii Nakryiko 	if (!off)
17607ca61121SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
17617ca61121SAndrii Nakryiko 
1762d81283d2SKui-Feng Lee 	/* Map the string offsets from src_btf to the offsets from btf to improve performance */
1763d81283d2SKui-Feng Lee 	p.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
1764d81283d2SKui-Feng Lee 	if (IS_ERR(p.str_off_map))
1765d81283d2SKui-Feng Lee 		return libbpf_err(-ENOMEM);
1766d81283d2SKui-Feng Lee 
17677ca61121SAndrii Nakryiko 	/* bulk copy types data for all types from src_btf */
17687ca61121SAndrii Nakryiko 	memcpy(t, src_btf->types_data, data_sz);
17697ca61121SAndrii Nakryiko 
17707ca61121SAndrii Nakryiko 	for (i = 0; i < cnt; i++) {
17717ca61121SAndrii Nakryiko 		sz = btf_type_size(t);
17727ca61121SAndrii Nakryiko 		if (sz < 0) {
17737ca61121SAndrii Nakryiko 			/* unlikely, has to be corrupted src_btf */
17747ca61121SAndrii Nakryiko 			err = sz;
17757ca61121SAndrii Nakryiko 			goto err_out;
17767ca61121SAndrii Nakryiko 		}
17777ca61121SAndrii Nakryiko 
17787ca61121SAndrii Nakryiko 		/* fill out type ID to type offset mapping for lookups by type ID */
17797ca61121SAndrii Nakryiko 		*off = t - btf->types_data;
17807ca61121SAndrii Nakryiko 
17817ca61121SAndrii Nakryiko 		/* add, dedup, and remap strings referenced by this BTF type */
17827ca61121SAndrii Nakryiko 		err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
17837ca61121SAndrii Nakryiko 		if (err)
17847ca61121SAndrii Nakryiko 			goto err_out;
17857ca61121SAndrii Nakryiko 
17867ca61121SAndrii Nakryiko 		/* remap all type IDs referenced from this BTF type */
17877ca61121SAndrii Nakryiko 		err = btf_type_visit_type_ids(t, btf_rewrite_type_ids, btf);
17887ca61121SAndrii Nakryiko 		if (err)
17897ca61121SAndrii Nakryiko 			goto err_out;
17907ca61121SAndrii Nakryiko 
17917ca61121SAndrii Nakryiko 		/* go to next type data and type offset index entry */
17927ca61121SAndrii Nakryiko 		t += sz;
17937ca61121SAndrii Nakryiko 		off++;
17947ca61121SAndrii Nakryiko 	}
17957ca61121SAndrii Nakryiko 
17967ca61121SAndrii Nakryiko 	/* Up until now any of the copied type data was effectively invisible,
17977ca61121SAndrii Nakryiko 	 * so if we exited early before this point due to error, BTF would be
17987ca61121SAndrii Nakryiko 	 * effectively unmodified. There would be extra internal memory
17997ca61121SAndrii Nakryiko 	 * pre-allocated, but it would not be available for querying.  But now
18007ca61121SAndrii Nakryiko 	 * that we've copied and rewritten all the data successfully, we can
18017ca61121SAndrii Nakryiko 	 * update type count and various internal offsets and sizes to
18027ca61121SAndrii Nakryiko 	 * "commit" the changes and made them visible to the outside world.
18037ca61121SAndrii Nakryiko 	 */
18047ca61121SAndrii Nakryiko 	btf->hdr->type_len += data_sz;
18057ca61121SAndrii Nakryiko 	btf->hdr->str_off += data_sz;
18067ca61121SAndrii Nakryiko 	btf->nr_types += cnt;
18077ca61121SAndrii Nakryiko 
1808d81283d2SKui-Feng Lee 	hashmap__free(p.str_off_map);
1809d81283d2SKui-Feng Lee 
18107ca61121SAndrii Nakryiko 	/* return type ID of the first added BTF type */
18117ca61121SAndrii Nakryiko 	return btf->start_id + btf->nr_types - cnt;
18127ca61121SAndrii Nakryiko err_out:
18137ca61121SAndrii Nakryiko 	/* zero out preallocated memory as if it was just allocated with
18147ca61121SAndrii Nakryiko 	 * libbpf_add_mem()
18157ca61121SAndrii Nakryiko 	 */
18167ca61121SAndrii Nakryiko 	memset(btf->types_data + btf->hdr->type_len, 0, data_sz);
18177ca61121SAndrii Nakryiko 	memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
18187ca61121SAndrii Nakryiko 
18197ca61121SAndrii Nakryiko 	/* and now restore original strings section size; types data size
18207ca61121SAndrii Nakryiko 	 * wasn't modified, so doesn't need restoring, see big comment above */
18217ca61121SAndrii Nakryiko 	btf->hdr->str_len = old_strs_len;
18227ca61121SAndrii Nakryiko 
1823d81283d2SKui-Feng Lee 	hashmap__free(p.str_off_map);
1824d81283d2SKui-Feng Lee 
18257ca61121SAndrii Nakryiko 	return libbpf_err(err);
18267ca61121SAndrii Nakryiko }
18277ca61121SAndrii Nakryiko 
18284a3b33f8SAndrii Nakryiko /*
18294a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_INT type with:
18304a3b33f8SAndrii Nakryiko  *   - *name* - non-empty, non-NULL type name;
18314a3b33f8SAndrii Nakryiko  *   - *sz* - power-of-2 (1, 2, 4, ..) size of the type, in bytes;
18324a3b33f8SAndrii Nakryiko  *   - encoding is a combination of BTF_INT_SIGNED, BTF_INT_CHAR, BTF_INT_BOOL.
18334a3b33f8SAndrii Nakryiko  * Returns:
18344a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
18354a3b33f8SAndrii Nakryiko  *   - <0, on error.
18364a3b33f8SAndrii Nakryiko  */
18374a3b33f8SAndrii Nakryiko int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding)
18384a3b33f8SAndrii Nakryiko {
18394a3b33f8SAndrii Nakryiko 	struct btf_type *t;
1840c81ed6d8SAndrii Nakryiko 	int sz, name_off;
18414a3b33f8SAndrii Nakryiko 
18424a3b33f8SAndrii Nakryiko 	/* non-empty name */
18434a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
1844e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
18454a3b33f8SAndrii Nakryiko 	/* byte_sz must be power of 2 */
18464a3b33f8SAndrii Nakryiko 	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16)
1847e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
18484a3b33f8SAndrii Nakryiko 	if (encoding & ~(BTF_INT_SIGNED | BTF_INT_CHAR | BTF_INT_BOOL))
1849e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
18504a3b33f8SAndrii Nakryiko 
18514a3b33f8SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
18524a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1853e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
18544a3b33f8SAndrii Nakryiko 
18554a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(int);
18564a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
18574a3b33f8SAndrii Nakryiko 	if (!t)
1858e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
18594a3b33f8SAndrii Nakryiko 
18604a3b33f8SAndrii Nakryiko 	/* if something goes wrong later, we might end up with an extra string,
18614a3b33f8SAndrii Nakryiko 	 * but that shouldn't be a problem, because BTF can't be constructed
18624a3b33f8SAndrii Nakryiko 	 * completely anyway and will most probably be just discarded
18634a3b33f8SAndrii Nakryiko 	 */
18644a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
18654a3b33f8SAndrii Nakryiko 	if (name_off < 0)
18664a3b33f8SAndrii Nakryiko 		return name_off;
18674a3b33f8SAndrii Nakryiko 
18684a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
18694a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_INT, 0, 0);
18704a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
18714a3b33f8SAndrii Nakryiko 	/* set INT info, we don't allow setting legacy bit offset/size */
18724a3b33f8SAndrii Nakryiko 	*(__u32 *)(t + 1) = (encoding << 24) | (byte_sz * 8);
18734a3b33f8SAndrii Nakryiko 
1874c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
18754a3b33f8SAndrii Nakryiko }
18764a3b33f8SAndrii Nakryiko 
187722541a9eSIlya Leoshkevich /*
187822541a9eSIlya Leoshkevich  * Append new BTF_KIND_FLOAT type with:
187922541a9eSIlya Leoshkevich  *   - *name* - non-empty, non-NULL type name;
188022541a9eSIlya Leoshkevich  *   - *sz* - size of the type, in bytes;
188122541a9eSIlya Leoshkevich  * Returns:
188222541a9eSIlya Leoshkevich  *   - >0, type ID of newly added BTF type;
188322541a9eSIlya Leoshkevich  *   - <0, on error.
188422541a9eSIlya Leoshkevich  */
188522541a9eSIlya Leoshkevich int btf__add_float(struct btf *btf, const char *name, size_t byte_sz)
188622541a9eSIlya Leoshkevich {
188722541a9eSIlya Leoshkevich 	struct btf_type *t;
188822541a9eSIlya Leoshkevich 	int sz, name_off;
188922541a9eSIlya Leoshkevich 
189022541a9eSIlya Leoshkevich 	/* non-empty name */
189122541a9eSIlya Leoshkevich 	if (!name || !name[0])
1892e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
189322541a9eSIlya Leoshkevich 
189422541a9eSIlya Leoshkevich 	/* byte_sz must be one of the explicitly allowed values */
189522541a9eSIlya Leoshkevich 	if (byte_sz != 2 && byte_sz != 4 && byte_sz != 8 && byte_sz != 12 &&
189622541a9eSIlya Leoshkevich 	    byte_sz != 16)
1897e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
189822541a9eSIlya Leoshkevich 
189922541a9eSIlya Leoshkevich 	if (btf_ensure_modifiable(btf))
1900e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
190122541a9eSIlya Leoshkevich 
190222541a9eSIlya Leoshkevich 	sz = sizeof(struct btf_type);
190322541a9eSIlya Leoshkevich 	t = btf_add_type_mem(btf, sz);
190422541a9eSIlya Leoshkevich 	if (!t)
1905e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
190622541a9eSIlya Leoshkevich 
190722541a9eSIlya Leoshkevich 	name_off = btf__add_str(btf, name);
190822541a9eSIlya Leoshkevich 	if (name_off < 0)
190922541a9eSIlya Leoshkevich 		return name_off;
191022541a9eSIlya Leoshkevich 
191122541a9eSIlya Leoshkevich 	t->name_off = name_off;
191222541a9eSIlya Leoshkevich 	t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0);
191322541a9eSIlya Leoshkevich 	t->size = byte_sz;
191422541a9eSIlya Leoshkevich 
191522541a9eSIlya Leoshkevich 	return btf_commit_type(btf, sz);
191622541a9eSIlya Leoshkevich }
191722541a9eSIlya Leoshkevich 
19184a3b33f8SAndrii Nakryiko /* it's completely legal to append BTF types with type IDs pointing forward to
19194a3b33f8SAndrii Nakryiko  * types that haven't been appended yet, so we only make sure that id looks
19204a3b33f8SAndrii Nakryiko  * sane, we can't guarantee that ID will always be valid
19214a3b33f8SAndrii Nakryiko  */
19224a3b33f8SAndrii Nakryiko static int validate_type_id(int id)
19234a3b33f8SAndrii Nakryiko {
19244a3b33f8SAndrii Nakryiko 	if (id < 0 || id > BTF_MAX_NR_TYPES)
19254a3b33f8SAndrii Nakryiko 		return -EINVAL;
19264a3b33f8SAndrii Nakryiko 	return 0;
19274a3b33f8SAndrii Nakryiko }
19284a3b33f8SAndrii Nakryiko 
19294a3b33f8SAndrii Nakryiko /* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */
19304a3b33f8SAndrii Nakryiko static int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id)
19314a3b33f8SAndrii Nakryiko {
19324a3b33f8SAndrii Nakryiko 	struct btf_type *t;
1933c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
19344a3b33f8SAndrii Nakryiko 
19354a3b33f8SAndrii Nakryiko 	if (validate_type_id(ref_type_id))
1936e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
19374a3b33f8SAndrii Nakryiko 
19384a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1939e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19404a3b33f8SAndrii Nakryiko 
19414a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
19424a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
19434a3b33f8SAndrii Nakryiko 	if (!t)
1944e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19454a3b33f8SAndrii Nakryiko 
19464a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
19474a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
19484a3b33f8SAndrii Nakryiko 		if (name_off < 0)
19494a3b33f8SAndrii Nakryiko 			return name_off;
19504a3b33f8SAndrii Nakryiko 	}
19514a3b33f8SAndrii Nakryiko 
19524a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
19534a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(kind, 0, 0);
19544a3b33f8SAndrii Nakryiko 	t->type = ref_type_id;
19554a3b33f8SAndrii Nakryiko 
1956c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
19574a3b33f8SAndrii Nakryiko }
19584a3b33f8SAndrii Nakryiko 
19594a3b33f8SAndrii Nakryiko /*
19604a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_PTR type with:
19614a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
19624a3b33f8SAndrii Nakryiko  * Returns:
19634a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
19644a3b33f8SAndrii Nakryiko  *   - <0, on error.
19654a3b33f8SAndrii Nakryiko  */
19664a3b33f8SAndrii Nakryiko int btf__add_ptr(struct btf *btf, int ref_type_id)
19674a3b33f8SAndrii Nakryiko {
19684a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id);
19694a3b33f8SAndrii Nakryiko }
19704a3b33f8SAndrii Nakryiko 
19714a3b33f8SAndrii Nakryiko /*
19724a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_ARRAY type with:
19734a3b33f8SAndrii Nakryiko  *   - *index_type_id* - type ID of the type describing array index;
19744a3b33f8SAndrii Nakryiko  *   - *elem_type_id* - type ID of the type describing array element;
19754a3b33f8SAndrii Nakryiko  *   - *nr_elems* - the size of the array;
19764a3b33f8SAndrii Nakryiko  * Returns:
19774a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
19784a3b33f8SAndrii Nakryiko  *   - <0, on error.
19794a3b33f8SAndrii Nakryiko  */
19804a3b33f8SAndrii Nakryiko int btf__add_array(struct btf *btf, int index_type_id, int elem_type_id, __u32 nr_elems)
19814a3b33f8SAndrii Nakryiko {
19824a3b33f8SAndrii Nakryiko 	struct btf_type *t;
19834a3b33f8SAndrii Nakryiko 	struct btf_array *a;
1984c81ed6d8SAndrii Nakryiko 	int sz;
19854a3b33f8SAndrii Nakryiko 
19864a3b33f8SAndrii Nakryiko 	if (validate_type_id(index_type_id) || validate_type_id(elem_type_id))
1987e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
19884a3b33f8SAndrii Nakryiko 
19894a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
1990e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19914a3b33f8SAndrii Nakryiko 
19924a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(struct btf_array);
19934a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
19944a3b33f8SAndrii Nakryiko 	if (!t)
1995e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
19964a3b33f8SAndrii Nakryiko 
19974a3b33f8SAndrii Nakryiko 	t->name_off = 0;
19984a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_ARRAY, 0, 0);
19994a3b33f8SAndrii Nakryiko 	t->size = 0;
20004a3b33f8SAndrii Nakryiko 
20014a3b33f8SAndrii Nakryiko 	a = btf_array(t);
20024a3b33f8SAndrii Nakryiko 	a->type = elem_type_id;
20034a3b33f8SAndrii Nakryiko 	a->index_type = index_type_id;
20044a3b33f8SAndrii Nakryiko 	a->nelems = nr_elems;
20054a3b33f8SAndrii Nakryiko 
2006c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
20074a3b33f8SAndrii Nakryiko }
20084a3b33f8SAndrii Nakryiko 
20094a3b33f8SAndrii Nakryiko /* generic STRUCT/UNION append function */
20104a3b33f8SAndrii Nakryiko static int btf_add_composite(struct btf *btf, int kind, const char *name, __u32 bytes_sz)
20114a3b33f8SAndrii Nakryiko {
20124a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2013c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
20144a3b33f8SAndrii Nakryiko 
20154a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2016e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20174a3b33f8SAndrii Nakryiko 
20184a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
20194a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
20204a3b33f8SAndrii Nakryiko 	if (!t)
2021e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
20224a3b33f8SAndrii Nakryiko 
20234a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
20244a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
20254a3b33f8SAndrii Nakryiko 		if (name_off < 0)
20264a3b33f8SAndrii Nakryiko 			return name_off;
20274a3b33f8SAndrii Nakryiko 	}
20284a3b33f8SAndrii Nakryiko 
20294a3b33f8SAndrii Nakryiko 	/* start out with vlen=0 and no kflag; this will be adjusted when
20304a3b33f8SAndrii Nakryiko 	 * adding each member
20314a3b33f8SAndrii Nakryiko 	 */
20324a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
20334a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(kind, 0, 0);
20344a3b33f8SAndrii Nakryiko 	t->size = bytes_sz;
20354a3b33f8SAndrii Nakryiko 
2036c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
20374a3b33f8SAndrii Nakryiko }
20384a3b33f8SAndrii Nakryiko 
20394a3b33f8SAndrii Nakryiko /*
20404a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_STRUCT type with:
20414a3b33f8SAndrii Nakryiko  *   - *name* - name of the struct, can be NULL or empty for anonymous structs;
20424a3b33f8SAndrii Nakryiko  *   - *byte_sz* - size of the struct, in bytes;
20434a3b33f8SAndrii Nakryiko  *
20444a3b33f8SAndrii Nakryiko  * Struct initially has no fields in it. Fields can be added by
20454a3b33f8SAndrii Nakryiko  * btf__add_field() right after btf__add_struct() succeeds.
20464a3b33f8SAndrii Nakryiko  *
20474a3b33f8SAndrii Nakryiko  * Returns:
20484a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
20494a3b33f8SAndrii Nakryiko  *   - <0, on error.
20504a3b33f8SAndrii Nakryiko  */
20514a3b33f8SAndrii Nakryiko int btf__add_struct(struct btf *btf, const char *name, __u32 byte_sz)
20524a3b33f8SAndrii Nakryiko {
20534a3b33f8SAndrii Nakryiko 	return btf_add_composite(btf, BTF_KIND_STRUCT, name, byte_sz);
20544a3b33f8SAndrii Nakryiko }
20554a3b33f8SAndrii Nakryiko 
20564a3b33f8SAndrii Nakryiko /*
20574a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_UNION type with:
20584a3b33f8SAndrii Nakryiko  *   - *name* - name of the union, can be NULL or empty for anonymous union;
20594a3b33f8SAndrii Nakryiko  *   - *byte_sz* - size of the union, in bytes;
20604a3b33f8SAndrii Nakryiko  *
20614a3b33f8SAndrii Nakryiko  * Union initially has no fields in it. Fields can be added by
20624a3b33f8SAndrii Nakryiko  * btf__add_field() right after btf__add_union() succeeds. All fields
20634a3b33f8SAndrii Nakryiko  * should have *bit_offset* of 0.
20644a3b33f8SAndrii Nakryiko  *
20654a3b33f8SAndrii Nakryiko  * Returns:
20664a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
20674a3b33f8SAndrii Nakryiko  *   - <0, on error.
20684a3b33f8SAndrii Nakryiko  */
20694a3b33f8SAndrii Nakryiko int btf__add_union(struct btf *btf, const char *name, __u32 byte_sz)
20704a3b33f8SAndrii Nakryiko {
20714a3b33f8SAndrii Nakryiko 	return btf_add_composite(btf, BTF_KIND_UNION, name, byte_sz);
20724a3b33f8SAndrii Nakryiko }
20734a3b33f8SAndrii Nakryiko 
2074c81ed6d8SAndrii Nakryiko static struct btf_type *btf_last_type(struct btf *btf)
2075c81ed6d8SAndrii Nakryiko {
20766a886de0SHengqi Chen 	return btf_type_by_id(btf, btf__type_cnt(btf) - 1);
2077c81ed6d8SAndrii Nakryiko }
2078c81ed6d8SAndrii Nakryiko 
20794a3b33f8SAndrii Nakryiko /*
20804a3b33f8SAndrii Nakryiko  * Append new field for the current STRUCT/UNION type with:
20814a3b33f8SAndrii Nakryiko  *   - *name* - name of the field, can be NULL or empty for anonymous field;
20824a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID for the type describing field type;
20834a3b33f8SAndrii Nakryiko  *   - *bit_offset* - bit offset of the start of the field within struct/union;
20844a3b33f8SAndrii Nakryiko  *   - *bit_size* - bit size of a bitfield, 0 for non-bitfield fields;
20854a3b33f8SAndrii Nakryiko  * Returns:
20864a3b33f8SAndrii Nakryiko  *   -  0, on success;
20874a3b33f8SAndrii Nakryiko  *   - <0, on error.
20884a3b33f8SAndrii Nakryiko  */
20894a3b33f8SAndrii Nakryiko int btf__add_field(struct btf *btf, const char *name, int type_id,
20904a3b33f8SAndrii Nakryiko 		   __u32 bit_offset, __u32 bit_size)
20914a3b33f8SAndrii Nakryiko {
20924a3b33f8SAndrii Nakryiko 	struct btf_type *t;
20934a3b33f8SAndrii Nakryiko 	struct btf_member *m;
20944a3b33f8SAndrii Nakryiko 	bool is_bitfield;
20954a3b33f8SAndrii Nakryiko 	int sz, name_off = 0;
20964a3b33f8SAndrii Nakryiko 
20974a3b33f8SAndrii Nakryiko 	/* last type should be union/struct */
20984a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2099e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2100c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
21014a3b33f8SAndrii Nakryiko 	if (!btf_is_composite(t))
2102e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21034a3b33f8SAndrii Nakryiko 
21044a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2105e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21064a3b33f8SAndrii Nakryiko 	/* best-effort bit field offset/size enforcement */
21074a3b33f8SAndrii Nakryiko 	is_bitfield = bit_size || (bit_offset % 8 != 0);
21084a3b33f8SAndrii Nakryiko 	if (is_bitfield && (bit_size == 0 || bit_size > 255 || bit_offset > 0xffffff))
2109e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21104a3b33f8SAndrii Nakryiko 
21114a3b33f8SAndrii Nakryiko 	/* only offset 0 is allowed for unions */
21124a3b33f8SAndrii Nakryiko 	if (btf_is_union(t) && bit_offset)
2113e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21144a3b33f8SAndrii Nakryiko 
21154a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
21164a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2117e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21184a3b33f8SAndrii Nakryiko 
21194a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_member);
21204a3b33f8SAndrii Nakryiko 	m = btf_add_type_mem(btf, sz);
21214a3b33f8SAndrii Nakryiko 	if (!m)
2122e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21234a3b33f8SAndrii Nakryiko 
21244a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
21254a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
21264a3b33f8SAndrii Nakryiko 		if (name_off < 0)
21274a3b33f8SAndrii Nakryiko 			return name_off;
21284a3b33f8SAndrii Nakryiko 	}
21294a3b33f8SAndrii Nakryiko 
21304a3b33f8SAndrii Nakryiko 	m->name_off = name_off;
21314a3b33f8SAndrii Nakryiko 	m->type = type_id;
21324a3b33f8SAndrii Nakryiko 	m->offset = bit_offset | (bit_size << 24);
21334a3b33f8SAndrii Nakryiko 
21344a3b33f8SAndrii Nakryiko 	/* btf_add_type_mem can invalidate t pointer */
2135c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
21364a3b33f8SAndrii Nakryiko 	/* update parent type's vlen and kflag */
21374a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
21384a3b33f8SAndrii Nakryiko 
21394a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
21404a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
21414a3b33f8SAndrii Nakryiko 	return 0;
21424a3b33f8SAndrii Nakryiko }
21434a3b33f8SAndrii Nakryiko 
21448479aa75SYonghong Song static int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
21458479aa75SYonghong Song 			       bool is_signed, __u8 kind)
21464a3b33f8SAndrii Nakryiko {
21474a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2148c81ed6d8SAndrii Nakryiko 	int sz, name_off = 0;
21494a3b33f8SAndrii Nakryiko 
21504a3b33f8SAndrii Nakryiko 	/* byte_sz must be power of 2 */
21514a3b33f8SAndrii Nakryiko 	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 8)
2152e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
21534a3b33f8SAndrii Nakryiko 
21544a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2155e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21564a3b33f8SAndrii Nakryiko 
21574a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
21584a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
21594a3b33f8SAndrii Nakryiko 	if (!t)
2160e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
21614a3b33f8SAndrii Nakryiko 
21624a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
21634a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
21644a3b33f8SAndrii Nakryiko 		if (name_off < 0)
21654a3b33f8SAndrii Nakryiko 			return name_off;
21664a3b33f8SAndrii Nakryiko 	}
21674a3b33f8SAndrii Nakryiko 
21684a3b33f8SAndrii Nakryiko 	/* start out with vlen=0; it will be adjusted when adding enum values */
21694a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
21708479aa75SYonghong Song 	t->info = btf_type_info(kind, 0, is_signed);
21714a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
21724a3b33f8SAndrii Nakryiko 
2173c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
21744a3b33f8SAndrii Nakryiko }
21754a3b33f8SAndrii Nakryiko 
21764a3b33f8SAndrii Nakryiko /*
21778479aa75SYonghong Song  * Append new BTF_KIND_ENUM type with:
21788479aa75SYonghong Song  *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
21798479aa75SYonghong Song  *   - *byte_sz* - size of the enum, in bytes.
21808479aa75SYonghong Song  *
21818479aa75SYonghong Song  * Enum initially has no enum values in it (and corresponds to enum forward
21828479aa75SYonghong Song  * declaration). Enumerator values can be added by btf__add_enum_value()
21838479aa75SYonghong Song  * immediately after btf__add_enum() succeeds.
21848479aa75SYonghong Song  *
21858479aa75SYonghong Song  * Returns:
21868479aa75SYonghong Song  *   - >0, type ID of newly added BTF type;
21878479aa75SYonghong Song  *   - <0, on error.
21888479aa75SYonghong Song  */
21898479aa75SYonghong Song int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
21908479aa75SYonghong Song {
2191dffbbdc2SYonghong Song 	/*
2192dffbbdc2SYonghong Song 	 * set the signedness to be unsigned, it will change to signed
2193dffbbdc2SYonghong Song 	 * if any later enumerator is negative.
2194dffbbdc2SYonghong Song 	 */
21958479aa75SYonghong Song 	return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
21968479aa75SYonghong Song }
21978479aa75SYonghong Song 
21988479aa75SYonghong Song /*
21994a3b33f8SAndrii Nakryiko  * Append new enum value for the current ENUM type with:
22004a3b33f8SAndrii Nakryiko  *   - *name* - name of the enumerator value, can't be NULL or empty;
22014a3b33f8SAndrii Nakryiko  *   - *value* - integer value corresponding to enum value *name*;
22024a3b33f8SAndrii Nakryiko  * Returns:
22034a3b33f8SAndrii Nakryiko  *   -  0, on success;
22044a3b33f8SAndrii Nakryiko  *   - <0, on error.
22054a3b33f8SAndrii Nakryiko  */
22064a3b33f8SAndrii Nakryiko int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
22074a3b33f8SAndrii Nakryiko {
22084a3b33f8SAndrii Nakryiko 	struct btf_type *t;
22094a3b33f8SAndrii Nakryiko 	struct btf_enum *v;
22104a3b33f8SAndrii Nakryiko 	int sz, name_off;
22114a3b33f8SAndrii Nakryiko 
22124a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_ENUM */
22134a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2214e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2215c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
22164a3b33f8SAndrii Nakryiko 	if (!btf_is_enum(t))
2217e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
22184a3b33f8SAndrii Nakryiko 
22194a3b33f8SAndrii Nakryiko 	/* non-empty name */
22204a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2221e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
22224a3b33f8SAndrii Nakryiko 	if (value < INT_MIN || value > UINT_MAX)
2223e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-E2BIG);
22244a3b33f8SAndrii Nakryiko 
22254a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
22264a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2227e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
22284a3b33f8SAndrii Nakryiko 
22294a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_enum);
22304a3b33f8SAndrii Nakryiko 	v = btf_add_type_mem(btf, sz);
22314a3b33f8SAndrii Nakryiko 	if (!v)
2232e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
22334a3b33f8SAndrii Nakryiko 
22344a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
22354a3b33f8SAndrii Nakryiko 	if (name_off < 0)
22364a3b33f8SAndrii Nakryiko 		return name_off;
22374a3b33f8SAndrii Nakryiko 
22384a3b33f8SAndrii Nakryiko 	v->name_off = name_off;
22394a3b33f8SAndrii Nakryiko 	v->val = value;
22404a3b33f8SAndrii Nakryiko 
22414a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2242c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
22434a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
22444a3b33f8SAndrii Nakryiko 
2245dffbbdc2SYonghong Song 	/* if negative value, set signedness to signed */
2246dffbbdc2SYonghong Song 	if (value < 0)
2247dffbbdc2SYonghong Song 		t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
2248dffbbdc2SYonghong Song 
2249dffbbdc2SYonghong Song 	btf->hdr->type_len += sz;
2250dffbbdc2SYonghong Song 	btf->hdr->str_off += sz;
2251dffbbdc2SYonghong Song 	return 0;
2252dffbbdc2SYonghong Song }
2253dffbbdc2SYonghong Song 
2254dffbbdc2SYonghong Song /*
2255dffbbdc2SYonghong Song  * Append new BTF_KIND_ENUM64 type with:
2256dffbbdc2SYonghong Song  *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
2257dffbbdc2SYonghong Song  *   - *byte_sz* - size of the enum, in bytes.
2258dffbbdc2SYonghong Song  *   - *is_signed* - whether the enum values are signed or not;
2259dffbbdc2SYonghong Song  *
2260dffbbdc2SYonghong Song  * Enum initially has no enum values in it (and corresponds to enum forward
2261dffbbdc2SYonghong Song  * declaration). Enumerator values can be added by btf__add_enum64_value()
2262dffbbdc2SYonghong Song  * immediately after btf__add_enum64() succeeds.
2263dffbbdc2SYonghong Song  *
2264dffbbdc2SYonghong Song  * Returns:
2265dffbbdc2SYonghong Song  *   - >0, type ID of newly added BTF type;
2266dffbbdc2SYonghong Song  *   - <0, on error.
2267dffbbdc2SYonghong Song  */
2268dffbbdc2SYonghong Song int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
2269dffbbdc2SYonghong Song 		    bool is_signed)
2270dffbbdc2SYonghong Song {
2271dffbbdc2SYonghong Song 	return btf_add_enum_common(btf, name, byte_sz, is_signed,
2272dffbbdc2SYonghong Song 				   BTF_KIND_ENUM64);
2273dffbbdc2SYonghong Song }
2274dffbbdc2SYonghong Song 
2275dffbbdc2SYonghong Song /*
2276dffbbdc2SYonghong Song  * Append new enum value for the current ENUM64 type with:
2277dffbbdc2SYonghong Song  *   - *name* - name of the enumerator value, can't be NULL or empty;
2278dffbbdc2SYonghong Song  *   - *value* - integer value corresponding to enum value *name*;
2279dffbbdc2SYonghong Song  * Returns:
2280dffbbdc2SYonghong Song  *   -  0, on success;
2281dffbbdc2SYonghong Song  *   - <0, on error.
2282dffbbdc2SYonghong Song  */
2283dffbbdc2SYonghong Song int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
2284dffbbdc2SYonghong Song {
2285dffbbdc2SYonghong Song 	struct btf_enum64 *v;
2286dffbbdc2SYonghong Song 	struct btf_type *t;
2287dffbbdc2SYonghong Song 	int sz, name_off;
2288dffbbdc2SYonghong Song 
2289dffbbdc2SYonghong Song 	/* last type should be BTF_KIND_ENUM64 */
2290dffbbdc2SYonghong Song 	if (btf->nr_types == 0)
2291dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2292dffbbdc2SYonghong Song 	t = btf_last_type(btf);
2293dffbbdc2SYonghong Song 	if (!btf_is_enum64(t))
2294dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2295dffbbdc2SYonghong Song 
2296dffbbdc2SYonghong Song 	/* non-empty name */
2297dffbbdc2SYonghong Song 	if (!name || !name[0])
2298dffbbdc2SYonghong Song 		return libbpf_err(-EINVAL);
2299dffbbdc2SYonghong Song 
2300dffbbdc2SYonghong Song 	/* decompose and invalidate raw data */
2301dffbbdc2SYonghong Song 	if (btf_ensure_modifiable(btf))
2302dffbbdc2SYonghong Song 		return libbpf_err(-ENOMEM);
2303dffbbdc2SYonghong Song 
2304dffbbdc2SYonghong Song 	sz = sizeof(struct btf_enum64);
2305dffbbdc2SYonghong Song 	v = btf_add_type_mem(btf, sz);
2306dffbbdc2SYonghong Song 	if (!v)
2307dffbbdc2SYonghong Song 		return libbpf_err(-ENOMEM);
2308dffbbdc2SYonghong Song 
2309dffbbdc2SYonghong Song 	name_off = btf__add_str(btf, name);
2310dffbbdc2SYonghong Song 	if (name_off < 0)
2311dffbbdc2SYonghong Song 		return name_off;
2312dffbbdc2SYonghong Song 
2313dffbbdc2SYonghong Song 	v->name_off = name_off;
2314dffbbdc2SYonghong Song 	v->val_lo32 = (__u32)value;
2315dffbbdc2SYonghong Song 	v->val_hi32 = value >> 32;
2316dffbbdc2SYonghong Song 
2317dffbbdc2SYonghong Song 	/* update parent type's vlen */
2318dffbbdc2SYonghong Song 	t = btf_last_type(btf);
2319dffbbdc2SYonghong Song 	btf_type_inc_vlen(t);
2320dffbbdc2SYonghong Song 
23214a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
23224a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
23234a3b33f8SAndrii Nakryiko 	return 0;
23244a3b33f8SAndrii Nakryiko }
23254a3b33f8SAndrii Nakryiko 
23264a3b33f8SAndrii Nakryiko /*
23274a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FWD type with:
23284a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
23294a3b33f8SAndrii Nakryiko  *   - *fwd_kind*, kind of forward declaration, one of BTF_FWD_STRUCT,
23304a3b33f8SAndrii Nakryiko  *     BTF_FWD_UNION, or BTF_FWD_ENUM;
23314a3b33f8SAndrii Nakryiko  * Returns:
23324a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23334a3b33f8SAndrii Nakryiko  *   - <0, on error.
23344a3b33f8SAndrii Nakryiko  */
23354a3b33f8SAndrii Nakryiko int btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind)
23364a3b33f8SAndrii Nakryiko {
23374a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2338e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23394a3b33f8SAndrii Nakryiko 
23404a3b33f8SAndrii Nakryiko 	switch (fwd_kind) {
23414a3b33f8SAndrii Nakryiko 	case BTF_FWD_STRUCT:
23424a3b33f8SAndrii Nakryiko 	case BTF_FWD_UNION: {
23434a3b33f8SAndrii Nakryiko 		struct btf_type *t;
23444a3b33f8SAndrii Nakryiko 		int id;
23454a3b33f8SAndrii Nakryiko 
23464a3b33f8SAndrii Nakryiko 		id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0);
23474a3b33f8SAndrii Nakryiko 		if (id <= 0)
23484a3b33f8SAndrii Nakryiko 			return id;
23494a3b33f8SAndrii Nakryiko 		t = btf_type_by_id(btf, id);
23504a3b33f8SAndrii Nakryiko 		t->info = btf_type_info(BTF_KIND_FWD, 0, fwd_kind == BTF_FWD_UNION);
23514a3b33f8SAndrii Nakryiko 		return id;
23524a3b33f8SAndrii Nakryiko 	}
23534a3b33f8SAndrii Nakryiko 	case BTF_FWD_ENUM:
23544a3b33f8SAndrii Nakryiko 		/* enum forward in BTF currently is just an enum with no enum
23554a3b33f8SAndrii Nakryiko 		 * values; we also assume a standard 4-byte size for it
23564a3b33f8SAndrii Nakryiko 		 */
23574a3b33f8SAndrii Nakryiko 		return btf__add_enum(btf, name, sizeof(int));
23584a3b33f8SAndrii Nakryiko 	default:
2359e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23604a3b33f8SAndrii Nakryiko 	}
23614a3b33f8SAndrii Nakryiko }
23624a3b33f8SAndrii Nakryiko 
23634a3b33f8SAndrii Nakryiko /*
23644a3b33f8SAndrii Nakryiko  * Append new BTF_KING_TYPEDEF type with:
23654a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
23664a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23674a3b33f8SAndrii Nakryiko  * Returns:
23684a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23694a3b33f8SAndrii Nakryiko  *   - <0, on error.
23704a3b33f8SAndrii Nakryiko  */
23714a3b33f8SAndrii Nakryiko int btf__add_typedef(struct btf *btf, const char *name, int ref_type_id)
23724a3b33f8SAndrii Nakryiko {
23734a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2374e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
23754a3b33f8SAndrii Nakryiko 
23764a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id);
23774a3b33f8SAndrii Nakryiko }
23784a3b33f8SAndrii Nakryiko 
23794a3b33f8SAndrii Nakryiko /*
23804a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_VOLATILE type with:
23814a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23824a3b33f8SAndrii Nakryiko  * Returns:
23834a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23844a3b33f8SAndrii Nakryiko  *   - <0, on error.
23854a3b33f8SAndrii Nakryiko  */
23864a3b33f8SAndrii Nakryiko int btf__add_volatile(struct btf *btf, int ref_type_id)
23874a3b33f8SAndrii Nakryiko {
23884a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id);
23894a3b33f8SAndrii Nakryiko }
23904a3b33f8SAndrii Nakryiko 
23914a3b33f8SAndrii Nakryiko /*
23924a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_CONST type with:
23934a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
23944a3b33f8SAndrii Nakryiko  * Returns:
23954a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
23964a3b33f8SAndrii Nakryiko  *   - <0, on error.
23974a3b33f8SAndrii Nakryiko  */
23984a3b33f8SAndrii Nakryiko int btf__add_const(struct btf *btf, int ref_type_id)
23994a3b33f8SAndrii Nakryiko {
24004a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id);
24014a3b33f8SAndrii Nakryiko }
24024a3b33f8SAndrii Nakryiko 
24034a3b33f8SAndrii Nakryiko /*
24044a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_RESTRICT type with:
24054a3b33f8SAndrii Nakryiko  *   - *ref_type_id* - referenced type ID, it might not exist yet;
24064a3b33f8SAndrii Nakryiko  * Returns:
24074a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
24084a3b33f8SAndrii Nakryiko  *   - <0, on error.
24094a3b33f8SAndrii Nakryiko  */
24104a3b33f8SAndrii Nakryiko int btf__add_restrict(struct btf *btf, int ref_type_id)
24114a3b33f8SAndrii Nakryiko {
24124a3b33f8SAndrii Nakryiko 	return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id);
24134a3b33f8SAndrii Nakryiko }
24144a3b33f8SAndrii Nakryiko 
24154a3b33f8SAndrii Nakryiko /*
24162dc1e488SYonghong Song  * Append new BTF_KIND_TYPE_TAG type with:
24172dc1e488SYonghong Song  *   - *value*, non-empty/non-NULL tag value;
24182dc1e488SYonghong Song  *   - *ref_type_id* - referenced type ID, it might not exist yet;
24192dc1e488SYonghong Song  * Returns:
24202dc1e488SYonghong Song  *   - >0, type ID of newly added BTF type;
24212dc1e488SYonghong Song  *   - <0, on error.
24222dc1e488SYonghong Song  */
24232dc1e488SYonghong Song int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
24242dc1e488SYonghong Song {
24252dc1e488SYonghong Song 	if (!value|| !value[0])
24262dc1e488SYonghong Song 		return libbpf_err(-EINVAL);
24272dc1e488SYonghong Song 
24282dc1e488SYonghong Song 	return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
24292dc1e488SYonghong Song }
24302dc1e488SYonghong Song 
24312dc1e488SYonghong Song /*
24324a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FUNC type with:
24334a3b33f8SAndrii Nakryiko  *   - *name*, non-empty/non-NULL name;
24344a3b33f8SAndrii Nakryiko  *   - *proto_type_id* - FUNC_PROTO's type ID, it might not exist yet;
24354a3b33f8SAndrii Nakryiko  * Returns:
24364a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
24374a3b33f8SAndrii Nakryiko  *   - <0, on error.
24384a3b33f8SAndrii Nakryiko  */
24394a3b33f8SAndrii Nakryiko int btf__add_func(struct btf *btf, const char *name,
24404a3b33f8SAndrii Nakryiko 		  enum btf_func_linkage linkage, int proto_type_id)
24414a3b33f8SAndrii Nakryiko {
24424a3b33f8SAndrii Nakryiko 	int id;
24434a3b33f8SAndrii Nakryiko 
24444a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2445e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24464a3b33f8SAndrii Nakryiko 	if (linkage != BTF_FUNC_STATIC && linkage != BTF_FUNC_GLOBAL &&
24474a3b33f8SAndrii Nakryiko 	    linkage != BTF_FUNC_EXTERN)
2448e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24494a3b33f8SAndrii Nakryiko 
24504a3b33f8SAndrii Nakryiko 	id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id);
24514a3b33f8SAndrii Nakryiko 	if (id > 0) {
24524a3b33f8SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(btf, id);
24534a3b33f8SAndrii Nakryiko 
24544a3b33f8SAndrii Nakryiko 		t->info = btf_type_info(BTF_KIND_FUNC, linkage, 0);
24554a3b33f8SAndrii Nakryiko 	}
2456e9fc3ce9SAndrii Nakryiko 	return libbpf_err(id);
24574a3b33f8SAndrii Nakryiko }
24584a3b33f8SAndrii Nakryiko 
24594a3b33f8SAndrii Nakryiko /*
24604a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_FUNC_PROTO with:
24614a3b33f8SAndrii Nakryiko  *   - *ret_type_id* - type ID for return result of a function.
24624a3b33f8SAndrii Nakryiko  *
24634a3b33f8SAndrii Nakryiko  * Function prototype initially has no arguments, but they can be added by
24644a3b33f8SAndrii Nakryiko  * btf__add_func_param() one by one, immediately after
24654a3b33f8SAndrii Nakryiko  * btf__add_func_proto() succeeded.
24664a3b33f8SAndrii Nakryiko  *
24674a3b33f8SAndrii Nakryiko  * Returns:
24684a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
24694a3b33f8SAndrii Nakryiko  *   - <0, on error.
24704a3b33f8SAndrii Nakryiko  */
24714a3b33f8SAndrii Nakryiko int btf__add_func_proto(struct btf *btf, int ret_type_id)
24724a3b33f8SAndrii Nakryiko {
24734a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2474c81ed6d8SAndrii Nakryiko 	int sz;
24754a3b33f8SAndrii Nakryiko 
24764a3b33f8SAndrii Nakryiko 	if (validate_type_id(ret_type_id))
2477e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
24784a3b33f8SAndrii Nakryiko 
24794a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2480e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24814a3b33f8SAndrii Nakryiko 
24824a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
24834a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
24844a3b33f8SAndrii Nakryiko 	if (!t)
2485e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
24864a3b33f8SAndrii Nakryiko 
24874a3b33f8SAndrii Nakryiko 	/* start out with vlen=0; this will be adjusted when adding enum
24884a3b33f8SAndrii Nakryiko 	 * values, if necessary
24894a3b33f8SAndrii Nakryiko 	 */
24904a3b33f8SAndrii Nakryiko 	t->name_off = 0;
24914a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_FUNC_PROTO, 0, 0);
24924a3b33f8SAndrii Nakryiko 	t->type = ret_type_id;
24934a3b33f8SAndrii Nakryiko 
2494c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
24954a3b33f8SAndrii Nakryiko }
24964a3b33f8SAndrii Nakryiko 
24974a3b33f8SAndrii Nakryiko /*
24984a3b33f8SAndrii Nakryiko  * Append new function parameter for current FUNC_PROTO type with:
24994a3b33f8SAndrii Nakryiko  *   - *name* - parameter name, can be NULL or empty;
25004a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID describing the type of the parameter.
25014a3b33f8SAndrii Nakryiko  * Returns:
25024a3b33f8SAndrii Nakryiko  *   -  0, on success;
25034a3b33f8SAndrii Nakryiko  *   - <0, on error.
25044a3b33f8SAndrii Nakryiko  */
25054a3b33f8SAndrii Nakryiko int btf__add_func_param(struct btf *btf, const char *name, int type_id)
25064a3b33f8SAndrii Nakryiko {
25074a3b33f8SAndrii Nakryiko 	struct btf_type *t;
25084a3b33f8SAndrii Nakryiko 	struct btf_param *p;
25094a3b33f8SAndrii Nakryiko 	int sz, name_off = 0;
25104a3b33f8SAndrii Nakryiko 
25114a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2512e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25134a3b33f8SAndrii Nakryiko 
25144a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_FUNC_PROTO */
25154a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2516e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2517c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
25184a3b33f8SAndrii Nakryiko 	if (!btf_is_func_proto(t))
2519e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25204a3b33f8SAndrii Nakryiko 
25214a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
25224a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2523e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25244a3b33f8SAndrii Nakryiko 
25254a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_param);
25264a3b33f8SAndrii Nakryiko 	p = btf_add_type_mem(btf, sz);
25274a3b33f8SAndrii Nakryiko 	if (!p)
2528e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25294a3b33f8SAndrii Nakryiko 
25304a3b33f8SAndrii Nakryiko 	if (name && name[0]) {
25314a3b33f8SAndrii Nakryiko 		name_off = btf__add_str(btf, name);
25324a3b33f8SAndrii Nakryiko 		if (name_off < 0)
25334a3b33f8SAndrii Nakryiko 			return name_off;
25344a3b33f8SAndrii Nakryiko 	}
25354a3b33f8SAndrii Nakryiko 
25364a3b33f8SAndrii Nakryiko 	p->name_off = name_off;
25374a3b33f8SAndrii Nakryiko 	p->type = type_id;
25384a3b33f8SAndrii Nakryiko 
25394a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2540c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
25414a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
25424a3b33f8SAndrii Nakryiko 
25434a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
25444a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
25454a3b33f8SAndrii Nakryiko 	return 0;
25464a3b33f8SAndrii Nakryiko }
25474a3b33f8SAndrii Nakryiko 
25484a3b33f8SAndrii Nakryiko /*
25494a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_VAR type with:
25504a3b33f8SAndrii Nakryiko  *   - *name* - non-empty/non-NULL name;
25514a3b33f8SAndrii Nakryiko  *   - *linkage* - variable linkage, one of BTF_VAR_STATIC,
25524a3b33f8SAndrii Nakryiko  *     BTF_VAR_GLOBAL_ALLOCATED, or BTF_VAR_GLOBAL_EXTERN;
25534a3b33f8SAndrii Nakryiko  *   - *type_id* - type ID of the type describing the type of the variable.
25544a3b33f8SAndrii Nakryiko  * Returns:
25554a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
25564a3b33f8SAndrii Nakryiko  *   - <0, on error.
25574a3b33f8SAndrii Nakryiko  */
25584a3b33f8SAndrii Nakryiko int btf__add_var(struct btf *btf, const char *name, int linkage, int type_id)
25594a3b33f8SAndrii Nakryiko {
25604a3b33f8SAndrii Nakryiko 	struct btf_type *t;
25614a3b33f8SAndrii Nakryiko 	struct btf_var *v;
2562c81ed6d8SAndrii Nakryiko 	int sz, name_off;
25634a3b33f8SAndrii Nakryiko 
25644a3b33f8SAndrii Nakryiko 	/* non-empty name */
25654a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2566e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25674a3b33f8SAndrii Nakryiko 	if (linkage != BTF_VAR_STATIC && linkage != BTF_VAR_GLOBAL_ALLOCATED &&
25684a3b33f8SAndrii Nakryiko 	    linkage != BTF_VAR_GLOBAL_EXTERN)
2569e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25704a3b33f8SAndrii Nakryiko 	if (validate_type_id(type_id))
2571e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
25724a3b33f8SAndrii Nakryiko 
25734a3b33f8SAndrii Nakryiko 	/* deconstruct BTF, if necessary, and invalidate raw_data */
25744a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2575e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25764a3b33f8SAndrii Nakryiko 
25774a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type) + sizeof(struct btf_var);
25784a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
25794a3b33f8SAndrii Nakryiko 	if (!t)
2580e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
25814a3b33f8SAndrii Nakryiko 
25824a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
25834a3b33f8SAndrii Nakryiko 	if (name_off < 0)
25844a3b33f8SAndrii Nakryiko 		return name_off;
25854a3b33f8SAndrii Nakryiko 
25864a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
25874a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_VAR, 0, 0);
25884a3b33f8SAndrii Nakryiko 	t->type = type_id;
25894a3b33f8SAndrii Nakryiko 
25904a3b33f8SAndrii Nakryiko 	v = btf_var(t);
25914a3b33f8SAndrii Nakryiko 	v->linkage = linkage;
25924a3b33f8SAndrii Nakryiko 
2593c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
25944a3b33f8SAndrii Nakryiko }
25954a3b33f8SAndrii Nakryiko 
25964a3b33f8SAndrii Nakryiko /*
25974a3b33f8SAndrii Nakryiko  * Append new BTF_KIND_DATASEC type with:
25984a3b33f8SAndrii Nakryiko  *   - *name* - non-empty/non-NULL name;
25994a3b33f8SAndrii Nakryiko  *   - *byte_sz* - data section size, in bytes.
26004a3b33f8SAndrii Nakryiko  *
26014a3b33f8SAndrii Nakryiko  * Data section is initially empty. Variables info can be added with
26024a3b33f8SAndrii Nakryiko  * btf__add_datasec_var_info() calls, after btf__add_datasec() succeeds.
26034a3b33f8SAndrii Nakryiko  *
26044a3b33f8SAndrii Nakryiko  * Returns:
26054a3b33f8SAndrii Nakryiko  *   - >0, type ID of newly added BTF type;
26064a3b33f8SAndrii Nakryiko  *   - <0, on error.
26074a3b33f8SAndrii Nakryiko  */
26084a3b33f8SAndrii Nakryiko int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz)
26094a3b33f8SAndrii Nakryiko {
26104a3b33f8SAndrii Nakryiko 	struct btf_type *t;
2611c81ed6d8SAndrii Nakryiko 	int sz, name_off;
26124a3b33f8SAndrii Nakryiko 
26134a3b33f8SAndrii Nakryiko 	/* non-empty name */
26144a3b33f8SAndrii Nakryiko 	if (!name || !name[0])
2615e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
26164a3b33f8SAndrii Nakryiko 
26174a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2618e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
26194a3b33f8SAndrii Nakryiko 
26204a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_type);
26214a3b33f8SAndrii Nakryiko 	t = btf_add_type_mem(btf, sz);
26224a3b33f8SAndrii Nakryiko 	if (!t)
2623e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
26244a3b33f8SAndrii Nakryiko 
26254a3b33f8SAndrii Nakryiko 	name_off = btf__add_str(btf, name);
26264a3b33f8SAndrii Nakryiko 	if (name_off < 0)
26274a3b33f8SAndrii Nakryiko 		return name_off;
26284a3b33f8SAndrii Nakryiko 
26294a3b33f8SAndrii Nakryiko 	/* start with vlen=0, which will be update as var_secinfos are added */
26304a3b33f8SAndrii Nakryiko 	t->name_off = name_off;
26314a3b33f8SAndrii Nakryiko 	t->info = btf_type_info(BTF_KIND_DATASEC, 0, 0);
26324a3b33f8SAndrii Nakryiko 	t->size = byte_sz;
26334a3b33f8SAndrii Nakryiko 
2634c81ed6d8SAndrii Nakryiko 	return btf_commit_type(btf, sz);
26354a3b33f8SAndrii Nakryiko }
26364a3b33f8SAndrii Nakryiko 
26374a3b33f8SAndrii Nakryiko /*
26384a3b33f8SAndrii Nakryiko  * Append new data section variable information entry for current DATASEC type:
26394a3b33f8SAndrii Nakryiko  *   - *var_type_id* - type ID, describing type of the variable;
26404a3b33f8SAndrii Nakryiko  *   - *offset* - variable offset within data section, in bytes;
26414a3b33f8SAndrii Nakryiko  *   - *byte_sz* - variable size, in bytes.
26424a3b33f8SAndrii Nakryiko  *
26434a3b33f8SAndrii Nakryiko  * Returns:
26444a3b33f8SAndrii Nakryiko  *   -  0, on success;
26454a3b33f8SAndrii Nakryiko  *   - <0, on error.
26464a3b33f8SAndrii Nakryiko  */
26474a3b33f8SAndrii Nakryiko int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz)
26484a3b33f8SAndrii Nakryiko {
26494a3b33f8SAndrii Nakryiko 	struct btf_type *t;
26504a3b33f8SAndrii Nakryiko 	struct btf_var_secinfo *v;
26514a3b33f8SAndrii Nakryiko 	int sz;
26524a3b33f8SAndrii Nakryiko 
26534a3b33f8SAndrii Nakryiko 	/* last type should be BTF_KIND_DATASEC */
26544a3b33f8SAndrii Nakryiko 	if (btf->nr_types == 0)
2655e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
2656c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
26574a3b33f8SAndrii Nakryiko 	if (!btf_is_datasec(t))
2658e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
26594a3b33f8SAndrii Nakryiko 
26604a3b33f8SAndrii Nakryiko 	if (validate_type_id(var_type_id))
2661e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
26624a3b33f8SAndrii Nakryiko 
26634a3b33f8SAndrii Nakryiko 	/* decompose and invalidate raw data */
26644a3b33f8SAndrii Nakryiko 	if (btf_ensure_modifiable(btf))
2665e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
26664a3b33f8SAndrii Nakryiko 
26674a3b33f8SAndrii Nakryiko 	sz = sizeof(struct btf_var_secinfo);
26684a3b33f8SAndrii Nakryiko 	v = btf_add_type_mem(btf, sz);
26694a3b33f8SAndrii Nakryiko 	if (!v)
2670e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-ENOMEM);
26714a3b33f8SAndrii Nakryiko 
26724a3b33f8SAndrii Nakryiko 	v->type = var_type_id;
26734a3b33f8SAndrii Nakryiko 	v->offset = offset;
26744a3b33f8SAndrii Nakryiko 	v->size = byte_sz;
26754a3b33f8SAndrii Nakryiko 
26764a3b33f8SAndrii Nakryiko 	/* update parent type's vlen */
2677c81ed6d8SAndrii Nakryiko 	t = btf_last_type(btf);
26784a3b33f8SAndrii Nakryiko 	btf_type_inc_vlen(t);
26794a3b33f8SAndrii Nakryiko 
26804a3b33f8SAndrii Nakryiko 	btf->hdr->type_len += sz;
26814a3b33f8SAndrii Nakryiko 	btf->hdr->str_off += sz;
26824a3b33f8SAndrii Nakryiko 	return 0;
26834a3b33f8SAndrii Nakryiko }
26844a3b33f8SAndrii Nakryiko 
26855b84bd10SYonghong Song /*
2686223f903eSYonghong Song  * Append new BTF_KIND_DECL_TAG type with:
26875b84bd10SYonghong Song  *   - *value* - non-empty/non-NULL string;
26885b84bd10SYonghong Song  *   - *ref_type_id* - referenced type ID, it might not exist yet;
26895b84bd10SYonghong Song  *   - *component_idx* - -1 for tagging reference type, otherwise struct/union
26905b84bd10SYonghong Song  *     member or function argument index;
26915b84bd10SYonghong Song  * Returns:
26925b84bd10SYonghong Song  *   - >0, type ID of newly added BTF type;
26935b84bd10SYonghong Song  *   - <0, on error.
26945b84bd10SYonghong Song  */
2695223f903eSYonghong Song int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
26965b84bd10SYonghong Song 		 int component_idx)
26975b84bd10SYonghong Song {
26985b84bd10SYonghong Song 	struct btf_type *t;
26995b84bd10SYonghong Song 	int sz, value_off;
27005b84bd10SYonghong Song 
27015b84bd10SYonghong Song 	if (!value || !value[0] || component_idx < -1)
27025b84bd10SYonghong Song 		return libbpf_err(-EINVAL);
27035b84bd10SYonghong Song 
27045b84bd10SYonghong Song 	if (validate_type_id(ref_type_id))
27055b84bd10SYonghong Song 		return libbpf_err(-EINVAL);
27065b84bd10SYonghong Song 
27075b84bd10SYonghong Song 	if (btf_ensure_modifiable(btf))
27085b84bd10SYonghong Song 		return libbpf_err(-ENOMEM);
27095b84bd10SYonghong Song 
2710223f903eSYonghong Song 	sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag);
27115b84bd10SYonghong Song 	t = btf_add_type_mem(btf, sz);
27125b84bd10SYonghong Song 	if (!t)
27135b84bd10SYonghong Song 		return libbpf_err(-ENOMEM);
27145b84bd10SYonghong Song 
27155b84bd10SYonghong Song 	value_off = btf__add_str(btf, value);
27165b84bd10SYonghong Song 	if (value_off < 0)
27175b84bd10SYonghong Song 		return value_off;
27185b84bd10SYonghong Song 
27195b84bd10SYonghong Song 	t->name_off = value_off;
2720223f903eSYonghong Song 	t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false);
27215b84bd10SYonghong Song 	t->type = ref_type_id;
2722223f903eSYonghong Song 	btf_decl_tag(t)->component_idx = component_idx;
27235b84bd10SYonghong Song 
27245b84bd10SYonghong Song 	return btf_commit_type(btf, sz);
27255b84bd10SYonghong Song }
27265b84bd10SYonghong Song 
2727ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param {
27283d650141SMartin KaFai Lau 	__u32 off;
27293d650141SMartin KaFai Lau 	__u32 len;
27303d650141SMartin KaFai Lau 	__u32 min_rec_size;
27313d650141SMartin KaFai Lau 	struct btf_ext_info *ext_info;
27323d650141SMartin KaFai Lau 	const char *desc;
27333d650141SMartin KaFai Lau };
27343d650141SMartin KaFai Lau 
2735ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_info(struct btf_ext *btf_ext,
2736ae4ab4b4SAndrii Nakryiko 			      struct btf_ext_sec_setup_param *ext_sec)
27372993e051SYonghong Song {
27383d650141SMartin KaFai Lau 	const struct btf_ext_info_sec *sinfo;
27393d650141SMartin KaFai Lau 	struct btf_ext_info *ext_info;
2740f0187f0bSMartin KaFai Lau 	__u32 info_left, record_size;
274111d5daa8SAndrii Nakryiko 	size_t sec_cnt = 0;
2742f0187f0bSMartin KaFai Lau 	/* The start of the info sec (including the __u32 record_size). */
2743ae4ab4b4SAndrii Nakryiko 	void *info;
2744f0187f0bSMartin KaFai Lau 
27454cedc0daSAndrii Nakryiko 	if (ext_sec->len == 0)
27464cedc0daSAndrii Nakryiko 		return 0;
27474cedc0daSAndrii Nakryiko 
27483d650141SMartin KaFai Lau 	if (ext_sec->off & 0x03) {
27498461ef8bSYonghong Song 		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
27503d650141SMartin KaFai Lau 		     ext_sec->desc);
2751f0187f0bSMartin KaFai Lau 		return -EINVAL;
2752f0187f0bSMartin KaFai Lau 	}
2753f0187f0bSMartin KaFai Lau 
2754ae4ab4b4SAndrii Nakryiko 	info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off;
2755ae4ab4b4SAndrii Nakryiko 	info_left = ext_sec->len;
2756ae4ab4b4SAndrii Nakryiko 
2757ae4ab4b4SAndrii Nakryiko 	if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) {
27588461ef8bSYonghong Song 		pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
27593d650141SMartin KaFai Lau 			 ext_sec->desc, ext_sec->off, ext_sec->len);
2760f0187f0bSMartin KaFai Lau 		return -EINVAL;
2761f0187f0bSMartin KaFai Lau 	}
2762f0187f0bSMartin KaFai Lau 
27633d650141SMartin KaFai Lau 	/* At least a record size */
2764f0187f0bSMartin KaFai Lau 	if (info_left < sizeof(__u32)) {
27658461ef8bSYonghong Song 		pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);
27662993e051SYonghong Song 		return -EINVAL;
27672993e051SYonghong Song 	}
27682993e051SYonghong Song 
2769f0187f0bSMartin KaFai Lau 	/* The record size needs to meet the minimum standard */
2770f0187f0bSMartin KaFai Lau 	record_size = *(__u32 *)info;
27713d650141SMartin KaFai Lau 	if (record_size < ext_sec->min_rec_size ||
2772f0187f0bSMartin KaFai Lau 	    record_size & 0x03) {
27738461ef8bSYonghong Song 		pr_debug("%s section in .BTF.ext has invalid record size %u\n",
27743d650141SMartin KaFai Lau 			 ext_sec->desc, record_size);
27752993e051SYonghong Song 		return -EINVAL;
27762993e051SYonghong Song 	}
27772993e051SYonghong Song 
2778f0187f0bSMartin KaFai Lau 	sinfo = info + sizeof(__u32);
2779f0187f0bSMartin KaFai Lau 	info_left -= sizeof(__u32);
27802993e051SYonghong Song 
27813d650141SMartin KaFai Lau 	/* If no records, return failure now so .BTF.ext won't be used. */
2782f0187f0bSMartin KaFai Lau 	if (!info_left) {
27838461ef8bSYonghong Song 		pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);
27842993e051SYonghong Song 		return -EINVAL;
27852993e051SYonghong Song 	}
27862993e051SYonghong Song 
2787f0187f0bSMartin KaFai Lau 	while (info_left) {
27883d650141SMartin KaFai Lau 		unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
2789f0187f0bSMartin KaFai Lau 		__u64 total_record_size;
2790f0187f0bSMartin KaFai Lau 		__u32 num_records;
2791f0187f0bSMartin KaFai Lau 
2792f0187f0bSMartin KaFai Lau 		if (info_left < sec_hdrlen) {
27938461ef8bSYonghong Song 			pr_debug("%s section header is not found in .BTF.ext\n",
27943d650141SMartin KaFai Lau 			     ext_sec->desc);
27952993e051SYonghong Song 			return -EINVAL;
27962993e051SYonghong Song 		}
27972993e051SYonghong Song 
27983d650141SMartin KaFai Lau 		num_records = sinfo->num_info;
27992993e051SYonghong Song 		if (num_records == 0) {
28008461ef8bSYonghong Song 			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
28013d650141SMartin KaFai Lau 			     ext_sec->desc);
28022993e051SYonghong Song 			return -EINVAL;
28032993e051SYonghong Song 		}
28042993e051SYonghong Song 
280511d5daa8SAndrii Nakryiko 		total_record_size = sec_hdrlen + (__u64)num_records * record_size;
2806f0187f0bSMartin KaFai Lau 		if (info_left < total_record_size) {
28078461ef8bSYonghong Song 			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
28083d650141SMartin KaFai Lau 			     ext_sec->desc);
28092993e051SYonghong Song 			return -EINVAL;
28102993e051SYonghong Song 		}
28112993e051SYonghong Song 
2812f0187f0bSMartin KaFai Lau 		info_left -= total_record_size;
28132993e051SYonghong Song 		sinfo = (void *)sinfo + total_record_size;
281411d5daa8SAndrii Nakryiko 		sec_cnt++;
28152993e051SYonghong Song 	}
28162993e051SYonghong Song 
28173d650141SMartin KaFai Lau 	ext_info = ext_sec->ext_info;
28183d650141SMartin KaFai Lau 	ext_info->len = ext_sec->len - sizeof(__u32);
28193d650141SMartin KaFai Lau 	ext_info->rec_size = record_size;
2820ae4ab4b4SAndrii Nakryiko 	ext_info->info = info + sizeof(__u32);
282111d5daa8SAndrii Nakryiko 	ext_info->sec_cnt = sec_cnt;
2822f0187f0bSMartin KaFai Lau 
28232993e051SYonghong Song 	return 0;
28242993e051SYonghong Song }
28252993e051SYonghong Song 
2826ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_func_info(struct btf_ext *btf_ext)
28273d650141SMartin KaFai Lau {
2828ae4ab4b4SAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
2829ae4ab4b4SAndrii Nakryiko 		.off = btf_ext->hdr->func_info_off,
2830ae4ab4b4SAndrii Nakryiko 		.len = btf_ext->hdr->func_info_len,
28313d650141SMartin KaFai Lau 		.min_rec_size = sizeof(struct bpf_func_info_min),
28323d650141SMartin KaFai Lau 		.ext_info = &btf_ext->func_info,
28333d650141SMartin KaFai Lau 		.desc = "func_info"
28343d650141SMartin KaFai Lau 	};
28353d650141SMartin KaFai Lau 
2836ae4ab4b4SAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
28373d650141SMartin KaFai Lau }
28383d650141SMartin KaFai Lau 
2839ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
28403d650141SMartin KaFai Lau {
2841ae4ab4b4SAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
2842ae4ab4b4SAndrii Nakryiko 		.off = btf_ext->hdr->line_info_off,
2843ae4ab4b4SAndrii Nakryiko 		.len = btf_ext->hdr->line_info_len,
28443d650141SMartin KaFai Lau 		.min_rec_size = sizeof(struct bpf_line_info_min),
28453d650141SMartin KaFai Lau 		.ext_info = &btf_ext->line_info,
28463d650141SMartin KaFai Lau 		.desc = "line_info",
28473d650141SMartin KaFai Lau 	};
28483d650141SMartin KaFai Lau 
2849ae4ab4b4SAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
28503d650141SMartin KaFai Lau }
28513d650141SMartin KaFai Lau 
285228b93c64SAndrii Nakryiko static int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
28534cedc0daSAndrii Nakryiko {
28544cedc0daSAndrii Nakryiko 	struct btf_ext_sec_setup_param param = {
285528b93c64SAndrii Nakryiko 		.off = btf_ext->hdr->core_relo_off,
285628b93c64SAndrii Nakryiko 		.len = btf_ext->hdr->core_relo_len,
285728b93c64SAndrii Nakryiko 		.min_rec_size = sizeof(struct bpf_core_relo),
285828b93c64SAndrii Nakryiko 		.ext_info = &btf_ext->core_relo_info,
285928b93c64SAndrii Nakryiko 		.desc = "core_relo",
28604cedc0daSAndrii Nakryiko 	};
28614cedc0daSAndrii Nakryiko 
28624cedc0daSAndrii Nakryiko 	return btf_ext_setup_info(btf_ext, &param);
28634cedc0daSAndrii Nakryiko }
28644cedc0daSAndrii Nakryiko 
28658461ef8bSYonghong Song static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
28662993e051SYonghong Song {
28672993e051SYonghong Song 	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
28682993e051SYonghong Song 
28694cedc0daSAndrii Nakryiko 	if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
28702993e051SYonghong Song 	    data_size < hdr->hdr_len) {
28718461ef8bSYonghong Song 		pr_debug("BTF.ext header not found");
28722993e051SYonghong Song 		return -EINVAL;
28732993e051SYonghong Song 	}
28742993e051SYonghong Song 
28753289959bSAndrii Nakryiko 	if (hdr->magic == bswap_16(BTF_MAGIC)) {
28763289959bSAndrii Nakryiko 		pr_warn("BTF.ext in non-native endianness is not supported\n");
28773289959bSAndrii Nakryiko 		return -ENOTSUP;
28783289959bSAndrii Nakryiko 	} else if (hdr->magic != BTF_MAGIC) {
28798461ef8bSYonghong Song 		pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
28802993e051SYonghong Song 		return -EINVAL;
28812993e051SYonghong Song 	}
28822993e051SYonghong Song 
28832993e051SYonghong Song 	if (hdr->version != BTF_VERSION) {
28848461ef8bSYonghong Song 		pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
28852993e051SYonghong Song 		return -ENOTSUP;
28862993e051SYonghong Song 	}
28872993e051SYonghong Song 
28882993e051SYonghong Song 	if (hdr->flags) {
28898461ef8bSYonghong Song 		pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
28902993e051SYonghong Song 		return -ENOTSUP;
28912993e051SYonghong Song 	}
28922993e051SYonghong Song 
2893f0187f0bSMartin KaFai Lau 	if (data_size == hdr->hdr_len) {
28948461ef8bSYonghong Song 		pr_debug("BTF.ext has no data\n");
28952993e051SYonghong Song 		return -EINVAL;
28962993e051SYonghong Song 	}
28972993e051SYonghong Song 
2898f0187f0bSMartin KaFai Lau 	return 0;
28992993e051SYonghong Song }
29002993e051SYonghong Song 
29012993e051SYonghong Song void btf_ext__free(struct btf_ext *btf_ext)
29022993e051SYonghong Song {
290350450fc7SAndrii Nakryiko 	if (IS_ERR_OR_NULL(btf_ext))
29042993e051SYonghong Song 		return;
290511d5daa8SAndrii Nakryiko 	free(btf_ext->func_info.sec_idxs);
290611d5daa8SAndrii Nakryiko 	free(btf_ext->line_info.sec_idxs);
290711d5daa8SAndrii Nakryiko 	free(btf_ext->core_relo_info.sec_idxs);
2908ae4ab4b4SAndrii Nakryiko 	free(btf_ext->data);
29092993e051SYonghong Song 	free(btf_ext);
29102993e051SYonghong Song }
29112993e051SYonghong Song 
2912401891a9SAndrii Nakryiko struct btf_ext *btf_ext__new(const __u8 *data, __u32 size)
29132993e051SYonghong Song {
29142993e051SYonghong Song 	struct btf_ext *btf_ext;
29152993e051SYonghong Song 	int err;
29162993e051SYonghong Song 
29172993e051SYonghong Song 	btf_ext = calloc(1, sizeof(struct btf_ext));
29182993e051SYonghong Song 	if (!btf_ext)
2919e9fc3ce9SAndrii Nakryiko 		return libbpf_err_ptr(-ENOMEM);
29202993e051SYonghong Song 
2921ae4ab4b4SAndrii Nakryiko 	btf_ext->data_size = size;
2922ae4ab4b4SAndrii Nakryiko 	btf_ext->data = malloc(size);
2923ae4ab4b4SAndrii Nakryiko 	if (!btf_ext->data) {
2924ae4ab4b4SAndrii Nakryiko 		err = -ENOMEM;
2925ae4ab4b4SAndrii Nakryiko 		goto done;
29262993e051SYonghong Song 	}
2927ae4ab4b4SAndrii Nakryiko 	memcpy(btf_ext->data, data, size);
29282993e051SYonghong Song 
2929401891a9SAndrii Nakryiko 	err = btf_ext_parse_hdr(btf_ext->data, size);
2930401891a9SAndrii Nakryiko 	if (err)
2931401891a9SAndrii Nakryiko 		goto done;
2932401891a9SAndrii Nakryiko 
2933e9fc3ce9SAndrii Nakryiko 	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
2934e9fc3ce9SAndrii Nakryiko 		err = -EINVAL;
29354cedc0daSAndrii Nakryiko 		goto done;
2936e9fc3ce9SAndrii Nakryiko 	}
2937e9fc3ce9SAndrii Nakryiko 
2938ae4ab4b4SAndrii Nakryiko 	err = btf_ext_setup_func_info(btf_ext);
2939ae4ab4b4SAndrii Nakryiko 	if (err)
2940ae4ab4b4SAndrii Nakryiko 		goto done;
2941ae4ab4b4SAndrii Nakryiko 
2942ae4ab4b4SAndrii Nakryiko 	err = btf_ext_setup_line_info(btf_ext);
2943ae4ab4b4SAndrii Nakryiko 	if (err)
2944ae4ab4b4SAndrii Nakryiko 		goto done;
2945ae4ab4b4SAndrii Nakryiko 
2946e93f3999SYuntao Wang 	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len))
2947e93f3999SYuntao Wang 		goto done; /* skip core relos parsing */
2948e9fc3ce9SAndrii Nakryiko 
294928b93c64SAndrii Nakryiko 	err = btf_ext_setup_core_relos(btf_ext);
29504cedc0daSAndrii Nakryiko 	if (err)
29514cedc0daSAndrii Nakryiko 		goto done;
29524cedc0daSAndrii Nakryiko 
2953ae4ab4b4SAndrii Nakryiko done:
29543d650141SMartin KaFai Lau 	if (err) {
29553d650141SMartin KaFai Lau 		btf_ext__free(btf_ext);
2956e9fc3ce9SAndrii Nakryiko 		return libbpf_err_ptr(err);
29573d650141SMartin KaFai Lau 	}
29583d650141SMartin KaFai Lau 
29592993e051SYonghong Song 	return btf_ext;
29602993e051SYonghong Song }
29612993e051SYonghong Song 
2962ae4ab4b4SAndrii Nakryiko const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)
2963ae4ab4b4SAndrii Nakryiko {
2964ae4ab4b4SAndrii Nakryiko 	*size = btf_ext->data_size;
2965ae4ab4b4SAndrii Nakryiko 	return btf_ext->data;
2966ae4ab4b4SAndrii Nakryiko }
2967ae4ab4b4SAndrii Nakryiko 
29683d650141SMartin KaFai Lau static int btf_ext_reloc_info(const struct btf *btf,
29693d650141SMartin KaFai Lau 			      const struct btf_ext_info *ext_info,
29702993e051SYonghong Song 			      const char *sec_name, __u32 insns_cnt,
29713d650141SMartin KaFai Lau 			      void **info, __u32 *cnt)
29722993e051SYonghong Song {
29733d650141SMartin KaFai Lau 	__u32 sec_hdrlen = sizeof(struct btf_ext_info_sec);
29743d650141SMartin KaFai Lau 	__u32 i, record_size, existing_len, records_len;
29753d650141SMartin KaFai Lau 	struct btf_ext_info_sec *sinfo;
29762993e051SYonghong Song 	const char *info_sec_name;
29772993e051SYonghong Song 	__u64 remain_len;
29782993e051SYonghong Song 	void *data;
29792993e051SYonghong Song 
29803d650141SMartin KaFai Lau 	record_size = ext_info->rec_size;
29813d650141SMartin KaFai Lau 	sinfo = ext_info->info;
29823d650141SMartin KaFai Lau 	remain_len = ext_info->len;
29832993e051SYonghong Song 	while (remain_len > 0) {
29843d650141SMartin KaFai Lau 		records_len = sinfo->num_info * record_size;
29852993e051SYonghong Song 		info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
29862993e051SYonghong Song 		if (strcmp(info_sec_name, sec_name)) {
29872993e051SYonghong Song 			remain_len -= sec_hdrlen + records_len;
29882993e051SYonghong Song 			sinfo = (void *)sinfo + sec_hdrlen + records_len;
29892993e051SYonghong Song 			continue;
29902993e051SYonghong Song 		}
29912993e051SYonghong Song 
29923d650141SMartin KaFai Lau 		existing_len = (*cnt) * record_size;
29933d650141SMartin KaFai Lau 		data = realloc(*info, existing_len + records_len);
29942993e051SYonghong Song 		if (!data)
2995e9fc3ce9SAndrii Nakryiko 			return libbpf_err(-ENOMEM);
29962993e051SYonghong Song 
29973d650141SMartin KaFai Lau 		memcpy(data + existing_len, sinfo->data, records_len);
299884ecc1f9SMartin KaFai Lau 		/* adjust insn_off only, the rest data will be passed
29992993e051SYonghong Song 		 * to the kernel.
30002993e051SYonghong Song 		 */
30013d650141SMartin KaFai Lau 		for (i = 0; i < sinfo->num_info; i++) {
30023d650141SMartin KaFai Lau 			__u32 *insn_off;
30032993e051SYonghong Song 
30043d650141SMartin KaFai Lau 			insn_off = data + existing_len + (i * record_size);
3005e9fc3ce9SAndrii Nakryiko 			*insn_off = *insn_off / sizeof(struct bpf_insn) + insns_cnt;
30062993e051SYonghong Song 		}
30073d650141SMartin KaFai Lau 		*info = data;
30083d650141SMartin KaFai Lau 		*cnt += sinfo->num_info;
30092993e051SYonghong Song 		return 0;
30102993e051SYonghong Song 	}
30112993e051SYonghong Song 
3012e9fc3ce9SAndrii Nakryiko 	return libbpf_err(-ENOENT);
3013f0187f0bSMartin KaFai Lau }
3014f0187f0bSMartin KaFai Lau 
3015ae4ab4b4SAndrii Nakryiko int btf_ext__reloc_func_info(const struct btf *btf,
3016ae4ab4b4SAndrii Nakryiko 			     const struct btf_ext *btf_ext,
30173d650141SMartin KaFai Lau 			     const char *sec_name, __u32 insns_cnt,
30183d650141SMartin KaFai Lau 			     void **func_info, __u32 *cnt)
30193d650141SMartin KaFai Lau {
30203d650141SMartin KaFai Lau 	return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
30213d650141SMartin KaFai Lau 				  insns_cnt, func_info, cnt);
30223d650141SMartin KaFai Lau }
30233d650141SMartin KaFai Lau 
3024ae4ab4b4SAndrii Nakryiko int btf_ext__reloc_line_info(const struct btf *btf,
3025ae4ab4b4SAndrii Nakryiko 			     const struct btf_ext *btf_ext,
30263d650141SMartin KaFai Lau 			     const char *sec_name, __u32 insns_cnt,
30273d650141SMartin KaFai Lau 			     void **line_info, __u32 *cnt)
30283d650141SMartin KaFai Lau {
30293d650141SMartin KaFai Lau 	return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
30303d650141SMartin KaFai Lau 				  insns_cnt, line_info, cnt);
30313d650141SMartin KaFai Lau }
30323d650141SMartin KaFai Lau 
3033f0187f0bSMartin KaFai Lau __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
3034f0187f0bSMartin KaFai Lau {
30353d650141SMartin KaFai Lau 	return btf_ext->func_info.rec_size;
30363d650141SMartin KaFai Lau }
30373d650141SMartin KaFai Lau 
30383d650141SMartin KaFai Lau __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext)
30393d650141SMartin KaFai Lau {
30403d650141SMartin KaFai Lau 	return btf_ext->line_info.rec_size;
30412993e051SYonghong Song }
3042d5caef5bSAndrii Nakryiko 
3043d5caef5bSAndrii Nakryiko struct btf_dedup;
3044d5caef5bSAndrii Nakryiko 
3045957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
3046d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d);
3047f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d);
3048d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d);
3049d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d);
3050d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d);
3051d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d);
3052d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d);
3053d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d);
3054d5caef5bSAndrii Nakryiko 
3055d5caef5bSAndrii Nakryiko /*
3056d5caef5bSAndrii Nakryiko  * Deduplicate BTF types and strings.
3057d5caef5bSAndrii Nakryiko  *
3058d5caef5bSAndrii Nakryiko  * BTF dedup algorithm takes as an input `struct btf` representing `.BTF` ELF
3059d5caef5bSAndrii Nakryiko  * section with all BTF type descriptors and string data. It overwrites that
3060d5caef5bSAndrii Nakryiko  * memory in-place with deduplicated types and strings without any loss of
3061d5caef5bSAndrii Nakryiko  * information. If optional `struct btf_ext` representing '.BTF.ext' ELF section
3062d5caef5bSAndrii Nakryiko  * is provided, all the strings referenced from .BTF.ext section are honored
3063d5caef5bSAndrii Nakryiko  * and updated to point to the right offsets after deduplication.
3064d5caef5bSAndrii Nakryiko  *
3065d5caef5bSAndrii Nakryiko  * If function returns with error, type/string data might be garbled and should
3066d5caef5bSAndrii Nakryiko  * be discarded.
3067d5caef5bSAndrii Nakryiko  *
3068d5caef5bSAndrii Nakryiko  * More verbose and detailed description of both problem btf_dedup is solving,
3069d5caef5bSAndrii Nakryiko  * as well as solution could be found at:
3070d5caef5bSAndrii Nakryiko  * https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html
3071d5caef5bSAndrii Nakryiko  *
3072d5caef5bSAndrii Nakryiko  * Problem description and justification
3073d5caef5bSAndrii Nakryiko  * =====================================
3074d5caef5bSAndrii Nakryiko  *
3075d5caef5bSAndrii Nakryiko  * BTF type information is typically emitted either as a result of conversion
3076d5caef5bSAndrii Nakryiko  * from DWARF to BTF or directly by compiler. In both cases, each compilation
3077d5caef5bSAndrii Nakryiko  * unit contains information about a subset of all the types that are used
3078d5caef5bSAndrii Nakryiko  * in an application. These subsets are frequently overlapping and contain a lot
3079d5caef5bSAndrii Nakryiko  * of duplicated information when later concatenated together into a single
3080d5caef5bSAndrii Nakryiko  * binary. This algorithm ensures that each unique type is represented by single
3081d5caef5bSAndrii Nakryiko  * BTF type descriptor, greatly reducing resulting size of BTF data.
3082d5caef5bSAndrii Nakryiko  *
3083d5caef5bSAndrii Nakryiko  * Compilation unit isolation and subsequent duplication of data is not the only
3084d5caef5bSAndrii Nakryiko  * problem. The same type hierarchy (e.g., struct and all the type that struct
3085d5caef5bSAndrii Nakryiko  * references) in different compilation units can be represented in BTF to
3086d5caef5bSAndrii Nakryiko  * various degrees of completeness (or, rather, incompleteness) due to
3087d5caef5bSAndrii Nakryiko  * struct/union forward declarations.
3088d5caef5bSAndrii Nakryiko  *
3089d5caef5bSAndrii Nakryiko  * Let's take a look at an example, that we'll use to better understand the
3090d5caef5bSAndrii Nakryiko  * problem (and solution). Suppose we have two compilation units, each using
3091d5caef5bSAndrii Nakryiko  * same `struct S`, but each of them having incomplete type information about
3092d5caef5bSAndrii Nakryiko  * struct's fields:
3093d5caef5bSAndrii Nakryiko  *
3094d5caef5bSAndrii Nakryiko  * // CU #1:
3095d5caef5bSAndrii Nakryiko  * struct S;
3096d5caef5bSAndrii Nakryiko  * struct A {
3097d5caef5bSAndrii Nakryiko  *	int a;
3098d5caef5bSAndrii Nakryiko  *	struct A* self;
3099d5caef5bSAndrii Nakryiko  *	struct S* parent;
3100d5caef5bSAndrii Nakryiko  * };
3101d5caef5bSAndrii Nakryiko  * struct B;
3102d5caef5bSAndrii Nakryiko  * struct S {
3103d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
3104d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
3105d5caef5bSAndrii Nakryiko  * };
3106d5caef5bSAndrii Nakryiko  *
3107d5caef5bSAndrii Nakryiko  * // CU #2:
3108d5caef5bSAndrii Nakryiko  * struct S;
3109d5caef5bSAndrii Nakryiko  * struct A;
3110d5caef5bSAndrii Nakryiko  * struct B {
3111d5caef5bSAndrii Nakryiko  *	int b;
3112d5caef5bSAndrii Nakryiko  *	struct B* self;
3113d5caef5bSAndrii Nakryiko  *	struct S* parent;
3114d5caef5bSAndrii Nakryiko  * };
3115d5caef5bSAndrii Nakryiko  * struct S {
3116d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
3117d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
3118d5caef5bSAndrii Nakryiko  * };
3119d5caef5bSAndrii Nakryiko  *
3120d5caef5bSAndrii Nakryiko  * In case of CU #1, BTF data will know only that `struct B` exist (but no
3121d5caef5bSAndrii Nakryiko  * more), but will know the complete type information about `struct A`. While
3122d5caef5bSAndrii Nakryiko  * for CU #2, it will know full type information about `struct B`, but will
3123d5caef5bSAndrii Nakryiko  * only know about forward declaration of `struct A` (in BTF terms, it will
3124d5caef5bSAndrii Nakryiko  * have `BTF_KIND_FWD` type descriptor with name `B`).
3125d5caef5bSAndrii Nakryiko  *
3126d5caef5bSAndrii Nakryiko  * This compilation unit isolation means that it's possible that there is no
3127d5caef5bSAndrii Nakryiko  * single CU with complete type information describing structs `S`, `A`, and
3128d5caef5bSAndrii Nakryiko  * `B`. Also, we might get tons of duplicated and redundant type information.
3129d5caef5bSAndrii Nakryiko  *
3130d5caef5bSAndrii Nakryiko  * Additional complication we need to keep in mind comes from the fact that
3131d5caef5bSAndrii Nakryiko  * types, in general, can form graphs containing cycles, not just DAGs.
3132d5caef5bSAndrii Nakryiko  *
3133d5caef5bSAndrii Nakryiko  * While algorithm does deduplication, it also merges and resolves type
3134d5caef5bSAndrii Nakryiko  * information (unless disabled throught `struct btf_opts`), whenever possible.
3135d5caef5bSAndrii Nakryiko  * E.g., in the example above with two compilation units having partial type
3136d5caef5bSAndrii Nakryiko  * information for structs `A` and `B`, the output of algorithm will emit
3137d5caef5bSAndrii Nakryiko  * a single copy of each BTF type that describes structs `A`, `B`, and `S`
3138d5caef5bSAndrii Nakryiko  * (as well as type information for `int` and pointers), as if they were defined
3139d5caef5bSAndrii Nakryiko  * in a single compilation unit as:
3140d5caef5bSAndrii Nakryiko  *
3141d5caef5bSAndrii Nakryiko  * struct A {
3142d5caef5bSAndrii Nakryiko  *	int a;
3143d5caef5bSAndrii Nakryiko  *	struct A* self;
3144d5caef5bSAndrii Nakryiko  *	struct S* parent;
3145d5caef5bSAndrii Nakryiko  * };
3146d5caef5bSAndrii Nakryiko  * struct B {
3147d5caef5bSAndrii Nakryiko  *	int b;
3148d5caef5bSAndrii Nakryiko  *	struct B* self;
3149d5caef5bSAndrii Nakryiko  *	struct S* parent;
3150d5caef5bSAndrii Nakryiko  * };
3151d5caef5bSAndrii Nakryiko  * struct S {
3152d5caef5bSAndrii Nakryiko  *	struct A* a_ptr;
3153d5caef5bSAndrii Nakryiko  *	struct B* b_ptr;
3154d5caef5bSAndrii Nakryiko  * };
3155d5caef5bSAndrii Nakryiko  *
3156d5caef5bSAndrii Nakryiko  * Algorithm summary
3157d5caef5bSAndrii Nakryiko  * =================
3158d5caef5bSAndrii Nakryiko  *
3159d5caef5bSAndrii Nakryiko  * Algorithm completes its work in 6 separate passes:
3160d5caef5bSAndrii Nakryiko  *
3161d5caef5bSAndrii Nakryiko  * 1. Strings deduplication.
3162d5caef5bSAndrii Nakryiko  * 2. Primitive types deduplication (int, enum, fwd).
3163d5caef5bSAndrii Nakryiko  * 3. Struct/union types deduplication.
3164d5caef5bSAndrii Nakryiko  * 4. Reference types deduplication (pointers, typedefs, arrays, funcs, func
3165d5caef5bSAndrii Nakryiko  *    protos, and const/volatile/restrict modifiers).
3166d5caef5bSAndrii Nakryiko  * 5. Types compaction.
3167d5caef5bSAndrii Nakryiko  * 6. Types remapping.
3168d5caef5bSAndrii Nakryiko  *
3169d5caef5bSAndrii Nakryiko  * Algorithm determines canonical type descriptor, which is a single
3170d5caef5bSAndrii Nakryiko  * representative type for each truly unique type. This canonical type is the
3171d5caef5bSAndrii Nakryiko  * one that will go into final deduplicated BTF type information. For
3172d5caef5bSAndrii Nakryiko  * struct/unions, it is also the type that algorithm will merge additional type
3173d5caef5bSAndrii Nakryiko  * information into (while resolving FWDs), as it discovers it from data in
3174d5caef5bSAndrii Nakryiko  * other CUs. Each input BTF type eventually gets either mapped to itself, if
3175d5caef5bSAndrii Nakryiko  * that type is canonical, or to some other type, if that type is equivalent
3176d5caef5bSAndrii Nakryiko  * and was chosen as canonical representative. This mapping is stored in
3177d5caef5bSAndrii Nakryiko  * `btf_dedup->map` array. This map is also used to record STRUCT/UNION that
3178d5caef5bSAndrii Nakryiko  * FWD type got resolved to.
3179d5caef5bSAndrii Nakryiko  *
3180d5caef5bSAndrii Nakryiko  * To facilitate fast discovery of canonical types, we also maintain canonical
3181d5caef5bSAndrii Nakryiko  * index (`btf_dedup->dedup_table`), which maps type descriptor's signature hash
3182d5caef5bSAndrii Nakryiko  * (i.e., hashed kind, name, size, fields, etc) into a list of canonical types
3183d5caef5bSAndrii Nakryiko  * that match that signature. With sufficiently good choice of type signature
3184d5caef5bSAndrii Nakryiko  * hashing function, we can limit number of canonical types for each unique type
3185d5caef5bSAndrii Nakryiko  * signature to a very small number, allowing to find canonical type for any
3186d5caef5bSAndrii Nakryiko  * duplicated type very quickly.
3187d5caef5bSAndrii Nakryiko  *
3188d5caef5bSAndrii Nakryiko  * Struct/union deduplication is the most critical part and algorithm for
3189d5caef5bSAndrii Nakryiko  * deduplicating structs/unions is described in greater details in comments for
3190d5caef5bSAndrii Nakryiko  * `btf_dedup_is_equiv` function.
3191d5caef5bSAndrii Nakryiko  */
3192957d350aSAndrii Nakryiko 
3193957d350aSAndrii Nakryiko DEFAULT_VERSION(btf__dedup_v0_6_0, btf__dedup, LIBBPF_0.6.0)
3194957d350aSAndrii Nakryiko int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts)
3195d5caef5bSAndrii Nakryiko {
3196957d350aSAndrii Nakryiko 	struct btf_dedup *d;
3197d5caef5bSAndrii Nakryiko 	int err;
3198d5caef5bSAndrii Nakryiko 
3199957d350aSAndrii Nakryiko 	if (!OPTS_VALID(opts, btf_dedup_opts))
3200957d350aSAndrii Nakryiko 		return libbpf_err(-EINVAL);
3201957d350aSAndrii Nakryiko 
3202957d350aSAndrii Nakryiko 	d = btf_dedup_new(btf, opts);
3203d5caef5bSAndrii Nakryiko 	if (IS_ERR(d)) {
3204d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d));
3205e9fc3ce9SAndrii Nakryiko 		return libbpf_err(-EINVAL);
3206d5caef5bSAndrii Nakryiko 	}
3207d5caef5bSAndrii Nakryiko 
32081000298cSMauricio Vásquez 	if (btf_ensure_modifiable(btf)) {
32091000298cSMauricio Vásquez 		err = -ENOMEM;
32101000298cSMauricio Vásquez 		goto done;
32111000298cSMauricio Vásquez 	}
3212919d2b1dSAndrii Nakryiko 
3213f86524efSAndrii Nakryiko 	err = btf_dedup_prep(d);
3214f86524efSAndrii Nakryiko 	if (err) {
3215f86524efSAndrii Nakryiko 		pr_debug("btf_dedup_prep failed:%d\n", err);
3216f86524efSAndrii Nakryiko 		goto done;
3217f86524efSAndrii Nakryiko 	}
3218d5caef5bSAndrii Nakryiko 	err = btf_dedup_strings(d);
3219d5caef5bSAndrii Nakryiko 	if (err < 0) {
3220d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_strings failed:%d\n", err);
3221d5caef5bSAndrii Nakryiko 		goto done;
3222d5caef5bSAndrii Nakryiko 	}
3223d5caef5bSAndrii Nakryiko 	err = btf_dedup_prim_types(d);
3224d5caef5bSAndrii Nakryiko 	if (err < 0) {
3225d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_prim_types failed:%d\n", err);
3226d5caef5bSAndrii Nakryiko 		goto done;
3227d5caef5bSAndrii Nakryiko 	}
3228d5caef5bSAndrii Nakryiko 	err = btf_dedup_struct_types(d);
3229d5caef5bSAndrii Nakryiko 	if (err < 0) {
3230d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_struct_types failed:%d\n", err);
3231d5caef5bSAndrii Nakryiko 		goto done;
3232d5caef5bSAndrii Nakryiko 	}
3233d5caef5bSAndrii Nakryiko 	err = btf_dedup_ref_types(d);
3234d5caef5bSAndrii Nakryiko 	if (err < 0) {
3235d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_ref_types failed:%d\n", err);
3236d5caef5bSAndrii Nakryiko 		goto done;
3237d5caef5bSAndrii Nakryiko 	}
3238d5caef5bSAndrii Nakryiko 	err = btf_dedup_compact_types(d);
3239d5caef5bSAndrii Nakryiko 	if (err < 0) {
3240d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_compact_types failed:%d\n", err);
3241d5caef5bSAndrii Nakryiko 		goto done;
3242d5caef5bSAndrii Nakryiko 	}
3243d5caef5bSAndrii Nakryiko 	err = btf_dedup_remap_types(d);
3244d5caef5bSAndrii Nakryiko 	if (err < 0) {
3245d5caef5bSAndrii Nakryiko 		pr_debug("btf_dedup_remap_types failed:%d\n", err);
3246d5caef5bSAndrii Nakryiko 		goto done;
3247d5caef5bSAndrii Nakryiko 	}
3248d5caef5bSAndrii Nakryiko 
3249d5caef5bSAndrii Nakryiko done:
3250d5caef5bSAndrii Nakryiko 	btf_dedup_free(d);
3251e9fc3ce9SAndrii Nakryiko 	return libbpf_err(err);
3252d5caef5bSAndrii Nakryiko }
3253d5caef5bSAndrii Nakryiko 
3254b69c5c07SVincent Minet COMPAT_VERSION(btf__dedup_deprecated, btf__dedup, LIBBPF_0.0.2)
3255957d350aSAndrii Nakryiko int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *unused_opts)
3256957d350aSAndrii Nakryiko {
3257957d350aSAndrii Nakryiko 	LIBBPF_OPTS(btf_dedup_opts, opts, .btf_ext = btf_ext);
3258957d350aSAndrii Nakryiko 
3259957d350aSAndrii Nakryiko 	if (unused_opts) {
3260957d350aSAndrii Nakryiko 		pr_warn("please use new version of btf__dedup() that supports options\n");
3261957d350aSAndrii Nakryiko 		return libbpf_err(-ENOTSUP);
3262957d350aSAndrii Nakryiko 	}
3263957d350aSAndrii Nakryiko 
3264957d350aSAndrii Nakryiko 	return btf__dedup(btf, &opts);
3265957d350aSAndrii Nakryiko }
3266957d350aSAndrii Nakryiko 
3267d5caef5bSAndrii Nakryiko #define BTF_UNPROCESSED_ID ((__u32)-1)
3268d5caef5bSAndrii Nakryiko #define BTF_IN_PROGRESS_ID ((__u32)-2)
3269d5caef5bSAndrii Nakryiko 
3270d5caef5bSAndrii Nakryiko struct btf_dedup {
3271d5caef5bSAndrii Nakryiko 	/* .BTF section to be deduped in-place */
3272d5caef5bSAndrii Nakryiko 	struct btf *btf;
3273d5caef5bSAndrii Nakryiko 	/*
3274d5caef5bSAndrii Nakryiko 	 * Optional .BTF.ext section. When provided, any strings referenced
3275d5caef5bSAndrii Nakryiko 	 * from it will be taken into account when deduping strings
3276d5caef5bSAndrii Nakryiko 	 */
3277d5caef5bSAndrii Nakryiko 	struct btf_ext *btf_ext;
3278d5caef5bSAndrii Nakryiko 	/*
3279d5caef5bSAndrii Nakryiko 	 * This is a map from any type's signature hash to a list of possible
3280d5caef5bSAndrii Nakryiko 	 * canonical representative type candidates. Hash collisions are
3281d5caef5bSAndrii Nakryiko 	 * ignored, so even types of various kinds can share same list of
3282d5caef5bSAndrii Nakryiko 	 * candidates, which is fine because we rely on subsequent
3283d5caef5bSAndrii Nakryiko 	 * btf_xxx_equal() checks to authoritatively verify type equality.
3284d5caef5bSAndrii Nakryiko 	 */
32852fc3fc0bSAndrii Nakryiko 	struct hashmap *dedup_table;
3286d5caef5bSAndrii Nakryiko 	/* Canonical types map */
3287d5caef5bSAndrii Nakryiko 	__u32 *map;
3288d5caef5bSAndrii Nakryiko 	/* Hypothetical mapping, used during type graph equivalence checks */
3289d5caef5bSAndrii Nakryiko 	__u32 *hypot_map;
3290d5caef5bSAndrii Nakryiko 	__u32 *hypot_list;
3291d5caef5bSAndrii Nakryiko 	size_t hypot_cnt;
3292d5caef5bSAndrii Nakryiko 	size_t hypot_cap;
3293f86524efSAndrii Nakryiko 	/* Whether hypothetical mapping, if successful, would need to adjust
3294f86524efSAndrii Nakryiko 	 * already canonicalized types (due to a new forward declaration to
3295f86524efSAndrii Nakryiko 	 * concrete type resolution). In such case, during split BTF dedup
3296f86524efSAndrii Nakryiko 	 * candidate type would still be considered as different, because base
3297f86524efSAndrii Nakryiko 	 * BTF is considered to be immutable.
3298f86524efSAndrii Nakryiko 	 */
3299f86524efSAndrii Nakryiko 	bool hypot_adjust_canon;
3300d5caef5bSAndrii Nakryiko 	/* Various option modifying behavior of algorithm */
3301d5caef5bSAndrii Nakryiko 	struct btf_dedup_opts opts;
330288a82c2aSAndrii Nakryiko 	/* temporary strings deduplication state */
330390d76d3eSAndrii Nakryiko 	struct strset *strs_set;
3304d5caef5bSAndrii Nakryiko };
3305d5caef5bSAndrii Nakryiko 
33062fc3fc0bSAndrii Nakryiko static long hash_combine(long h, long value)
3307d5caef5bSAndrii Nakryiko {
33082fc3fc0bSAndrii Nakryiko 	return h * 31 + value;
3309d5caef5bSAndrii Nakryiko }
3310d5caef5bSAndrii Nakryiko 
33112fc3fc0bSAndrii Nakryiko #define for_each_dedup_cand(d, node, hash) \
33122fc3fc0bSAndrii Nakryiko 	hashmap__for_each_key_entry(d->dedup_table, node, (void *)hash)
3313d5caef5bSAndrii Nakryiko 
33142fc3fc0bSAndrii Nakryiko static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
3315d5caef5bSAndrii Nakryiko {
33162fc3fc0bSAndrii Nakryiko 	return hashmap__append(d->dedup_table,
33172fc3fc0bSAndrii Nakryiko 			       (void *)hash, (void *)(long)type_id);
3318d5caef5bSAndrii Nakryiko }
3319d5caef5bSAndrii Nakryiko 
3320d5caef5bSAndrii Nakryiko static int btf_dedup_hypot_map_add(struct btf_dedup *d,
3321d5caef5bSAndrii Nakryiko 				   __u32 from_id, __u32 to_id)
3322d5caef5bSAndrii Nakryiko {
3323d5caef5bSAndrii Nakryiko 	if (d->hypot_cnt == d->hypot_cap) {
3324d5caef5bSAndrii Nakryiko 		__u32 *new_list;
3325d5caef5bSAndrii Nakryiko 
3326fb2426adSMartin KaFai Lau 		d->hypot_cap += max((size_t)16, d->hypot_cap / 2);
3327029258d7SAndrii Nakryiko 		new_list = libbpf_reallocarray(d->hypot_list, d->hypot_cap, sizeof(__u32));
3328d5caef5bSAndrii Nakryiko 		if (!new_list)
3329d5caef5bSAndrii Nakryiko 			return -ENOMEM;
3330d5caef5bSAndrii Nakryiko 		d->hypot_list = new_list;
3331d5caef5bSAndrii Nakryiko 	}
3332d5caef5bSAndrii Nakryiko 	d->hypot_list[d->hypot_cnt++] = from_id;
3333d5caef5bSAndrii Nakryiko 	d->hypot_map[from_id] = to_id;
3334d5caef5bSAndrii Nakryiko 	return 0;
3335d5caef5bSAndrii Nakryiko }
3336d5caef5bSAndrii Nakryiko 
3337d5caef5bSAndrii Nakryiko static void btf_dedup_clear_hypot_map(struct btf_dedup *d)
3338d5caef5bSAndrii Nakryiko {
3339d5caef5bSAndrii Nakryiko 	int i;
3340d5caef5bSAndrii Nakryiko 
3341d5caef5bSAndrii Nakryiko 	for (i = 0; i < d->hypot_cnt; i++)
3342d5caef5bSAndrii Nakryiko 		d->hypot_map[d->hypot_list[i]] = BTF_UNPROCESSED_ID;
3343d5caef5bSAndrii Nakryiko 	d->hypot_cnt = 0;
3344f86524efSAndrii Nakryiko 	d->hypot_adjust_canon = false;
3345d5caef5bSAndrii Nakryiko }
3346d5caef5bSAndrii Nakryiko 
3347d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d)
3348d5caef5bSAndrii Nakryiko {
33492fc3fc0bSAndrii Nakryiko 	hashmap__free(d->dedup_table);
33502fc3fc0bSAndrii Nakryiko 	d->dedup_table = NULL;
3351d5caef5bSAndrii Nakryiko 
3352d5caef5bSAndrii Nakryiko 	free(d->map);
3353d5caef5bSAndrii Nakryiko 	d->map = NULL;
3354d5caef5bSAndrii Nakryiko 
3355d5caef5bSAndrii Nakryiko 	free(d->hypot_map);
3356d5caef5bSAndrii Nakryiko 	d->hypot_map = NULL;
3357d5caef5bSAndrii Nakryiko 
3358d5caef5bSAndrii Nakryiko 	free(d->hypot_list);
3359d5caef5bSAndrii Nakryiko 	d->hypot_list = NULL;
3360d5caef5bSAndrii Nakryiko 
3361d5caef5bSAndrii Nakryiko 	free(d);
3362d5caef5bSAndrii Nakryiko }
3363d5caef5bSAndrii Nakryiko 
33642fc3fc0bSAndrii Nakryiko static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx)
336551edf5f6SAndrii Nakryiko {
33662fc3fc0bSAndrii Nakryiko 	return (size_t)key;
336751edf5f6SAndrii Nakryiko }
336851edf5f6SAndrii Nakryiko 
33692fc3fc0bSAndrii Nakryiko static size_t btf_dedup_collision_hash_fn(const void *key, void *ctx)
33702fc3fc0bSAndrii Nakryiko {
33712fc3fc0bSAndrii Nakryiko 	return 0;
33722fc3fc0bSAndrii Nakryiko }
33732fc3fc0bSAndrii Nakryiko 
33742fc3fc0bSAndrii Nakryiko static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx)
33752fc3fc0bSAndrii Nakryiko {
33762fc3fc0bSAndrii Nakryiko 	return k1 == k2;
33772fc3fc0bSAndrii Nakryiko }
337851edf5f6SAndrii Nakryiko 
3379957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts)
3380d5caef5bSAndrii Nakryiko {
3381d5caef5bSAndrii Nakryiko 	struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup));
33822fc3fc0bSAndrii Nakryiko 	hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn;
3383f86524efSAndrii Nakryiko 	int i, err = 0, type_cnt;
3384d5caef5bSAndrii Nakryiko 
3385d5caef5bSAndrii Nakryiko 	if (!d)
3386d5caef5bSAndrii Nakryiko 		return ERR_PTR(-ENOMEM);
3387d5caef5bSAndrii Nakryiko 
3388957d350aSAndrii Nakryiko 	if (OPTS_GET(opts, force_collisions, false))
33892fc3fc0bSAndrii Nakryiko 		hash_fn = btf_dedup_collision_hash_fn;
339051edf5f6SAndrii Nakryiko 
3391d5caef5bSAndrii Nakryiko 	d->btf = btf;
3392957d350aSAndrii Nakryiko 	d->btf_ext = OPTS_GET(opts, btf_ext, NULL);
3393d5caef5bSAndrii Nakryiko 
33942fc3fc0bSAndrii Nakryiko 	d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL);
33952fc3fc0bSAndrii Nakryiko 	if (IS_ERR(d->dedup_table)) {
33962fc3fc0bSAndrii Nakryiko 		err = PTR_ERR(d->dedup_table);
33972fc3fc0bSAndrii Nakryiko 		d->dedup_table = NULL;
3398d5caef5bSAndrii Nakryiko 		goto done;
3399d5caef5bSAndrii Nakryiko 	}
3400d5caef5bSAndrii Nakryiko 
34016a886de0SHengqi Chen 	type_cnt = btf__type_cnt(btf);
3402f86524efSAndrii Nakryiko 	d->map = malloc(sizeof(__u32) * type_cnt);
3403d5caef5bSAndrii Nakryiko 	if (!d->map) {
3404d5caef5bSAndrii Nakryiko 		err = -ENOMEM;
3405d5caef5bSAndrii Nakryiko 		goto done;
3406d5caef5bSAndrii Nakryiko 	}
3407d5caef5bSAndrii Nakryiko 	/* special BTF "void" type is made canonical immediately */
3408d5caef5bSAndrii Nakryiko 	d->map[0] = 0;
3409f86524efSAndrii Nakryiko 	for (i = 1; i < type_cnt; i++) {
3410740e69c3SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, i);
3411189cf5a4SAndrii Nakryiko 
3412189cf5a4SAndrii Nakryiko 		/* VAR and DATASEC are never deduped and are self-canonical */
3413b03bc685SAndrii Nakryiko 		if (btf_is_var(t) || btf_is_datasec(t))
3414189cf5a4SAndrii Nakryiko 			d->map[i] = i;
3415189cf5a4SAndrii Nakryiko 		else
3416d5caef5bSAndrii Nakryiko 			d->map[i] = BTF_UNPROCESSED_ID;
3417189cf5a4SAndrii Nakryiko 	}
3418d5caef5bSAndrii Nakryiko 
3419f86524efSAndrii Nakryiko 	d->hypot_map = malloc(sizeof(__u32) * type_cnt);
3420d5caef5bSAndrii Nakryiko 	if (!d->hypot_map) {
3421d5caef5bSAndrii Nakryiko 		err = -ENOMEM;
3422d5caef5bSAndrii Nakryiko 		goto done;
3423d5caef5bSAndrii Nakryiko 	}
3424f86524efSAndrii Nakryiko 	for (i = 0; i < type_cnt; i++)
3425d5caef5bSAndrii Nakryiko 		d->hypot_map[i] = BTF_UNPROCESSED_ID;
3426d5caef5bSAndrii Nakryiko 
3427d5caef5bSAndrii Nakryiko done:
3428d5caef5bSAndrii Nakryiko 	if (err) {
3429d5caef5bSAndrii Nakryiko 		btf_dedup_free(d);
3430d5caef5bSAndrii Nakryiko 		return ERR_PTR(err);
3431d5caef5bSAndrii Nakryiko 	}
3432d5caef5bSAndrii Nakryiko 
3433d5caef5bSAndrii Nakryiko 	return d;
3434d5caef5bSAndrii Nakryiko }
3435d5caef5bSAndrii Nakryiko 
3436d5caef5bSAndrii Nakryiko /*
3437d5caef5bSAndrii Nakryiko  * Iterate over all possible places in .BTF and .BTF.ext that can reference
3438d5caef5bSAndrii Nakryiko  * string and pass pointer to it to a provided callback `fn`.
3439d5caef5bSAndrii Nakryiko  */
3440f36e99a4SAndrii Nakryiko static int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx)
3441d5caef5bSAndrii Nakryiko {
3442f36e99a4SAndrii Nakryiko 	int i, r;
3443d5caef5bSAndrii Nakryiko 
3444f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
3445f36e99a4SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
3446f36e99a4SAndrii Nakryiko 
3447f36e99a4SAndrii Nakryiko 		r = btf_type_visit_str_offs(t, fn, ctx);
3448d5caef5bSAndrii Nakryiko 		if (r)
3449d5caef5bSAndrii Nakryiko 			return r;
3450d5caef5bSAndrii Nakryiko 	}
3451d5caef5bSAndrii Nakryiko 
3452d5caef5bSAndrii Nakryiko 	if (!d->btf_ext)
3453d5caef5bSAndrii Nakryiko 		return 0;
3454d5caef5bSAndrii Nakryiko 
3455f36e99a4SAndrii Nakryiko 	r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx);
3456d5caef5bSAndrii Nakryiko 	if (r)
3457d5caef5bSAndrii Nakryiko 		return r;
3458d5caef5bSAndrii Nakryiko 
3459d5caef5bSAndrii Nakryiko 	return 0;
3460d5caef5bSAndrii Nakryiko }
3461d5caef5bSAndrii Nakryiko 
346288a82c2aSAndrii Nakryiko static int strs_dedup_remap_str_off(__u32 *str_off_ptr, void *ctx)
3463d5caef5bSAndrii Nakryiko {
346488a82c2aSAndrii Nakryiko 	struct btf_dedup *d = ctx;
3465f86524efSAndrii Nakryiko 	__u32 str_off = *str_off_ptr;
346688a82c2aSAndrii Nakryiko 	const char *s;
346790d76d3eSAndrii Nakryiko 	int off, err;
3468d5caef5bSAndrii Nakryiko 
3469f86524efSAndrii Nakryiko 	/* don't touch empty string or string in main BTF */
3470f86524efSAndrii Nakryiko 	if (str_off == 0 || str_off < d->btf->start_str_off)
3471d5caef5bSAndrii Nakryiko 		return 0;
3472d5caef5bSAndrii Nakryiko 
3473f86524efSAndrii Nakryiko 	s = btf__str_by_offset(d->btf, str_off);
3474f86524efSAndrii Nakryiko 	if (d->btf->base_btf) {
3475f86524efSAndrii Nakryiko 		err = btf__find_str(d->btf->base_btf, s);
3476f86524efSAndrii Nakryiko 		if (err >= 0) {
3477f86524efSAndrii Nakryiko 			*str_off_ptr = err;
3478f86524efSAndrii Nakryiko 			return 0;
3479f86524efSAndrii Nakryiko 		}
3480f86524efSAndrii Nakryiko 		if (err != -ENOENT)
3481f86524efSAndrii Nakryiko 			return err;
3482f86524efSAndrii Nakryiko 	}
3483f86524efSAndrii Nakryiko 
348490d76d3eSAndrii Nakryiko 	off = strset__add_str(d->strs_set, s);
348590d76d3eSAndrii Nakryiko 	if (off < 0)
348690d76d3eSAndrii Nakryiko 		return off;
348788a82c2aSAndrii Nakryiko 
348890d76d3eSAndrii Nakryiko 	*str_off_ptr = d->btf->start_str_off + off;
3489d5caef5bSAndrii Nakryiko 	return 0;
3490d5caef5bSAndrii Nakryiko }
3491d5caef5bSAndrii Nakryiko 
3492d5caef5bSAndrii Nakryiko /*
3493d5caef5bSAndrii Nakryiko  * Dedup string and filter out those that are not referenced from either .BTF
3494d5caef5bSAndrii Nakryiko  * or .BTF.ext (if provided) sections.
3495d5caef5bSAndrii Nakryiko  *
3496d5caef5bSAndrii Nakryiko  * This is done by building index of all strings in BTF's string section,
3497d5caef5bSAndrii Nakryiko  * then iterating over all entities that can reference strings (e.g., type
3498d5caef5bSAndrii Nakryiko  * names, struct field names, .BTF.ext line info, etc) and marking corresponding
3499d5caef5bSAndrii Nakryiko  * strings as used. After that all used strings are deduped and compacted into
3500d5caef5bSAndrii Nakryiko  * sequential blob of memory and new offsets are calculated. Then all the string
3501d5caef5bSAndrii Nakryiko  * references are iterated again and rewritten using new offsets.
3502d5caef5bSAndrii Nakryiko  */
3503d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d)
3504d5caef5bSAndrii Nakryiko {
350588a82c2aSAndrii Nakryiko 	int err;
3506d5caef5bSAndrii Nakryiko 
3507919d2b1dSAndrii Nakryiko 	if (d->btf->strs_deduped)
3508919d2b1dSAndrii Nakryiko 		return 0;
3509919d2b1dSAndrii Nakryiko 
351090d76d3eSAndrii Nakryiko 	d->strs_set = strset__new(BTF_MAX_STR_OFFSET, NULL, 0);
351190d76d3eSAndrii Nakryiko 	if (IS_ERR(d->strs_set)) {
351290d76d3eSAndrii Nakryiko 		err = PTR_ERR(d->strs_set);
351388a82c2aSAndrii Nakryiko 		goto err_out;
3514d5caef5bSAndrii Nakryiko 	}
3515d5caef5bSAndrii Nakryiko 
3516f86524efSAndrii Nakryiko 	if (!d->btf->base_btf) {
351788a82c2aSAndrii Nakryiko 		/* insert empty string; we won't be looking it up during strings
351888a82c2aSAndrii Nakryiko 		 * dedup, but it's good to have it for generic BTF string lookups
351988a82c2aSAndrii Nakryiko 		 */
352090d76d3eSAndrii Nakryiko 		err = strset__add_str(d->strs_set, "");
352190d76d3eSAndrii Nakryiko 		if (err < 0)
352288a82c2aSAndrii Nakryiko 			goto err_out;
3523f86524efSAndrii Nakryiko 	}
3524d5caef5bSAndrii Nakryiko 
3525d5caef5bSAndrii Nakryiko 	/* remap string offsets */
352688a82c2aSAndrii Nakryiko 	err = btf_for_each_str_off(d, strs_dedup_remap_str_off, d);
3527d5caef5bSAndrii Nakryiko 	if (err)
352888a82c2aSAndrii Nakryiko 		goto err_out;
3529d5caef5bSAndrii Nakryiko 
353088a82c2aSAndrii Nakryiko 	/* replace BTF string data and hash with deduped ones */
353190d76d3eSAndrii Nakryiko 	strset__free(d->btf->strs_set);
353290d76d3eSAndrii Nakryiko 	d->btf->hdr->str_len = strset__data_size(d->strs_set);
353390d76d3eSAndrii Nakryiko 	d->btf->strs_set = d->strs_set;
353490d76d3eSAndrii Nakryiko 	d->strs_set = NULL;
3535919d2b1dSAndrii Nakryiko 	d->btf->strs_deduped = true;
353688a82c2aSAndrii Nakryiko 	return 0;
3537d5caef5bSAndrii Nakryiko 
353888a82c2aSAndrii Nakryiko err_out:
353990d76d3eSAndrii Nakryiko 	strset__free(d->strs_set);
354090d76d3eSAndrii Nakryiko 	d->strs_set = NULL;
354188a82c2aSAndrii Nakryiko 
3542d5caef5bSAndrii Nakryiko 	return err;
3543d5caef5bSAndrii Nakryiko }
3544d5caef5bSAndrii Nakryiko 
35452fc3fc0bSAndrii Nakryiko static long btf_hash_common(struct btf_type *t)
3546d5caef5bSAndrii Nakryiko {
35472fc3fc0bSAndrii Nakryiko 	long h;
3548d5caef5bSAndrii Nakryiko 
3549d5caef5bSAndrii Nakryiko 	h = hash_combine(0, t->name_off);
3550d5caef5bSAndrii Nakryiko 	h = hash_combine(h, t->info);
3551d5caef5bSAndrii Nakryiko 	h = hash_combine(h, t->size);
3552d5caef5bSAndrii Nakryiko 	return h;
3553d5caef5bSAndrii Nakryiko }
3554d5caef5bSAndrii Nakryiko 
3555d5caef5bSAndrii Nakryiko static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2)
3556d5caef5bSAndrii Nakryiko {
3557d5caef5bSAndrii Nakryiko 	return t1->name_off == t2->name_off &&
3558d5caef5bSAndrii Nakryiko 	       t1->info == t2->info &&
3559d5caef5bSAndrii Nakryiko 	       t1->size == t2->size;
3560d5caef5bSAndrii Nakryiko }
3561d5caef5bSAndrii Nakryiko 
356230025e8bSYonghong Song /* Calculate type signature hash of INT or TAG. */
3563223f903eSYonghong Song static long btf_hash_int_decl_tag(struct btf_type *t)
3564d5caef5bSAndrii Nakryiko {
3565d5caef5bSAndrii Nakryiko 	__u32 info = *(__u32 *)(t + 1);
35662fc3fc0bSAndrii Nakryiko 	long h;
3567d5caef5bSAndrii Nakryiko 
3568d5caef5bSAndrii Nakryiko 	h = btf_hash_common(t);
3569d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info);
3570d5caef5bSAndrii Nakryiko 	return h;
3571d5caef5bSAndrii Nakryiko }
3572d5caef5bSAndrii Nakryiko 
357330025e8bSYonghong Song /* Check structural equality of two INTs or TAGs. */
357430025e8bSYonghong Song static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
3575d5caef5bSAndrii Nakryiko {
3576d5caef5bSAndrii Nakryiko 	__u32 info1, info2;
3577d5caef5bSAndrii Nakryiko 
3578d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3579d5caef5bSAndrii Nakryiko 		return false;
3580d5caef5bSAndrii Nakryiko 	info1 = *(__u32 *)(t1 + 1);
3581d5caef5bSAndrii Nakryiko 	info2 = *(__u32 *)(t2 + 1);
3582d5caef5bSAndrii Nakryiko 	return info1 == info2;
3583d5caef5bSAndrii Nakryiko }
3584d5caef5bSAndrii Nakryiko 
3585*2ef20263SYonghong Song /* Calculate type signature hash of ENUM/ENUM64. */
35862fc3fc0bSAndrii Nakryiko static long btf_hash_enum(struct btf_type *t)
3587d5caef5bSAndrii Nakryiko {
35882fc3fc0bSAndrii Nakryiko 	long h;
3589d5caef5bSAndrii Nakryiko 
35909768095bSAndrii Nakryiko 	/* don't hash vlen and enum members to support enum fwd resolving */
35919768095bSAndrii Nakryiko 	h = hash_combine(0, t->name_off);
35929768095bSAndrii Nakryiko 	h = hash_combine(h, t->info & ~0xffff);
35939768095bSAndrii Nakryiko 	h = hash_combine(h, t->size);
3594d5caef5bSAndrii Nakryiko 	return h;
3595d5caef5bSAndrii Nakryiko }
3596d5caef5bSAndrii Nakryiko 
3597d5caef5bSAndrii Nakryiko /* Check structural equality of two ENUMs. */
3598d5caef5bSAndrii Nakryiko static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
3599d5caef5bSAndrii Nakryiko {
3600b03bc685SAndrii Nakryiko 	const struct btf_enum *m1, *m2;
3601d5caef5bSAndrii Nakryiko 	__u16 vlen;
3602d5caef5bSAndrii Nakryiko 	int i;
3603d5caef5bSAndrii Nakryiko 
3604d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3605d5caef5bSAndrii Nakryiko 		return false;
3606d5caef5bSAndrii Nakryiko 
3607b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3608b03bc685SAndrii Nakryiko 	m1 = btf_enum(t1);
3609b03bc685SAndrii Nakryiko 	m2 = btf_enum(t2);
3610d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3611d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->val != m2->val)
3612d5caef5bSAndrii Nakryiko 			return false;
3613d5caef5bSAndrii Nakryiko 		m1++;
3614d5caef5bSAndrii Nakryiko 		m2++;
3615d5caef5bSAndrii Nakryiko 	}
3616d5caef5bSAndrii Nakryiko 	return true;
3617d5caef5bSAndrii Nakryiko }
3618d5caef5bSAndrii Nakryiko 
3619*2ef20263SYonghong Song static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
3620*2ef20263SYonghong Song {
3621*2ef20263SYonghong Song 	const struct btf_enum64 *m1, *m2;
3622*2ef20263SYonghong Song 	__u16 vlen;
3623*2ef20263SYonghong Song 	int i;
3624*2ef20263SYonghong Song 
3625*2ef20263SYonghong Song 	if (!btf_equal_common(t1, t2))
3626*2ef20263SYonghong Song 		return false;
3627*2ef20263SYonghong Song 
3628*2ef20263SYonghong Song 	vlen = btf_vlen(t1);
3629*2ef20263SYonghong Song 	m1 = btf_enum64(t1);
3630*2ef20263SYonghong Song 	m2 = btf_enum64(t2);
3631*2ef20263SYonghong Song 	for (i = 0; i < vlen; i++) {
3632*2ef20263SYonghong Song 		if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
3633*2ef20263SYonghong Song 		    m1->val_hi32 != m2->val_hi32)
3634*2ef20263SYonghong Song 			return false;
3635*2ef20263SYonghong Song 		m1++;
3636*2ef20263SYonghong Song 		m2++;
3637*2ef20263SYonghong Song 	}
3638*2ef20263SYonghong Song 	return true;
3639*2ef20263SYonghong Song }
3640*2ef20263SYonghong Song 
36419768095bSAndrii Nakryiko static inline bool btf_is_enum_fwd(struct btf_type *t)
36429768095bSAndrii Nakryiko {
3643*2ef20263SYonghong Song 	return btf_is_any_enum(t) && btf_vlen(t) == 0;
36449768095bSAndrii Nakryiko }
36459768095bSAndrii Nakryiko 
36469768095bSAndrii Nakryiko static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
36479768095bSAndrii Nakryiko {
36489768095bSAndrii Nakryiko 	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
36499768095bSAndrii Nakryiko 		return btf_equal_enum(t1, t2);
36509768095bSAndrii Nakryiko 	/* ignore vlen when comparing */
36519768095bSAndrii Nakryiko 	return t1->name_off == t2->name_off &&
36529768095bSAndrii Nakryiko 	       (t1->info & ~0xffff) == (t2->info & ~0xffff) &&
36539768095bSAndrii Nakryiko 	       t1->size == t2->size;
36549768095bSAndrii Nakryiko }
36559768095bSAndrii Nakryiko 
3656*2ef20263SYonghong Song static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2)
3657*2ef20263SYonghong Song {
3658*2ef20263SYonghong Song 	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
3659*2ef20263SYonghong Song 		return btf_equal_enum64(t1, t2);
3660*2ef20263SYonghong Song 
3661*2ef20263SYonghong Song 	/* ignore vlen when comparing */
3662*2ef20263SYonghong Song 	return t1->name_off == t2->name_off &&
3663*2ef20263SYonghong Song 	       (t1->info & ~0xffff) == (t2->info & ~0xffff) &&
3664*2ef20263SYonghong Song 	       t1->size == t2->size;
3665*2ef20263SYonghong Song }
3666*2ef20263SYonghong Song 
3667d5caef5bSAndrii Nakryiko /*
3668d5caef5bSAndrii Nakryiko  * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
3669d5caef5bSAndrii Nakryiko  * as referenced type IDs equivalence is established separately during type
3670d5caef5bSAndrii Nakryiko  * graph equivalence check algorithm.
3671d5caef5bSAndrii Nakryiko  */
36722fc3fc0bSAndrii Nakryiko static long btf_hash_struct(struct btf_type *t)
3673d5caef5bSAndrii Nakryiko {
3674b03bc685SAndrii Nakryiko 	const struct btf_member *member = btf_members(t);
3675b03bc685SAndrii Nakryiko 	__u32 vlen = btf_vlen(t);
36762fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3677d5caef5bSAndrii Nakryiko 	int i;
3678d5caef5bSAndrii Nakryiko 
3679d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3680d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->name_off);
3681d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->offset);
3682d5caef5bSAndrii Nakryiko 		/* no hashing of referenced type ID, it can be unresolved yet */
3683d5caef5bSAndrii Nakryiko 		member++;
3684d5caef5bSAndrii Nakryiko 	}
3685d5caef5bSAndrii Nakryiko 	return h;
3686d5caef5bSAndrii Nakryiko }
3687d5caef5bSAndrii Nakryiko 
3688d5caef5bSAndrii Nakryiko /*
3689efdd3eb8SAndrii Nakryiko  * Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced
3690efdd3eb8SAndrii Nakryiko  * type IDs. This check is performed during type graph equivalence check and
3691d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3692d5caef5bSAndrii Nakryiko  */
369391097fbeSAndrii Nakryiko static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
3694d5caef5bSAndrii Nakryiko {
3695b03bc685SAndrii Nakryiko 	const struct btf_member *m1, *m2;
3696d5caef5bSAndrii Nakryiko 	__u16 vlen;
3697d5caef5bSAndrii Nakryiko 	int i;
3698d5caef5bSAndrii Nakryiko 
3699d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3700d5caef5bSAndrii Nakryiko 		return false;
3701d5caef5bSAndrii Nakryiko 
3702b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3703b03bc685SAndrii Nakryiko 	m1 = btf_members(t1);
3704b03bc685SAndrii Nakryiko 	m2 = btf_members(t2);
3705d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3706d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
3707d5caef5bSAndrii Nakryiko 			return false;
3708d5caef5bSAndrii Nakryiko 		m1++;
3709d5caef5bSAndrii Nakryiko 		m2++;
3710d5caef5bSAndrii Nakryiko 	}
3711d5caef5bSAndrii Nakryiko 	return true;
3712d5caef5bSAndrii Nakryiko }
3713d5caef5bSAndrii Nakryiko 
3714d5caef5bSAndrii Nakryiko /*
3715d5caef5bSAndrii Nakryiko  * Calculate type signature hash of ARRAY, including referenced type IDs,
3716d5caef5bSAndrii Nakryiko  * under assumption that they were already resolved to canonical type IDs and
3717d5caef5bSAndrii Nakryiko  * are not going to change.
3718d5caef5bSAndrii Nakryiko  */
37192fc3fc0bSAndrii Nakryiko static long btf_hash_array(struct btf_type *t)
3720d5caef5bSAndrii Nakryiko {
3721b03bc685SAndrii Nakryiko 	const struct btf_array *info = btf_array(t);
37222fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3723d5caef5bSAndrii Nakryiko 
3724d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->type);
3725d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->index_type);
3726d5caef5bSAndrii Nakryiko 	h = hash_combine(h, info->nelems);
3727d5caef5bSAndrii Nakryiko 	return h;
3728d5caef5bSAndrii Nakryiko }
3729d5caef5bSAndrii Nakryiko 
3730d5caef5bSAndrii Nakryiko /*
3731d5caef5bSAndrii Nakryiko  * Check exact equality of two ARRAYs, taking into account referenced
3732d5caef5bSAndrii Nakryiko  * type IDs, under assumption that they were already resolved to canonical
3733d5caef5bSAndrii Nakryiko  * type IDs and are not going to change.
3734d5caef5bSAndrii Nakryiko  * This function is called during reference types deduplication to compare
3735d5caef5bSAndrii Nakryiko  * ARRAY to potential canonical representative.
3736d5caef5bSAndrii Nakryiko  */
3737d5caef5bSAndrii Nakryiko static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
3738d5caef5bSAndrii Nakryiko {
3739b03bc685SAndrii Nakryiko 	const struct btf_array *info1, *info2;
3740d5caef5bSAndrii Nakryiko 
3741d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3742d5caef5bSAndrii Nakryiko 		return false;
3743d5caef5bSAndrii Nakryiko 
3744b03bc685SAndrii Nakryiko 	info1 = btf_array(t1);
3745b03bc685SAndrii Nakryiko 	info2 = btf_array(t2);
3746d5caef5bSAndrii Nakryiko 	return info1->type == info2->type &&
3747d5caef5bSAndrii Nakryiko 	       info1->index_type == info2->index_type &&
3748d5caef5bSAndrii Nakryiko 	       info1->nelems == info2->nelems;
3749d5caef5bSAndrii Nakryiko }
3750d5caef5bSAndrii Nakryiko 
3751d5caef5bSAndrii Nakryiko /*
3752d5caef5bSAndrii Nakryiko  * Check structural compatibility of two ARRAYs, ignoring referenced type
3753d5caef5bSAndrii Nakryiko  * IDs. This check is performed during type graph equivalence check and
3754d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3755d5caef5bSAndrii Nakryiko  */
3756d5caef5bSAndrii Nakryiko static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
3757d5caef5bSAndrii Nakryiko {
3758d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3759d5caef5bSAndrii Nakryiko 		return false;
3760d5caef5bSAndrii Nakryiko 
3761b03bc685SAndrii Nakryiko 	return btf_array(t1)->nelems == btf_array(t2)->nelems;
3762d5caef5bSAndrii Nakryiko }
3763d5caef5bSAndrii Nakryiko 
3764d5caef5bSAndrii Nakryiko /*
3765d5caef5bSAndrii Nakryiko  * Calculate type signature hash of FUNC_PROTO, including referenced type IDs,
3766d5caef5bSAndrii Nakryiko  * under assumption that they were already resolved to canonical type IDs and
3767d5caef5bSAndrii Nakryiko  * are not going to change.
3768d5caef5bSAndrii Nakryiko  */
37692fc3fc0bSAndrii Nakryiko static long btf_hash_fnproto(struct btf_type *t)
3770d5caef5bSAndrii Nakryiko {
3771b03bc685SAndrii Nakryiko 	const struct btf_param *member = btf_params(t);
3772b03bc685SAndrii Nakryiko 	__u16 vlen = btf_vlen(t);
37732fc3fc0bSAndrii Nakryiko 	long h = btf_hash_common(t);
3774d5caef5bSAndrii Nakryiko 	int i;
3775d5caef5bSAndrii Nakryiko 
3776d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3777d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->name_off);
3778d5caef5bSAndrii Nakryiko 		h = hash_combine(h, member->type);
3779d5caef5bSAndrii Nakryiko 		member++;
3780d5caef5bSAndrii Nakryiko 	}
3781d5caef5bSAndrii Nakryiko 	return h;
3782d5caef5bSAndrii Nakryiko }
3783d5caef5bSAndrii Nakryiko 
3784d5caef5bSAndrii Nakryiko /*
3785d5caef5bSAndrii Nakryiko  * Check exact equality of two FUNC_PROTOs, taking into account referenced
3786d5caef5bSAndrii Nakryiko  * type IDs, under assumption that they were already resolved to canonical
3787d5caef5bSAndrii Nakryiko  * type IDs and are not going to change.
3788d5caef5bSAndrii Nakryiko  * This function is called during reference types deduplication to compare
3789d5caef5bSAndrii Nakryiko  * FUNC_PROTO to potential canonical representative.
3790d5caef5bSAndrii Nakryiko  */
37912fc3fc0bSAndrii Nakryiko static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
3792d5caef5bSAndrii Nakryiko {
3793b03bc685SAndrii Nakryiko 	const struct btf_param *m1, *m2;
3794d5caef5bSAndrii Nakryiko 	__u16 vlen;
3795d5caef5bSAndrii Nakryiko 	int i;
3796d5caef5bSAndrii Nakryiko 
3797d5caef5bSAndrii Nakryiko 	if (!btf_equal_common(t1, t2))
3798d5caef5bSAndrii Nakryiko 		return false;
3799d5caef5bSAndrii Nakryiko 
3800b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3801b03bc685SAndrii Nakryiko 	m1 = btf_params(t1);
3802b03bc685SAndrii Nakryiko 	m2 = btf_params(t2);
3803d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3804d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off || m1->type != m2->type)
3805d5caef5bSAndrii Nakryiko 			return false;
3806d5caef5bSAndrii Nakryiko 		m1++;
3807d5caef5bSAndrii Nakryiko 		m2++;
3808d5caef5bSAndrii Nakryiko 	}
3809d5caef5bSAndrii Nakryiko 	return true;
3810d5caef5bSAndrii Nakryiko }
3811d5caef5bSAndrii Nakryiko 
3812d5caef5bSAndrii Nakryiko /*
3813d5caef5bSAndrii Nakryiko  * Check structural compatibility of two FUNC_PROTOs, ignoring referenced type
3814d5caef5bSAndrii Nakryiko  * IDs. This check is performed during type graph equivalence check and
3815d5caef5bSAndrii Nakryiko  * referenced types equivalence is checked separately.
3816d5caef5bSAndrii Nakryiko  */
38172fc3fc0bSAndrii Nakryiko static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
3818d5caef5bSAndrii Nakryiko {
3819b03bc685SAndrii Nakryiko 	const struct btf_param *m1, *m2;
3820d5caef5bSAndrii Nakryiko 	__u16 vlen;
3821d5caef5bSAndrii Nakryiko 	int i;
3822d5caef5bSAndrii Nakryiko 
3823d5caef5bSAndrii Nakryiko 	/* skip return type ID */
3824d5caef5bSAndrii Nakryiko 	if (t1->name_off != t2->name_off || t1->info != t2->info)
3825d5caef5bSAndrii Nakryiko 		return false;
3826d5caef5bSAndrii Nakryiko 
3827b03bc685SAndrii Nakryiko 	vlen = btf_vlen(t1);
3828b03bc685SAndrii Nakryiko 	m1 = btf_params(t1);
3829b03bc685SAndrii Nakryiko 	m2 = btf_params(t2);
3830d5caef5bSAndrii Nakryiko 	for (i = 0; i < vlen; i++) {
3831d5caef5bSAndrii Nakryiko 		if (m1->name_off != m2->name_off)
3832d5caef5bSAndrii Nakryiko 			return false;
3833d5caef5bSAndrii Nakryiko 		m1++;
3834d5caef5bSAndrii Nakryiko 		m2++;
3835d5caef5bSAndrii Nakryiko 	}
3836d5caef5bSAndrii Nakryiko 	return true;
3837d5caef5bSAndrii Nakryiko }
3838d5caef5bSAndrii Nakryiko 
3839f86524efSAndrii Nakryiko /* Prepare split BTF for deduplication by calculating hashes of base BTF's
3840f86524efSAndrii Nakryiko  * types and initializing the rest of the state (canonical type mapping) for
3841f86524efSAndrii Nakryiko  * the fixed base BTF part.
3842f86524efSAndrii Nakryiko  */
3843f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d)
3844f86524efSAndrii Nakryiko {
3845f86524efSAndrii Nakryiko 	struct btf_type *t;
3846f86524efSAndrii Nakryiko 	int type_id;
3847f86524efSAndrii Nakryiko 	long h;
3848f86524efSAndrii Nakryiko 
3849f86524efSAndrii Nakryiko 	if (!d->btf->base_btf)
3850f86524efSAndrii Nakryiko 		return 0;
3851f86524efSAndrii Nakryiko 
3852f86524efSAndrii Nakryiko 	for (type_id = 1; type_id < d->btf->start_id; type_id++) {
3853f86524efSAndrii Nakryiko 		t = btf_type_by_id(d->btf, type_id);
3854f86524efSAndrii Nakryiko 
3855f86524efSAndrii Nakryiko 		/* all base BTF types are self-canonical by definition */
3856f86524efSAndrii Nakryiko 		d->map[type_id] = type_id;
3857f86524efSAndrii Nakryiko 
3858f86524efSAndrii Nakryiko 		switch (btf_kind(t)) {
3859f86524efSAndrii Nakryiko 		case BTF_KIND_VAR:
3860f86524efSAndrii Nakryiko 		case BTF_KIND_DATASEC:
3861f86524efSAndrii Nakryiko 			/* VAR and DATASEC are never hash/deduplicated */
3862f86524efSAndrii Nakryiko 			continue;
3863f86524efSAndrii Nakryiko 		case BTF_KIND_CONST:
3864f86524efSAndrii Nakryiko 		case BTF_KIND_VOLATILE:
3865f86524efSAndrii Nakryiko 		case BTF_KIND_RESTRICT:
3866f86524efSAndrii Nakryiko 		case BTF_KIND_PTR:
3867f86524efSAndrii Nakryiko 		case BTF_KIND_FWD:
3868f86524efSAndrii Nakryiko 		case BTF_KIND_TYPEDEF:
3869f86524efSAndrii Nakryiko 		case BTF_KIND_FUNC:
387022541a9eSIlya Leoshkevich 		case BTF_KIND_FLOAT:
38712dc1e488SYonghong Song 		case BTF_KIND_TYPE_TAG:
3872f86524efSAndrii Nakryiko 			h = btf_hash_common(t);
3873f86524efSAndrii Nakryiko 			break;
3874f86524efSAndrii Nakryiko 		case BTF_KIND_INT:
3875223f903eSYonghong Song 		case BTF_KIND_DECL_TAG:
3876223f903eSYonghong Song 			h = btf_hash_int_decl_tag(t);
3877f86524efSAndrii Nakryiko 			break;
3878f86524efSAndrii Nakryiko 		case BTF_KIND_ENUM:
3879*2ef20263SYonghong Song 		case BTF_KIND_ENUM64:
3880f86524efSAndrii Nakryiko 			h = btf_hash_enum(t);
3881f86524efSAndrii Nakryiko 			break;
3882f86524efSAndrii Nakryiko 		case BTF_KIND_STRUCT:
3883f86524efSAndrii Nakryiko 		case BTF_KIND_UNION:
3884f86524efSAndrii Nakryiko 			h = btf_hash_struct(t);
3885f86524efSAndrii Nakryiko 			break;
3886f86524efSAndrii Nakryiko 		case BTF_KIND_ARRAY:
3887f86524efSAndrii Nakryiko 			h = btf_hash_array(t);
3888f86524efSAndrii Nakryiko 			break;
3889f86524efSAndrii Nakryiko 		case BTF_KIND_FUNC_PROTO:
3890f86524efSAndrii Nakryiko 			h = btf_hash_fnproto(t);
3891f86524efSAndrii Nakryiko 			break;
3892f86524efSAndrii Nakryiko 		default:
3893f86524efSAndrii Nakryiko 			pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id);
3894f86524efSAndrii Nakryiko 			return -EINVAL;
3895f86524efSAndrii Nakryiko 		}
3896f86524efSAndrii Nakryiko 		if (btf_dedup_table_add(d, h, type_id))
3897f86524efSAndrii Nakryiko 			return -ENOMEM;
3898f86524efSAndrii Nakryiko 	}
3899f86524efSAndrii Nakryiko 
3900f86524efSAndrii Nakryiko 	return 0;
3901f86524efSAndrii Nakryiko }
3902f86524efSAndrii Nakryiko 
3903d5caef5bSAndrii Nakryiko /*
3904d5caef5bSAndrii Nakryiko  * Deduplicate primitive types, that can't reference other types, by calculating
3905d5caef5bSAndrii Nakryiko  * their type signature hash and comparing them with any possible canonical
3906d5caef5bSAndrii Nakryiko  * candidate. If no canonical candidate matches, type itself is marked as
3907d5caef5bSAndrii Nakryiko  * canonical and is added into `btf_dedup->dedup_table` as another candidate.
3908d5caef5bSAndrii Nakryiko  */
3909d5caef5bSAndrii Nakryiko static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
3910d5caef5bSAndrii Nakryiko {
3911740e69c3SAndrii Nakryiko 	struct btf_type *t = btf_type_by_id(d->btf, type_id);
39122fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
3913d5caef5bSAndrii Nakryiko 	struct btf_type *cand;
3914d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are canonical */
3915d5caef5bSAndrii Nakryiko 	__u32 new_id = type_id;
39162fc3fc0bSAndrii Nakryiko 	__u32 cand_id;
39172fc3fc0bSAndrii Nakryiko 	long h;
3918d5caef5bSAndrii Nakryiko 
3919b03bc685SAndrii Nakryiko 	switch (btf_kind(t)) {
3920d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
3921d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
3922d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
3923d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
3924d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
3925d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY:
3926d5caef5bSAndrii Nakryiko 	case BTF_KIND_STRUCT:
3927d5caef5bSAndrii Nakryiko 	case BTF_KIND_UNION:
3928d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
3929d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO:
3930189cf5a4SAndrii Nakryiko 	case BTF_KIND_VAR:
3931189cf5a4SAndrii Nakryiko 	case BTF_KIND_DATASEC:
3932223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
39332dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
3934d5caef5bSAndrii Nakryiko 		return 0;
3935d5caef5bSAndrii Nakryiko 
3936d5caef5bSAndrii Nakryiko 	case BTF_KIND_INT:
3937223f903eSYonghong Song 		h = btf_hash_int_decl_tag(t);
39382fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
39392fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
3940740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
394130025e8bSYonghong Song 			if (btf_equal_int_tag(t, cand)) {
39422fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3943d5caef5bSAndrii Nakryiko 				break;
3944d5caef5bSAndrii Nakryiko 			}
3945d5caef5bSAndrii Nakryiko 		}
3946d5caef5bSAndrii Nakryiko 		break;
3947d5caef5bSAndrii Nakryiko 
3948d5caef5bSAndrii Nakryiko 	case BTF_KIND_ENUM:
3949d5caef5bSAndrii Nakryiko 		h = btf_hash_enum(t);
39502fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
39512fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
3952740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
3953d5caef5bSAndrii Nakryiko 			if (btf_equal_enum(t, cand)) {
39542fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3955d5caef5bSAndrii Nakryiko 				break;
3956d5caef5bSAndrii Nakryiko 			}
39579768095bSAndrii Nakryiko 			if (btf_compat_enum(t, cand)) {
39589768095bSAndrii Nakryiko 				if (btf_is_enum_fwd(t)) {
39599768095bSAndrii Nakryiko 					/* resolve fwd to full enum */
39602fc3fc0bSAndrii Nakryiko 					new_id = cand_id;
39619768095bSAndrii Nakryiko 					break;
39629768095bSAndrii Nakryiko 				}
39639768095bSAndrii Nakryiko 				/* resolve canonical enum fwd to full enum */
39642fc3fc0bSAndrii Nakryiko 				d->map[cand_id] = type_id;
39659768095bSAndrii Nakryiko 			}
3966d5caef5bSAndrii Nakryiko 		}
3967d5caef5bSAndrii Nakryiko 		break;
3968d5caef5bSAndrii Nakryiko 
3969*2ef20263SYonghong Song 	case BTF_KIND_ENUM64:
3970*2ef20263SYonghong Song 		h = btf_hash_enum(t);
3971*2ef20263SYonghong Song 		for_each_dedup_cand(d, hash_entry, h) {
3972*2ef20263SYonghong Song 			cand_id = (__u32)(long)hash_entry->value;
3973*2ef20263SYonghong Song 			cand = btf_type_by_id(d->btf, cand_id);
3974*2ef20263SYonghong Song 			if (btf_equal_enum64(t, cand)) {
3975*2ef20263SYonghong Song 				new_id = cand_id;
3976*2ef20263SYonghong Song 				break;
3977*2ef20263SYonghong Song 			}
3978*2ef20263SYonghong Song 			if (btf_compat_enum64(t, cand)) {
3979*2ef20263SYonghong Song 				if (btf_is_enum_fwd(t)) {
3980*2ef20263SYonghong Song 					/* resolve fwd to full enum */
3981*2ef20263SYonghong Song 					new_id = cand_id;
3982*2ef20263SYonghong Song 					break;
3983*2ef20263SYonghong Song 				}
3984*2ef20263SYonghong Song 				/* resolve canonical enum fwd to full enum */
3985*2ef20263SYonghong Song 				d->map[cand_id] = type_id;
3986*2ef20263SYonghong Song 			}
3987*2ef20263SYonghong Song 		}
3988*2ef20263SYonghong Song 		break;
3989*2ef20263SYonghong Song 
3990d5caef5bSAndrii Nakryiko 	case BTF_KIND_FWD:
399122541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
3992d5caef5bSAndrii Nakryiko 		h = btf_hash_common(t);
39932fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
39942fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
3995740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
3996d5caef5bSAndrii Nakryiko 			if (btf_equal_common(t, cand)) {
39972fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
3998d5caef5bSAndrii Nakryiko 				break;
3999d5caef5bSAndrii Nakryiko 			}
4000d5caef5bSAndrii Nakryiko 		}
4001d5caef5bSAndrii Nakryiko 		break;
4002d5caef5bSAndrii Nakryiko 
4003d5caef5bSAndrii Nakryiko 	default:
4004d5caef5bSAndrii Nakryiko 		return -EINVAL;
4005d5caef5bSAndrii Nakryiko 	}
4006d5caef5bSAndrii Nakryiko 
4007d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
4008d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
4009d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4010d5caef5bSAndrii Nakryiko 
4011d5caef5bSAndrii Nakryiko 	return 0;
4012d5caef5bSAndrii Nakryiko }
4013d5caef5bSAndrii Nakryiko 
4014d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d)
4015d5caef5bSAndrii Nakryiko {
4016d5caef5bSAndrii Nakryiko 	int i, err;
4017d5caef5bSAndrii Nakryiko 
4018f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4019f86524efSAndrii Nakryiko 		err = btf_dedup_prim_type(d, d->btf->start_id + i);
4020d5caef5bSAndrii Nakryiko 		if (err)
4021d5caef5bSAndrii Nakryiko 			return err;
4022d5caef5bSAndrii Nakryiko 	}
4023d5caef5bSAndrii Nakryiko 	return 0;
4024d5caef5bSAndrii Nakryiko }
4025d5caef5bSAndrii Nakryiko 
4026d5caef5bSAndrii Nakryiko /*
4027d5caef5bSAndrii Nakryiko  * Check whether type is already mapped into canonical one (could be to itself).
4028d5caef5bSAndrii Nakryiko  */
4029d5caef5bSAndrii Nakryiko static inline bool is_type_mapped(struct btf_dedup *d, uint32_t type_id)
4030d5caef5bSAndrii Nakryiko {
40315aab392cSAndrii Nakryiko 	return d->map[type_id] <= BTF_MAX_NR_TYPES;
4032d5caef5bSAndrii Nakryiko }
4033d5caef5bSAndrii Nakryiko 
4034d5caef5bSAndrii Nakryiko /*
4035d5caef5bSAndrii Nakryiko  * Resolve type ID into its canonical type ID, if any; otherwise return original
4036d5caef5bSAndrii Nakryiko  * type ID. If type is FWD and is resolved into STRUCT/UNION already, follow
4037d5caef5bSAndrii Nakryiko  * STRUCT/UNION link and resolve it into canonical type ID as well.
4038d5caef5bSAndrii Nakryiko  */
4039d5caef5bSAndrii Nakryiko static inline __u32 resolve_type_id(struct btf_dedup *d, __u32 type_id)
4040d5caef5bSAndrii Nakryiko {
4041d5caef5bSAndrii Nakryiko 	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
4042d5caef5bSAndrii Nakryiko 		type_id = d->map[type_id];
4043d5caef5bSAndrii Nakryiko 	return type_id;
4044d5caef5bSAndrii Nakryiko }
4045d5caef5bSAndrii Nakryiko 
4046d5caef5bSAndrii Nakryiko /*
4047d5caef5bSAndrii Nakryiko  * Resolve FWD to underlying STRUCT/UNION, if any; otherwise return original
4048d5caef5bSAndrii Nakryiko  * type ID.
4049d5caef5bSAndrii Nakryiko  */
4050d5caef5bSAndrii Nakryiko static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
4051d5caef5bSAndrii Nakryiko {
4052d5caef5bSAndrii Nakryiko 	__u32 orig_type_id = type_id;
4053d5caef5bSAndrii Nakryiko 
4054740e69c3SAndrii Nakryiko 	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
4055d5caef5bSAndrii Nakryiko 		return type_id;
4056d5caef5bSAndrii Nakryiko 
4057d5caef5bSAndrii Nakryiko 	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
4058d5caef5bSAndrii Nakryiko 		type_id = d->map[type_id];
4059d5caef5bSAndrii Nakryiko 
4060740e69c3SAndrii Nakryiko 	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
4061d5caef5bSAndrii Nakryiko 		return type_id;
4062d5caef5bSAndrii Nakryiko 
4063d5caef5bSAndrii Nakryiko 	return orig_type_id;
4064d5caef5bSAndrii Nakryiko }
4065d5caef5bSAndrii Nakryiko 
4066d5caef5bSAndrii Nakryiko 
4067d5caef5bSAndrii Nakryiko static inline __u16 btf_fwd_kind(struct btf_type *t)
4068d5caef5bSAndrii Nakryiko {
4069b03bc685SAndrii Nakryiko 	return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
4070d5caef5bSAndrii Nakryiko }
4071d5caef5bSAndrii Nakryiko 
40726b6e6b1dSAndrii Nakryiko /* Check if given two types are identical ARRAY definitions */
40736b6e6b1dSAndrii Nakryiko static int btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
40746b6e6b1dSAndrii Nakryiko {
40756b6e6b1dSAndrii Nakryiko 	struct btf_type *t1, *t2;
40766b6e6b1dSAndrii Nakryiko 
40776b6e6b1dSAndrii Nakryiko 	t1 = btf_type_by_id(d->btf, id1);
40786b6e6b1dSAndrii Nakryiko 	t2 = btf_type_by_id(d->btf, id2);
40796b6e6b1dSAndrii Nakryiko 	if (!btf_is_array(t1) || !btf_is_array(t2))
40806b6e6b1dSAndrii Nakryiko 		return 0;
40816b6e6b1dSAndrii Nakryiko 
40826b6e6b1dSAndrii Nakryiko 	return btf_equal_array(t1, t2);
40836b6e6b1dSAndrii Nakryiko }
40846b6e6b1dSAndrii Nakryiko 
4085efdd3eb8SAndrii Nakryiko /* Check if given two types are identical STRUCT/UNION definitions */
4086efdd3eb8SAndrii Nakryiko static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2)
4087efdd3eb8SAndrii Nakryiko {
4088efdd3eb8SAndrii Nakryiko 	const struct btf_member *m1, *m2;
4089efdd3eb8SAndrii Nakryiko 	struct btf_type *t1, *t2;
4090efdd3eb8SAndrii Nakryiko 	int n, i;
4091efdd3eb8SAndrii Nakryiko 
4092efdd3eb8SAndrii Nakryiko 	t1 = btf_type_by_id(d->btf, id1);
4093efdd3eb8SAndrii Nakryiko 	t2 = btf_type_by_id(d->btf, id2);
4094efdd3eb8SAndrii Nakryiko 
4095efdd3eb8SAndrii Nakryiko 	if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2))
4096efdd3eb8SAndrii Nakryiko 		return false;
4097efdd3eb8SAndrii Nakryiko 
4098efdd3eb8SAndrii Nakryiko 	if (!btf_shallow_equal_struct(t1, t2))
4099efdd3eb8SAndrii Nakryiko 		return false;
4100efdd3eb8SAndrii Nakryiko 
4101efdd3eb8SAndrii Nakryiko 	m1 = btf_members(t1);
4102efdd3eb8SAndrii Nakryiko 	m2 = btf_members(t2);
4103efdd3eb8SAndrii Nakryiko 	for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
4104efdd3eb8SAndrii Nakryiko 		if (m1->type != m2->type)
4105efdd3eb8SAndrii Nakryiko 			return false;
4106efdd3eb8SAndrii Nakryiko 	}
4107efdd3eb8SAndrii Nakryiko 	return true;
4108efdd3eb8SAndrii Nakryiko }
4109efdd3eb8SAndrii Nakryiko 
4110d5caef5bSAndrii Nakryiko /*
4111d5caef5bSAndrii Nakryiko  * Check equivalence of BTF type graph formed by candidate struct/union (we'll
4112d5caef5bSAndrii Nakryiko  * call it "candidate graph" in this description for brevity) to a type graph
4113d5caef5bSAndrii Nakryiko  * formed by (potential) canonical struct/union ("canonical graph" for brevity
4114d5caef5bSAndrii Nakryiko  * here, though keep in mind that not all types in canonical graph are
4115d5caef5bSAndrii Nakryiko  * necessarily canonical representatives themselves, some of them might be
4116d5caef5bSAndrii Nakryiko  * duplicates or its uniqueness might not have been established yet).
4117d5caef5bSAndrii Nakryiko  * Returns:
4118d5caef5bSAndrii Nakryiko  *  - >0, if type graphs are equivalent;
4119d5caef5bSAndrii Nakryiko  *  -  0, if not equivalent;
4120d5caef5bSAndrii Nakryiko  *  - <0, on error.
4121d5caef5bSAndrii Nakryiko  *
4122d5caef5bSAndrii Nakryiko  * Algorithm performs side-by-side DFS traversal of both type graphs and checks
4123d5caef5bSAndrii Nakryiko  * equivalence of BTF types at each step. If at any point BTF types in candidate
4124d5caef5bSAndrii Nakryiko  * and canonical graphs are not compatible structurally, whole graphs are
4125d5caef5bSAndrii Nakryiko  * incompatible. If types are structurally equivalent (i.e., all information
4126d5caef5bSAndrii Nakryiko  * except referenced type IDs is exactly the same), a mapping from `canon_id` to
4127d5caef5bSAndrii Nakryiko  * a `cand_id` is recored in hypothetical mapping (`btf_dedup->hypot_map`).
4128d5caef5bSAndrii Nakryiko  * If a type references other types, then those referenced types are checked
4129d5caef5bSAndrii Nakryiko  * for equivalence recursively.
4130d5caef5bSAndrii Nakryiko  *
4131d5caef5bSAndrii Nakryiko  * During DFS traversal, if we find that for current `canon_id` type we
4132d5caef5bSAndrii Nakryiko  * already have some mapping in hypothetical map, we check for two possible
4133d5caef5bSAndrii Nakryiko  * situations:
4134d5caef5bSAndrii Nakryiko  *   - `canon_id` is mapped to exactly the same type as `cand_id`. This will
4135d5caef5bSAndrii Nakryiko  *     happen when type graphs have cycles. In this case we assume those two
4136d5caef5bSAndrii Nakryiko  *     types are equivalent.
4137d5caef5bSAndrii Nakryiko  *   - `canon_id` is mapped to different type. This is contradiction in our
4138d5caef5bSAndrii Nakryiko  *     hypothetical mapping, because same graph in canonical graph corresponds
4139d5caef5bSAndrii Nakryiko  *     to two different types in candidate graph, which for equivalent type
4140d5caef5bSAndrii Nakryiko  *     graphs shouldn't happen. This condition terminates equivalence check
4141d5caef5bSAndrii Nakryiko  *     with negative result.
4142d5caef5bSAndrii Nakryiko  *
4143d5caef5bSAndrii Nakryiko  * If type graphs traversal exhausts types to check and find no contradiction,
4144d5caef5bSAndrii Nakryiko  * then type graphs are equivalent.
4145d5caef5bSAndrii Nakryiko  *
4146d5caef5bSAndrii Nakryiko  * When checking types for equivalence, there is one special case: FWD types.
4147d5caef5bSAndrii Nakryiko  * If FWD type resolution is allowed and one of the types (either from canonical
4148d5caef5bSAndrii Nakryiko  * or candidate graph) is FWD and other is STRUCT/UNION (depending on FWD's kind
4149d5caef5bSAndrii Nakryiko  * flag) and their names match, hypothetical mapping is updated to point from
4150d5caef5bSAndrii Nakryiko  * FWD to STRUCT/UNION. If graphs will be determined as equivalent successfully,
4151d5caef5bSAndrii Nakryiko  * this mapping will be used to record FWD -> STRUCT/UNION mapping permanently.
4152d5caef5bSAndrii Nakryiko  *
4153d5caef5bSAndrii Nakryiko  * Technically, this could lead to incorrect FWD to STRUCT/UNION resolution,
4154d5caef5bSAndrii Nakryiko  * if there are two exactly named (or anonymous) structs/unions that are
4155d5caef5bSAndrii Nakryiko  * compatible structurally, one of which has FWD field, while other is concrete
4156d5caef5bSAndrii Nakryiko  * STRUCT/UNION, but according to C sources they are different structs/unions
4157d5caef5bSAndrii Nakryiko  * that are referencing different types with the same name. This is extremely
4158d5caef5bSAndrii Nakryiko  * unlikely to happen, but btf_dedup API allows to disable FWD resolution if
4159d5caef5bSAndrii Nakryiko  * this logic is causing problems.
4160d5caef5bSAndrii Nakryiko  *
4161d5caef5bSAndrii Nakryiko  * Doing FWD resolution means that both candidate and/or canonical graphs can
4162d5caef5bSAndrii Nakryiko  * consists of portions of the graph that come from multiple compilation units.
4163d5caef5bSAndrii Nakryiko  * This is due to the fact that types within single compilation unit are always
4164d5caef5bSAndrii Nakryiko  * deduplicated and FWDs are already resolved, if referenced struct/union
4165d5caef5bSAndrii Nakryiko  * definiton is available. So, if we had unresolved FWD and found corresponding
4166d5caef5bSAndrii Nakryiko  * STRUCT/UNION, they will be from different compilation units. This
4167d5caef5bSAndrii Nakryiko  * consequently means that when we "link" FWD to corresponding STRUCT/UNION,
4168d5caef5bSAndrii Nakryiko  * type graph will likely have at least two different BTF types that describe
4169d5caef5bSAndrii Nakryiko  * same type (e.g., most probably there will be two different BTF types for the
4170d5caef5bSAndrii Nakryiko  * same 'int' primitive type) and could even have "overlapping" parts of type
4171d5caef5bSAndrii Nakryiko  * graph that describe same subset of types.
4172d5caef5bSAndrii Nakryiko  *
4173d5caef5bSAndrii Nakryiko  * This in turn means that our assumption that each type in canonical graph
4174d5caef5bSAndrii Nakryiko  * must correspond to exactly one type in candidate graph might not hold
4175d5caef5bSAndrii Nakryiko  * anymore and will make it harder to detect contradictions using hypothetical
4176d5caef5bSAndrii Nakryiko  * map. To handle this problem, we allow to follow FWD -> STRUCT/UNION
4177d5caef5bSAndrii Nakryiko  * resolution only in canonical graph. FWDs in candidate graphs are never
4178d5caef5bSAndrii Nakryiko  * resolved. To see why it's OK, let's check all possible situations w.r.t. FWDs
4179d5caef5bSAndrii Nakryiko  * that can occur:
4180d5caef5bSAndrii Nakryiko  *   - Both types in canonical and candidate graphs are FWDs. If they are
4181d5caef5bSAndrii Nakryiko  *     structurally equivalent, then they can either be both resolved to the
4182d5caef5bSAndrii Nakryiko  *     same STRUCT/UNION or not resolved at all. In both cases they are
4183d5caef5bSAndrii Nakryiko  *     equivalent and there is no need to resolve FWD on candidate side.
4184d5caef5bSAndrii Nakryiko  *   - Both types in canonical and candidate graphs are concrete STRUCT/UNION,
4185d5caef5bSAndrii Nakryiko  *     so nothing to resolve as well, algorithm will check equivalence anyway.
4186d5caef5bSAndrii Nakryiko  *   - Type in canonical graph is FWD, while type in candidate is concrete
4187d5caef5bSAndrii Nakryiko  *     STRUCT/UNION. In this case candidate graph comes from single compilation
4188d5caef5bSAndrii Nakryiko  *     unit, so there is exactly one BTF type for each unique C type. After
4189d5caef5bSAndrii Nakryiko  *     resolving FWD into STRUCT/UNION, there might be more than one BTF type
4190d5caef5bSAndrii Nakryiko  *     in canonical graph mapping to single BTF type in candidate graph, but
4191d5caef5bSAndrii Nakryiko  *     because hypothetical mapping maps from canonical to candidate types, it's
4192d5caef5bSAndrii Nakryiko  *     alright, and we still maintain the property of having single `canon_id`
4193d5caef5bSAndrii Nakryiko  *     mapping to single `cand_id` (there could be two different `canon_id`
4194d5caef5bSAndrii Nakryiko  *     mapped to the same `cand_id`, but it's not contradictory).
4195d5caef5bSAndrii Nakryiko  *   - Type in canonical graph is concrete STRUCT/UNION, while type in candidate
4196d5caef5bSAndrii Nakryiko  *     graph is FWD. In this case we are just going to check compatibility of
4197d5caef5bSAndrii Nakryiko  *     STRUCT/UNION and corresponding FWD, and if they are compatible, we'll
4198d5caef5bSAndrii Nakryiko  *     assume that whatever STRUCT/UNION FWD resolves to must be equivalent to
4199d5caef5bSAndrii Nakryiko  *     a concrete STRUCT/UNION from canonical graph. If the rest of type graphs
4200d5caef5bSAndrii Nakryiko  *     turn out equivalent, we'll re-resolve FWD to concrete STRUCT/UNION from
4201d5caef5bSAndrii Nakryiko  *     canonical graph.
4202d5caef5bSAndrii Nakryiko  */
4203d5caef5bSAndrii Nakryiko static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
4204d5caef5bSAndrii Nakryiko 			      __u32 canon_id)
4205d5caef5bSAndrii Nakryiko {
4206d5caef5bSAndrii Nakryiko 	struct btf_type *cand_type;
4207d5caef5bSAndrii Nakryiko 	struct btf_type *canon_type;
4208d5caef5bSAndrii Nakryiko 	__u32 hypot_type_id;
4209d5caef5bSAndrii Nakryiko 	__u16 cand_kind;
4210d5caef5bSAndrii Nakryiko 	__u16 canon_kind;
4211d5caef5bSAndrii Nakryiko 	int i, eq;
4212d5caef5bSAndrii Nakryiko 
4213d5caef5bSAndrii Nakryiko 	/* if both resolve to the same canonical, they must be equivalent */
4214d5caef5bSAndrii Nakryiko 	if (resolve_type_id(d, cand_id) == resolve_type_id(d, canon_id))
4215d5caef5bSAndrii Nakryiko 		return 1;
4216d5caef5bSAndrii Nakryiko 
4217d5caef5bSAndrii Nakryiko 	canon_id = resolve_fwd_id(d, canon_id);
4218d5caef5bSAndrii Nakryiko 
4219d5caef5bSAndrii Nakryiko 	hypot_type_id = d->hypot_map[canon_id];
42206b6e6b1dSAndrii Nakryiko 	if (hypot_type_id <= BTF_MAX_NR_TYPES) {
4221efdd3eb8SAndrii Nakryiko 		if (hypot_type_id == cand_id)
4222efdd3eb8SAndrii Nakryiko 			return 1;
42236b6e6b1dSAndrii Nakryiko 		/* In some cases compiler will generate different DWARF types
42246b6e6b1dSAndrii Nakryiko 		 * for *identical* array type definitions and use them for
42256b6e6b1dSAndrii Nakryiko 		 * different fields within the *same* struct. This breaks type
42266b6e6b1dSAndrii Nakryiko 		 * equivalence check, which makes an assumption that candidate
42276b6e6b1dSAndrii Nakryiko 		 * types sub-graph has a consistent and deduped-by-compiler
42286b6e6b1dSAndrii Nakryiko 		 * types within a single CU. So work around that by explicitly
42296b6e6b1dSAndrii Nakryiko 		 * allowing identical array types here.
42306b6e6b1dSAndrii Nakryiko 		 */
4231efdd3eb8SAndrii Nakryiko 		if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id))
4232efdd3eb8SAndrii Nakryiko 			return 1;
4233efdd3eb8SAndrii Nakryiko 		/* It turns out that similar situation can happen with
4234efdd3eb8SAndrii Nakryiko 		 * struct/union sometimes, sigh... Handle the case where
4235efdd3eb8SAndrii Nakryiko 		 * structs/unions are exactly the same, down to the referenced
4236efdd3eb8SAndrii Nakryiko 		 * type IDs. Anything more complicated (e.g., if referenced
4237efdd3eb8SAndrii Nakryiko 		 * types are different, but equivalent) is *way more*
4238efdd3eb8SAndrii Nakryiko 		 * complicated and requires a many-to-many equivalence mapping.
4239efdd3eb8SAndrii Nakryiko 		 */
4240efdd3eb8SAndrii Nakryiko 		if (btf_dedup_identical_structs(d, hypot_type_id, cand_id))
4241efdd3eb8SAndrii Nakryiko 			return 1;
4242efdd3eb8SAndrii Nakryiko 		return 0;
42436b6e6b1dSAndrii Nakryiko 	}
4244d5caef5bSAndrii Nakryiko 
4245d5caef5bSAndrii Nakryiko 	if (btf_dedup_hypot_map_add(d, canon_id, cand_id))
4246d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4247d5caef5bSAndrii Nakryiko 
4248740e69c3SAndrii Nakryiko 	cand_type = btf_type_by_id(d->btf, cand_id);
4249740e69c3SAndrii Nakryiko 	canon_type = btf_type_by_id(d->btf, canon_id);
4250b03bc685SAndrii Nakryiko 	cand_kind = btf_kind(cand_type);
4251b03bc685SAndrii Nakryiko 	canon_kind = btf_kind(canon_type);
4252d5caef5bSAndrii Nakryiko 
4253d5caef5bSAndrii Nakryiko 	if (cand_type->name_off != canon_type->name_off)
4254d5caef5bSAndrii Nakryiko 		return 0;
4255d5caef5bSAndrii Nakryiko 
4256d5caef5bSAndrii Nakryiko 	/* FWD <--> STRUCT/UNION equivalence check, if enabled */
4257957d350aSAndrii Nakryiko 	if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
4258d5caef5bSAndrii Nakryiko 	    && cand_kind != canon_kind) {
4259d5caef5bSAndrii Nakryiko 		__u16 real_kind;
4260d5caef5bSAndrii Nakryiko 		__u16 fwd_kind;
4261d5caef5bSAndrii Nakryiko 
4262d5caef5bSAndrii Nakryiko 		if (cand_kind == BTF_KIND_FWD) {
4263d5caef5bSAndrii Nakryiko 			real_kind = canon_kind;
4264d5caef5bSAndrii Nakryiko 			fwd_kind = btf_fwd_kind(cand_type);
4265d5caef5bSAndrii Nakryiko 		} else {
4266d5caef5bSAndrii Nakryiko 			real_kind = cand_kind;
4267d5caef5bSAndrii Nakryiko 			fwd_kind = btf_fwd_kind(canon_type);
4268f86524efSAndrii Nakryiko 			/* we'd need to resolve base FWD to STRUCT/UNION */
4269f86524efSAndrii Nakryiko 			if (fwd_kind == real_kind && canon_id < d->btf->start_id)
4270f86524efSAndrii Nakryiko 				d->hypot_adjust_canon = true;
4271d5caef5bSAndrii Nakryiko 		}
4272d5caef5bSAndrii Nakryiko 		return fwd_kind == real_kind;
4273d5caef5bSAndrii Nakryiko 	}
4274d5caef5bSAndrii Nakryiko 
42759ec71c1cSAndrii Nakryiko 	if (cand_kind != canon_kind)
42769ec71c1cSAndrii Nakryiko 		return 0;
42779ec71c1cSAndrii Nakryiko 
4278d5caef5bSAndrii Nakryiko 	switch (cand_kind) {
4279d5caef5bSAndrii Nakryiko 	case BTF_KIND_INT:
428030025e8bSYonghong Song 		return btf_equal_int_tag(cand_type, canon_type);
4281d5caef5bSAndrii Nakryiko 
4282d5caef5bSAndrii Nakryiko 	case BTF_KIND_ENUM:
42839768095bSAndrii Nakryiko 		return btf_compat_enum(cand_type, canon_type);
4284d5caef5bSAndrii Nakryiko 
4285*2ef20263SYonghong Song 	case BTF_KIND_ENUM64:
4286*2ef20263SYonghong Song 		return btf_compat_enum64(cand_type, canon_type);
4287*2ef20263SYonghong Song 
4288d5caef5bSAndrii Nakryiko 	case BTF_KIND_FWD:
428922541a9eSIlya Leoshkevich 	case BTF_KIND_FLOAT:
4290d5caef5bSAndrii Nakryiko 		return btf_equal_common(cand_type, canon_type);
4291d5caef5bSAndrii Nakryiko 
4292d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
4293d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4294d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4295d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
4296d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4297d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
429869a055d5SYonghong Song 	case BTF_KIND_TYPE_TAG:
42999768095bSAndrii Nakryiko 		if (cand_type->info != canon_type->info)
43009768095bSAndrii Nakryiko 			return 0;
4301d5caef5bSAndrii Nakryiko 		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
4302d5caef5bSAndrii Nakryiko 
4303d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4304b03bc685SAndrii Nakryiko 		const struct btf_array *cand_arr, *canon_arr;
4305d5caef5bSAndrii Nakryiko 
4306d5caef5bSAndrii Nakryiko 		if (!btf_compat_array(cand_type, canon_type))
4307d5caef5bSAndrii Nakryiko 			return 0;
4308b03bc685SAndrii Nakryiko 		cand_arr = btf_array(cand_type);
4309b03bc685SAndrii Nakryiko 		canon_arr = btf_array(canon_type);
4310f86524efSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, cand_arr->index_type, canon_arr->index_type);
4311d5caef5bSAndrii Nakryiko 		if (eq <= 0)
4312d5caef5bSAndrii Nakryiko 			return eq;
4313d5caef5bSAndrii Nakryiko 		return btf_dedup_is_equiv(d, cand_arr->type, canon_arr->type);
4314d5caef5bSAndrii Nakryiko 	}
4315d5caef5bSAndrii Nakryiko 
4316d5caef5bSAndrii Nakryiko 	case BTF_KIND_STRUCT:
4317d5caef5bSAndrii Nakryiko 	case BTF_KIND_UNION: {
4318b03bc685SAndrii Nakryiko 		const struct btf_member *cand_m, *canon_m;
4319d5caef5bSAndrii Nakryiko 		__u16 vlen;
4320d5caef5bSAndrii Nakryiko 
432191097fbeSAndrii Nakryiko 		if (!btf_shallow_equal_struct(cand_type, canon_type))
4322d5caef5bSAndrii Nakryiko 			return 0;
4323b03bc685SAndrii Nakryiko 		vlen = btf_vlen(cand_type);
4324b03bc685SAndrii Nakryiko 		cand_m = btf_members(cand_type);
4325b03bc685SAndrii Nakryiko 		canon_m = btf_members(canon_type);
4326d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4327d5caef5bSAndrii Nakryiko 			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
4328d5caef5bSAndrii Nakryiko 			if (eq <= 0)
4329d5caef5bSAndrii Nakryiko 				return eq;
4330d5caef5bSAndrii Nakryiko 			cand_m++;
4331d5caef5bSAndrii Nakryiko 			canon_m++;
4332d5caef5bSAndrii Nakryiko 		}
4333d5caef5bSAndrii Nakryiko 
4334d5caef5bSAndrii Nakryiko 		return 1;
4335d5caef5bSAndrii Nakryiko 	}
4336d5caef5bSAndrii Nakryiko 
4337d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4338b03bc685SAndrii Nakryiko 		const struct btf_param *cand_p, *canon_p;
4339d5caef5bSAndrii Nakryiko 		__u16 vlen;
4340d5caef5bSAndrii Nakryiko 
4341d5caef5bSAndrii Nakryiko 		if (!btf_compat_fnproto(cand_type, canon_type))
4342d5caef5bSAndrii Nakryiko 			return 0;
4343d5caef5bSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
4344d5caef5bSAndrii Nakryiko 		if (eq <= 0)
4345d5caef5bSAndrii Nakryiko 			return eq;
4346b03bc685SAndrii Nakryiko 		vlen = btf_vlen(cand_type);
4347b03bc685SAndrii Nakryiko 		cand_p = btf_params(cand_type);
4348b03bc685SAndrii Nakryiko 		canon_p = btf_params(canon_type);
4349d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4350d5caef5bSAndrii Nakryiko 			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
4351d5caef5bSAndrii Nakryiko 			if (eq <= 0)
4352d5caef5bSAndrii Nakryiko 				return eq;
4353d5caef5bSAndrii Nakryiko 			cand_p++;
4354d5caef5bSAndrii Nakryiko 			canon_p++;
4355d5caef5bSAndrii Nakryiko 		}
4356d5caef5bSAndrii Nakryiko 		return 1;
4357d5caef5bSAndrii Nakryiko 	}
4358d5caef5bSAndrii Nakryiko 
4359d5caef5bSAndrii Nakryiko 	default:
4360d5caef5bSAndrii Nakryiko 		return -EINVAL;
4361d5caef5bSAndrii Nakryiko 	}
4362d5caef5bSAndrii Nakryiko 	return 0;
4363d5caef5bSAndrii Nakryiko }
4364d5caef5bSAndrii Nakryiko 
4365d5caef5bSAndrii Nakryiko /*
4366d5caef5bSAndrii Nakryiko  * Use hypothetical mapping, produced by successful type graph equivalence
4367d5caef5bSAndrii Nakryiko  * check, to augment existing struct/union canonical mapping, where possible.
4368d5caef5bSAndrii Nakryiko  *
4369d5caef5bSAndrii Nakryiko  * If BTF_KIND_FWD resolution is allowed, this mapping is also used to record
4370d5caef5bSAndrii Nakryiko  * FWD -> STRUCT/UNION correspondence as well. FWD resolution is bidirectional:
4371d5caef5bSAndrii Nakryiko  * it doesn't matter if FWD type was part of canonical graph or candidate one,
4372d5caef5bSAndrii Nakryiko  * we are recording the mapping anyway. As opposed to carefulness required
4373d5caef5bSAndrii Nakryiko  * for struct/union correspondence mapping (described below), for FWD resolution
4374d5caef5bSAndrii Nakryiko  * it's not important, as by the time that FWD type (reference type) will be
4375d5caef5bSAndrii Nakryiko  * deduplicated all structs/unions will be deduped already anyway.
4376d5caef5bSAndrii Nakryiko  *
4377d5caef5bSAndrii Nakryiko  * Recording STRUCT/UNION mapping is purely a performance optimization and is
4378d5caef5bSAndrii Nakryiko  * not required for correctness. It needs to be done carefully to ensure that
4379d5caef5bSAndrii Nakryiko  * struct/union from candidate's type graph is not mapped into corresponding
4380d5caef5bSAndrii Nakryiko  * struct/union from canonical type graph that itself hasn't been resolved into
4381d5caef5bSAndrii Nakryiko  * canonical representative. The only guarantee we have is that canonical
4382d5caef5bSAndrii Nakryiko  * struct/union was determined as canonical and that won't change. But any
4383d5caef5bSAndrii Nakryiko  * types referenced through that struct/union fields could have been not yet
4384d5caef5bSAndrii Nakryiko  * resolved, so in case like that it's too early to establish any kind of
4385d5caef5bSAndrii Nakryiko  * correspondence between structs/unions.
4386d5caef5bSAndrii Nakryiko  *
4387d5caef5bSAndrii Nakryiko  * No canonical correspondence is derived for primitive types (they are already
4388d5caef5bSAndrii Nakryiko  * deduplicated completely already anyway) or reference types (they rely on
4389d5caef5bSAndrii Nakryiko  * stability of struct/union canonical relationship for equivalence checks).
4390d5caef5bSAndrii Nakryiko  */
4391d5caef5bSAndrii Nakryiko static void btf_dedup_merge_hypot_map(struct btf_dedup *d)
4392d5caef5bSAndrii Nakryiko {
4393f86524efSAndrii Nakryiko 	__u32 canon_type_id, targ_type_id;
4394d5caef5bSAndrii Nakryiko 	__u16 t_kind, c_kind;
4395d5caef5bSAndrii Nakryiko 	__u32 t_id, c_id;
4396d5caef5bSAndrii Nakryiko 	int i;
4397d5caef5bSAndrii Nakryiko 
4398d5caef5bSAndrii Nakryiko 	for (i = 0; i < d->hypot_cnt; i++) {
4399f86524efSAndrii Nakryiko 		canon_type_id = d->hypot_list[i];
4400f86524efSAndrii Nakryiko 		targ_type_id = d->hypot_map[canon_type_id];
4401d5caef5bSAndrii Nakryiko 		t_id = resolve_type_id(d, targ_type_id);
4402f86524efSAndrii Nakryiko 		c_id = resolve_type_id(d, canon_type_id);
4403740e69c3SAndrii Nakryiko 		t_kind = btf_kind(btf__type_by_id(d->btf, t_id));
4404740e69c3SAndrii Nakryiko 		c_kind = btf_kind(btf__type_by_id(d->btf, c_id));
4405d5caef5bSAndrii Nakryiko 		/*
4406d5caef5bSAndrii Nakryiko 		 * Resolve FWD into STRUCT/UNION.
4407d5caef5bSAndrii Nakryiko 		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
4408d5caef5bSAndrii Nakryiko 		 * mapped to canonical representative (as opposed to
4409d5caef5bSAndrii Nakryiko 		 * STRUCT/UNION <--> STRUCT/UNION mapping logic below), because
4410d5caef5bSAndrii Nakryiko 		 * eventually that struct is going to be mapped and all resolved
4411d5caef5bSAndrii Nakryiko 		 * FWDs will automatically resolve to correct canonical
4412d5caef5bSAndrii Nakryiko 		 * representative. This will happen before ref type deduping,
4413d5caef5bSAndrii Nakryiko 		 * which critically depends on stability of these mapping. This
4414d5caef5bSAndrii Nakryiko 		 * stability is not a requirement for STRUCT/UNION equivalence
4415d5caef5bSAndrii Nakryiko 		 * checks, though.
4416d5caef5bSAndrii Nakryiko 		 */
4417f86524efSAndrii Nakryiko 
4418f86524efSAndrii Nakryiko 		/* if it's the split BTF case, we still need to point base FWD
4419f86524efSAndrii Nakryiko 		 * to STRUCT/UNION in a split BTF, because FWDs from split BTF
4420f86524efSAndrii Nakryiko 		 * will be resolved against base FWD. If we don't point base
4421f86524efSAndrii Nakryiko 		 * canonical FWD to the resolved STRUCT/UNION, then all the
4422f86524efSAndrii Nakryiko 		 * FWDs in split BTF won't be correctly resolved to a proper
4423f86524efSAndrii Nakryiko 		 * STRUCT/UNION.
4424f86524efSAndrii Nakryiko 		 */
4425d5caef5bSAndrii Nakryiko 		if (t_kind != BTF_KIND_FWD && c_kind == BTF_KIND_FWD)
4426d5caef5bSAndrii Nakryiko 			d->map[c_id] = t_id;
4427f86524efSAndrii Nakryiko 
4428f86524efSAndrii Nakryiko 		/* if graph equivalence determined that we'd need to adjust
4429f86524efSAndrii Nakryiko 		 * base canonical types, then we need to only point base FWDs
4430f86524efSAndrii Nakryiko 		 * to STRUCTs/UNIONs and do no more modifications. For all
4431f86524efSAndrii Nakryiko 		 * other purposes the type graphs were not equivalent.
4432f86524efSAndrii Nakryiko 		 */
4433f86524efSAndrii Nakryiko 		if (d->hypot_adjust_canon)
4434f86524efSAndrii Nakryiko 			continue;
4435f86524efSAndrii Nakryiko 
4436f86524efSAndrii Nakryiko 		if (t_kind == BTF_KIND_FWD && c_kind != BTF_KIND_FWD)
4437d5caef5bSAndrii Nakryiko 			d->map[t_id] = c_id;
4438d5caef5bSAndrii Nakryiko 
4439d5caef5bSAndrii Nakryiko 		if ((t_kind == BTF_KIND_STRUCT || t_kind == BTF_KIND_UNION) &&
4440d5caef5bSAndrii Nakryiko 		    c_kind != BTF_KIND_FWD &&
4441d5caef5bSAndrii Nakryiko 		    is_type_mapped(d, c_id) &&
4442d5caef5bSAndrii Nakryiko 		    !is_type_mapped(d, t_id)) {
4443d5caef5bSAndrii Nakryiko 			/*
4444d5caef5bSAndrii Nakryiko 			 * as a perf optimization, we can map struct/union
4445d5caef5bSAndrii Nakryiko 			 * that's part of type graph we just verified for
4446d5caef5bSAndrii Nakryiko 			 * equivalence. We can do that for struct/union that has
4447d5caef5bSAndrii Nakryiko 			 * canonical representative only, though.
4448d5caef5bSAndrii Nakryiko 			 */
4449d5caef5bSAndrii Nakryiko 			d->map[t_id] = c_id;
4450d5caef5bSAndrii Nakryiko 		}
4451d5caef5bSAndrii Nakryiko 	}
4452d5caef5bSAndrii Nakryiko }
4453d5caef5bSAndrii Nakryiko 
4454d5caef5bSAndrii Nakryiko /*
4455d5caef5bSAndrii Nakryiko  * Deduplicate struct/union types.
4456d5caef5bSAndrii Nakryiko  *
4457d5caef5bSAndrii Nakryiko  * For each struct/union type its type signature hash is calculated, taking
4458d5caef5bSAndrii Nakryiko  * into account type's name, size, number, order and names of fields, but
4459d5caef5bSAndrii Nakryiko  * ignoring type ID's referenced from fields, because they might not be deduped
4460d5caef5bSAndrii Nakryiko  * completely until after reference types deduplication phase. This type hash
4461d5caef5bSAndrii Nakryiko  * is used to iterate over all potential canonical types, sharing same hash.
4462d5caef5bSAndrii Nakryiko  * For each canonical candidate we check whether type graphs that they form
4463d5caef5bSAndrii Nakryiko  * (through referenced types in fields and so on) are equivalent using algorithm
4464d5caef5bSAndrii Nakryiko  * implemented in `btf_dedup_is_equiv`. If such equivalence is found and
4465d5caef5bSAndrii Nakryiko  * BTF_KIND_FWD resolution is allowed, then hypothetical mapping
4466d5caef5bSAndrii Nakryiko  * (btf_dedup->hypot_map) produced by aforementioned type graph equivalence
4467d5caef5bSAndrii Nakryiko  * algorithm is used to record FWD -> STRUCT/UNION mapping. It's also used to
4468d5caef5bSAndrii Nakryiko  * potentially map other structs/unions to their canonical representatives,
4469d5caef5bSAndrii Nakryiko  * if such relationship hasn't yet been established. This speeds up algorithm
4470d5caef5bSAndrii Nakryiko  * by eliminating some of the duplicate work.
4471d5caef5bSAndrii Nakryiko  *
4472d5caef5bSAndrii Nakryiko  * If no matching canonical representative was found, struct/union is marked
4473d5caef5bSAndrii Nakryiko  * as canonical for itself and is added into btf_dedup->dedup_table hash map
4474d5caef5bSAndrii Nakryiko  * for further look ups.
4475d5caef5bSAndrii Nakryiko  */
4476d5caef5bSAndrii Nakryiko static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
4477d5caef5bSAndrii Nakryiko {
447891097fbeSAndrii Nakryiko 	struct btf_type *cand_type, *t;
44792fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
4480d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are canonical */
4481d5caef5bSAndrii Nakryiko 	__u32 new_id = type_id;
4482d5caef5bSAndrii Nakryiko 	__u16 kind;
44832fc3fc0bSAndrii Nakryiko 	long h;
4484d5caef5bSAndrii Nakryiko 
4485d5caef5bSAndrii Nakryiko 	/* already deduped or is in process of deduping (loop detected) */
44865aab392cSAndrii Nakryiko 	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
4487d5caef5bSAndrii Nakryiko 		return 0;
4488d5caef5bSAndrii Nakryiko 
4489740e69c3SAndrii Nakryiko 	t = btf_type_by_id(d->btf, type_id);
4490b03bc685SAndrii Nakryiko 	kind = btf_kind(t);
4491d5caef5bSAndrii Nakryiko 
4492d5caef5bSAndrii Nakryiko 	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
4493d5caef5bSAndrii Nakryiko 		return 0;
4494d5caef5bSAndrii Nakryiko 
4495d5caef5bSAndrii Nakryiko 	h = btf_hash_struct(t);
44962fc3fc0bSAndrii Nakryiko 	for_each_dedup_cand(d, hash_entry, h) {
44972fc3fc0bSAndrii Nakryiko 		__u32 cand_id = (__u32)(long)hash_entry->value;
4498d5caef5bSAndrii Nakryiko 		int eq;
4499d5caef5bSAndrii Nakryiko 
450091097fbeSAndrii Nakryiko 		/*
450191097fbeSAndrii Nakryiko 		 * Even though btf_dedup_is_equiv() checks for
450291097fbeSAndrii Nakryiko 		 * btf_shallow_equal_struct() internally when checking two
450391097fbeSAndrii Nakryiko 		 * structs (unions) for equivalence, we need to guard here
450491097fbeSAndrii Nakryiko 		 * from picking matching FWD type as a dedup candidate.
450591097fbeSAndrii Nakryiko 		 * This can happen due to hash collision. In such case just
450691097fbeSAndrii Nakryiko 		 * relying on btf_dedup_is_equiv() would lead to potentially
450791097fbeSAndrii Nakryiko 		 * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because
450891097fbeSAndrii Nakryiko 		 * FWD and compatible STRUCT/UNION are considered equivalent.
450991097fbeSAndrii Nakryiko 		 */
4510740e69c3SAndrii Nakryiko 		cand_type = btf_type_by_id(d->btf, cand_id);
451191097fbeSAndrii Nakryiko 		if (!btf_shallow_equal_struct(t, cand_type))
451291097fbeSAndrii Nakryiko 			continue;
451391097fbeSAndrii Nakryiko 
4514d5caef5bSAndrii Nakryiko 		btf_dedup_clear_hypot_map(d);
45152fc3fc0bSAndrii Nakryiko 		eq = btf_dedup_is_equiv(d, type_id, cand_id);
4516d5caef5bSAndrii Nakryiko 		if (eq < 0)
4517d5caef5bSAndrii Nakryiko 			return eq;
4518d5caef5bSAndrii Nakryiko 		if (!eq)
4519d5caef5bSAndrii Nakryiko 			continue;
4520d5caef5bSAndrii Nakryiko 		btf_dedup_merge_hypot_map(d);
4521f86524efSAndrii Nakryiko 		if (d->hypot_adjust_canon) /* not really equivalent */
4522f86524efSAndrii Nakryiko 			continue;
4523f86524efSAndrii Nakryiko 		new_id = cand_id;
4524d5caef5bSAndrii Nakryiko 		break;
4525d5caef5bSAndrii Nakryiko 	}
4526d5caef5bSAndrii Nakryiko 
4527d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
4528d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
4529d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4530d5caef5bSAndrii Nakryiko 
4531d5caef5bSAndrii Nakryiko 	return 0;
4532d5caef5bSAndrii Nakryiko }
4533d5caef5bSAndrii Nakryiko 
4534d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d)
4535d5caef5bSAndrii Nakryiko {
4536d5caef5bSAndrii Nakryiko 	int i, err;
4537d5caef5bSAndrii Nakryiko 
4538f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4539f86524efSAndrii Nakryiko 		err = btf_dedup_struct_type(d, d->btf->start_id + i);
4540d5caef5bSAndrii Nakryiko 		if (err)
4541d5caef5bSAndrii Nakryiko 			return err;
4542d5caef5bSAndrii Nakryiko 	}
4543d5caef5bSAndrii Nakryiko 	return 0;
4544d5caef5bSAndrii Nakryiko }
4545d5caef5bSAndrii Nakryiko 
4546d5caef5bSAndrii Nakryiko /*
4547d5caef5bSAndrii Nakryiko  * Deduplicate reference type.
4548d5caef5bSAndrii Nakryiko  *
4549d5caef5bSAndrii Nakryiko  * Once all primitive and struct/union types got deduplicated, we can easily
4550d5caef5bSAndrii Nakryiko  * deduplicate all other (reference) BTF types. This is done in two steps:
4551d5caef5bSAndrii Nakryiko  *
4552d5caef5bSAndrii Nakryiko  * 1. Resolve all referenced type IDs into their canonical type IDs. This
4553d5caef5bSAndrii Nakryiko  * resolution can be done either immediately for primitive or struct/union types
4554d5caef5bSAndrii Nakryiko  * (because they were deduped in previous two phases) or recursively for
4555d5caef5bSAndrii Nakryiko  * reference types. Recursion will always terminate at either primitive or
4556d5caef5bSAndrii Nakryiko  * struct/union type, at which point we can "unwind" chain of reference types
4557d5caef5bSAndrii Nakryiko  * one by one. There is no danger of encountering cycles because in C type
4558d5caef5bSAndrii Nakryiko  * system the only way to form type cycle is through struct/union, so any chain
4559d5caef5bSAndrii Nakryiko  * of reference types, even those taking part in a type cycle, will inevitably
4560d5caef5bSAndrii Nakryiko  * reach struct/union at some point.
4561d5caef5bSAndrii Nakryiko  *
4562d5caef5bSAndrii Nakryiko  * 2. Once all referenced type IDs are resolved into canonical ones, BTF type
4563d5caef5bSAndrii Nakryiko  * becomes "stable", in the sense that no further deduplication will cause
4564d5caef5bSAndrii Nakryiko  * any changes to it. With that, it's now possible to calculate type's signature
4565d5caef5bSAndrii Nakryiko  * hash (this time taking into account referenced type IDs) and loop over all
4566d5caef5bSAndrii Nakryiko  * potential canonical representatives. If no match was found, current type
4567d5caef5bSAndrii Nakryiko  * will become canonical representative of itself and will be added into
4568d5caef5bSAndrii Nakryiko  * btf_dedup->dedup_table as another possible canonical representative.
4569d5caef5bSAndrii Nakryiko  */
4570d5caef5bSAndrii Nakryiko static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
4571d5caef5bSAndrii Nakryiko {
45722fc3fc0bSAndrii Nakryiko 	struct hashmap_entry *hash_entry;
45732fc3fc0bSAndrii Nakryiko 	__u32 new_id = type_id, cand_id;
4574d5caef5bSAndrii Nakryiko 	struct btf_type *t, *cand;
4575d5caef5bSAndrii Nakryiko 	/* if we don't find equivalent type, then we are representative type */
45763d8669e6SDan Carpenter 	int ref_type_id;
45772fc3fc0bSAndrii Nakryiko 	long h;
4578d5caef5bSAndrii Nakryiko 
4579d5caef5bSAndrii Nakryiko 	if (d->map[type_id] == BTF_IN_PROGRESS_ID)
4580d5caef5bSAndrii Nakryiko 		return -ELOOP;
45815aab392cSAndrii Nakryiko 	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
4582d5caef5bSAndrii Nakryiko 		return resolve_type_id(d, type_id);
4583d5caef5bSAndrii Nakryiko 
4584740e69c3SAndrii Nakryiko 	t = btf_type_by_id(d->btf, type_id);
4585d5caef5bSAndrii Nakryiko 	d->map[type_id] = BTF_IN_PROGRESS_ID;
4586d5caef5bSAndrii Nakryiko 
4587b03bc685SAndrii Nakryiko 	switch (btf_kind(t)) {
4588d5caef5bSAndrii Nakryiko 	case BTF_KIND_CONST:
4589d5caef5bSAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4590d5caef5bSAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4591d5caef5bSAndrii Nakryiko 	case BTF_KIND_PTR:
4592d5caef5bSAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4593d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC:
45942dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
4595d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, t->type);
4596d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4597d5caef5bSAndrii Nakryiko 			return ref_type_id;
4598d5caef5bSAndrii Nakryiko 		t->type = ref_type_id;
4599d5caef5bSAndrii Nakryiko 
4600d5caef5bSAndrii Nakryiko 		h = btf_hash_common(t);
46012fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
46022fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
4603740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4604d5caef5bSAndrii Nakryiko 			if (btf_equal_common(t, cand)) {
46052fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4606d5caef5bSAndrii Nakryiko 				break;
4607d5caef5bSAndrii Nakryiko 			}
4608d5caef5bSAndrii Nakryiko 		}
4609d5caef5bSAndrii Nakryiko 		break;
4610d5caef5bSAndrii Nakryiko 
4611223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
46125b84bd10SYonghong Song 		ref_type_id = btf_dedup_ref_type(d, t->type);
46135b84bd10SYonghong Song 		if (ref_type_id < 0)
46145b84bd10SYonghong Song 			return ref_type_id;
46155b84bd10SYonghong Song 		t->type = ref_type_id;
46165b84bd10SYonghong Song 
4617223f903eSYonghong Song 		h = btf_hash_int_decl_tag(t);
46185b84bd10SYonghong Song 		for_each_dedup_cand(d, hash_entry, h) {
46195b84bd10SYonghong Song 			cand_id = (__u32)(long)hash_entry->value;
46205b84bd10SYonghong Song 			cand = btf_type_by_id(d->btf, cand_id);
46215b84bd10SYonghong Song 			if (btf_equal_int_tag(t, cand)) {
46225b84bd10SYonghong Song 				new_id = cand_id;
46235b84bd10SYonghong Song 				break;
46245b84bd10SYonghong Song 			}
46255b84bd10SYonghong Song 		}
46265b84bd10SYonghong Song 		break;
46275b84bd10SYonghong Song 
4628d5caef5bSAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4629b03bc685SAndrii Nakryiko 		struct btf_array *info = btf_array(t);
4630d5caef5bSAndrii Nakryiko 
4631d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, info->type);
4632d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4633d5caef5bSAndrii Nakryiko 			return ref_type_id;
4634d5caef5bSAndrii Nakryiko 		info->type = ref_type_id;
4635d5caef5bSAndrii Nakryiko 
4636d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, info->index_type);
4637d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4638d5caef5bSAndrii Nakryiko 			return ref_type_id;
4639d5caef5bSAndrii Nakryiko 		info->index_type = ref_type_id;
4640d5caef5bSAndrii Nakryiko 
4641d5caef5bSAndrii Nakryiko 		h = btf_hash_array(t);
46422fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
46432fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
4644740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4645d5caef5bSAndrii Nakryiko 			if (btf_equal_array(t, cand)) {
46462fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4647d5caef5bSAndrii Nakryiko 				break;
4648d5caef5bSAndrii Nakryiko 			}
4649d5caef5bSAndrii Nakryiko 		}
4650d5caef5bSAndrii Nakryiko 		break;
4651d5caef5bSAndrii Nakryiko 	}
4652d5caef5bSAndrii Nakryiko 
4653d5caef5bSAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4654d5caef5bSAndrii Nakryiko 		struct btf_param *param;
4655d5caef5bSAndrii Nakryiko 		__u16 vlen;
4656d5caef5bSAndrii Nakryiko 		int i;
4657d5caef5bSAndrii Nakryiko 
4658d5caef5bSAndrii Nakryiko 		ref_type_id = btf_dedup_ref_type(d, t->type);
4659d5caef5bSAndrii Nakryiko 		if (ref_type_id < 0)
4660d5caef5bSAndrii Nakryiko 			return ref_type_id;
4661d5caef5bSAndrii Nakryiko 		t->type = ref_type_id;
4662d5caef5bSAndrii Nakryiko 
4663b03bc685SAndrii Nakryiko 		vlen = btf_vlen(t);
4664b03bc685SAndrii Nakryiko 		param = btf_params(t);
4665d5caef5bSAndrii Nakryiko 		for (i = 0; i < vlen; i++) {
4666d5caef5bSAndrii Nakryiko 			ref_type_id = btf_dedup_ref_type(d, param->type);
4667d5caef5bSAndrii Nakryiko 			if (ref_type_id < 0)
4668d5caef5bSAndrii Nakryiko 				return ref_type_id;
4669d5caef5bSAndrii Nakryiko 			param->type = ref_type_id;
4670d5caef5bSAndrii Nakryiko 			param++;
4671d5caef5bSAndrii Nakryiko 		}
4672d5caef5bSAndrii Nakryiko 
4673d5caef5bSAndrii Nakryiko 		h = btf_hash_fnproto(t);
46742fc3fc0bSAndrii Nakryiko 		for_each_dedup_cand(d, hash_entry, h) {
46752fc3fc0bSAndrii Nakryiko 			cand_id = (__u32)(long)hash_entry->value;
4676740e69c3SAndrii Nakryiko 			cand = btf_type_by_id(d->btf, cand_id);
4677d5caef5bSAndrii Nakryiko 			if (btf_equal_fnproto(t, cand)) {
46782fc3fc0bSAndrii Nakryiko 				new_id = cand_id;
4679d5caef5bSAndrii Nakryiko 				break;
4680d5caef5bSAndrii Nakryiko 			}
4681d5caef5bSAndrii Nakryiko 		}
4682d5caef5bSAndrii Nakryiko 		break;
4683d5caef5bSAndrii Nakryiko 	}
4684d5caef5bSAndrii Nakryiko 
4685d5caef5bSAndrii Nakryiko 	default:
4686d5caef5bSAndrii Nakryiko 		return -EINVAL;
4687d5caef5bSAndrii Nakryiko 	}
4688d5caef5bSAndrii Nakryiko 
4689d5caef5bSAndrii Nakryiko 	d->map[type_id] = new_id;
4690d5caef5bSAndrii Nakryiko 	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
4691d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4692d5caef5bSAndrii Nakryiko 
4693d5caef5bSAndrii Nakryiko 	return new_id;
4694d5caef5bSAndrii Nakryiko }
4695d5caef5bSAndrii Nakryiko 
4696d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d)
4697d5caef5bSAndrii Nakryiko {
4698d5caef5bSAndrii Nakryiko 	int i, err;
4699d5caef5bSAndrii Nakryiko 
4700f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4701f86524efSAndrii Nakryiko 		err = btf_dedup_ref_type(d, d->btf->start_id + i);
4702d5caef5bSAndrii Nakryiko 		if (err < 0)
4703d5caef5bSAndrii Nakryiko 			return err;
4704d5caef5bSAndrii Nakryiko 	}
47052fc3fc0bSAndrii Nakryiko 	/* we won't need d->dedup_table anymore */
47062fc3fc0bSAndrii Nakryiko 	hashmap__free(d->dedup_table);
47072fc3fc0bSAndrii Nakryiko 	d->dedup_table = NULL;
4708d5caef5bSAndrii Nakryiko 	return 0;
4709d5caef5bSAndrii Nakryiko }
4710d5caef5bSAndrii Nakryiko 
4711d5caef5bSAndrii Nakryiko /*
4712d5caef5bSAndrii Nakryiko  * Compact types.
4713d5caef5bSAndrii Nakryiko  *
4714d5caef5bSAndrii Nakryiko  * After we established for each type its corresponding canonical representative
4715d5caef5bSAndrii Nakryiko  * type, we now can eliminate types that are not canonical and leave only
4716d5caef5bSAndrii Nakryiko  * canonical ones layed out sequentially in memory by copying them over
4717d5caef5bSAndrii Nakryiko  * duplicates. During compaction btf_dedup->hypot_map array is reused to store
4718d5caef5bSAndrii Nakryiko  * a map from original type ID to a new compacted type ID, which will be used
4719d5caef5bSAndrii Nakryiko  * during next phase to "fix up" type IDs, referenced from struct/union and
4720d5caef5bSAndrii Nakryiko  * reference types.
4721d5caef5bSAndrii Nakryiko  */
4722d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d)
4723d5caef5bSAndrii Nakryiko {
4724740e69c3SAndrii Nakryiko 	__u32 *new_offs;
4725f86524efSAndrii Nakryiko 	__u32 next_type_id = d->btf->start_id;
4726f86524efSAndrii Nakryiko 	const struct btf_type *t;
4727740e69c3SAndrii Nakryiko 	void *p;
4728f86524efSAndrii Nakryiko 	int i, id, len;
4729d5caef5bSAndrii Nakryiko 
4730d5caef5bSAndrii Nakryiko 	/* we are going to reuse hypot_map to store compaction remapping */
4731d5caef5bSAndrii Nakryiko 	d->hypot_map[0] = 0;
4732f86524efSAndrii Nakryiko 	/* base BTF types are not renumbered */
4733f86524efSAndrii Nakryiko 	for (id = 1; id < d->btf->start_id; id++)
4734f86524efSAndrii Nakryiko 		d->hypot_map[id] = id;
4735f86524efSAndrii Nakryiko 	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++)
4736f86524efSAndrii Nakryiko 		d->hypot_map[id] = BTF_UNPROCESSED_ID;
4737d5caef5bSAndrii Nakryiko 
4738740e69c3SAndrii Nakryiko 	p = d->btf->types_data;
4739d5caef5bSAndrii Nakryiko 
4740f86524efSAndrii Nakryiko 	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) {
4741f86524efSAndrii Nakryiko 		if (d->map[id] != id)
4742d5caef5bSAndrii Nakryiko 			continue;
4743d5caef5bSAndrii Nakryiko 
4744f86524efSAndrii Nakryiko 		t = btf__type_by_id(d->btf, id);
4745f86524efSAndrii Nakryiko 		len = btf_type_size(t);
4746d5caef5bSAndrii Nakryiko 		if (len < 0)
4747d5caef5bSAndrii Nakryiko 			return len;
4748d5caef5bSAndrii Nakryiko 
4749f86524efSAndrii Nakryiko 		memmove(p, t, len);
4750f86524efSAndrii Nakryiko 		d->hypot_map[id] = next_type_id;
4751f86524efSAndrii Nakryiko 		d->btf->type_offs[next_type_id - d->btf->start_id] = p - d->btf->types_data;
4752d5caef5bSAndrii Nakryiko 		p += len;
4753d5caef5bSAndrii Nakryiko 		next_type_id++;
4754d5caef5bSAndrii Nakryiko 	}
4755d5caef5bSAndrii Nakryiko 
4756d5caef5bSAndrii Nakryiko 	/* shrink struct btf's internal types index and update btf_header */
4757f86524efSAndrii Nakryiko 	d->btf->nr_types = next_type_id - d->btf->start_id;
4758ba451366SAndrii Nakryiko 	d->btf->type_offs_cap = d->btf->nr_types;
4759740e69c3SAndrii Nakryiko 	d->btf->hdr->type_len = p - d->btf->types_data;
4760740e69c3SAndrii Nakryiko 	new_offs = libbpf_reallocarray(d->btf->type_offs, d->btf->type_offs_cap,
4761740e69c3SAndrii Nakryiko 				       sizeof(*new_offs));
4762f86524efSAndrii Nakryiko 	if (d->btf->type_offs_cap && !new_offs)
4763d5caef5bSAndrii Nakryiko 		return -ENOMEM;
4764740e69c3SAndrii Nakryiko 	d->btf->type_offs = new_offs;
4765919d2b1dSAndrii Nakryiko 	d->btf->hdr->str_off = d->btf->hdr->type_len;
4766b8604247SAndrii Nakryiko 	d->btf->raw_size = d->btf->hdr->hdr_len + d->btf->hdr->type_len + d->btf->hdr->str_len;
4767d5caef5bSAndrii Nakryiko 	return 0;
4768d5caef5bSAndrii Nakryiko }
4769d5caef5bSAndrii Nakryiko 
4770d5caef5bSAndrii Nakryiko /*
4771d5caef5bSAndrii Nakryiko  * Figure out final (deduplicated and compacted) type ID for provided original
4772d5caef5bSAndrii Nakryiko  * `type_id` by first resolving it into corresponding canonical type ID and
4773d5caef5bSAndrii Nakryiko  * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map,
4774d5caef5bSAndrii Nakryiko  * which is populated during compaction phase.
4775d5caef5bSAndrii Nakryiko  */
4776f36e99a4SAndrii Nakryiko static int btf_dedup_remap_type_id(__u32 *type_id, void *ctx)
4777d5caef5bSAndrii Nakryiko {
4778f36e99a4SAndrii Nakryiko 	struct btf_dedup *d = ctx;
4779d5caef5bSAndrii Nakryiko 	__u32 resolved_type_id, new_type_id;
4780d5caef5bSAndrii Nakryiko 
4781f36e99a4SAndrii Nakryiko 	resolved_type_id = resolve_type_id(d, *type_id);
4782d5caef5bSAndrii Nakryiko 	new_type_id = d->hypot_map[resolved_type_id];
47835aab392cSAndrii Nakryiko 	if (new_type_id > BTF_MAX_NR_TYPES)
4784d5caef5bSAndrii Nakryiko 		return -EINVAL;
4785f36e99a4SAndrii Nakryiko 
4786f36e99a4SAndrii Nakryiko 	*type_id = new_type_id;
4787f36e99a4SAndrii Nakryiko 	return 0;
4788d5caef5bSAndrii Nakryiko }
4789d5caef5bSAndrii Nakryiko 
4790d5caef5bSAndrii Nakryiko /*
4791d5caef5bSAndrii Nakryiko  * Remap referenced type IDs into deduped type IDs.
4792d5caef5bSAndrii Nakryiko  *
4793d5caef5bSAndrii Nakryiko  * After BTF types are deduplicated and compacted, their final type IDs may
4794d5caef5bSAndrii Nakryiko  * differ from original ones. The map from original to a corresponding
4795d5caef5bSAndrii Nakryiko  * deduped type ID is stored in btf_dedup->hypot_map and is populated during
4796d5caef5bSAndrii Nakryiko  * compaction phase. During remapping phase we are rewriting all type IDs
4797d5caef5bSAndrii Nakryiko  * referenced from any BTF type (e.g., struct fields, func proto args, etc) to
4798d5caef5bSAndrii Nakryiko  * their final deduped type IDs.
4799d5caef5bSAndrii Nakryiko  */
4800d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d)
4801d5caef5bSAndrii Nakryiko {
4802d5caef5bSAndrii Nakryiko 	int i, r;
4803d5caef5bSAndrii Nakryiko 
4804f86524efSAndrii Nakryiko 	for (i = 0; i < d->btf->nr_types; i++) {
4805f36e99a4SAndrii Nakryiko 		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
4806f36e99a4SAndrii Nakryiko 
4807f36e99a4SAndrii Nakryiko 		r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d);
4808f36e99a4SAndrii Nakryiko 		if (r)
4809d5caef5bSAndrii Nakryiko 			return r;
4810d5caef5bSAndrii Nakryiko 	}
4811f36e99a4SAndrii Nakryiko 
4812f36e99a4SAndrii Nakryiko 	if (!d->btf_ext)
4813f36e99a4SAndrii Nakryiko 		return 0;
4814f36e99a4SAndrii Nakryiko 
4815f36e99a4SAndrii Nakryiko 	r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d);
4816f36e99a4SAndrii Nakryiko 	if (r)
4817f36e99a4SAndrii Nakryiko 		return r;
4818f36e99a4SAndrii Nakryiko 
4819d5caef5bSAndrii Nakryiko 	return 0;
4820d5caef5bSAndrii Nakryiko }
4821fb2426adSMartin KaFai Lau 
4822fb2426adSMartin KaFai Lau /*
4823fb2426adSMartin KaFai Lau  * Probe few well-known locations for vmlinux kernel image and try to load BTF
4824fb2426adSMartin KaFai Lau  * data out of it to use for target BTF.
4825fb2426adSMartin KaFai Lau  */
4826a710eed3SHengqi Chen struct btf *btf__load_vmlinux_btf(void)
4827fb2426adSMartin KaFai Lau {
4828fb2426adSMartin KaFai Lau 	struct {
4829fb2426adSMartin KaFai Lau 		const char *path_fmt;
4830fb2426adSMartin KaFai Lau 		bool raw_btf;
4831fb2426adSMartin KaFai Lau 	} locations[] = {
4832fb2426adSMartin KaFai Lau 		/* try canonical vmlinux BTF through sysfs first */
4833fb2426adSMartin KaFai Lau 		{ "/sys/kernel/btf/vmlinux", true /* raw BTF */ },
4834fb2426adSMartin KaFai Lau 		/* fall back to trying to find vmlinux ELF on disk otherwise */
4835fb2426adSMartin KaFai Lau 		{ "/boot/vmlinux-%1$s" },
4836fb2426adSMartin KaFai Lau 		{ "/lib/modules/%1$s/vmlinux-%1$s" },
4837fb2426adSMartin KaFai Lau 		{ "/lib/modules/%1$s/build/vmlinux" },
4838fb2426adSMartin KaFai Lau 		{ "/usr/lib/modules/%1$s/kernel/vmlinux" },
4839fb2426adSMartin KaFai Lau 		{ "/usr/lib/debug/boot/vmlinux-%1$s" },
4840fb2426adSMartin KaFai Lau 		{ "/usr/lib/debug/boot/vmlinux-%1$s.debug" },
4841fb2426adSMartin KaFai Lau 		{ "/usr/lib/debug/lib/modules/%1$s/vmlinux" },
4842fb2426adSMartin KaFai Lau 	};
4843fb2426adSMartin KaFai Lau 	char path[PATH_MAX + 1];
4844fb2426adSMartin KaFai Lau 	struct utsname buf;
4845fb2426adSMartin KaFai Lau 	struct btf *btf;
4846e9fc3ce9SAndrii Nakryiko 	int i, err;
4847fb2426adSMartin KaFai Lau 
4848fb2426adSMartin KaFai Lau 	uname(&buf);
4849fb2426adSMartin KaFai Lau 
4850fb2426adSMartin KaFai Lau 	for (i = 0; i < ARRAY_SIZE(locations); i++) {
4851fb2426adSMartin KaFai Lau 		snprintf(path, PATH_MAX, locations[i].path_fmt, buf.release);
4852fb2426adSMartin KaFai Lau 
4853fb2426adSMartin KaFai Lau 		if (access(path, R_OK))
4854fb2426adSMartin KaFai Lau 			continue;
4855fb2426adSMartin KaFai Lau 
4856fb2426adSMartin KaFai Lau 		if (locations[i].raw_btf)
485794a1feddSAndrii Nakryiko 			btf = btf__parse_raw(path);
4858fb2426adSMartin KaFai Lau 		else
4859fb2426adSMartin KaFai Lau 			btf = btf__parse_elf(path, NULL);
4860e9fc3ce9SAndrii Nakryiko 		err = libbpf_get_error(btf);
4861e9fc3ce9SAndrii Nakryiko 		pr_debug("loading kernel BTF '%s': %d\n", path, err);
4862e9fc3ce9SAndrii Nakryiko 		if (err)
4863fb2426adSMartin KaFai Lau 			continue;
4864fb2426adSMartin KaFai Lau 
4865fb2426adSMartin KaFai Lau 		return btf;
4866fb2426adSMartin KaFai Lau 	}
4867fb2426adSMartin KaFai Lau 
4868fb2426adSMartin KaFai Lau 	pr_warn("failed to find valid kernel BTF\n");
4869e9fc3ce9SAndrii Nakryiko 	return libbpf_err_ptr(-ESRCH);
4870fb2426adSMartin KaFai Lau }
4871f36e99a4SAndrii Nakryiko 
4872a710eed3SHengqi Chen struct btf *libbpf_find_kernel_btf(void) __attribute__((alias("btf__load_vmlinux_btf")));
4873a710eed3SHengqi Chen 
4874a710eed3SHengqi Chen struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf)
4875a710eed3SHengqi Chen {
4876a710eed3SHengqi Chen 	char path[80];
4877a710eed3SHengqi Chen 
4878a710eed3SHengqi Chen 	snprintf(path, sizeof(path), "/sys/kernel/btf/%s", module_name);
4879a710eed3SHengqi Chen 	return btf__parse_split(path, vmlinux_btf);
4880a710eed3SHengqi Chen }
4881a710eed3SHengqi Chen 
4882f36e99a4SAndrii Nakryiko int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx)
4883f36e99a4SAndrii Nakryiko {
4884f36e99a4SAndrii Nakryiko 	int i, n, err;
4885f36e99a4SAndrii Nakryiko 
4886f36e99a4SAndrii Nakryiko 	switch (btf_kind(t)) {
4887f36e99a4SAndrii Nakryiko 	case BTF_KIND_INT:
4888f36e99a4SAndrii Nakryiko 	case BTF_KIND_FLOAT:
4889f36e99a4SAndrii Nakryiko 	case BTF_KIND_ENUM:
4890dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64:
4891f36e99a4SAndrii Nakryiko 		return 0;
4892f36e99a4SAndrii Nakryiko 
4893f36e99a4SAndrii Nakryiko 	case BTF_KIND_FWD:
4894f36e99a4SAndrii Nakryiko 	case BTF_KIND_CONST:
4895f36e99a4SAndrii Nakryiko 	case BTF_KIND_VOLATILE:
4896f36e99a4SAndrii Nakryiko 	case BTF_KIND_RESTRICT:
4897f36e99a4SAndrii Nakryiko 	case BTF_KIND_PTR:
4898f36e99a4SAndrii Nakryiko 	case BTF_KIND_TYPEDEF:
4899f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC:
4900f36e99a4SAndrii Nakryiko 	case BTF_KIND_VAR:
4901223f903eSYonghong Song 	case BTF_KIND_DECL_TAG:
49022dc1e488SYonghong Song 	case BTF_KIND_TYPE_TAG:
4903f36e99a4SAndrii Nakryiko 		return visit(&t->type, ctx);
4904f36e99a4SAndrii Nakryiko 
4905f36e99a4SAndrii Nakryiko 	case BTF_KIND_ARRAY: {
4906f36e99a4SAndrii Nakryiko 		struct btf_array *a = btf_array(t);
4907f36e99a4SAndrii Nakryiko 
4908f36e99a4SAndrii Nakryiko 		err = visit(&a->type, ctx);
4909f36e99a4SAndrii Nakryiko 		err = err ?: visit(&a->index_type, ctx);
4910f36e99a4SAndrii Nakryiko 		return err;
4911f36e99a4SAndrii Nakryiko 	}
4912f36e99a4SAndrii Nakryiko 
4913f36e99a4SAndrii Nakryiko 	case BTF_KIND_STRUCT:
4914f36e99a4SAndrii Nakryiko 	case BTF_KIND_UNION: {
4915f36e99a4SAndrii Nakryiko 		struct btf_member *m = btf_members(t);
4916f36e99a4SAndrii Nakryiko 
4917f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4918f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4919f36e99a4SAndrii Nakryiko 			if (err)
4920f36e99a4SAndrii Nakryiko 				return err;
4921f36e99a4SAndrii Nakryiko 		}
4922f36e99a4SAndrii Nakryiko 		return 0;
4923f36e99a4SAndrii Nakryiko 	}
4924f36e99a4SAndrii Nakryiko 
4925f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4926f36e99a4SAndrii Nakryiko 		struct btf_param *m = btf_params(t);
4927f36e99a4SAndrii Nakryiko 
4928f36e99a4SAndrii Nakryiko 		err = visit(&t->type, ctx);
4929f36e99a4SAndrii Nakryiko 		if (err)
4930f36e99a4SAndrii Nakryiko 			return err;
4931f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4932f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4933f36e99a4SAndrii Nakryiko 			if (err)
4934f36e99a4SAndrii Nakryiko 				return err;
4935f36e99a4SAndrii Nakryiko 		}
4936f36e99a4SAndrii Nakryiko 		return 0;
4937f36e99a4SAndrii Nakryiko 	}
4938f36e99a4SAndrii Nakryiko 
4939f36e99a4SAndrii Nakryiko 	case BTF_KIND_DATASEC: {
4940f36e99a4SAndrii Nakryiko 		struct btf_var_secinfo *m = btf_var_secinfos(t);
4941f36e99a4SAndrii Nakryiko 
4942f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4943f36e99a4SAndrii Nakryiko 			err = visit(&m->type, ctx);
4944f36e99a4SAndrii Nakryiko 			if (err)
4945f36e99a4SAndrii Nakryiko 				return err;
4946f36e99a4SAndrii Nakryiko 		}
4947f36e99a4SAndrii Nakryiko 		return 0;
4948f36e99a4SAndrii Nakryiko 	}
4949f36e99a4SAndrii Nakryiko 
4950f36e99a4SAndrii Nakryiko 	default:
4951f36e99a4SAndrii Nakryiko 		return -EINVAL;
4952f36e99a4SAndrii Nakryiko 	}
4953f36e99a4SAndrii Nakryiko }
4954f36e99a4SAndrii Nakryiko 
4955f36e99a4SAndrii Nakryiko int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx)
4956f36e99a4SAndrii Nakryiko {
4957f36e99a4SAndrii Nakryiko 	int i, n, err;
4958f36e99a4SAndrii Nakryiko 
4959f36e99a4SAndrii Nakryiko 	err = visit(&t->name_off, ctx);
4960f36e99a4SAndrii Nakryiko 	if (err)
4961f36e99a4SAndrii Nakryiko 		return err;
4962f36e99a4SAndrii Nakryiko 
4963f36e99a4SAndrii Nakryiko 	switch (btf_kind(t)) {
4964f36e99a4SAndrii Nakryiko 	case BTF_KIND_STRUCT:
4965f36e99a4SAndrii Nakryiko 	case BTF_KIND_UNION: {
4966f36e99a4SAndrii Nakryiko 		struct btf_member *m = btf_members(t);
4967f36e99a4SAndrii Nakryiko 
4968f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4969f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
4970f36e99a4SAndrii Nakryiko 			if (err)
4971f36e99a4SAndrii Nakryiko 				return err;
4972f36e99a4SAndrii Nakryiko 		}
4973f36e99a4SAndrii Nakryiko 		break;
4974f36e99a4SAndrii Nakryiko 	}
4975f36e99a4SAndrii Nakryiko 	case BTF_KIND_ENUM: {
4976f36e99a4SAndrii Nakryiko 		struct btf_enum *m = btf_enum(t);
4977f36e99a4SAndrii Nakryiko 
4978f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4979f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
4980f36e99a4SAndrii Nakryiko 			if (err)
4981f36e99a4SAndrii Nakryiko 				return err;
4982f36e99a4SAndrii Nakryiko 		}
4983f36e99a4SAndrii Nakryiko 		break;
4984f36e99a4SAndrii Nakryiko 	}
4985dffbbdc2SYonghong Song 	case BTF_KIND_ENUM64: {
4986dffbbdc2SYonghong Song 		struct btf_enum64 *m = btf_enum64(t);
4987dffbbdc2SYonghong Song 
4988dffbbdc2SYonghong Song 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4989dffbbdc2SYonghong Song 			err = visit(&m->name_off, ctx);
4990dffbbdc2SYonghong Song 			if (err)
4991dffbbdc2SYonghong Song 				return err;
4992dffbbdc2SYonghong Song 		}
4993dffbbdc2SYonghong Song 		break;
4994dffbbdc2SYonghong Song 	}
4995f36e99a4SAndrii Nakryiko 	case BTF_KIND_FUNC_PROTO: {
4996f36e99a4SAndrii Nakryiko 		struct btf_param *m = btf_params(t);
4997f36e99a4SAndrii Nakryiko 
4998f36e99a4SAndrii Nakryiko 		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
4999f36e99a4SAndrii Nakryiko 			err = visit(&m->name_off, ctx);
5000f36e99a4SAndrii Nakryiko 			if (err)
5001f36e99a4SAndrii Nakryiko 				return err;
5002f36e99a4SAndrii Nakryiko 		}
5003f36e99a4SAndrii Nakryiko 		break;
5004f36e99a4SAndrii Nakryiko 	}
5005f36e99a4SAndrii Nakryiko 	default:
5006f36e99a4SAndrii Nakryiko 		break;
5007f36e99a4SAndrii Nakryiko 	}
5008f36e99a4SAndrii Nakryiko 
5009f36e99a4SAndrii Nakryiko 	return 0;
5010f36e99a4SAndrii Nakryiko }
5011f36e99a4SAndrii Nakryiko 
5012f36e99a4SAndrii Nakryiko int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx)
5013f36e99a4SAndrii Nakryiko {
5014f36e99a4SAndrii Nakryiko 	const struct btf_ext_info *seg;
5015f36e99a4SAndrii Nakryiko 	struct btf_ext_info_sec *sec;
5016f36e99a4SAndrii Nakryiko 	int i, err;
5017f36e99a4SAndrii Nakryiko 
5018f36e99a4SAndrii Nakryiko 	seg = &btf_ext->func_info;
5019f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5020f36e99a4SAndrii Nakryiko 		struct bpf_func_info_min *rec;
5021f36e99a4SAndrii Nakryiko 
5022f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5023f36e99a4SAndrii Nakryiko 			err = visit(&rec->type_id, ctx);
5024f36e99a4SAndrii Nakryiko 			if (err < 0)
5025f36e99a4SAndrii Nakryiko 				return err;
5026f36e99a4SAndrii Nakryiko 		}
5027f36e99a4SAndrii Nakryiko 	}
5028f36e99a4SAndrii Nakryiko 
5029f36e99a4SAndrii Nakryiko 	seg = &btf_ext->core_relo_info;
5030f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5031f36e99a4SAndrii Nakryiko 		struct bpf_core_relo *rec;
5032f36e99a4SAndrii Nakryiko 
5033f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5034f36e99a4SAndrii Nakryiko 			err = visit(&rec->type_id, ctx);
5035f36e99a4SAndrii Nakryiko 			if (err < 0)
5036f36e99a4SAndrii Nakryiko 				return err;
5037f36e99a4SAndrii Nakryiko 		}
5038f36e99a4SAndrii Nakryiko 	}
5039f36e99a4SAndrii Nakryiko 
5040f36e99a4SAndrii Nakryiko 	return 0;
5041f36e99a4SAndrii Nakryiko }
5042f36e99a4SAndrii Nakryiko 
5043f36e99a4SAndrii Nakryiko int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx)
5044f36e99a4SAndrii Nakryiko {
5045f36e99a4SAndrii Nakryiko 	const struct btf_ext_info *seg;
5046f36e99a4SAndrii Nakryiko 	struct btf_ext_info_sec *sec;
5047f36e99a4SAndrii Nakryiko 	int i, err;
5048f36e99a4SAndrii Nakryiko 
5049f36e99a4SAndrii Nakryiko 	seg = &btf_ext->func_info;
5050f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5051f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
5052f36e99a4SAndrii Nakryiko 		if (err)
5053f36e99a4SAndrii Nakryiko 			return err;
5054f36e99a4SAndrii Nakryiko 	}
5055f36e99a4SAndrii Nakryiko 
5056f36e99a4SAndrii Nakryiko 	seg = &btf_ext->line_info;
5057f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5058f36e99a4SAndrii Nakryiko 		struct bpf_line_info_min *rec;
5059f36e99a4SAndrii Nakryiko 
5060f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
5061f36e99a4SAndrii Nakryiko 		if (err)
5062f36e99a4SAndrii Nakryiko 			return err;
5063f36e99a4SAndrii Nakryiko 
5064f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5065f36e99a4SAndrii Nakryiko 			err = visit(&rec->file_name_off, ctx);
5066f36e99a4SAndrii Nakryiko 			if (err)
5067f36e99a4SAndrii Nakryiko 				return err;
5068f36e99a4SAndrii Nakryiko 			err = visit(&rec->line_off, ctx);
5069f36e99a4SAndrii Nakryiko 			if (err)
5070f36e99a4SAndrii Nakryiko 				return err;
5071f36e99a4SAndrii Nakryiko 		}
5072f36e99a4SAndrii Nakryiko 	}
5073f36e99a4SAndrii Nakryiko 
5074f36e99a4SAndrii Nakryiko 	seg = &btf_ext->core_relo_info;
5075f36e99a4SAndrii Nakryiko 	for_each_btf_ext_sec(seg, sec) {
5076f36e99a4SAndrii Nakryiko 		struct bpf_core_relo *rec;
5077f36e99a4SAndrii Nakryiko 
5078f36e99a4SAndrii Nakryiko 		err = visit(&sec->sec_name_off, ctx);
5079f36e99a4SAndrii Nakryiko 		if (err)
5080f36e99a4SAndrii Nakryiko 			return err;
5081f36e99a4SAndrii Nakryiko 
5082f36e99a4SAndrii Nakryiko 		for_each_btf_ext_rec(seg, sec, i, rec) {
5083f36e99a4SAndrii Nakryiko 			err = visit(&rec->access_str_off, ctx);
5084f36e99a4SAndrii Nakryiko 			if (err)
5085f36e99a4SAndrii Nakryiko 				return err;
5086f36e99a4SAndrii Nakryiko 		}
5087f36e99a4SAndrii Nakryiko 	}
5088f36e99a4SAndrii Nakryiko 
5089f36e99a4SAndrii Nakryiko 	return 0;
5090f36e99a4SAndrii Nakryiko }
5091