162306a36Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (c) 2018 Facebook */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <byteswap.h>
562306a36Sopenharmony_ci#include <endian.h>
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include <stdlib.h>
862306a36Sopenharmony_ci#include <string.h>
962306a36Sopenharmony_ci#include <fcntl.h>
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <sys/utsname.h>
1362306a36Sopenharmony_ci#include <sys/param.h>
1462306a36Sopenharmony_ci#include <sys/stat.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/btf.h>
1862306a36Sopenharmony_ci#include <gelf.h>
1962306a36Sopenharmony_ci#include "btf.h"
2062306a36Sopenharmony_ci#include "bpf.h"
2162306a36Sopenharmony_ci#include "libbpf.h"
2262306a36Sopenharmony_ci#include "libbpf_internal.h"
2362306a36Sopenharmony_ci#include "hashmap.h"
2462306a36Sopenharmony_ci#include "strset.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define BTF_MAX_NR_TYPES 0x7fffffffU
2762306a36Sopenharmony_ci#define BTF_MAX_STR_OFFSET 0x7fffffffU
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic struct btf_type btf_void;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct btf {
3262306a36Sopenharmony_ci	/* raw BTF data in native endianness */
3362306a36Sopenharmony_ci	void *raw_data;
3462306a36Sopenharmony_ci	/* raw BTF data in non-native endianness */
3562306a36Sopenharmony_ci	void *raw_data_swapped;
3662306a36Sopenharmony_ci	__u32 raw_size;
3762306a36Sopenharmony_ci	/* whether target endianness differs from the native one */
3862306a36Sopenharmony_ci	bool swapped_endian;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/*
4162306a36Sopenharmony_ci	 * When BTF is loaded from an ELF or raw memory it is stored
4262306a36Sopenharmony_ci	 * in a contiguous memory block. The hdr, type_data, and, strs_data
4362306a36Sopenharmony_ci	 * point inside that memory region to their respective parts of BTF
4462306a36Sopenharmony_ci	 * representation:
4562306a36Sopenharmony_ci	 *
4662306a36Sopenharmony_ci	 * +--------------------------------+
4762306a36Sopenharmony_ci	 * |  Header  |  Types  |  Strings  |
4862306a36Sopenharmony_ci	 * +--------------------------------+
4962306a36Sopenharmony_ci	 * ^          ^         ^
5062306a36Sopenharmony_ci	 * |          |         |
5162306a36Sopenharmony_ci	 * hdr        |         |
5262306a36Sopenharmony_ci	 * types_data-+         |
5362306a36Sopenharmony_ci	 * strs_data------------+
5462306a36Sopenharmony_ci	 *
5562306a36Sopenharmony_ci	 * If BTF data is later modified, e.g., due to types added or
5662306a36Sopenharmony_ci	 * removed, BTF deduplication performed, etc, this contiguous
5762306a36Sopenharmony_ci	 * representation is broken up into three independently allocated
5862306a36Sopenharmony_ci	 * memory regions to be able to modify them independently.
5962306a36Sopenharmony_ci	 * raw_data is nulled out at that point, but can be later allocated
6062306a36Sopenharmony_ci	 * and cached again if user calls btf__raw_data(), at which point
6162306a36Sopenharmony_ci	 * raw_data will contain a contiguous copy of header, types, and
6262306a36Sopenharmony_ci	 * strings:
6362306a36Sopenharmony_ci	 *
6462306a36Sopenharmony_ci	 * +----------+  +---------+  +-----------+
6562306a36Sopenharmony_ci	 * |  Header  |  |  Types  |  |  Strings  |
6662306a36Sopenharmony_ci	 * +----------+  +---------+  +-----------+
6762306a36Sopenharmony_ci	 * ^             ^            ^
6862306a36Sopenharmony_ci	 * |             |            |
6962306a36Sopenharmony_ci	 * hdr           |            |
7062306a36Sopenharmony_ci	 * types_data----+            |
7162306a36Sopenharmony_ci	 * strset__data(strs_set)-----+
7262306a36Sopenharmony_ci	 *
7362306a36Sopenharmony_ci	 *               +----------+---------+-----------+
7462306a36Sopenharmony_ci	 *               |  Header  |  Types  |  Strings  |
7562306a36Sopenharmony_ci	 * raw_data----->+----------+---------+-----------+
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci	struct btf_header *hdr;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	void *types_data;
8062306a36Sopenharmony_ci	size_t types_data_cap; /* used size stored in hdr->type_len */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* type ID to `struct btf_type *` lookup index
8362306a36Sopenharmony_ci	 * type_offs[0] corresponds to the first non-VOID type:
8462306a36Sopenharmony_ci	 *   - for base BTF it's type [1];
8562306a36Sopenharmony_ci	 *   - for split BTF it's the first non-base BTF type.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	__u32 *type_offs;
8862306a36Sopenharmony_ci	size_t type_offs_cap;
8962306a36Sopenharmony_ci	/* number of types in this BTF instance:
9062306a36Sopenharmony_ci	 *   - doesn't include special [0] void type;
9162306a36Sopenharmony_ci	 *   - for split BTF counts number of types added on top of base BTF.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	__u32 nr_types;
9462306a36Sopenharmony_ci	/* if not NULL, points to the base BTF on top of which the current
9562306a36Sopenharmony_ci	 * split BTF is based
9662306a36Sopenharmony_ci	 */
9762306a36Sopenharmony_ci	struct btf *base_btf;
9862306a36Sopenharmony_ci	/* BTF type ID of the first type in this BTF instance:
9962306a36Sopenharmony_ci	 *   - for base BTF it's equal to 1;
10062306a36Sopenharmony_ci	 *   - for split BTF it's equal to biggest type ID of base BTF plus 1.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	int start_id;
10362306a36Sopenharmony_ci	/* logical string offset of this BTF instance:
10462306a36Sopenharmony_ci	 *   - for base BTF it's equal to 0;
10562306a36Sopenharmony_ci	 *   - for split BTF it's equal to total size of base BTF's string section size.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci	int start_str_off;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* only one of strs_data or strs_set can be non-NULL, depending on
11062306a36Sopenharmony_ci	 * whether BTF is in a modifiable state (strs_set is used) or not
11162306a36Sopenharmony_ci	 * (strs_data points inside raw_data)
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	void *strs_data;
11462306a36Sopenharmony_ci	/* a set of unique strings */
11562306a36Sopenharmony_ci	struct strset *strs_set;
11662306a36Sopenharmony_ci	/* whether strings are already deduplicated */
11762306a36Sopenharmony_ci	bool strs_deduped;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* BTF object FD, if loaded into kernel */
12062306a36Sopenharmony_ci	int fd;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Pointer size (in bytes) for a target architecture of this BTF */
12362306a36Sopenharmony_ci	int ptr_sz;
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline __u64 ptr_to_u64(const void *ptr)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return (__u64) (unsigned long) ptr;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* Ensure given dynamically allocated memory region pointed to by *data* with
13262306a36Sopenharmony_ci * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough
13362306a36Sopenharmony_ci * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements
13462306a36Sopenharmony_ci * are already used. At most *max_cnt* elements can be ever allocated.
13562306a36Sopenharmony_ci * If necessary, memory is reallocated and all existing data is copied over,
13662306a36Sopenharmony_ci * new pointer to the memory region is stored at *data, new memory region
13762306a36Sopenharmony_ci * capacity (in number of elements) is stored in *cap.
13862306a36Sopenharmony_ci * On success, memory pointer to the beginning of unused memory is returned.
13962306a36Sopenharmony_ci * On error, NULL is returned.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_civoid *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
14262306a36Sopenharmony_ci		     size_t cur_cnt, size_t max_cnt, size_t add_cnt)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	size_t new_cnt;
14562306a36Sopenharmony_ci	void *new_data;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (cur_cnt + add_cnt <= *cap_cnt)
14862306a36Sopenharmony_ci		return *data + cur_cnt * elem_sz;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* requested more than the set limit */
15162306a36Sopenharmony_ci	if (cur_cnt + add_cnt > max_cnt)
15262306a36Sopenharmony_ci		return NULL;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	new_cnt = *cap_cnt;
15562306a36Sopenharmony_ci	new_cnt += new_cnt / 4;		  /* expand by 25% */
15662306a36Sopenharmony_ci	if (new_cnt < 16)		  /* but at least 16 elements */
15762306a36Sopenharmony_ci		new_cnt = 16;
15862306a36Sopenharmony_ci	if (new_cnt > max_cnt)		  /* but not exceeding a set limit */
15962306a36Sopenharmony_ci		new_cnt = max_cnt;
16062306a36Sopenharmony_ci	if (new_cnt < cur_cnt + add_cnt)  /* also ensure we have enough memory */
16162306a36Sopenharmony_ci		new_cnt = cur_cnt + add_cnt;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	new_data = libbpf_reallocarray(*data, new_cnt, elem_sz);
16462306a36Sopenharmony_ci	if (!new_data)
16562306a36Sopenharmony_ci		return NULL;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* zero out newly allocated portion of memory */
16862306a36Sopenharmony_ci	memset(new_data + (*cap_cnt) * elem_sz, 0, (new_cnt - *cap_cnt) * elem_sz);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	*data = new_data;
17162306a36Sopenharmony_ci	*cap_cnt = new_cnt;
17262306a36Sopenharmony_ci	return new_data + cur_cnt * elem_sz;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/* Ensure given dynamically allocated memory region has enough allocated space
17662306a36Sopenharmony_ci * to accommodate *need_cnt* elements of size *elem_sz* bytes each
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_ciint libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	void *p;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (need_cnt <= *cap_cnt)
18362306a36Sopenharmony_ci		return 0;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	p = libbpf_add_mem(data, cap_cnt, elem_sz, *cap_cnt, SIZE_MAX, need_cnt - *cap_cnt);
18662306a36Sopenharmony_ci	if (!p)
18762306a36Sopenharmony_ci		return -ENOMEM;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic void *btf_add_type_offs_mem(struct btf *btf, size_t add_cnt)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return libbpf_add_mem((void **)&btf->type_offs, &btf->type_offs_cap, sizeof(__u32),
19562306a36Sopenharmony_ci			      btf->nr_types, BTF_MAX_NR_TYPES, add_cnt);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int btf_add_type_idx_entry(struct btf *btf, __u32 type_off)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	__u32 *p;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	p = btf_add_type_offs_mem(btf, 1);
20362306a36Sopenharmony_ci	if (!p)
20462306a36Sopenharmony_ci		return -ENOMEM;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	*p = type_off;
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void btf_bswap_hdr(struct btf_header *h)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	h->magic = bswap_16(h->magic);
21362306a36Sopenharmony_ci	h->hdr_len = bswap_32(h->hdr_len);
21462306a36Sopenharmony_ci	h->type_off = bswap_32(h->type_off);
21562306a36Sopenharmony_ci	h->type_len = bswap_32(h->type_len);
21662306a36Sopenharmony_ci	h->str_off = bswap_32(h->str_off);
21762306a36Sopenharmony_ci	h->str_len = bswap_32(h->str_len);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic int btf_parse_hdr(struct btf *btf)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
22362306a36Sopenharmony_ci	__u32 meta_left;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (btf->raw_size < sizeof(struct btf_header)) {
22662306a36Sopenharmony_ci		pr_debug("BTF header not found\n");
22762306a36Sopenharmony_ci		return -EINVAL;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (hdr->magic == bswap_16(BTF_MAGIC)) {
23162306a36Sopenharmony_ci		btf->swapped_endian = true;
23262306a36Sopenharmony_ci		if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) {
23362306a36Sopenharmony_ci			pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n",
23462306a36Sopenharmony_ci				bswap_32(hdr->hdr_len));
23562306a36Sopenharmony_ci			return -ENOTSUP;
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci		btf_bswap_hdr(hdr);
23862306a36Sopenharmony_ci	} else if (hdr->magic != BTF_MAGIC) {
23962306a36Sopenharmony_ci		pr_debug("Invalid BTF magic: %x\n", hdr->magic);
24062306a36Sopenharmony_ci		return -EINVAL;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (btf->raw_size < hdr->hdr_len) {
24462306a36Sopenharmony_ci		pr_debug("BTF header len %u larger than data size %u\n",
24562306a36Sopenharmony_ci			 hdr->hdr_len, btf->raw_size);
24662306a36Sopenharmony_ci		return -EINVAL;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	meta_left = btf->raw_size - hdr->hdr_len;
25062306a36Sopenharmony_ci	if (meta_left < (long long)hdr->str_off + hdr->str_len) {
25162306a36Sopenharmony_ci		pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
25662306a36Sopenharmony_ci		pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
25762306a36Sopenharmony_ci			 hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
25862306a36Sopenharmony_ci		return -EINVAL;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (hdr->type_off % 4) {
26262306a36Sopenharmony_ci		pr_debug("BTF type section is not aligned to 4 bytes\n");
26362306a36Sopenharmony_ci		return -EINVAL;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int btf_parse_str_sec(struct btf *btf)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	const struct btf_header *hdr = btf->hdr;
27262306a36Sopenharmony_ci	const char *start = btf->strs_data;
27362306a36Sopenharmony_ci	const char *end = start + btf->hdr->str_len;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (btf->base_btf && hdr->str_len == 0)
27662306a36Sopenharmony_ci		return 0;
27762306a36Sopenharmony_ci	if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_STR_OFFSET || end[-1]) {
27862306a36Sopenharmony_ci		pr_debug("Invalid BTF string section\n");
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	if (!btf->base_btf && start[0]) {
28262306a36Sopenharmony_ci		pr_debug("Invalid BTF string section\n");
28362306a36Sopenharmony_ci		return -EINVAL;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int btf_type_size(const struct btf_type *t)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	const int base_size = sizeof(struct btf_type);
29162306a36Sopenharmony_ci	__u16 vlen = btf_vlen(t);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	switch (btf_kind(t)) {
29462306a36Sopenharmony_ci	case BTF_KIND_FWD:
29562306a36Sopenharmony_ci	case BTF_KIND_CONST:
29662306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
29762306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
29862306a36Sopenharmony_ci	case BTF_KIND_PTR:
29962306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
30062306a36Sopenharmony_ci	case BTF_KIND_FUNC:
30162306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
30262306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
30362306a36Sopenharmony_ci		return base_size;
30462306a36Sopenharmony_ci	case BTF_KIND_INT:
30562306a36Sopenharmony_ci		return base_size + sizeof(__u32);
30662306a36Sopenharmony_ci	case BTF_KIND_ENUM:
30762306a36Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_enum);
30862306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
30962306a36Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_enum64);
31062306a36Sopenharmony_ci	case BTF_KIND_ARRAY:
31162306a36Sopenharmony_ci		return base_size + sizeof(struct btf_array);
31262306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
31362306a36Sopenharmony_ci	case BTF_KIND_UNION:
31462306a36Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_member);
31562306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
31662306a36Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_param);
31762306a36Sopenharmony_ci	case BTF_KIND_VAR:
31862306a36Sopenharmony_ci		return base_size + sizeof(struct btf_var);
31962306a36Sopenharmony_ci	case BTF_KIND_DATASEC:
32062306a36Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_var_secinfo);
32162306a36Sopenharmony_ci	case BTF_KIND_DECL_TAG:
32262306a36Sopenharmony_ci		return base_size + sizeof(struct btf_decl_tag);
32362306a36Sopenharmony_ci	default:
32462306a36Sopenharmony_ci		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
32562306a36Sopenharmony_ci		return -EINVAL;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void btf_bswap_type_base(struct btf_type *t)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	t->name_off = bswap_32(t->name_off);
33262306a36Sopenharmony_ci	t->info = bswap_32(t->info);
33362306a36Sopenharmony_ci	t->type = bswap_32(t->type);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int btf_bswap_type_rest(struct btf_type *t)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct btf_var_secinfo *v;
33962306a36Sopenharmony_ci	struct btf_enum64 *e64;
34062306a36Sopenharmony_ci	struct btf_member *m;
34162306a36Sopenharmony_ci	struct btf_array *a;
34262306a36Sopenharmony_ci	struct btf_param *p;
34362306a36Sopenharmony_ci	struct btf_enum *e;
34462306a36Sopenharmony_ci	__u16 vlen = btf_vlen(t);
34562306a36Sopenharmony_ci	int i;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	switch (btf_kind(t)) {
34862306a36Sopenharmony_ci	case BTF_KIND_FWD:
34962306a36Sopenharmony_ci	case BTF_KIND_CONST:
35062306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
35162306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
35262306a36Sopenharmony_ci	case BTF_KIND_PTR:
35362306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
35462306a36Sopenharmony_ci	case BTF_KIND_FUNC:
35562306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
35662306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
35762306a36Sopenharmony_ci		return 0;
35862306a36Sopenharmony_ci	case BTF_KIND_INT:
35962306a36Sopenharmony_ci		*(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1));
36062306a36Sopenharmony_ci		return 0;
36162306a36Sopenharmony_ci	case BTF_KIND_ENUM:
36262306a36Sopenharmony_ci		for (i = 0, e = btf_enum(t); i < vlen; i++, e++) {
36362306a36Sopenharmony_ci			e->name_off = bswap_32(e->name_off);
36462306a36Sopenharmony_ci			e->val = bswap_32(e->val);
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci		return 0;
36762306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
36862306a36Sopenharmony_ci		for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) {
36962306a36Sopenharmony_ci			e64->name_off = bswap_32(e64->name_off);
37062306a36Sopenharmony_ci			e64->val_lo32 = bswap_32(e64->val_lo32);
37162306a36Sopenharmony_ci			e64->val_hi32 = bswap_32(e64->val_hi32);
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci		return 0;
37462306a36Sopenharmony_ci	case BTF_KIND_ARRAY:
37562306a36Sopenharmony_ci		a = btf_array(t);
37662306a36Sopenharmony_ci		a->type = bswap_32(a->type);
37762306a36Sopenharmony_ci		a->index_type = bswap_32(a->index_type);
37862306a36Sopenharmony_ci		a->nelems = bswap_32(a->nelems);
37962306a36Sopenharmony_ci		return 0;
38062306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
38162306a36Sopenharmony_ci	case BTF_KIND_UNION:
38262306a36Sopenharmony_ci		for (i = 0, m = btf_members(t); i < vlen; i++, m++) {
38362306a36Sopenharmony_ci			m->name_off = bswap_32(m->name_off);
38462306a36Sopenharmony_ci			m->type = bswap_32(m->type);
38562306a36Sopenharmony_ci			m->offset = bswap_32(m->offset);
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		return 0;
38862306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
38962306a36Sopenharmony_ci		for (i = 0, p = btf_params(t); i < vlen; i++, p++) {
39062306a36Sopenharmony_ci			p->name_off = bswap_32(p->name_off);
39162306a36Sopenharmony_ci			p->type = bswap_32(p->type);
39262306a36Sopenharmony_ci		}
39362306a36Sopenharmony_ci		return 0;
39462306a36Sopenharmony_ci	case BTF_KIND_VAR:
39562306a36Sopenharmony_ci		btf_var(t)->linkage = bswap_32(btf_var(t)->linkage);
39662306a36Sopenharmony_ci		return 0;
39762306a36Sopenharmony_ci	case BTF_KIND_DATASEC:
39862306a36Sopenharmony_ci		for (i = 0, v = btf_var_secinfos(t); i < vlen; i++, v++) {
39962306a36Sopenharmony_ci			v->type = bswap_32(v->type);
40062306a36Sopenharmony_ci			v->offset = bswap_32(v->offset);
40162306a36Sopenharmony_ci			v->size = bswap_32(v->size);
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci		return 0;
40462306a36Sopenharmony_ci	case BTF_KIND_DECL_TAG:
40562306a36Sopenharmony_ci		btf_decl_tag(t)->component_idx = bswap_32(btf_decl_tag(t)->component_idx);
40662306a36Sopenharmony_ci		return 0;
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
40962306a36Sopenharmony_ci		return -EINVAL;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int btf_parse_type_sec(struct btf *btf)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
41662306a36Sopenharmony_ci	void *next_type = btf->types_data;
41762306a36Sopenharmony_ci	void *end_type = next_type + hdr->type_len;
41862306a36Sopenharmony_ci	int err, type_size;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	while (next_type + sizeof(struct btf_type) <= end_type) {
42162306a36Sopenharmony_ci		if (btf->swapped_endian)
42262306a36Sopenharmony_ci			btf_bswap_type_base(next_type);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		type_size = btf_type_size(next_type);
42562306a36Sopenharmony_ci		if (type_size < 0)
42662306a36Sopenharmony_ci			return type_size;
42762306a36Sopenharmony_ci		if (next_type + type_size > end_type) {
42862306a36Sopenharmony_ci			pr_warn("BTF type [%d] is malformed\n", btf->start_id + btf->nr_types);
42962306a36Sopenharmony_ci			return -EINVAL;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		if (btf->swapped_endian && btf_bswap_type_rest(next_type))
43362306a36Sopenharmony_ci			return -EINVAL;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		err = btf_add_type_idx_entry(btf, next_type - btf->types_data);
43662306a36Sopenharmony_ci		if (err)
43762306a36Sopenharmony_ci			return err;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		next_type += type_size;
44062306a36Sopenharmony_ci		btf->nr_types++;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (next_type != end_type) {
44462306a36Sopenharmony_ci		pr_warn("BTF types data is malformed\n");
44562306a36Sopenharmony_ci		return -EINVAL;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci__u32 btf__type_cnt(const struct btf *btf)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	return btf->start_id + btf->nr_types;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ciconst struct btf *btf__base_btf(const struct btf *btf)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	return btf->base_btf;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/* internal helper returning non-const pointer to a type */
46262306a36Sopenharmony_cistruct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	if (type_id == 0)
46562306a36Sopenharmony_ci		return &btf_void;
46662306a36Sopenharmony_ci	if (type_id < btf->start_id)
46762306a36Sopenharmony_ci		return btf_type_by_id(btf->base_btf, type_id);
46862306a36Sopenharmony_ci	return btf->types_data + btf->type_offs[type_id - btf->start_id];
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ciconst struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	if (type_id >= btf->start_id + btf->nr_types)
47462306a36Sopenharmony_ci		return errno = EINVAL, NULL;
47562306a36Sopenharmony_ci	return btf_type_by_id((struct btf *)btf, type_id);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int determine_ptr_size(const struct btf *btf)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	static const char * const long_aliases[] = {
48162306a36Sopenharmony_ci		"long",
48262306a36Sopenharmony_ci		"long int",
48362306a36Sopenharmony_ci		"int long",
48462306a36Sopenharmony_ci		"unsigned long",
48562306a36Sopenharmony_ci		"long unsigned",
48662306a36Sopenharmony_ci		"unsigned long int",
48762306a36Sopenharmony_ci		"unsigned int long",
48862306a36Sopenharmony_ci		"long unsigned int",
48962306a36Sopenharmony_ci		"long int unsigned",
49062306a36Sopenharmony_ci		"int unsigned long",
49162306a36Sopenharmony_ci		"int long unsigned",
49262306a36Sopenharmony_ci	};
49362306a36Sopenharmony_ci	const struct btf_type *t;
49462306a36Sopenharmony_ci	const char *name;
49562306a36Sopenharmony_ci	int i, j, n;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (btf->base_btf && btf->base_btf->ptr_sz > 0)
49862306a36Sopenharmony_ci		return btf->base_btf->ptr_sz;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	n = btf__type_cnt(btf);
50162306a36Sopenharmony_ci	for (i = 1; i < n; i++) {
50262306a36Sopenharmony_ci		t = btf__type_by_id(btf, i);
50362306a36Sopenharmony_ci		if (!btf_is_int(t))
50462306a36Sopenharmony_ci			continue;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		if (t->size != 4 && t->size != 8)
50762306a36Sopenharmony_ci			continue;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		name = btf__name_by_offset(btf, t->name_off);
51062306a36Sopenharmony_ci		if (!name)
51162306a36Sopenharmony_ci			continue;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(long_aliases); j++) {
51462306a36Sopenharmony_ci			if (strcmp(name, long_aliases[j]) == 0)
51562306a36Sopenharmony_ci				return t->size;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return -1;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic size_t btf_ptr_sz(const struct btf *btf)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	if (!btf->ptr_sz)
52562306a36Sopenharmony_ci		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
52662306a36Sopenharmony_ci	return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/* Return pointer size this BTF instance assumes. The size is heuristically
53062306a36Sopenharmony_ci * determined by looking for 'long' or 'unsigned long' integer type and
53162306a36Sopenharmony_ci * recording its size in bytes. If BTF type information doesn't have any such
53262306a36Sopenharmony_ci * type, this function returns 0. In the latter case, native architecture's
53362306a36Sopenharmony_ci * pointer size is assumed, so will be either 4 or 8, depending on
53462306a36Sopenharmony_ci * architecture that libbpf was compiled for. It's possible to override
53562306a36Sopenharmony_ci * guessed value by using btf__set_pointer_size() API.
53662306a36Sopenharmony_ci */
53762306a36Sopenharmony_cisize_t btf__pointer_size(const struct btf *btf)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	if (!btf->ptr_sz)
54062306a36Sopenharmony_ci		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (btf->ptr_sz < 0)
54362306a36Sopenharmony_ci		/* not enough BTF type info to guess */
54462306a36Sopenharmony_ci		return 0;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return btf->ptr_sz;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/* Override or set pointer size in bytes. Only values of 4 and 8 are
55062306a36Sopenharmony_ci * supported.
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_ciint btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	if (ptr_sz != 4 && ptr_sz != 8)
55562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
55662306a36Sopenharmony_ci	btf->ptr_sz = ptr_sz;
55762306a36Sopenharmony_ci	return 0;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic bool is_host_big_endian(void)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
56362306a36Sopenharmony_ci	return false;
56462306a36Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
56562306a36Sopenharmony_ci	return true;
56662306a36Sopenharmony_ci#else
56762306a36Sopenharmony_ci# error "Unrecognized __BYTE_ORDER__"
56862306a36Sopenharmony_ci#endif
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cienum btf_endianness btf__endianness(const struct btf *btf)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	if (is_host_big_endian())
57462306a36Sopenharmony_ci		return btf->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN;
57562306a36Sopenharmony_ci	else
57662306a36Sopenharmony_ci		return btf->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ciint btf__set_endianness(struct btf *btf, enum btf_endianness endian)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN)
58262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	btf->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN);
58562306a36Sopenharmony_ci	if (!btf->swapped_endian) {
58662306a36Sopenharmony_ci		free(btf->raw_data_swapped);
58762306a36Sopenharmony_ci		btf->raw_data_swapped = NULL;
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic bool btf_type_is_void(const struct btf_type *t)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	return t == &btf_void || btf_is_fwd(t);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic bool btf_type_is_void_or_null(const struct btf_type *t)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	return !t || btf_type_is_void(t);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci#define MAX_RESOLVE_DEPTH 32
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci__s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	const struct btf_array *array;
60762306a36Sopenharmony_ci	const struct btf_type *t;
60862306a36Sopenharmony_ci	__u32 nelems = 1;
60962306a36Sopenharmony_ci	__s64 size = -1;
61062306a36Sopenharmony_ci	int i;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	t = btf__type_by_id(btf, type_id);
61362306a36Sopenharmony_ci	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); i++) {
61462306a36Sopenharmony_ci		switch (btf_kind(t)) {
61562306a36Sopenharmony_ci		case BTF_KIND_INT:
61662306a36Sopenharmony_ci		case BTF_KIND_STRUCT:
61762306a36Sopenharmony_ci		case BTF_KIND_UNION:
61862306a36Sopenharmony_ci		case BTF_KIND_ENUM:
61962306a36Sopenharmony_ci		case BTF_KIND_ENUM64:
62062306a36Sopenharmony_ci		case BTF_KIND_DATASEC:
62162306a36Sopenharmony_ci		case BTF_KIND_FLOAT:
62262306a36Sopenharmony_ci			size = t->size;
62362306a36Sopenharmony_ci			goto done;
62462306a36Sopenharmony_ci		case BTF_KIND_PTR:
62562306a36Sopenharmony_ci			size = btf_ptr_sz(btf);
62662306a36Sopenharmony_ci			goto done;
62762306a36Sopenharmony_ci		case BTF_KIND_TYPEDEF:
62862306a36Sopenharmony_ci		case BTF_KIND_VOLATILE:
62962306a36Sopenharmony_ci		case BTF_KIND_CONST:
63062306a36Sopenharmony_ci		case BTF_KIND_RESTRICT:
63162306a36Sopenharmony_ci		case BTF_KIND_VAR:
63262306a36Sopenharmony_ci		case BTF_KIND_DECL_TAG:
63362306a36Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
63462306a36Sopenharmony_ci			type_id = t->type;
63562306a36Sopenharmony_ci			break;
63662306a36Sopenharmony_ci		case BTF_KIND_ARRAY:
63762306a36Sopenharmony_ci			array = btf_array(t);
63862306a36Sopenharmony_ci			if (nelems && array->nelems > UINT32_MAX / nelems)
63962306a36Sopenharmony_ci				return libbpf_err(-E2BIG);
64062306a36Sopenharmony_ci			nelems *= array->nelems;
64162306a36Sopenharmony_ci			type_id = array->type;
64262306a36Sopenharmony_ci			break;
64362306a36Sopenharmony_ci		default:
64462306a36Sopenharmony_ci			return libbpf_err(-EINVAL);
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		t = btf__type_by_id(btf, type_id);
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cidone:
65162306a36Sopenharmony_ci	if (size < 0)
65262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
65362306a36Sopenharmony_ci	if (nelems && size > UINT32_MAX / nelems)
65462306a36Sopenharmony_ci		return libbpf_err(-E2BIG);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return nelems * size;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ciint btf__align_of(const struct btf *btf, __u32 id)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	const struct btf_type *t = btf__type_by_id(btf, id);
66262306a36Sopenharmony_ci	__u16 kind = btf_kind(t);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	switch (kind) {
66562306a36Sopenharmony_ci	case BTF_KIND_INT:
66662306a36Sopenharmony_ci	case BTF_KIND_ENUM:
66762306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
66862306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
66962306a36Sopenharmony_ci		return min(btf_ptr_sz(btf), (size_t)t->size);
67062306a36Sopenharmony_ci	case BTF_KIND_PTR:
67162306a36Sopenharmony_ci		return btf_ptr_sz(btf);
67262306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
67362306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
67462306a36Sopenharmony_ci	case BTF_KIND_CONST:
67562306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
67662306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
67762306a36Sopenharmony_ci		return btf__align_of(btf, t->type);
67862306a36Sopenharmony_ci	case BTF_KIND_ARRAY:
67962306a36Sopenharmony_ci		return btf__align_of(btf, btf_array(t)->type);
68062306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
68162306a36Sopenharmony_ci	case BTF_KIND_UNION: {
68262306a36Sopenharmony_ci		const struct btf_member *m = btf_members(t);
68362306a36Sopenharmony_ci		__u16 vlen = btf_vlen(t);
68462306a36Sopenharmony_ci		int i, max_align = 1, align;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		for (i = 0; i < vlen; i++, m++) {
68762306a36Sopenharmony_ci			align = btf__align_of(btf, m->type);
68862306a36Sopenharmony_ci			if (align <= 0)
68962306a36Sopenharmony_ci				return libbpf_err(align);
69062306a36Sopenharmony_ci			max_align = max(max_align, align);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci			/* if field offset isn't aligned according to field
69362306a36Sopenharmony_ci			 * type's alignment, then struct must be packed
69462306a36Sopenharmony_ci			 */
69562306a36Sopenharmony_ci			if (btf_member_bitfield_size(t, i) == 0 &&
69662306a36Sopenharmony_ci			    (m->offset % (8 * align)) != 0)
69762306a36Sopenharmony_ci				return 1;
69862306a36Sopenharmony_ci		}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		/* if struct/union size isn't a multiple of its alignment,
70162306a36Sopenharmony_ci		 * then struct must be packed
70262306a36Sopenharmony_ci		 */
70362306a36Sopenharmony_ci		if ((t->size % max_align) != 0)
70462306a36Sopenharmony_ci			return 1;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		return max_align;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	default:
70962306a36Sopenharmony_ci		pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t));
71062306a36Sopenharmony_ci		return errno = EINVAL, 0;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ciint btf__resolve_type(const struct btf *btf, __u32 type_id)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	const struct btf_type *t;
71762306a36Sopenharmony_ci	int depth = 0;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	t = btf__type_by_id(btf, type_id);
72062306a36Sopenharmony_ci	while (depth < MAX_RESOLVE_DEPTH &&
72162306a36Sopenharmony_ci	       !btf_type_is_void_or_null(t) &&
72262306a36Sopenharmony_ci	       (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
72362306a36Sopenharmony_ci		type_id = t->type;
72462306a36Sopenharmony_ci		t = btf__type_by_id(btf, type_id);
72562306a36Sopenharmony_ci		depth++;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
72962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return type_id;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	__u32 i, nr_types = btf__type_cnt(btf);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (!strcmp(type_name, "void"))
73962306a36Sopenharmony_ci		return 0;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	for (i = 1; i < nr_types; i++) {
74262306a36Sopenharmony_ci		const struct btf_type *t = btf__type_by_id(btf, i);
74362306a36Sopenharmony_ci		const char *name = btf__name_by_offset(btf, t->name_off);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		if (name && !strcmp(type_name, name))
74662306a36Sopenharmony_ci			return i;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return libbpf_err(-ENOENT);
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
75362306a36Sopenharmony_ci				   const char *type_name, __u32 kind)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	__u32 i, nr_types = btf__type_cnt(btf);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
75862306a36Sopenharmony_ci		return 0;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	for (i = start_id; i < nr_types; i++) {
76162306a36Sopenharmony_ci		const struct btf_type *t = btf__type_by_id(btf, i);
76262306a36Sopenharmony_ci		const char *name;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		if (btf_kind(t) != kind)
76562306a36Sopenharmony_ci			continue;
76662306a36Sopenharmony_ci		name = btf__name_by_offset(btf, t->name_off);
76762306a36Sopenharmony_ci		if (name && !strcmp(type_name, name))
76862306a36Sopenharmony_ci			return i;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return libbpf_err(-ENOENT);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
77562306a36Sopenharmony_ci				 __u32 kind)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	return btf_find_by_name_kind(btf, btf->start_id, type_name, kind);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci__s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
78162306a36Sopenharmony_ci			     __u32 kind)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	return btf_find_by_name_kind(btf, 1, type_name, kind);
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic bool btf_is_modifiable(const struct btf *btf)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	return (void *)btf->hdr != btf->raw_data;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_civoid btf__free(struct btf *btf)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(btf))
79462306a36Sopenharmony_ci		return;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (btf->fd >= 0)
79762306a36Sopenharmony_ci		close(btf->fd);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (btf_is_modifiable(btf)) {
80062306a36Sopenharmony_ci		/* if BTF was modified after loading, it will have a split
80162306a36Sopenharmony_ci		 * in-memory representation for header, types, and strings
80262306a36Sopenharmony_ci		 * sections, so we need to free all of them individually. It
80362306a36Sopenharmony_ci		 * might still have a cached contiguous raw data present,
80462306a36Sopenharmony_ci		 * which will be unconditionally freed below.
80562306a36Sopenharmony_ci		 */
80662306a36Sopenharmony_ci		free(btf->hdr);
80762306a36Sopenharmony_ci		free(btf->types_data);
80862306a36Sopenharmony_ci		strset__free(btf->strs_set);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci	free(btf->raw_data);
81162306a36Sopenharmony_ci	free(btf->raw_data_swapped);
81262306a36Sopenharmony_ci	free(btf->type_offs);
81362306a36Sopenharmony_ci	free(btf);
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic struct btf *btf_new_empty(struct btf *base_btf)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	struct btf *btf;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	btf = calloc(1, sizeof(*btf));
82162306a36Sopenharmony_ci	if (!btf)
82262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	btf->nr_types = 0;
82562306a36Sopenharmony_ci	btf->start_id = 1;
82662306a36Sopenharmony_ci	btf->start_str_off = 0;
82762306a36Sopenharmony_ci	btf->fd = -1;
82862306a36Sopenharmony_ci	btf->ptr_sz = sizeof(void *);
82962306a36Sopenharmony_ci	btf->swapped_endian = false;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (base_btf) {
83262306a36Sopenharmony_ci		btf->base_btf = base_btf;
83362306a36Sopenharmony_ci		btf->start_id = btf__type_cnt(base_btf);
83462306a36Sopenharmony_ci		btf->start_str_off = base_btf->hdr->str_len;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/* +1 for empty string at offset 0 */
83862306a36Sopenharmony_ci	btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1);
83962306a36Sopenharmony_ci	btf->raw_data = calloc(1, btf->raw_size);
84062306a36Sopenharmony_ci	if (!btf->raw_data) {
84162306a36Sopenharmony_ci		free(btf);
84262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	btf->hdr = btf->raw_data;
84662306a36Sopenharmony_ci	btf->hdr->hdr_len = sizeof(struct btf_header);
84762306a36Sopenharmony_ci	btf->hdr->magic = BTF_MAGIC;
84862306a36Sopenharmony_ci	btf->hdr->version = BTF_VERSION;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	btf->types_data = btf->raw_data + btf->hdr->hdr_len;
85162306a36Sopenharmony_ci	btf->strs_data = btf->raw_data + btf->hdr->hdr_len;
85262306a36Sopenharmony_ci	btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	return btf;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistruct btf *btf__new_empty(void)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	return libbpf_ptr(btf_new_empty(NULL));
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistruct btf *btf__new_empty_split(struct btf *base_btf)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	return libbpf_ptr(btf_new_empty(base_btf));
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct btf *btf;
87062306a36Sopenharmony_ci	int err;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	btf = calloc(1, sizeof(struct btf));
87362306a36Sopenharmony_ci	if (!btf)
87462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	btf->nr_types = 0;
87762306a36Sopenharmony_ci	btf->start_id = 1;
87862306a36Sopenharmony_ci	btf->start_str_off = 0;
87962306a36Sopenharmony_ci	btf->fd = -1;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (base_btf) {
88262306a36Sopenharmony_ci		btf->base_btf = base_btf;
88362306a36Sopenharmony_ci		btf->start_id = btf__type_cnt(base_btf);
88462306a36Sopenharmony_ci		btf->start_str_off = base_btf->hdr->str_len;
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	btf->raw_data = malloc(size);
88862306a36Sopenharmony_ci	if (!btf->raw_data) {
88962306a36Sopenharmony_ci		err = -ENOMEM;
89062306a36Sopenharmony_ci		goto done;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci	memcpy(btf->raw_data, data, size);
89362306a36Sopenharmony_ci	btf->raw_size = size;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	btf->hdr = btf->raw_data;
89662306a36Sopenharmony_ci	err = btf_parse_hdr(btf);
89762306a36Sopenharmony_ci	if (err)
89862306a36Sopenharmony_ci		goto done;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	btf->strs_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->str_off;
90162306a36Sopenharmony_ci	btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	err = btf_parse_str_sec(btf);
90462306a36Sopenharmony_ci	err = err ?: btf_parse_type_sec(btf);
90562306a36Sopenharmony_ci	if (err)
90662306a36Sopenharmony_ci		goto done;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cidone:
90962306a36Sopenharmony_ci	if (err) {
91062306a36Sopenharmony_ci		btf__free(btf);
91162306a36Sopenharmony_ci		return ERR_PTR(err);
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return btf;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistruct btf *btf__new(const void *data, __u32 size)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	return libbpf_ptr(btf_new(data, size, NULL));
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
92362306a36Sopenharmony_ci				 struct btf_ext **btf_ext)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	Elf_Data *btf_data = NULL, *btf_ext_data = NULL;
92662306a36Sopenharmony_ci	int err = 0, fd = -1, idx = 0;
92762306a36Sopenharmony_ci	struct btf *btf = NULL;
92862306a36Sopenharmony_ci	Elf_Scn *scn = NULL;
92962306a36Sopenharmony_ci	Elf *elf = NULL;
93062306a36Sopenharmony_ci	GElf_Ehdr ehdr;
93162306a36Sopenharmony_ci	size_t shstrndx;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (elf_version(EV_CURRENT) == EV_NONE) {
93462306a36Sopenharmony_ci		pr_warn("failed to init libelf for %s\n", path);
93562306a36Sopenharmony_ci		return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	fd = open(path, O_RDONLY | O_CLOEXEC);
93962306a36Sopenharmony_ci	if (fd < 0) {
94062306a36Sopenharmony_ci		err = -errno;
94162306a36Sopenharmony_ci		pr_warn("failed to open %s: %s\n", path, strerror(errno));
94262306a36Sopenharmony_ci		return ERR_PTR(err);
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	err = -LIBBPF_ERRNO__FORMAT;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	elf = elf_begin(fd, ELF_C_READ, NULL);
94862306a36Sopenharmony_ci	if (!elf) {
94962306a36Sopenharmony_ci		pr_warn("failed to open %s as ELF file\n", path);
95062306a36Sopenharmony_ci		goto done;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci	if (!gelf_getehdr(elf, &ehdr)) {
95362306a36Sopenharmony_ci		pr_warn("failed to get EHDR from %s\n", path);
95462306a36Sopenharmony_ci		goto done;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (elf_getshdrstrndx(elf, &shstrndx)) {
95862306a36Sopenharmony_ci		pr_warn("failed to get section names section index for %s\n",
95962306a36Sopenharmony_ci			path);
96062306a36Sopenharmony_ci		goto done;
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) {
96462306a36Sopenharmony_ci		pr_warn("failed to get e_shstrndx from %s\n", path);
96562306a36Sopenharmony_ci		goto done;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	while ((scn = elf_nextscn(elf, scn)) != NULL) {
96962306a36Sopenharmony_ci		GElf_Shdr sh;
97062306a36Sopenharmony_ci		char *name;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci		idx++;
97362306a36Sopenharmony_ci		if (gelf_getshdr(scn, &sh) != &sh) {
97462306a36Sopenharmony_ci			pr_warn("failed to get section(%d) header from %s\n",
97562306a36Sopenharmony_ci				idx, path);
97662306a36Sopenharmony_ci			goto done;
97762306a36Sopenharmony_ci		}
97862306a36Sopenharmony_ci		name = elf_strptr(elf, shstrndx, sh.sh_name);
97962306a36Sopenharmony_ci		if (!name) {
98062306a36Sopenharmony_ci			pr_warn("failed to get section(%d) name from %s\n",
98162306a36Sopenharmony_ci				idx, path);
98262306a36Sopenharmony_ci			goto done;
98362306a36Sopenharmony_ci		}
98462306a36Sopenharmony_ci		if (strcmp(name, BTF_ELF_SEC) == 0) {
98562306a36Sopenharmony_ci			btf_data = elf_getdata(scn, 0);
98662306a36Sopenharmony_ci			if (!btf_data) {
98762306a36Sopenharmony_ci				pr_warn("failed to get section(%d, %s) data from %s\n",
98862306a36Sopenharmony_ci					idx, name, path);
98962306a36Sopenharmony_ci				goto done;
99062306a36Sopenharmony_ci			}
99162306a36Sopenharmony_ci			continue;
99262306a36Sopenharmony_ci		} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
99362306a36Sopenharmony_ci			btf_ext_data = elf_getdata(scn, 0);
99462306a36Sopenharmony_ci			if (!btf_ext_data) {
99562306a36Sopenharmony_ci				pr_warn("failed to get section(%d, %s) data from %s\n",
99662306a36Sopenharmony_ci					idx, name, path);
99762306a36Sopenharmony_ci				goto done;
99862306a36Sopenharmony_ci			}
99962306a36Sopenharmony_ci			continue;
100062306a36Sopenharmony_ci		}
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (!btf_data) {
100462306a36Sopenharmony_ci		pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path);
100562306a36Sopenharmony_ci		err = -ENODATA;
100662306a36Sopenharmony_ci		goto done;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci	btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
100962306a36Sopenharmony_ci	err = libbpf_get_error(btf);
101062306a36Sopenharmony_ci	if (err)
101162306a36Sopenharmony_ci		goto done;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	switch (gelf_getclass(elf)) {
101462306a36Sopenharmony_ci	case ELFCLASS32:
101562306a36Sopenharmony_ci		btf__set_pointer_size(btf, 4);
101662306a36Sopenharmony_ci		break;
101762306a36Sopenharmony_ci	case ELFCLASS64:
101862306a36Sopenharmony_ci		btf__set_pointer_size(btf, 8);
101962306a36Sopenharmony_ci		break;
102062306a36Sopenharmony_ci	default:
102162306a36Sopenharmony_ci		pr_warn("failed to get ELF class (bitness) for %s\n", path);
102262306a36Sopenharmony_ci		break;
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (btf_ext && btf_ext_data) {
102662306a36Sopenharmony_ci		*btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size);
102762306a36Sopenharmony_ci		err = libbpf_get_error(*btf_ext);
102862306a36Sopenharmony_ci		if (err)
102962306a36Sopenharmony_ci			goto done;
103062306a36Sopenharmony_ci	} else if (btf_ext) {
103162306a36Sopenharmony_ci		*btf_ext = NULL;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_cidone:
103462306a36Sopenharmony_ci	if (elf)
103562306a36Sopenharmony_ci		elf_end(elf);
103662306a36Sopenharmony_ci	close(fd);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (!err)
103962306a36Sopenharmony_ci		return btf;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (btf_ext)
104262306a36Sopenharmony_ci		btf_ext__free(*btf_ext);
104362306a36Sopenharmony_ci	btf__free(btf);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	return ERR_PTR(err);
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistruct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext));
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistruct btf *btf__parse_elf_split(const char *path, struct btf *base_btf)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	return libbpf_ptr(btf_parse_elf(path, base_btf, NULL));
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct btf *btf = NULL;
106162306a36Sopenharmony_ci	void *data = NULL;
106262306a36Sopenharmony_ci	FILE *f = NULL;
106362306a36Sopenharmony_ci	__u16 magic;
106462306a36Sopenharmony_ci	int err = 0;
106562306a36Sopenharmony_ci	long sz;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	f = fopen(path, "rbe");
106862306a36Sopenharmony_ci	if (!f) {
106962306a36Sopenharmony_ci		err = -errno;
107062306a36Sopenharmony_ci		goto err_out;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/* check BTF magic */
107462306a36Sopenharmony_ci	if (fread(&magic, 1, sizeof(magic), f) < sizeof(magic)) {
107562306a36Sopenharmony_ci		err = -EIO;
107662306a36Sopenharmony_ci		goto err_out;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci	if (magic != BTF_MAGIC && magic != bswap_16(BTF_MAGIC)) {
107962306a36Sopenharmony_ci		/* definitely not a raw BTF */
108062306a36Sopenharmony_ci		err = -EPROTO;
108162306a36Sopenharmony_ci		goto err_out;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	/* get file size */
108562306a36Sopenharmony_ci	if (fseek(f, 0, SEEK_END)) {
108662306a36Sopenharmony_ci		err = -errno;
108762306a36Sopenharmony_ci		goto err_out;
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci	sz = ftell(f);
109062306a36Sopenharmony_ci	if (sz < 0) {
109162306a36Sopenharmony_ci		err = -errno;
109262306a36Sopenharmony_ci		goto err_out;
109362306a36Sopenharmony_ci	}
109462306a36Sopenharmony_ci	/* rewind to the start */
109562306a36Sopenharmony_ci	if (fseek(f, 0, SEEK_SET)) {
109662306a36Sopenharmony_ci		err = -errno;
109762306a36Sopenharmony_ci		goto err_out;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* pre-alloc memory and read all of BTF data */
110162306a36Sopenharmony_ci	data = malloc(sz);
110262306a36Sopenharmony_ci	if (!data) {
110362306a36Sopenharmony_ci		err = -ENOMEM;
110462306a36Sopenharmony_ci		goto err_out;
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci	if (fread(data, 1, sz, f) < sz) {
110762306a36Sopenharmony_ci		err = -EIO;
110862306a36Sopenharmony_ci		goto err_out;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/* finally parse BTF data */
111262306a36Sopenharmony_ci	btf = btf_new(data, sz, base_btf);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cierr_out:
111562306a36Sopenharmony_ci	free(data);
111662306a36Sopenharmony_ci	if (f)
111762306a36Sopenharmony_ci		fclose(f);
111862306a36Sopenharmony_ci	return err ? ERR_PTR(err) : btf;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistruct btf *btf__parse_raw(const char *path)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	return libbpf_ptr(btf_parse_raw(path, NULL));
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistruct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	return libbpf_ptr(btf_parse_raw(path, base_btf));
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	struct btf *btf;
113462306a36Sopenharmony_ci	int err;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	if (btf_ext)
113762306a36Sopenharmony_ci		*btf_ext = NULL;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	btf = btf_parse_raw(path, base_btf);
114062306a36Sopenharmony_ci	err = libbpf_get_error(btf);
114162306a36Sopenharmony_ci	if (!err)
114262306a36Sopenharmony_ci		return btf;
114362306a36Sopenharmony_ci	if (err != -EPROTO)
114462306a36Sopenharmony_ci		return ERR_PTR(err);
114562306a36Sopenharmony_ci	return btf_parse_elf(path, base_btf, btf_ext);
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistruct btf *btf__parse(const char *path, struct btf_ext **btf_ext)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	return libbpf_ptr(btf_parse(path, NULL, btf_ext));
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistruct btf *btf__parse_split(const char *path, struct btf *base_btf)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	return libbpf_ptr(btf_parse(path, base_btf, NULL));
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ciint btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_btf_load_opts, opts);
116362306a36Sopenharmony_ci	__u32 buf_sz = 0, raw_size;
116462306a36Sopenharmony_ci	char *buf = NULL, *tmp;
116562306a36Sopenharmony_ci	void *raw_data;
116662306a36Sopenharmony_ci	int err = 0;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (btf->fd >= 0)
116962306a36Sopenharmony_ci		return libbpf_err(-EEXIST);
117062306a36Sopenharmony_ci	if (log_sz && !log_buf)
117162306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/* cache native raw data representation */
117462306a36Sopenharmony_ci	raw_data = btf_get_raw_data(btf, &raw_size, false);
117562306a36Sopenharmony_ci	if (!raw_data) {
117662306a36Sopenharmony_ci		err = -ENOMEM;
117762306a36Sopenharmony_ci		goto done;
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci	btf->raw_size = raw_size;
118062306a36Sopenharmony_ci	btf->raw_data = raw_data;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ciretry_load:
118362306a36Sopenharmony_ci	/* if log_level is 0, we won't provide log_buf/log_size to the kernel,
118462306a36Sopenharmony_ci	 * initially. Only if BTF loading fails, we bump log_level to 1 and
118562306a36Sopenharmony_ci	 * retry, using either auto-allocated or custom log_buf. This way
118662306a36Sopenharmony_ci	 * non-NULL custom log_buf provides a buffer just in case, but hopes
118762306a36Sopenharmony_ci	 * for successful load and no need for log_buf.
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci	if (log_level) {
119062306a36Sopenharmony_ci		/* if caller didn't provide custom log_buf, we'll keep
119162306a36Sopenharmony_ci		 * allocating our own progressively bigger buffers for BTF
119262306a36Sopenharmony_ci		 * verification log
119362306a36Sopenharmony_ci		 */
119462306a36Sopenharmony_ci		if (!log_buf) {
119562306a36Sopenharmony_ci			buf_sz = max((__u32)BPF_LOG_BUF_SIZE, buf_sz * 2);
119662306a36Sopenharmony_ci			tmp = realloc(buf, buf_sz);
119762306a36Sopenharmony_ci			if (!tmp) {
119862306a36Sopenharmony_ci				err = -ENOMEM;
119962306a36Sopenharmony_ci				goto done;
120062306a36Sopenharmony_ci			}
120162306a36Sopenharmony_ci			buf = tmp;
120262306a36Sopenharmony_ci			buf[0] = '\0';
120362306a36Sopenharmony_ci		}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci		opts.log_buf = log_buf ? log_buf : buf;
120662306a36Sopenharmony_ci		opts.log_size = log_buf ? log_sz : buf_sz;
120762306a36Sopenharmony_ci		opts.log_level = log_level;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	btf->fd = bpf_btf_load(raw_data, raw_size, &opts);
121162306a36Sopenharmony_ci	if (btf->fd < 0) {
121262306a36Sopenharmony_ci		/* time to turn on verbose mode and try again */
121362306a36Sopenharmony_ci		if (log_level == 0) {
121462306a36Sopenharmony_ci			log_level = 1;
121562306a36Sopenharmony_ci			goto retry_load;
121662306a36Sopenharmony_ci		}
121762306a36Sopenharmony_ci		/* only retry if caller didn't provide custom log_buf, but
121862306a36Sopenharmony_ci		 * make sure we can never overflow buf_sz
121962306a36Sopenharmony_ci		 */
122062306a36Sopenharmony_ci		if (!log_buf && errno == ENOSPC && buf_sz <= UINT_MAX / 2)
122162306a36Sopenharmony_ci			goto retry_load;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		err = -errno;
122462306a36Sopenharmony_ci		pr_warn("BTF loading error: %d\n", err);
122562306a36Sopenharmony_ci		/* don't print out contents of custom log_buf */
122662306a36Sopenharmony_ci		if (!log_buf && buf[0])
122762306a36Sopenharmony_ci			pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf);
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_cidone:
123162306a36Sopenharmony_ci	free(buf);
123262306a36Sopenharmony_ci	return libbpf_err(err);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ciint btf__load_into_kernel(struct btf *btf)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	return btf_load_into_kernel(btf, NULL, 0, 0);
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ciint btf__fd(const struct btf *btf)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	return btf->fd;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_civoid btf__set_fd(struct btf *btf, int fd)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	btf->fd = fd;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic const void *btf_strs_data(const struct btf *btf)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	return btf->strs_data ? btf->strs_data : strset__data(btf->strs_set);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
125862306a36Sopenharmony_ci	struct btf_type *t;
125962306a36Sopenharmony_ci	void *data, *p;
126062306a36Sopenharmony_ci	__u32 data_sz;
126162306a36Sopenharmony_ci	int i;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	data = swap_endian ? btf->raw_data_swapped : btf->raw_data;
126462306a36Sopenharmony_ci	if (data) {
126562306a36Sopenharmony_ci		*size = btf->raw_size;
126662306a36Sopenharmony_ci		return data;
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len;
127062306a36Sopenharmony_ci	data = calloc(1, data_sz);
127162306a36Sopenharmony_ci	if (!data)
127262306a36Sopenharmony_ci		return NULL;
127362306a36Sopenharmony_ci	p = data;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	memcpy(p, hdr, hdr->hdr_len);
127662306a36Sopenharmony_ci	if (swap_endian)
127762306a36Sopenharmony_ci		btf_bswap_hdr(p);
127862306a36Sopenharmony_ci	p += hdr->hdr_len;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	memcpy(p, btf->types_data, hdr->type_len);
128162306a36Sopenharmony_ci	if (swap_endian) {
128262306a36Sopenharmony_ci		for (i = 0; i < btf->nr_types; i++) {
128362306a36Sopenharmony_ci			t = p + btf->type_offs[i];
128462306a36Sopenharmony_ci			/* btf_bswap_type_rest() relies on native t->info, so
128562306a36Sopenharmony_ci			 * we swap base type info after we swapped all the
128662306a36Sopenharmony_ci			 * additional information
128762306a36Sopenharmony_ci			 */
128862306a36Sopenharmony_ci			if (btf_bswap_type_rest(t))
128962306a36Sopenharmony_ci				goto err_out;
129062306a36Sopenharmony_ci			btf_bswap_type_base(t);
129162306a36Sopenharmony_ci		}
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci	p += hdr->type_len;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	memcpy(p, btf_strs_data(btf), hdr->str_len);
129662306a36Sopenharmony_ci	p += hdr->str_len;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	*size = data_sz;
129962306a36Sopenharmony_ci	return data;
130062306a36Sopenharmony_cierr_out:
130162306a36Sopenharmony_ci	free(data);
130262306a36Sopenharmony_ci	return NULL;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ciconst void *btf__raw_data(const struct btf *btf_ro, __u32 *size)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	struct btf *btf = (struct btf *)btf_ro;
130862306a36Sopenharmony_ci	__u32 data_sz;
130962306a36Sopenharmony_ci	void *data;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian);
131262306a36Sopenharmony_ci	if (!data)
131362306a36Sopenharmony_ci		return errno = ENOMEM, NULL;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	btf->raw_size = data_sz;
131662306a36Sopenharmony_ci	if (btf->swapped_endian)
131762306a36Sopenharmony_ci		btf->raw_data_swapped = data;
131862306a36Sopenharmony_ci	else
131962306a36Sopenharmony_ci		btf->raw_data = data;
132062306a36Sopenharmony_ci	*size = data_sz;
132162306a36Sopenharmony_ci	return data;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci__attribute__((alias("btf__raw_data")))
132562306a36Sopenharmony_ciconst void *btf__get_raw_data(const struct btf *btf, __u32 *size);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ciconst char *btf__str_by_offset(const struct btf *btf, __u32 offset)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	if (offset < btf->start_str_off)
133062306a36Sopenharmony_ci		return btf__str_by_offset(btf->base_btf, offset);
133162306a36Sopenharmony_ci	else if (offset - btf->start_str_off < btf->hdr->str_len)
133262306a36Sopenharmony_ci		return btf_strs_data(btf) + (offset - btf->start_str_off);
133362306a36Sopenharmony_ci	else
133462306a36Sopenharmony_ci		return errno = EINVAL, NULL;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ciconst char *btf__name_by_offset(const struct btf *btf, __u32 offset)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	return btf__str_by_offset(btf, offset);
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistruct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	struct bpf_btf_info btf_info;
134562306a36Sopenharmony_ci	__u32 len = sizeof(btf_info);
134662306a36Sopenharmony_ci	__u32 last_size;
134762306a36Sopenharmony_ci	struct btf *btf;
134862306a36Sopenharmony_ci	void *ptr;
134962306a36Sopenharmony_ci	int err;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/* we won't know btf_size until we call bpf_btf_get_info_by_fd(). so
135262306a36Sopenharmony_ci	 * let's start with a sane default - 4KiB here - and resize it only if
135362306a36Sopenharmony_ci	 * bpf_btf_get_info_by_fd() needs a bigger buffer.
135462306a36Sopenharmony_ci	 */
135562306a36Sopenharmony_ci	last_size = 4096;
135662306a36Sopenharmony_ci	ptr = malloc(last_size);
135762306a36Sopenharmony_ci	if (!ptr)
135862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	memset(&btf_info, 0, sizeof(btf_info));
136162306a36Sopenharmony_ci	btf_info.btf = ptr_to_u64(ptr);
136262306a36Sopenharmony_ci	btf_info.btf_size = last_size;
136362306a36Sopenharmony_ci	err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (!err && btf_info.btf_size > last_size) {
136662306a36Sopenharmony_ci		void *temp_ptr;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci		last_size = btf_info.btf_size;
136962306a36Sopenharmony_ci		temp_ptr = realloc(ptr, last_size);
137062306a36Sopenharmony_ci		if (!temp_ptr) {
137162306a36Sopenharmony_ci			btf = ERR_PTR(-ENOMEM);
137262306a36Sopenharmony_ci			goto exit_free;
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci		ptr = temp_ptr;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci		len = sizeof(btf_info);
137762306a36Sopenharmony_ci		memset(&btf_info, 0, sizeof(btf_info));
137862306a36Sopenharmony_ci		btf_info.btf = ptr_to_u64(ptr);
137962306a36Sopenharmony_ci		btf_info.btf_size = last_size;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	if (err || btf_info.btf_size > last_size) {
138562306a36Sopenharmony_ci		btf = err ? ERR_PTR(-errno) : ERR_PTR(-E2BIG);
138662306a36Sopenharmony_ci		goto exit_free;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	btf = btf_new(ptr, btf_info.btf_size, base_btf);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ciexit_free:
139262306a36Sopenharmony_ci	free(ptr);
139362306a36Sopenharmony_ci	return btf;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistruct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct btf *btf;
139962306a36Sopenharmony_ci	int btf_fd;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	btf_fd = bpf_btf_get_fd_by_id(id);
140262306a36Sopenharmony_ci	if (btf_fd < 0)
140362306a36Sopenharmony_ci		return libbpf_err_ptr(-errno);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	btf = btf_get_from_fd(btf_fd, base_btf);
140662306a36Sopenharmony_ci	close(btf_fd);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	return libbpf_ptr(btf);
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistruct btf *btf__load_from_kernel_by_id(__u32 id)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	return btf__load_from_kernel_by_id_split(id, NULL);
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic void btf_invalidate_raw_data(struct btf *btf)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	if (btf->raw_data) {
141962306a36Sopenharmony_ci		free(btf->raw_data);
142062306a36Sopenharmony_ci		btf->raw_data = NULL;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci	if (btf->raw_data_swapped) {
142362306a36Sopenharmony_ci		free(btf->raw_data_swapped);
142462306a36Sopenharmony_ci		btf->raw_data_swapped = NULL;
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci/* Ensure BTF is ready to be modified (by splitting into a three memory
142962306a36Sopenharmony_ci * regions for header, types, and strings). Also invalidate cached
143062306a36Sopenharmony_ci * raw_data, if any.
143162306a36Sopenharmony_ci */
143262306a36Sopenharmony_cistatic int btf_ensure_modifiable(struct btf *btf)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	void *hdr, *types;
143562306a36Sopenharmony_ci	struct strset *set = NULL;
143662306a36Sopenharmony_ci	int err = -ENOMEM;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	if (btf_is_modifiable(btf)) {
143962306a36Sopenharmony_ci		/* any BTF modification invalidates raw_data */
144062306a36Sopenharmony_ci		btf_invalidate_raw_data(btf);
144162306a36Sopenharmony_ci		return 0;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/* split raw data into three memory regions */
144562306a36Sopenharmony_ci	hdr = malloc(btf->hdr->hdr_len);
144662306a36Sopenharmony_ci	types = malloc(btf->hdr->type_len);
144762306a36Sopenharmony_ci	if (!hdr || !types)
144862306a36Sopenharmony_ci		goto err_out;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	memcpy(hdr, btf->hdr, btf->hdr->hdr_len);
145162306a36Sopenharmony_ci	memcpy(types, btf->types_data, btf->hdr->type_len);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	/* build lookup index for all strings */
145462306a36Sopenharmony_ci	set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len);
145562306a36Sopenharmony_ci	if (IS_ERR(set)) {
145662306a36Sopenharmony_ci		err = PTR_ERR(set);
145762306a36Sopenharmony_ci		goto err_out;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* only when everything was successful, update internal state */
146162306a36Sopenharmony_ci	btf->hdr = hdr;
146262306a36Sopenharmony_ci	btf->types_data = types;
146362306a36Sopenharmony_ci	btf->types_data_cap = btf->hdr->type_len;
146462306a36Sopenharmony_ci	btf->strs_data = NULL;
146562306a36Sopenharmony_ci	btf->strs_set = set;
146662306a36Sopenharmony_ci	/* if BTF was created from scratch, all strings are guaranteed to be
146762306a36Sopenharmony_ci	 * unique and deduplicated
146862306a36Sopenharmony_ci	 */
146962306a36Sopenharmony_ci	if (btf->hdr->str_len == 0)
147062306a36Sopenharmony_ci		btf->strs_deduped = true;
147162306a36Sopenharmony_ci	if (!btf->base_btf && btf->hdr->str_len == 1)
147262306a36Sopenharmony_ci		btf->strs_deduped = true;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* invalidate raw_data representation */
147562306a36Sopenharmony_ci	btf_invalidate_raw_data(btf);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	return 0;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cierr_out:
148062306a36Sopenharmony_ci	strset__free(set);
148162306a36Sopenharmony_ci	free(hdr);
148262306a36Sopenharmony_ci	free(types);
148362306a36Sopenharmony_ci	return err;
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci/* Find an offset in BTF string section that corresponds to a given string *s*.
148762306a36Sopenharmony_ci * Returns:
148862306a36Sopenharmony_ci *   - >0 offset into string section, if string is found;
148962306a36Sopenharmony_ci *   - -ENOENT, if string is not in the string section;
149062306a36Sopenharmony_ci *   - <0, on any other error.
149162306a36Sopenharmony_ci */
149262306a36Sopenharmony_ciint btf__find_str(struct btf *btf, const char *s)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	int off;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (btf->base_btf) {
149762306a36Sopenharmony_ci		off = btf__find_str(btf->base_btf, s);
149862306a36Sopenharmony_ci		if (off != -ENOENT)
149962306a36Sopenharmony_ci			return off;
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	/* BTF needs to be in a modifiable state to build string lookup index */
150362306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
150462306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	off = strset__find_str(btf->strs_set, s);
150762306a36Sopenharmony_ci	if (off < 0)
150862306a36Sopenharmony_ci		return libbpf_err(off);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	return btf->start_str_off + off;
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci/* Add a string s to the BTF string section.
151462306a36Sopenharmony_ci * Returns:
151562306a36Sopenharmony_ci *   - > 0 offset into string section, on success;
151662306a36Sopenharmony_ci *   - < 0, on error.
151762306a36Sopenharmony_ci */
151862306a36Sopenharmony_ciint btf__add_str(struct btf *btf, const char *s)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	int off;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (btf->base_btf) {
152362306a36Sopenharmony_ci		off = btf__find_str(btf->base_btf, s);
152462306a36Sopenharmony_ci		if (off != -ENOENT)
152562306a36Sopenharmony_ci			return off;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
152962306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	off = strset__add_str(btf->strs_set, s);
153262306a36Sopenharmony_ci	if (off < 0)
153362306a36Sopenharmony_ci		return libbpf_err(off);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	btf->hdr->str_len = strset__data_size(btf->strs_set);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return btf->start_str_off + off;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_cistatic void *btf_add_type_mem(struct btf *btf, size_t add_sz)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	return libbpf_add_mem(&btf->types_data, &btf->types_data_cap, 1,
154362306a36Sopenharmony_ci			      btf->hdr->type_len, UINT_MAX, add_sz);
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic void btf_type_inc_vlen(struct btf_type *t)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic int btf_commit_type(struct btf *btf, int data_sz)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	int err;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	err = btf_add_type_idx_entry(btf, btf->hdr->type_len);
155662306a36Sopenharmony_ci	if (err)
155762306a36Sopenharmony_ci		return libbpf_err(err);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	btf->hdr->type_len += data_sz;
156062306a36Sopenharmony_ci	btf->hdr->str_off += data_sz;
156162306a36Sopenharmony_ci	btf->nr_types++;
156262306a36Sopenharmony_ci	return btf->start_id + btf->nr_types - 1;
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_cistruct btf_pipe {
156662306a36Sopenharmony_ci	const struct btf *src;
156762306a36Sopenharmony_ci	struct btf *dst;
156862306a36Sopenharmony_ci	struct hashmap *str_off_map; /* map string offsets from src to dst */
156962306a36Sopenharmony_ci};
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic int btf_rewrite_str(__u32 *str_off, void *ctx)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	struct btf_pipe *p = ctx;
157462306a36Sopenharmony_ci	long mapped_off;
157562306a36Sopenharmony_ci	int off, err;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (!*str_off) /* nothing to do for empty strings */
157862306a36Sopenharmony_ci		return 0;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (p->str_off_map &&
158162306a36Sopenharmony_ci	    hashmap__find(p->str_off_map, *str_off, &mapped_off)) {
158262306a36Sopenharmony_ci		*str_off = mapped_off;
158362306a36Sopenharmony_ci		return 0;
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off));
158762306a36Sopenharmony_ci	if (off < 0)
158862306a36Sopenharmony_ci		return off;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	/* Remember string mapping from src to dst.  It avoids
159162306a36Sopenharmony_ci	 * performing expensive string comparisons.
159262306a36Sopenharmony_ci	 */
159362306a36Sopenharmony_ci	if (p->str_off_map) {
159462306a36Sopenharmony_ci		err = hashmap__append(p->str_off_map, *str_off, off);
159562306a36Sopenharmony_ci		if (err)
159662306a36Sopenharmony_ci			return err;
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	*str_off = off;
160062306a36Sopenharmony_ci	return 0;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ciint btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct btf_pipe p = { .src = src_btf, .dst = btf };
160662306a36Sopenharmony_ci	struct btf_type *t;
160762306a36Sopenharmony_ci	int sz, err;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	sz = btf_type_size(src_type);
161062306a36Sopenharmony_ci	if (sz < 0)
161162306a36Sopenharmony_ci		return libbpf_err(sz);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
161462306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
161562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
161862306a36Sopenharmony_ci	if (!t)
161962306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	memcpy(t, src_type, sz);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
162462306a36Sopenharmony_ci	if (err)
162562306a36Sopenharmony_ci		return libbpf_err(err);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_cistatic int btf_rewrite_type_ids(__u32 *type_id, void *ctx)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	struct btf *btf = ctx;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if (!*type_id) /* nothing to do for VOID references */
163562306a36Sopenharmony_ci		return 0;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	/* we haven't updated btf's type count yet, so
163862306a36Sopenharmony_ci	 * btf->start_id + btf->nr_types - 1 is the type ID offset we should
163962306a36Sopenharmony_ci	 * add to all newly added BTF types
164062306a36Sopenharmony_ci	 */
164162306a36Sopenharmony_ci	*type_id += btf->start_id + btf->nr_types - 1;
164262306a36Sopenharmony_ci	return 0;
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic size_t btf_dedup_identity_hash_fn(long key, void *ctx);
164662306a36Sopenharmony_cistatic bool btf_dedup_equal_fn(long k1, long k2, void *ctx);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ciint btf__add_btf(struct btf *btf, const struct btf *src_btf)
164962306a36Sopenharmony_ci{
165062306a36Sopenharmony_ci	struct btf_pipe p = { .src = src_btf, .dst = btf };
165162306a36Sopenharmony_ci	int data_sz, sz, cnt, i, err, old_strs_len;
165262306a36Sopenharmony_ci	__u32 *off;
165362306a36Sopenharmony_ci	void *t;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	/* appending split BTF isn't supported yet */
165662306a36Sopenharmony_ci	if (src_btf->base_btf)
165762306a36Sopenharmony_ci		return libbpf_err(-ENOTSUP);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
166062306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
166162306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/* remember original strings section size if we have to roll back
166462306a36Sopenharmony_ci	 * partial strings section changes
166562306a36Sopenharmony_ci	 */
166662306a36Sopenharmony_ci	old_strs_len = btf->hdr->str_len;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	data_sz = src_btf->hdr->type_len;
166962306a36Sopenharmony_ci	cnt = btf__type_cnt(src_btf) - 1;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	/* pre-allocate enough memory for new types */
167262306a36Sopenharmony_ci	t = btf_add_type_mem(btf, data_sz);
167362306a36Sopenharmony_ci	if (!t)
167462306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	/* pre-allocate enough memory for type offset index for new types */
167762306a36Sopenharmony_ci	off = btf_add_type_offs_mem(btf, cnt);
167862306a36Sopenharmony_ci	if (!off)
167962306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* Map the string offsets from src_btf to the offsets from btf to improve performance */
168262306a36Sopenharmony_ci	p.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
168362306a36Sopenharmony_ci	if (IS_ERR(p.str_off_map))
168462306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	/* bulk copy types data for all types from src_btf */
168762306a36Sopenharmony_ci	memcpy(t, src_btf->types_data, data_sz);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	for (i = 0; i < cnt; i++) {
169062306a36Sopenharmony_ci		sz = btf_type_size(t);
169162306a36Sopenharmony_ci		if (sz < 0) {
169262306a36Sopenharmony_ci			/* unlikely, has to be corrupted src_btf */
169362306a36Sopenharmony_ci			err = sz;
169462306a36Sopenharmony_ci			goto err_out;
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		/* fill out type ID to type offset mapping for lookups by type ID */
169862306a36Sopenharmony_ci		*off = t - btf->types_data;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci		/* add, dedup, and remap strings referenced by this BTF type */
170162306a36Sopenharmony_ci		err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
170262306a36Sopenharmony_ci		if (err)
170362306a36Sopenharmony_ci			goto err_out;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		/* remap all type IDs referenced from this BTF type */
170662306a36Sopenharmony_ci		err = btf_type_visit_type_ids(t, btf_rewrite_type_ids, btf);
170762306a36Sopenharmony_ci		if (err)
170862306a36Sopenharmony_ci			goto err_out;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		/* go to next type data and type offset index entry */
171162306a36Sopenharmony_ci		t += sz;
171262306a36Sopenharmony_ci		off++;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/* Up until now any of the copied type data was effectively invisible,
171662306a36Sopenharmony_ci	 * so if we exited early before this point due to error, BTF would be
171762306a36Sopenharmony_ci	 * effectively unmodified. There would be extra internal memory
171862306a36Sopenharmony_ci	 * pre-allocated, but it would not be available for querying.  But now
171962306a36Sopenharmony_ci	 * that we've copied and rewritten all the data successfully, we can
172062306a36Sopenharmony_ci	 * update type count and various internal offsets and sizes to
172162306a36Sopenharmony_ci	 * "commit" the changes and made them visible to the outside world.
172262306a36Sopenharmony_ci	 */
172362306a36Sopenharmony_ci	btf->hdr->type_len += data_sz;
172462306a36Sopenharmony_ci	btf->hdr->str_off += data_sz;
172562306a36Sopenharmony_ci	btf->nr_types += cnt;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	hashmap__free(p.str_off_map);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/* return type ID of the first added BTF type */
173062306a36Sopenharmony_ci	return btf->start_id + btf->nr_types - cnt;
173162306a36Sopenharmony_cierr_out:
173262306a36Sopenharmony_ci	/* zero out preallocated memory as if it was just allocated with
173362306a36Sopenharmony_ci	 * libbpf_add_mem()
173462306a36Sopenharmony_ci	 */
173562306a36Sopenharmony_ci	memset(btf->types_data + btf->hdr->type_len, 0, data_sz);
173662306a36Sopenharmony_ci	memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	/* and now restore original strings section size; types data size
173962306a36Sopenharmony_ci	 * wasn't modified, so doesn't need restoring, see big comment above
174062306a36Sopenharmony_ci	 */
174162306a36Sopenharmony_ci	btf->hdr->str_len = old_strs_len;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	hashmap__free(p.str_off_map);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	return libbpf_err(err);
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci/*
174962306a36Sopenharmony_ci * Append new BTF_KIND_INT type with:
175062306a36Sopenharmony_ci *   - *name* - non-empty, non-NULL type name;
175162306a36Sopenharmony_ci *   - *sz* - power-of-2 (1, 2, 4, ..) size of the type, in bytes;
175262306a36Sopenharmony_ci *   - encoding is a combination of BTF_INT_SIGNED, BTF_INT_CHAR, BTF_INT_BOOL.
175362306a36Sopenharmony_ci * Returns:
175462306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
175562306a36Sopenharmony_ci *   - <0, on error.
175662306a36Sopenharmony_ci */
175762306a36Sopenharmony_ciint btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding)
175862306a36Sopenharmony_ci{
175962306a36Sopenharmony_ci	struct btf_type *t;
176062306a36Sopenharmony_ci	int sz, name_off;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* non-empty name */
176362306a36Sopenharmony_ci	if (!name || !name[0])
176462306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
176562306a36Sopenharmony_ci	/* byte_sz must be power of 2 */
176662306a36Sopenharmony_ci	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16)
176762306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
176862306a36Sopenharmony_ci	if (encoding & ~(BTF_INT_SIGNED | BTF_INT_CHAR | BTF_INT_BOOL))
176962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
177262306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
177362306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(int);
177662306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
177762306a36Sopenharmony_ci	if (!t)
177862306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/* if something goes wrong later, we might end up with an extra string,
178162306a36Sopenharmony_ci	 * but that shouldn't be a problem, because BTF can't be constructed
178262306a36Sopenharmony_ci	 * completely anyway and will most probably be just discarded
178362306a36Sopenharmony_ci	 */
178462306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
178562306a36Sopenharmony_ci	if (name_off < 0)
178662306a36Sopenharmony_ci		return name_off;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	t->name_off = name_off;
178962306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_INT, 0, 0);
179062306a36Sopenharmony_ci	t->size = byte_sz;
179162306a36Sopenharmony_ci	/* set INT info, we don't allow setting legacy bit offset/size */
179262306a36Sopenharmony_ci	*(__u32 *)(t + 1) = (encoding << 24) | (byte_sz * 8);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci/*
179862306a36Sopenharmony_ci * Append new BTF_KIND_FLOAT type with:
179962306a36Sopenharmony_ci *   - *name* - non-empty, non-NULL type name;
180062306a36Sopenharmony_ci *   - *sz* - size of the type, in bytes;
180162306a36Sopenharmony_ci * Returns:
180262306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
180362306a36Sopenharmony_ci *   - <0, on error.
180462306a36Sopenharmony_ci */
180562306a36Sopenharmony_ciint btf__add_float(struct btf *btf, const char *name, size_t byte_sz)
180662306a36Sopenharmony_ci{
180762306a36Sopenharmony_ci	struct btf_type *t;
180862306a36Sopenharmony_ci	int sz, name_off;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	/* non-empty name */
181162306a36Sopenharmony_ci	if (!name || !name[0])
181262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	/* byte_sz must be one of the explicitly allowed values */
181562306a36Sopenharmony_ci	if (byte_sz != 2 && byte_sz != 4 && byte_sz != 8 && byte_sz != 12 &&
181662306a36Sopenharmony_ci	    byte_sz != 16)
181762306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
182062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
182362306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
182462306a36Sopenharmony_ci	if (!t)
182562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
182862306a36Sopenharmony_ci	if (name_off < 0)
182962306a36Sopenharmony_ci		return name_off;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	t->name_off = name_off;
183262306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0);
183362306a36Sopenharmony_ci	t->size = byte_sz;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
183662306a36Sopenharmony_ci}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci/* it's completely legal to append BTF types with type IDs pointing forward to
183962306a36Sopenharmony_ci * types that haven't been appended yet, so we only make sure that id looks
184062306a36Sopenharmony_ci * sane, we can't guarantee that ID will always be valid
184162306a36Sopenharmony_ci */
184262306a36Sopenharmony_cistatic int validate_type_id(int id)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	if (id < 0 || id > BTF_MAX_NR_TYPES)
184562306a36Sopenharmony_ci		return -EINVAL;
184662306a36Sopenharmony_ci	return 0;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci/* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */
185062306a36Sopenharmony_cistatic int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	struct btf_type *t;
185362306a36Sopenharmony_ci	int sz, name_off = 0;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (validate_type_id(ref_type_id))
185662306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
185962306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
186262306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
186362306a36Sopenharmony_ci	if (!t)
186462306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (name && name[0]) {
186762306a36Sopenharmony_ci		name_off = btf__add_str(btf, name);
186862306a36Sopenharmony_ci		if (name_off < 0)
186962306a36Sopenharmony_ci			return name_off;
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	t->name_off = name_off;
187362306a36Sopenharmony_ci	t->info = btf_type_info(kind, 0, 0);
187462306a36Sopenharmony_ci	t->type = ref_type_id;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci/*
188062306a36Sopenharmony_ci * Append new BTF_KIND_PTR type with:
188162306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
188262306a36Sopenharmony_ci * Returns:
188362306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
188462306a36Sopenharmony_ci *   - <0, on error.
188562306a36Sopenharmony_ci */
188662306a36Sopenharmony_ciint btf__add_ptr(struct btf *btf, int ref_type_id)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci/*
189262306a36Sopenharmony_ci * Append new BTF_KIND_ARRAY type with:
189362306a36Sopenharmony_ci *   - *index_type_id* - type ID of the type describing array index;
189462306a36Sopenharmony_ci *   - *elem_type_id* - type ID of the type describing array element;
189562306a36Sopenharmony_ci *   - *nr_elems* - the size of the array;
189662306a36Sopenharmony_ci * Returns:
189762306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
189862306a36Sopenharmony_ci *   - <0, on error.
189962306a36Sopenharmony_ci */
190062306a36Sopenharmony_ciint btf__add_array(struct btf *btf, int index_type_id, int elem_type_id, __u32 nr_elems)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	struct btf_type *t;
190362306a36Sopenharmony_ci	struct btf_array *a;
190462306a36Sopenharmony_ci	int sz;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (validate_type_id(index_type_id) || validate_type_id(elem_type_id))
190762306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
191062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_array);
191362306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
191462306a36Sopenharmony_ci	if (!t)
191562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	t->name_off = 0;
191862306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_ARRAY, 0, 0);
191962306a36Sopenharmony_ci	t->size = 0;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	a = btf_array(t);
192262306a36Sopenharmony_ci	a->type = elem_type_id;
192362306a36Sopenharmony_ci	a->index_type = index_type_id;
192462306a36Sopenharmony_ci	a->nelems = nr_elems;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci/* generic STRUCT/UNION append function */
193062306a36Sopenharmony_cistatic int btf_add_composite(struct btf *btf, int kind, const char *name, __u32 bytes_sz)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	struct btf_type *t;
193362306a36Sopenharmony_ci	int sz, name_off = 0;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
193662306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
193962306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
194062306a36Sopenharmony_ci	if (!t)
194162306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	if (name && name[0]) {
194462306a36Sopenharmony_ci		name_off = btf__add_str(btf, name);
194562306a36Sopenharmony_ci		if (name_off < 0)
194662306a36Sopenharmony_ci			return name_off;
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	/* start out with vlen=0 and no kflag; this will be adjusted when
195062306a36Sopenharmony_ci	 * adding each member
195162306a36Sopenharmony_ci	 */
195262306a36Sopenharmony_ci	t->name_off = name_off;
195362306a36Sopenharmony_ci	t->info = btf_type_info(kind, 0, 0);
195462306a36Sopenharmony_ci	t->size = bytes_sz;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci/*
196062306a36Sopenharmony_ci * Append new BTF_KIND_STRUCT type with:
196162306a36Sopenharmony_ci *   - *name* - name of the struct, can be NULL or empty for anonymous structs;
196262306a36Sopenharmony_ci *   - *byte_sz* - size of the struct, in bytes;
196362306a36Sopenharmony_ci *
196462306a36Sopenharmony_ci * Struct initially has no fields in it. Fields can be added by
196562306a36Sopenharmony_ci * btf__add_field() right after btf__add_struct() succeeds.
196662306a36Sopenharmony_ci *
196762306a36Sopenharmony_ci * Returns:
196862306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
196962306a36Sopenharmony_ci *   - <0, on error.
197062306a36Sopenharmony_ci */
197162306a36Sopenharmony_ciint btf__add_struct(struct btf *btf, const char *name, __u32 byte_sz)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	return btf_add_composite(btf, BTF_KIND_STRUCT, name, byte_sz);
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci/*
197762306a36Sopenharmony_ci * Append new BTF_KIND_UNION type with:
197862306a36Sopenharmony_ci *   - *name* - name of the union, can be NULL or empty for anonymous union;
197962306a36Sopenharmony_ci *   - *byte_sz* - size of the union, in bytes;
198062306a36Sopenharmony_ci *
198162306a36Sopenharmony_ci * Union initially has no fields in it. Fields can be added by
198262306a36Sopenharmony_ci * btf__add_field() right after btf__add_union() succeeds. All fields
198362306a36Sopenharmony_ci * should have *bit_offset* of 0.
198462306a36Sopenharmony_ci *
198562306a36Sopenharmony_ci * Returns:
198662306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
198762306a36Sopenharmony_ci *   - <0, on error.
198862306a36Sopenharmony_ci */
198962306a36Sopenharmony_ciint btf__add_union(struct btf *btf, const char *name, __u32 byte_sz)
199062306a36Sopenharmony_ci{
199162306a36Sopenharmony_ci	return btf_add_composite(btf, BTF_KIND_UNION, name, byte_sz);
199262306a36Sopenharmony_ci}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_cistatic struct btf_type *btf_last_type(struct btf *btf)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	return btf_type_by_id(btf, btf__type_cnt(btf) - 1);
199762306a36Sopenharmony_ci}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci/*
200062306a36Sopenharmony_ci * Append new field for the current STRUCT/UNION type with:
200162306a36Sopenharmony_ci *   - *name* - name of the field, can be NULL or empty for anonymous field;
200262306a36Sopenharmony_ci *   - *type_id* - type ID for the type describing field type;
200362306a36Sopenharmony_ci *   - *bit_offset* - bit offset of the start of the field within struct/union;
200462306a36Sopenharmony_ci *   - *bit_size* - bit size of a bitfield, 0 for non-bitfield fields;
200562306a36Sopenharmony_ci * Returns:
200662306a36Sopenharmony_ci *   -  0, on success;
200762306a36Sopenharmony_ci *   - <0, on error.
200862306a36Sopenharmony_ci */
200962306a36Sopenharmony_ciint btf__add_field(struct btf *btf, const char *name, int type_id,
201062306a36Sopenharmony_ci		   __u32 bit_offset, __u32 bit_size)
201162306a36Sopenharmony_ci{
201262306a36Sopenharmony_ci	struct btf_type *t;
201362306a36Sopenharmony_ci	struct btf_member *m;
201462306a36Sopenharmony_ci	bool is_bitfield;
201562306a36Sopenharmony_ci	int sz, name_off = 0;
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/* last type should be union/struct */
201862306a36Sopenharmony_ci	if (btf->nr_types == 0)
201962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
202062306a36Sopenharmony_ci	t = btf_last_type(btf);
202162306a36Sopenharmony_ci	if (!btf_is_composite(t))
202262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	if (validate_type_id(type_id))
202562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
202662306a36Sopenharmony_ci	/* best-effort bit field offset/size enforcement */
202762306a36Sopenharmony_ci	is_bitfield = bit_size || (bit_offset % 8 != 0);
202862306a36Sopenharmony_ci	if (is_bitfield && (bit_size == 0 || bit_size > 255 || bit_offset > 0xffffff))
202962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	/* only offset 0 is allowed for unions */
203262306a36Sopenharmony_ci	if (btf_is_union(t) && bit_offset)
203362306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	/* decompose and invalidate raw data */
203662306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
203762306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	sz = sizeof(struct btf_member);
204062306a36Sopenharmony_ci	m = btf_add_type_mem(btf, sz);
204162306a36Sopenharmony_ci	if (!m)
204262306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	if (name && name[0]) {
204562306a36Sopenharmony_ci		name_off = btf__add_str(btf, name);
204662306a36Sopenharmony_ci		if (name_off < 0)
204762306a36Sopenharmony_ci			return name_off;
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	m->name_off = name_off;
205162306a36Sopenharmony_ci	m->type = type_id;
205262306a36Sopenharmony_ci	m->offset = bit_offset | (bit_size << 24);
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	/* btf_add_type_mem can invalidate t pointer */
205562306a36Sopenharmony_ci	t = btf_last_type(btf);
205662306a36Sopenharmony_ci	/* update parent type's vlen and kflag */
205762306a36Sopenharmony_ci	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	btf->hdr->type_len += sz;
206062306a36Sopenharmony_ci	btf->hdr->str_off += sz;
206162306a36Sopenharmony_ci	return 0;
206262306a36Sopenharmony_ci}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_cistatic int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
206562306a36Sopenharmony_ci			       bool is_signed, __u8 kind)
206662306a36Sopenharmony_ci{
206762306a36Sopenharmony_ci	struct btf_type *t;
206862306a36Sopenharmony_ci	int sz, name_off = 0;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	/* byte_sz must be power of 2 */
207162306a36Sopenharmony_ci	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 8)
207262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
207562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
207862306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
207962306a36Sopenharmony_ci	if (!t)
208062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	if (name && name[0]) {
208362306a36Sopenharmony_ci		name_off = btf__add_str(btf, name);
208462306a36Sopenharmony_ci		if (name_off < 0)
208562306a36Sopenharmony_ci			return name_off;
208662306a36Sopenharmony_ci	}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	/* start out with vlen=0; it will be adjusted when adding enum values */
208962306a36Sopenharmony_ci	t->name_off = name_off;
209062306a36Sopenharmony_ci	t->info = btf_type_info(kind, 0, is_signed);
209162306a36Sopenharmony_ci	t->size = byte_sz;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
209462306a36Sopenharmony_ci}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci/*
209762306a36Sopenharmony_ci * Append new BTF_KIND_ENUM type with:
209862306a36Sopenharmony_ci *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
209962306a36Sopenharmony_ci *   - *byte_sz* - size of the enum, in bytes.
210062306a36Sopenharmony_ci *
210162306a36Sopenharmony_ci * Enum initially has no enum values in it (and corresponds to enum forward
210262306a36Sopenharmony_ci * declaration). Enumerator values can be added by btf__add_enum_value()
210362306a36Sopenharmony_ci * immediately after btf__add_enum() succeeds.
210462306a36Sopenharmony_ci *
210562306a36Sopenharmony_ci * Returns:
210662306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
210762306a36Sopenharmony_ci *   - <0, on error.
210862306a36Sopenharmony_ci */
210962306a36Sopenharmony_ciint btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	/*
211262306a36Sopenharmony_ci	 * set the signedness to be unsigned, it will change to signed
211362306a36Sopenharmony_ci	 * if any later enumerator is negative.
211462306a36Sopenharmony_ci	 */
211562306a36Sopenharmony_ci	return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
211662306a36Sopenharmony_ci}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci/*
211962306a36Sopenharmony_ci * Append new enum value for the current ENUM type with:
212062306a36Sopenharmony_ci *   - *name* - name of the enumerator value, can't be NULL or empty;
212162306a36Sopenharmony_ci *   - *value* - integer value corresponding to enum value *name*;
212262306a36Sopenharmony_ci * Returns:
212362306a36Sopenharmony_ci *   -  0, on success;
212462306a36Sopenharmony_ci *   - <0, on error.
212562306a36Sopenharmony_ci */
212662306a36Sopenharmony_ciint btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
212762306a36Sopenharmony_ci{
212862306a36Sopenharmony_ci	struct btf_type *t;
212962306a36Sopenharmony_ci	struct btf_enum *v;
213062306a36Sopenharmony_ci	int sz, name_off;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	/* last type should be BTF_KIND_ENUM */
213362306a36Sopenharmony_ci	if (btf->nr_types == 0)
213462306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
213562306a36Sopenharmony_ci	t = btf_last_type(btf);
213662306a36Sopenharmony_ci	if (!btf_is_enum(t))
213762306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	/* non-empty name */
214062306a36Sopenharmony_ci	if (!name || !name[0])
214162306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
214262306a36Sopenharmony_ci	if (value < INT_MIN || value > UINT_MAX)
214362306a36Sopenharmony_ci		return libbpf_err(-E2BIG);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	/* decompose and invalidate raw data */
214662306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
214762306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	sz = sizeof(struct btf_enum);
215062306a36Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
215162306a36Sopenharmony_ci	if (!v)
215262306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
215562306a36Sopenharmony_ci	if (name_off < 0)
215662306a36Sopenharmony_ci		return name_off;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	v->name_off = name_off;
215962306a36Sopenharmony_ci	v->val = value;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	/* update parent type's vlen */
216262306a36Sopenharmony_ci	t = btf_last_type(btf);
216362306a36Sopenharmony_ci	btf_type_inc_vlen(t);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	/* if negative value, set signedness to signed */
216662306a36Sopenharmony_ci	if (value < 0)
216762306a36Sopenharmony_ci		t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	btf->hdr->type_len += sz;
217062306a36Sopenharmony_ci	btf->hdr->str_off += sz;
217162306a36Sopenharmony_ci	return 0;
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci/*
217562306a36Sopenharmony_ci * Append new BTF_KIND_ENUM64 type with:
217662306a36Sopenharmony_ci *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
217762306a36Sopenharmony_ci *   - *byte_sz* - size of the enum, in bytes.
217862306a36Sopenharmony_ci *   - *is_signed* - whether the enum values are signed or not;
217962306a36Sopenharmony_ci *
218062306a36Sopenharmony_ci * Enum initially has no enum values in it (and corresponds to enum forward
218162306a36Sopenharmony_ci * declaration). Enumerator values can be added by btf__add_enum64_value()
218262306a36Sopenharmony_ci * immediately after btf__add_enum64() succeeds.
218362306a36Sopenharmony_ci *
218462306a36Sopenharmony_ci * Returns:
218562306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
218662306a36Sopenharmony_ci *   - <0, on error.
218762306a36Sopenharmony_ci */
218862306a36Sopenharmony_ciint btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
218962306a36Sopenharmony_ci		    bool is_signed)
219062306a36Sopenharmony_ci{
219162306a36Sopenharmony_ci	return btf_add_enum_common(btf, name, byte_sz, is_signed,
219262306a36Sopenharmony_ci				   BTF_KIND_ENUM64);
219362306a36Sopenharmony_ci}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci/*
219662306a36Sopenharmony_ci * Append new enum value for the current ENUM64 type with:
219762306a36Sopenharmony_ci *   - *name* - name of the enumerator value, can't be NULL or empty;
219862306a36Sopenharmony_ci *   - *value* - integer value corresponding to enum value *name*;
219962306a36Sopenharmony_ci * Returns:
220062306a36Sopenharmony_ci *   -  0, on success;
220162306a36Sopenharmony_ci *   - <0, on error.
220262306a36Sopenharmony_ci */
220362306a36Sopenharmony_ciint btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct btf_enum64 *v;
220662306a36Sopenharmony_ci	struct btf_type *t;
220762306a36Sopenharmony_ci	int sz, name_off;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	/* last type should be BTF_KIND_ENUM64 */
221062306a36Sopenharmony_ci	if (btf->nr_types == 0)
221162306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
221262306a36Sopenharmony_ci	t = btf_last_type(btf);
221362306a36Sopenharmony_ci	if (!btf_is_enum64(t))
221462306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	/* non-empty name */
221762306a36Sopenharmony_ci	if (!name || !name[0])
221862306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	/* decompose and invalidate raw data */
222162306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
222262306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	sz = sizeof(struct btf_enum64);
222562306a36Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
222662306a36Sopenharmony_ci	if (!v)
222762306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
223062306a36Sopenharmony_ci	if (name_off < 0)
223162306a36Sopenharmony_ci		return name_off;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	v->name_off = name_off;
223462306a36Sopenharmony_ci	v->val_lo32 = (__u32)value;
223562306a36Sopenharmony_ci	v->val_hi32 = value >> 32;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	/* update parent type's vlen */
223862306a36Sopenharmony_ci	t = btf_last_type(btf);
223962306a36Sopenharmony_ci	btf_type_inc_vlen(t);
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	btf->hdr->type_len += sz;
224262306a36Sopenharmony_ci	btf->hdr->str_off += sz;
224362306a36Sopenharmony_ci	return 0;
224462306a36Sopenharmony_ci}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci/*
224762306a36Sopenharmony_ci * Append new BTF_KIND_FWD type with:
224862306a36Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
224962306a36Sopenharmony_ci *   - *fwd_kind*, kind of forward declaration, one of BTF_FWD_STRUCT,
225062306a36Sopenharmony_ci *     BTF_FWD_UNION, or BTF_FWD_ENUM;
225162306a36Sopenharmony_ci * Returns:
225262306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
225362306a36Sopenharmony_ci *   - <0, on error.
225462306a36Sopenharmony_ci */
225562306a36Sopenharmony_ciint btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind)
225662306a36Sopenharmony_ci{
225762306a36Sopenharmony_ci	if (!name || !name[0])
225862306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	switch (fwd_kind) {
226162306a36Sopenharmony_ci	case BTF_FWD_STRUCT:
226262306a36Sopenharmony_ci	case BTF_FWD_UNION: {
226362306a36Sopenharmony_ci		struct btf_type *t;
226462306a36Sopenharmony_ci		int id;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci		id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0);
226762306a36Sopenharmony_ci		if (id <= 0)
226862306a36Sopenharmony_ci			return id;
226962306a36Sopenharmony_ci		t = btf_type_by_id(btf, id);
227062306a36Sopenharmony_ci		t->info = btf_type_info(BTF_KIND_FWD, 0, fwd_kind == BTF_FWD_UNION);
227162306a36Sopenharmony_ci		return id;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci	case BTF_FWD_ENUM:
227462306a36Sopenharmony_ci		/* enum forward in BTF currently is just an enum with no enum
227562306a36Sopenharmony_ci		 * values; we also assume a standard 4-byte size for it
227662306a36Sopenharmony_ci		 */
227762306a36Sopenharmony_ci		return btf__add_enum(btf, name, sizeof(int));
227862306a36Sopenharmony_ci	default:
227962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci/*
228462306a36Sopenharmony_ci * Append new BTF_KING_TYPEDEF type with:
228562306a36Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
228662306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
228762306a36Sopenharmony_ci * Returns:
228862306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
228962306a36Sopenharmony_ci *   - <0, on error.
229062306a36Sopenharmony_ci */
229162306a36Sopenharmony_ciint btf__add_typedef(struct btf *btf, const char *name, int ref_type_id)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	if (!name || !name[0])
229462306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id);
229762306a36Sopenharmony_ci}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci/*
230062306a36Sopenharmony_ci * Append new BTF_KIND_VOLATILE type with:
230162306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
230262306a36Sopenharmony_ci * Returns:
230362306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
230462306a36Sopenharmony_ci *   - <0, on error.
230562306a36Sopenharmony_ci */
230662306a36Sopenharmony_ciint btf__add_volatile(struct btf *btf, int ref_type_id)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id);
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci/*
231262306a36Sopenharmony_ci * Append new BTF_KIND_CONST type with:
231362306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
231462306a36Sopenharmony_ci * Returns:
231562306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
231662306a36Sopenharmony_ci *   - <0, on error.
231762306a36Sopenharmony_ci */
231862306a36Sopenharmony_ciint btf__add_const(struct btf *btf, int ref_type_id)
231962306a36Sopenharmony_ci{
232062306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id);
232162306a36Sopenharmony_ci}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci/*
232462306a36Sopenharmony_ci * Append new BTF_KIND_RESTRICT type with:
232562306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
232662306a36Sopenharmony_ci * Returns:
232762306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
232862306a36Sopenharmony_ci *   - <0, on error.
232962306a36Sopenharmony_ci */
233062306a36Sopenharmony_ciint btf__add_restrict(struct btf *btf, int ref_type_id)
233162306a36Sopenharmony_ci{
233262306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id);
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci/*
233662306a36Sopenharmony_ci * Append new BTF_KIND_TYPE_TAG type with:
233762306a36Sopenharmony_ci *   - *value*, non-empty/non-NULL tag value;
233862306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
233962306a36Sopenharmony_ci * Returns:
234062306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
234162306a36Sopenharmony_ci *   - <0, on error.
234262306a36Sopenharmony_ci */
234362306a36Sopenharmony_ciint btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
234462306a36Sopenharmony_ci{
234562306a36Sopenharmony_ci	if (!value || !value[0])
234662306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci/*
235262306a36Sopenharmony_ci * Append new BTF_KIND_FUNC type with:
235362306a36Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
235462306a36Sopenharmony_ci *   - *proto_type_id* - FUNC_PROTO's type ID, it might not exist yet;
235562306a36Sopenharmony_ci * Returns:
235662306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
235762306a36Sopenharmony_ci *   - <0, on error.
235862306a36Sopenharmony_ci */
235962306a36Sopenharmony_ciint btf__add_func(struct btf *btf, const char *name,
236062306a36Sopenharmony_ci		  enum btf_func_linkage linkage, int proto_type_id)
236162306a36Sopenharmony_ci{
236262306a36Sopenharmony_ci	int id;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	if (!name || !name[0])
236562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
236662306a36Sopenharmony_ci	if (linkage != BTF_FUNC_STATIC && linkage != BTF_FUNC_GLOBAL &&
236762306a36Sopenharmony_ci	    linkage != BTF_FUNC_EXTERN)
236862306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id);
237162306a36Sopenharmony_ci	if (id > 0) {
237262306a36Sopenharmony_ci		struct btf_type *t = btf_type_by_id(btf, id);
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci		t->info = btf_type_info(BTF_KIND_FUNC, linkage, 0);
237562306a36Sopenharmony_ci	}
237662306a36Sopenharmony_ci	return libbpf_err(id);
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci/*
238062306a36Sopenharmony_ci * Append new BTF_KIND_FUNC_PROTO with:
238162306a36Sopenharmony_ci *   - *ret_type_id* - type ID for return result of a function.
238262306a36Sopenharmony_ci *
238362306a36Sopenharmony_ci * Function prototype initially has no arguments, but they can be added by
238462306a36Sopenharmony_ci * btf__add_func_param() one by one, immediately after
238562306a36Sopenharmony_ci * btf__add_func_proto() succeeded.
238662306a36Sopenharmony_ci *
238762306a36Sopenharmony_ci * Returns:
238862306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
238962306a36Sopenharmony_ci *   - <0, on error.
239062306a36Sopenharmony_ci */
239162306a36Sopenharmony_ciint btf__add_func_proto(struct btf *btf, int ret_type_id)
239262306a36Sopenharmony_ci{
239362306a36Sopenharmony_ci	struct btf_type *t;
239462306a36Sopenharmony_ci	int sz;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	if (validate_type_id(ret_type_id))
239762306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
240062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
240362306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
240462306a36Sopenharmony_ci	if (!t)
240562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	/* start out with vlen=0; this will be adjusted when adding enum
240862306a36Sopenharmony_ci	 * values, if necessary
240962306a36Sopenharmony_ci	 */
241062306a36Sopenharmony_ci	t->name_off = 0;
241162306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_FUNC_PROTO, 0, 0);
241262306a36Sopenharmony_ci	t->type = ret_type_id;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci/*
241862306a36Sopenharmony_ci * Append new function parameter for current FUNC_PROTO type with:
241962306a36Sopenharmony_ci *   - *name* - parameter name, can be NULL or empty;
242062306a36Sopenharmony_ci *   - *type_id* - type ID describing the type of the parameter.
242162306a36Sopenharmony_ci * Returns:
242262306a36Sopenharmony_ci *   -  0, on success;
242362306a36Sopenharmony_ci *   - <0, on error.
242462306a36Sopenharmony_ci */
242562306a36Sopenharmony_ciint btf__add_func_param(struct btf *btf, const char *name, int type_id)
242662306a36Sopenharmony_ci{
242762306a36Sopenharmony_ci	struct btf_type *t;
242862306a36Sopenharmony_ci	struct btf_param *p;
242962306a36Sopenharmony_ci	int sz, name_off = 0;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (validate_type_id(type_id))
243262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	/* last type should be BTF_KIND_FUNC_PROTO */
243562306a36Sopenharmony_ci	if (btf->nr_types == 0)
243662306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
243762306a36Sopenharmony_ci	t = btf_last_type(btf);
243862306a36Sopenharmony_ci	if (!btf_is_func_proto(t))
243962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	/* decompose and invalidate raw data */
244262306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
244362306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	sz = sizeof(struct btf_param);
244662306a36Sopenharmony_ci	p = btf_add_type_mem(btf, sz);
244762306a36Sopenharmony_ci	if (!p)
244862306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	if (name && name[0]) {
245162306a36Sopenharmony_ci		name_off = btf__add_str(btf, name);
245262306a36Sopenharmony_ci		if (name_off < 0)
245362306a36Sopenharmony_ci			return name_off;
245462306a36Sopenharmony_ci	}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	p->name_off = name_off;
245762306a36Sopenharmony_ci	p->type = type_id;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	/* update parent type's vlen */
246062306a36Sopenharmony_ci	t = btf_last_type(btf);
246162306a36Sopenharmony_ci	btf_type_inc_vlen(t);
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	btf->hdr->type_len += sz;
246462306a36Sopenharmony_ci	btf->hdr->str_off += sz;
246562306a36Sopenharmony_ci	return 0;
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci/*
246962306a36Sopenharmony_ci * Append new BTF_KIND_VAR type with:
247062306a36Sopenharmony_ci *   - *name* - non-empty/non-NULL name;
247162306a36Sopenharmony_ci *   - *linkage* - variable linkage, one of BTF_VAR_STATIC,
247262306a36Sopenharmony_ci *     BTF_VAR_GLOBAL_ALLOCATED, or BTF_VAR_GLOBAL_EXTERN;
247362306a36Sopenharmony_ci *   - *type_id* - type ID of the type describing the type of the variable.
247462306a36Sopenharmony_ci * Returns:
247562306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
247662306a36Sopenharmony_ci *   - <0, on error.
247762306a36Sopenharmony_ci */
247862306a36Sopenharmony_ciint btf__add_var(struct btf *btf, const char *name, int linkage, int type_id)
247962306a36Sopenharmony_ci{
248062306a36Sopenharmony_ci	struct btf_type *t;
248162306a36Sopenharmony_ci	struct btf_var *v;
248262306a36Sopenharmony_ci	int sz, name_off;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	/* non-empty name */
248562306a36Sopenharmony_ci	if (!name || !name[0])
248662306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
248762306a36Sopenharmony_ci	if (linkage != BTF_VAR_STATIC && linkage != BTF_VAR_GLOBAL_ALLOCATED &&
248862306a36Sopenharmony_ci	    linkage != BTF_VAR_GLOBAL_EXTERN)
248962306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
249062306a36Sopenharmony_ci	if (validate_type_id(type_id))
249162306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
249462306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
249562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_var);
249862306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
249962306a36Sopenharmony_ci	if (!t)
250062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
250362306a36Sopenharmony_ci	if (name_off < 0)
250462306a36Sopenharmony_ci		return name_off;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	t->name_off = name_off;
250762306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_VAR, 0, 0);
250862306a36Sopenharmony_ci	t->type = type_id;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	v = btf_var(t);
251162306a36Sopenharmony_ci	v->linkage = linkage;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
251462306a36Sopenharmony_ci}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci/*
251762306a36Sopenharmony_ci * Append new BTF_KIND_DATASEC type with:
251862306a36Sopenharmony_ci *   - *name* - non-empty/non-NULL name;
251962306a36Sopenharmony_ci *   - *byte_sz* - data section size, in bytes.
252062306a36Sopenharmony_ci *
252162306a36Sopenharmony_ci * Data section is initially empty. Variables info can be added with
252262306a36Sopenharmony_ci * btf__add_datasec_var_info() calls, after btf__add_datasec() succeeds.
252362306a36Sopenharmony_ci *
252462306a36Sopenharmony_ci * Returns:
252562306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
252662306a36Sopenharmony_ci *   - <0, on error.
252762306a36Sopenharmony_ci */
252862306a36Sopenharmony_ciint btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	struct btf_type *t;
253162306a36Sopenharmony_ci	int sz, name_off;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	/* non-empty name */
253462306a36Sopenharmony_ci	if (!name || !name[0])
253562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
253862306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	sz = sizeof(struct btf_type);
254162306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
254262306a36Sopenharmony_ci	if (!t)
254362306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	name_off = btf__add_str(btf, name);
254662306a36Sopenharmony_ci	if (name_off < 0)
254762306a36Sopenharmony_ci		return name_off;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	/* start with vlen=0, which will be update as var_secinfos are added */
255062306a36Sopenharmony_ci	t->name_off = name_off;
255162306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_DATASEC, 0, 0);
255262306a36Sopenharmony_ci	t->size = byte_sz;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
255562306a36Sopenharmony_ci}
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci/*
255862306a36Sopenharmony_ci * Append new data section variable information entry for current DATASEC type:
255962306a36Sopenharmony_ci *   - *var_type_id* - type ID, describing type of the variable;
256062306a36Sopenharmony_ci *   - *offset* - variable offset within data section, in bytes;
256162306a36Sopenharmony_ci *   - *byte_sz* - variable size, in bytes.
256262306a36Sopenharmony_ci *
256362306a36Sopenharmony_ci * Returns:
256462306a36Sopenharmony_ci *   -  0, on success;
256562306a36Sopenharmony_ci *   - <0, on error.
256662306a36Sopenharmony_ci */
256762306a36Sopenharmony_ciint btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz)
256862306a36Sopenharmony_ci{
256962306a36Sopenharmony_ci	struct btf_type *t;
257062306a36Sopenharmony_ci	struct btf_var_secinfo *v;
257162306a36Sopenharmony_ci	int sz;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	/* last type should be BTF_KIND_DATASEC */
257462306a36Sopenharmony_ci	if (btf->nr_types == 0)
257562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
257662306a36Sopenharmony_ci	t = btf_last_type(btf);
257762306a36Sopenharmony_ci	if (!btf_is_datasec(t))
257862306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	if (validate_type_id(var_type_id))
258162306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/* decompose and invalidate raw data */
258462306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
258562306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	sz = sizeof(struct btf_var_secinfo);
258862306a36Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
258962306a36Sopenharmony_ci	if (!v)
259062306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	v->type = var_type_id;
259362306a36Sopenharmony_ci	v->offset = offset;
259462306a36Sopenharmony_ci	v->size = byte_sz;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	/* update parent type's vlen */
259762306a36Sopenharmony_ci	t = btf_last_type(btf);
259862306a36Sopenharmony_ci	btf_type_inc_vlen(t);
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	btf->hdr->type_len += sz;
260162306a36Sopenharmony_ci	btf->hdr->str_off += sz;
260262306a36Sopenharmony_ci	return 0;
260362306a36Sopenharmony_ci}
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci/*
260662306a36Sopenharmony_ci * Append new BTF_KIND_DECL_TAG type with:
260762306a36Sopenharmony_ci *   - *value* - non-empty/non-NULL string;
260862306a36Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
260962306a36Sopenharmony_ci *   - *component_idx* - -1 for tagging reference type, otherwise struct/union
261062306a36Sopenharmony_ci *     member or function argument index;
261162306a36Sopenharmony_ci * Returns:
261262306a36Sopenharmony_ci *   - >0, type ID of newly added BTF type;
261362306a36Sopenharmony_ci *   - <0, on error.
261462306a36Sopenharmony_ci */
261562306a36Sopenharmony_ciint btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
261662306a36Sopenharmony_ci		 int component_idx)
261762306a36Sopenharmony_ci{
261862306a36Sopenharmony_ci	struct btf_type *t;
261962306a36Sopenharmony_ci	int sz, value_off;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	if (!value || !value[0] || component_idx < -1)
262262306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	if (validate_type_id(ref_type_id))
262562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf))
262862306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag);
263162306a36Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
263262306a36Sopenharmony_ci	if (!t)
263362306a36Sopenharmony_ci		return libbpf_err(-ENOMEM);
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	value_off = btf__add_str(btf, value);
263662306a36Sopenharmony_ci	if (value_off < 0)
263762306a36Sopenharmony_ci		return value_off;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	t->name_off = value_off;
264062306a36Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false);
264162306a36Sopenharmony_ci	t->type = ref_type_id;
264262306a36Sopenharmony_ci	btf_decl_tag(t)->component_idx = component_idx;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	return btf_commit_type(btf, sz);
264562306a36Sopenharmony_ci}
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_cistruct btf_ext_sec_setup_param {
264862306a36Sopenharmony_ci	__u32 off;
264962306a36Sopenharmony_ci	__u32 len;
265062306a36Sopenharmony_ci	__u32 min_rec_size;
265162306a36Sopenharmony_ci	struct btf_ext_info *ext_info;
265262306a36Sopenharmony_ci	const char *desc;
265362306a36Sopenharmony_ci};
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic int btf_ext_setup_info(struct btf_ext *btf_ext,
265662306a36Sopenharmony_ci			      struct btf_ext_sec_setup_param *ext_sec)
265762306a36Sopenharmony_ci{
265862306a36Sopenharmony_ci	const struct btf_ext_info_sec *sinfo;
265962306a36Sopenharmony_ci	struct btf_ext_info *ext_info;
266062306a36Sopenharmony_ci	__u32 info_left, record_size;
266162306a36Sopenharmony_ci	size_t sec_cnt = 0;
266262306a36Sopenharmony_ci	/* The start of the info sec (including the __u32 record_size). */
266362306a36Sopenharmony_ci	void *info;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	if (ext_sec->len == 0)
266662306a36Sopenharmony_ci		return 0;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	if (ext_sec->off & 0x03) {
266962306a36Sopenharmony_ci		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
267062306a36Sopenharmony_ci		     ext_sec->desc);
267162306a36Sopenharmony_ci		return -EINVAL;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off;
267562306a36Sopenharmony_ci	info_left = ext_sec->len;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) {
267862306a36Sopenharmony_ci		pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
267962306a36Sopenharmony_ci			 ext_sec->desc, ext_sec->off, ext_sec->len);
268062306a36Sopenharmony_ci		return -EINVAL;
268162306a36Sopenharmony_ci	}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	/* At least a record size */
268462306a36Sopenharmony_ci	if (info_left < sizeof(__u32)) {
268562306a36Sopenharmony_ci		pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);
268662306a36Sopenharmony_ci		return -EINVAL;
268762306a36Sopenharmony_ci	}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	/* The record size needs to meet the minimum standard */
269062306a36Sopenharmony_ci	record_size = *(__u32 *)info;
269162306a36Sopenharmony_ci	if (record_size < ext_sec->min_rec_size ||
269262306a36Sopenharmony_ci	    record_size & 0x03) {
269362306a36Sopenharmony_ci		pr_debug("%s section in .BTF.ext has invalid record size %u\n",
269462306a36Sopenharmony_ci			 ext_sec->desc, record_size);
269562306a36Sopenharmony_ci		return -EINVAL;
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	sinfo = info + sizeof(__u32);
269962306a36Sopenharmony_ci	info_left -= sizeof(__u32);
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	/* If no records, return failure now so .BTF.ext won't be used. */
270262306a36Sopenharmony_ci	if (!info_left) {
270362306a36Sopenharmony_ci		pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);
270462306a36Sopenharmony_ci		return -EINVAL;
270562306a36Sopenharmony_ci	}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	while (info_left) {
270862306a36Sopenharmony_ci		unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
270962306a36Sopenharmony_ci		__u64 total_record_size;
271062306a36Sopenharmony_ci		__u32 num_records;
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci		if (info_left < sec_hdrlen) {
271362306a36Sopenharmony_ci			pr_debug("%s section header is not found in .BTF.ext\n",
271462306a36Sopenharmony_ci			     ext_sec->desc);
271562306a36Sopenharmony_ci			return -EINVAL;
271662306a36Sopenharmony_ci		}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci		num_records = sinfo->num_info;
271962306a36Sopenharmony_ci		if (num_records == 0) {
272062306a36Sopenharmony_ci			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
272162306a36Sopenharmony_ci			     ext_sec->desc);
272262306a36Sopenharmony_ci			return -EINVAL;
272362306a36Sopenharmony_ci		}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci		total_record_size = sec_hdrlen + (__u64)num_records * record_size;
272662306a36Sopenharmony_ci		if (info_left < total_record_size) {
272762306a36Sopenharmony_ci			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
272862306a36Sopenharmony_ci			     ext_sec->desc);
272962306a36Sopenharmony_ci			return -EINVAL;
273062306a36Sopenharmony_ci		}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci		info_left -= total_record_size;
273362306a36Sopenharmony_ci		sinfo = (void *)sinfo + total_record_size;
273462306a36Sopenharmony_ci		sec_cnt++;
273562306a36Sopenharmony_ci	}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	ext_info = ext_sec->ext_info;
273862306a36Sopenharmony_ci	ext_info->len = ext_sec->len - sizeof(__u32);
273962306a36Sopenharmony_ci	ext_info->rec_size = record_size;
274062306a36Sopenharmony_ci	ext_info->info = info + sizeof(__u32);
274162306a36Sopenharmony_ci	ext_info->sec_cnt = sec_cnt;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	return 0;
274462306a36Sopenharmony_ci}
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_cistatic int btf_ext_setup_func_info(struct btf_ext *btf_ext)
274762306a36Sopenharmony_ci{
274862306a36Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
274962306a36Sopenharmony_ci		.off = btf_ext->hdr->func_info_off,
275062306a36Sopenharmony_ci		.len = btf_ext->hdr->func_info_len,
275162306a36Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_func_info_min),
275262306a36Sopenharmony_ci		.ext_info = &btf_ext->func_info,
275362306a36Sopenharmony_ci		.desc = "func_info"
275462306a36Sopenharmony_ci	};
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_cistatic int btf_ext_setup_line_info(struct btf_ext *btf_ext)
276062306a36Sopenharmony_ci{
276162306a36Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
276262306a36Sopenharmony_ci		.off = btf_ext->hdr->line_info_off,
276362306a36Sopenharmony_ci		.len = btf_ext->hdr->line_info_len,
276462306a36Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_line_info_min),
276562306a36Sopenharmony_ci		.ext_info = &btf_ext->line_info,
276662306a36Sopenharmony_ci		.desc = "line_info",
276762306a36Sopenharmony_ci	};
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
277062306a36Sopenharmony_ci}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_cistatic int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
277362306a36Sopenharmony_ci{
277462306a36Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
277562306a36Sopenharmony_ci		.off = btf_ext->hdr->core_relo_off,
277662306a36Sopenharmony_ci		.len = btf_ext->hdr->core_relo_len,
277762306a36Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_core_relo),
277862306a36Sopenharmony_ci		.ext_info = &btf_ext->core_relo_info,
277962306a36Sopenharmony_ci		.desc = "core_relo",
278062306a36Sopenharmony_ci	};
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
278362306a36Sopenharmony_ci}
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_cistatic int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
278662306a36Sopenharmony_ci{
278762306a36Sopenharmony_ci	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
279062306a36Sopenharmony_ci	    data_size < hdr->hdr_len) {
279162306a36Sopenharmony_ci		pr_debug("BTF.ext header not found");
279262306a36Sopenharmony_ci		return -EINVAL;
279362306a36Sopenharmony_ci	}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	if (hdr->magic == bswap_16(BTF_MAGIC)) {
279662306a36Sopenharmony_ci		pr_warn("BTF.ext in non-native endianness is not supported\n");
279762306a36Sopenharmony_ci		return -ENOTSUP;
279862306a36Sopenharmony_ci	} else if (hdr->magic != BTF_MAGIC) {
279962306a36Sopenharmony_ci		pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
280062306a36Sopenharmony_ci		return -EINVAL;
280162306a36Sopenharmony_ci	}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (hdr->version != BTF_VERSION) {
280462306a36Sopenharmony_ci		pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
280562306a36Sopenharmony_ci		return -ENOTSUP;
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	if (hdr->flags) {
280962306a36Sopenharmony_ci		pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
281062306a36Sopenharmony_ci		return -ENOTSUP;
281162306a36Sopenharmony_ci	}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	if (data_size == hdr->hdr_len) {
281462306a36Sopenharmony_ci		pr_debug("BTF.ext has no data\n");
281562306a36Sopenharmony_ci		return -EINVAL;
281662306a36Sopenharmony_ci	}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	return 0;
281962306a36Sopenharmony_ci}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_civoid btf_ext__free(struct btf_ext *btf_ext)
282262306a36Sopenharmony_ci{
282362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(btf_ext))
282462306a36Sopenharmony_ci		return;
282562306a36Sopenharmony_ci	free(btf_ext->func_info.sec_idxs);
282662306a36Sopenharmony_ci	free(btf_ext->line_info.sec_idxs);
282762306a36Sopenharmony_ci	free(btf_ext->core_relo_info.sec_idxs);
282862306a36Sopenharmony_ci	free(btf_ext->data);
282962306a36Sopenharmony_ci	free(btf_ext);
283062306a36Sopenharmony_ci}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_cistruct btf_ext *btf_ext__new(const __u8 *data, __u32 size)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci	struct btf_ext *btf_ext;
283562306a36Sopenharmony_ci	int err;
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	btf_ext = calloc(1, sizeof(struct btf_ext));
283862306a36Sopenharmony_ci	if (!btf_ext)
283962306a36Sopenharmony_ci		return libbpf_err_ptr(-ENOMEM);
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	btf_ext->data_size = size;
284262306a36Sopenharmony_ci	btf_ext->data = malloc(size);
284362306a36Sopenharmony_ci	if (!btf_ext->data) {
284462306a36Sopenharmony_ci		err = -ENOMEM;
284562306a36Sopenharmony_ci		goto done;
284662306a36Sopenharmony_ci	}
284762306a36Sopenharmony_ci	memcpy(btf_ext->data, data, size);
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	err = btf_ext_parse_hdr(btf_ext->data, size);
285062306a36Sopenharmony_ci	if (err)
285162306a36Sopenharmony_ci		goto done;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
285462306a36Sopenharmony_ci		err = -EINVAL;
285562306a36Sopenharmony_ci		goto done;
285662306a36Sopenharmony_ci	}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	err = btf_ext_setup_func_info(btf_ext);
285962306a36Sopenharmony_ci	if (err)
286062306a36Sopenharmony_ci		goto done;
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	err = btf_ext_setup_line_info(btf_ext);
286362306a36Sopenharmony_ci	if (err)
286462306a36Sopenharmony_ci		goto done;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len))
286762306a36Sopenharmony_ci		goto done; /* skip core relos parsing */
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	err = btf_ext_setup_core_relos(btf_ext);
287062306a36Sopenharmony_ci	if (err)
287162306a36Sopenharmony_ci		goto done;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_cidone:
287462306a36Sopenharmony_ci	if (err) {
287562306a36Sopenharmony_ci		btf_ext__free(btf_ext);
287662306a36Sopenharmony_ci		return libbpf_err_ptr(err);
287762306a36Sopenharmony_ci	}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci	return btf_ext;
288062306a36Sopenharmony_ci}
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ciconst void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)
288362306a36Sopenharmony_ci{
288462306a36Sopenharmony_ci	*size = btf_ext->data_size;
288562306a36Sopenharmony_ci	return btf_ext->data;
288662306a36Sopenharmony_ci}
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_cistruct btf_dedup;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_cistatic struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
289162306a36Sopenharmony_cistatic void btf_dedup_free(struct btf_dedup *d);
289262306a36Sopenharmony_cistatic int btf_dedup_prep(struct btf_dedup *d);
289362306a36Sopenharmony_cistatic int btf_dedup_strings(struct btf_dedup *d);
289462306a36Sopenharmony_cistatic int btf_dedup_prim_types(struct btf_dedup *d);
289562306a36Sopenharmony_cistatic int btf_dedup_struct_types(struct btf_dedup *d);
289662306a36Sopenharmony_cistatic int btf_dedup_ref_types(struct btf_dedup *d);
289762306a36Sopenharmony_cistatic int btf_dedup_resolve_fwds(struct btf_dedup *d);
289862306a36Sopenharmony_cistatic int btf_dedup_compact_types(struct btf_dedup *d);
289962306a36Sopenharmony_cistatic int btf_dedup_remap_types(struct btf_dedup *d);
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci/*
290262306a36Sopenharmony_ci * Deduplicate BTF types and strings.
290362306a36Sopenharmony_ci *
290462306a36Sopenharmony_ci * BTF dedup algorithm takes as an input `struct btf` representing `.BTF` ELF
290562306a36Sopenharmony_ci * section with all BTF type descriptors and string data. It overwrites that
290662306a36Sopenharmony_ci * memory in-place with deduplicated types and strings without any loss of
290762306a36Sopenharmony_ci * information. If optional `struct btf_ext` representing '.BTF.ext' ELF section
290862306a36Sopenharmony_ci * is provided, all the strings referenced from .BTF.ext section are honored
290962306a36Sopenharmony_ci * and updated to point to the right offsets after deduplication.
291062306a36Sopenharmony_ci *
291162306a36Sopenharmony_ci * If function returns with error, type/string data might be garbled and should
291262306a36Sopenharmony_ci * be discarded.
291362306a36Sopenharmony_ci *
291462306a36Sopenharmony_ci * More verbose and detailed description of both problem btf_dedup is solving,
291562306a36Sopenharmony_ci * as well as solution could be found at:
291662306a36Sopenharmony_ci * https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html
291762306a36Sopenharmony_ci *
291862306a36Sopenharmony_ci * Problem description and justification
291962306a36Sopenharmony_ci * =====================================
292062306a36Sopenharmony_ci *
292162306a36Sopenharmony_ci * BTF type information is typically emitted either as a result of conversion
292262306a36Sopenharmony_ci * from DWARF to BTF or directly by compiler. In both cases, each compilation
292362306a36Sopenharmony_ci * unit contains information about a subset of all the types that are used
292462306a36Sopenharmony_ci * in an application. These subsets are frequently overlapping and contain a lot
292562306a36Sopenharmony_ci * of duplicated information when later concatenated together into a single
292662306a36Sopenharmony_ci * binary. This algorithm ensures that each unique type is represented by single
292762306a36Sopenharmony_ci * BTF type descriptor, greatly reducing resulting size of BTF data.
292862306a36Sopenharmony_ci *
292962306a36Sopenharmony_ci * Compilation unit isolation and subsequent duplication of data is not the only
293062306a36Sopenharmony_ci * problem. The same type hierarchy (e.g., struct and all the type that struct
293162306a36Sopenharmony_ci * references) in different compilation units can be represented in BTF to
293262306a36Sopenharmony_ci * various degrees of completeness (or, rather, incompleteness) due to
293362306a36Sopenharmony_ci * struct/union forward declarations.
293462306a36Sopenharmony_ci *
293562306a36Sopenharmony_ci * Let's take a look at an example, that we'll use to better understand the
293662306a36Sopenharmony_ci * problem (and solution). Suppose we have two compilation units, each using
293762306a36Sopenharmony_ci * same `struct S`, but each of them having incomplete type information about
293862306a36Sopenharmony_ci * struct's fields:
293962306a36Sopenharmony_ci *
294062306a36Sopenharmony_ci * // CU #1:
294162306a36Sopenharmony_ci * struct S;
294262306a36Sopenharmony_ci * struct A {
294362306a36Sopenharmony_ci *	int a;
294462306a36Sopenharmony_ci *	struct A* self;
294562306a36Sopenharmony_ci *	struct S* parent;
294662306a36Sopenharmony_ci * };
294762306a36Sopenharmony_ci * struct B;
294862306a36Sopenharmony_ci * struct S {
294962306a36Sopenharmony_ci *	struct A* a_ptr;
295062306a36Sopenharmony_ci *	struct B* b_ptr;
295162306a36Sopenharmony_ci * };
295262306a36Sopenharmony_ci *
295362306a36Sopenharmony_ci * // CU #2:
295462306a36Sopenharmony_ci * struct S;
295562306a36Sopenharmony_ci * struct A;
295662306a36Sopenharmony_ci * struct B {
295762306a36Sopenharmony_ci *	int b;
295862306a36Sopenharmony_ci *	struct B* self;
295962306a36Sopenharmony_ci *	struct S* parent;
296062306a36Sopenharmony_ci * };
296162306a36Sopenharmony_ci * struct S {
296262306a36Sopenharmony_ci *	struct A* a_ptr;
296362306a36Sopenharmony_ci *	struct B* b_ptr;
296462306a36Sopenharmony_ci * };
296562306a36Sopenharmony_ci *
296662306a36Sopenharmony_ci * In case of CU #1, BTF data will know only that `struct B` exist (but no
296762306a36Sopenharmony_ci * more), but will know the complete type information about `struct A`. While
296862306a36Sopenharmony_ci * for CU #2, it will know full type information about `struct B`, but will
296962306a36Sopenharmony_ci * only know about forward declaration of `struct A` (in BTF terms, it will
297062306a36Sopenharmony_ci * have `BTF_KIND_FWD` type descriptor with name `B`).
297162306a36Sopenharmony_ci *
297262306a36Sopenharmony_ci * This compilation unit isolation means that it's possible that there is no
297362306a36Sopenharmony_ci * single CU with complete type information describing structs `S`, `A`, and
297462306a36Sopenharmony_ci * `B`. Also, we might get tons of duplicated and redundant type information.
297562306a36Sopenharmony_ci *
297662306a36Sopenharmony_ci * Additional complication we need to keep in mind comes from the fact that
297762306a36Sopenharmony_ci * types, in general, can form graphs containing cycles, not just DAGs.
297862306a36Sopenharmony_ci *
297962306a36Sopenharmony_ci * While algorithm does deduplication, it also merges and resolves type
298062306a36Sopenharmony_ci * information (unless disabled throught `struct btf_opts`), whenever possible.
298162306a36Sopenharmony_ci * E.g., in the example above with two compilation units having partial type
298262306a36Sopenharmony_ci * information for structs `A` and `B`, the output of algorithm will emit
298362306a36Sopenharmony_ci * a single copy of each BTF type that describes structs `A`, `B`, and `S`
298462306a36Sopenharmony_ci * (as well as type information for `int` and pointers), as if they were defined
298562306a36Sopenharmony_ci * in a single compilation unit as:
298662306a36Sopenharmony_ci *
298762306a36Sopenharmony_ci * struct A {
298862306a36Sopenharmony_ci *	int a;
298962306a36Sopenharmony_ci *	struct A* self;
299062306a36Sopenharmony_ci *	struct S* parent;
299162306a36Sopenharmony_ci * };
299262306a36Sopenharmony_ci * struct B {
299362306a36Sopenharmony_ci *	int b;
299462306a36Sopenharmony_ci *	struct B* self;
299562306a36Sopenharmony_ci *	struct S* parent;
299662306a36Sopenharmony_ci * };
299762306a36Sopenharmony_ci * struct S {
299862306a36Sopenharmony_ci *	struct A* a_ptr;
299962306a36Sopenharmony_ci *	struct B* b_ptr;
300062306a36Sopenharmony_ci * };
300162306a36Sopenharmony_ci *
300262306a36Sopenharmony_ci * Algorithm summary
300362306a36Sopenharmony_ci * =================
300462306a36Sopenharmony_ci *
300562306a36Sopenharmony_ci * Algorithm completes its work in 7 separate passes:
300662306a36Sopenharmony_ci *
300762306a36Sopenharmony_ci * 1. Strings deduplication.
300862306a36Sopenharmony_ci * 2. Primitive types deduplication (int, enum, fwd).
300962306a36Sopenharmony_ci * 3. Struct/union types deduplication.
301062306a36Sopenharmony_ci * 4. Resolve unambiguous forward declarations.
301162306a36Sopenharmony_ci * 5. Reference types deduplication (pointers, typedefs, arrays, funcs, func
301262306a36Sopenharmony_ci *    protos, and const/volatile/restrict modifiers).
301362306a36Sopenharmony_ci * 6. Types compaction.
301462306a36Sopenharmony_ci * 7. Types remapping.
301562306a36Sopenharmony_ci *
301662306a36Sopenharmony_ci * Algorithm determines canonical type descriptor, which is a single
301762306a36Sopenharmony_ci * representative type for each truly unique type. This canonical type is the
301862306a36Sopenharmony_ci * one that will go into final deduplicated BTF type information. For
301962306a36Sopenharmony_ci * struct/unions, it is also the type that algorithm will merge additional type
302062306a36Sopenharmony_ci * information into (while resolving FWDs), as it discovers it from data in
302162306a36Sopenharmony_ci * other CUs. Each input BTF type eventually gets either mapped to itself, if
302262306a36Sopenharmony_ci * that type is canonical, or to some other type, if that type is equivalent
302362306a36Sopenharmony_ci * and was chosen as canonical representative. This mapping is stored in
302462306a36Sopenharmony_ci * `btf_dedup->map` array. This map is also used to record STRUCT/UNION that
302562306a36Sopenharmony_ci * FWD type got resolved to.
302662306a36Sopenharmony_ci *
302762306a36Sopenharmony_ci * To facilitate fast discovery of canonical types, we also maintain canonical
302862306a36Sopenharmony_ci * index (`btf_dedup->dedup_table`), which maps type descriptor's signature hash
302962306a36Sopenharmony_ci * (i.e., hashed kind, name, size, fields, etc) into a list of canonical types
303062306a36Sopenharmony_ci * that match that signature. With sufficiently good choice of type signature
303162306a36Sopenharmony_ci * hashing function, we can limit number of canonical types for each unique type
303262306a36Sopenharmony_ci * signature to a very small number, allowing to find canonical type for any
303362306a36Sopenharmony_ci * duplicated type very quickly.
303462306a36Sopenharmony_ci *
303562306a36Sopenharmony_ci * Struct/union deduplication is the most critical part and algorithm for
303662306a36Sopenharmony_ci * deduplicating structs/unions is described in greater details in comments for
303762306a36Sopenharmony_ci * `btf_dedup_is_equiv` function.
303862306a36Sopenharmony_ci */
303962306a36Sopenharmony_ciint btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	struct btf_dedup *d;
304262306a36Sopenharmony_ci	int err;
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (!OPTS_VALID(opts, btf_dedup_opts))
304562306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	d = btf_dedup_new(btf, opts);
304862306a36Sopenharmony_ci	if (IS_ERR(d)) {
304962306a36Sopenharmony_ci		pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d));
305062306a36Sopenharmony_ci		return libbpf_err(-EINVAL);
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	if (btf_ensure_modifiable(btf)) {
305462306a36Sopenharmony_ci		err = -ENOMEM;
305562306a36Sopenharmony_ci		goto done;
305662306a36Sopenharmony_ci	}
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	err = btf_dedup_prep(d);
305962306a36Sopenharmony_ci	if (err) {
306062306a36Sopenharmony_ci		pr_debug("btf_dedup_prep failed:%d\n", err);
306162306a36Sopenharmony_ci		goto done;
306262306a36Sopenharmony_ci	}
306362306a36Sopenharmony_ci	err = btf_dedup_strings(d);
306462306a36Sopenharmony_ci	if (err < 0) {
306562306a36Sopenharmony_ci		pr_debug("btf_dedup_strings failed:%d\n", err);
306662306a36Sopenharmony_ci		goto done;
306762306a36Sopenharmony_ci	}
306862306a36Sopenharmony_ci	err = btf_dedup_prim_types(d);
306962306a36Sopenharmony_ci	if (err < 0) {
307062306a36Sopenharmony_ci		pr_debug("btf_dedup_prim_types failed:%d\n", err);
307162306a36Sopenharmony_ci		goto done;
307262306a36Sopenharmony_ci	}
307362306a36Sopenharmony_ci	err = btf_dedup_struct_types(d);
307462306a36Sopenharmony_ci	if (err < 0) {
307562306a36Sopenharmony_ci		pr_debug("btf_dedup_struct_types failed:%d\n", err);
307662306a36Sopenharmony_ci		goto done;
307762306a36Sopenharmony_ci	}
307862306a36Sopenharmony_ci	err = btf_dedup_resolve_fwds(d);
307962306a36Sopenharmony_ci	if (err < 0) {
308062306a36Sopenharmony_ci		pr_debug("btf_dedup_resolve_fwds failed:%d\n", err);
308162306a36Sopenharmony_ci		goto done;
308262306a36Sopenharmony_ci	}
308362306a36Sopenharmony_ci	err = btf_dedup_ref_types(d);
308462306a36Sopenharmony_ci	if (err < 0) {
308562306a36Sopenharmony_ci		pr_debug("btf_dedup_ref_types failed:%d\n", err);
308662306a36Sopenharmony_ci		goto done;
308762306a36Sopenharmony_ci	}
308862306a36Sopenharmony_ci	err = btf_dedup_compact_types(d);
308962306a36Sopenharmony_ci	if (err < 0) {
309062306a36Sopenharmony_ci		pr_debug("btf_dedup_compact_types failed:%d\n", err);
309162306a36Sopenharmony_ci		goto done;
309262306a36Sopenharmony_ci	}
309362306a36Sopenharmony_ci	err = btf_dedup_remap_types(d);
309462306a36Sopenharmony_ci	if (err < 0) {
309562306a36Sopenharmony_ci		pr_debug("btf_dedup_remap_types failed:%d\n", err);
309662306a36Sopenharmony_ci		goto done;
309762306a36Sopenharmony_ci	}
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_cidone:
310062306a36Sopenharmony_ci	btf_dedup_free(d);
310162306a36Sopenharmony_ci	return libbpf_err(err);
310262306a36Sopenharmony_ci}
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci#define BTF_UNPROCESSED_ID ((__u32)-1)
310562306a36Sopenharmony_ci#define BTF_IN_PROGRESS_ID ((__u32)-2)
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_cistruct btf_dedup {
310862306a36Sopenharmony_ci	/* .BTF section to be deduped in-place */
310962306a36Sopenharmony_ci	struct btf *btf;
311062306a36Sopenharmony_ci	/*
311162306a36Sopenharmony_ci	 * Optional .BTF.ext section. When provided, any strings referenced
311262306a36Sopenharmony_ci	 * from it will be taken into account when deduping strings
311362306a36Sopenharmony_ci	 */
311462306a36Sopenharmony_ci	struct btf_ext *btf_ext;
311562306a36Sopenharmony_ci	/*
311662306a36Sopenharmony_ci	 * This is a map from any type's signature hash to a list of possible
311762306a36Sopenharmony_ci	 * canonical representative type candidates. Hash collisions are
311862306a36Sopenharmony_ci	 * ignored, so even types of various kinds can share same list of
311962306a36Sopenharmony_ci	 * candidates, which is fine because we rely on subsequent
312062306a36Sopenharmony_ci	 * btf_xxx_equal() checks to authoritatively verify type equality.
312162306a36Sopenharmony_ci	 */
312262306a36Sopenharmony_ci	struct hashmap *dedup_table;
312362306a36Sopenharmony_ci	/* Canonical types map */
312462306a36Sopenharmony_ci	__u32 *map;
312562306a36Sopenharmony_ci	/* Hypothetical mapping, used during type graph equivalence checks */
312662306a36Sopenharmony_ci	__u32 *hypot_map;
312762306a36Sopenharmony_ci	__u32 *hypot_list;
312862306a36Sopenharmony_ci	size_t hypot_cnt;
312962306a36Sopenharmony_ci	size_t hypot_cap;
313062306a36Sopenharmony_ci	/* Whether hypothetical mapping, if successful, would need to adjust
313162306a36Sopenharmony_ci	 * already canonicalized types (due to a new forward declaration to
313262306a36Sopenharmony_ci	 * concrete type resolution). In such case, during split BTF dedup
313362306a36Sopenharmony_ci	 * candidate type would still be considered as different, because base
313462306a36Sopenharmony_ci	 * BTF is considered to be immutable.
313562306a36Sopenharmony_ci	 */
313662306a36Sopenharmony_ci	bool hypot_adjust_canon;
313762306a36Sopenharmony_ci	/* Various option modifying behavior of algorithm */
313862306a36Sopenharmony_ci	struct btf_dedup_opts opts;
313962306a36Sopenharmony_ci	/* temporary strings deduplication state */
314062306a36Sopenharmony_ci	struct strset *strs_set;
314162306a36Sopenharmony_ci};
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_cistatic long hash_combine(long h, long value)
314462306a36Sopenharmony_ci{
314562306a36Sopenharmony_ci	return h * 31 + value;
314662306a36Sopenharmony_ci}
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci#define for_each_dedup_cand(d, node, hash) \
314962306a36Sopenharmony_ci	hashmap__for_each_key_entry(d->dedup_table, node, hash)
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_cistatic int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
315262306a36Sopenharmony_ci{
315362306a36Sopenharmony_ci	return hashmap__append(d->dedup_table, hash, type_id);
315462306a36Sopenharmony_ci}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_cistatic int btf_dedup_hypot_map_add(struct btf_dedup *d,
315762306a36Sopenharmony_ci				   __u32 from_id, __u32 to_id)
315862306a36Sopenharmony_ci{
315962306a36Sopenharmony_ci	if (d->hypot_cnt == d->hypot_cap) {
316062306a36Sopenharmony_ci		__u32 *new_list;
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci		d->hypot_cap += max((size_t)16, d->hypot_cap / 2);
316362306a36Sopenharmony_ci		new_list = libbpf_reallocarray(d->hypot_list, d->hypot_cap, sizeof(__u32));
316462306a36Sopenharmony_ci		if (!new_list)
316562306a36Sopenharmony_ci			return -ENOMEM;
316662306a36Sopenharmony_ci		d->hypot_list = new_list;
316762306a36Sopenharmony_ci	}
316862306a36Sopenharmony_ci	d->hypot_list[d->hypot_cnt++] = from_id;
316962306a36Sopenharmony_ci	d->hypot_map[from_id] = to_id;
317062306a36Sopenharmony_ci	return 0;
317162306a36Sopenharmony_ci}
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_cistatic void btf_dedup_clear_hypot_map(struct btf_dedup *d)
317462306a36Sopenharmony_ci{
317562306a36Sopenharmony_ci	int i;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	for (i = 0; i < d->hypot_cnt; i++)
317862306a36Sopenharmony_ci		d->hypot_map[d->hypot_list[i]] = BTF_UNPROCESSED_ID;
317962306a36Sopenharmony_ci	d->hypot_cnt = 0;
318062306a36Sopenharmony_ci	d->hypot_adjust_canon = false;
318162306a36Sopenharmony_ci}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_cistatic void btf_dedup_free(struct btf_dedup *d)
318462306a36Sopenharmony_ci{
318562306a36Sopenharmony_ci	hashmap__free(d->dedup_table);
318662306a36Sopenharmony_ci	d->dedup_table = NULL;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	free(d->map);
318962306a36Sopenharmony_ci	d->map = NULL;
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	free(d->hypot_map);
319262306a36Sopenharmony_ci	d->hypot_map = NULL;
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	free(d->hypot_list);
319562306a36Sopenharmony_ci	d->hypot_list = NULL;
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	free(d);
319862306a36Sopenharmony_ci}
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_cistatic size_t btf_dedup_identity_hash_fn(long key, void *ctx)
320162306a36Sopenharmony_ci{
320262306a36Sopenharmony_ci	return key;
320362306a36Sopenharmony_ci}
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_cistatic size_t btf_dedup_collision_hash_fn(long key, void *ctx)
320662306a36Sopenharmony_ci{
320762306a36Sopenharmony_ci	return 0;
320862306a36Sopenharmony_ci}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_cistatic bool btf_dedup_equal_fn(long k1, long k2, void *ctx)
321162306a36Sopenharmony_ci{
321262306a36Sopenharmony_ci	return k1 == k2;
321362306a36Sopenharmony_ci}
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_cistatic struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts)
321662306a36Sopenharmony_ci{
321762306a36Sopenharmony_ci	struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup));
321862306a36Sopenharmony_ci	hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn;
321962306a36Sopenharmony_ci	int i, err = 0, type_cnt;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	if (!d)
322262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	if (OPTS_GET(opts, force_collisions, false))
322562306a36Sopenharmony_ci		hash_fn = btf_dedup_collision_hash_fn;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	d->btf = btf;
322862306a36Sopenharmony_ci	d->btf_ext = OPTS_GET(opts, btf_ext, NULL);
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL);
323162306a36Sopenharmony_ci	if (IS_ERR(d->dedup_table)) {
323262306a36Sopenharmony_ci		err = PTR_ERR(d->dedup_table);
323362306a36Sopenharmony_ci		d->dedup_table = NULL;
323462306a36Sopenharmony_ci		goto done;
323562306a36Sopenharmony_ci	}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci	type_cnt = btf__type_cnt(btf);
323862306a36Sopenharmony_ci	d->map = malloc(sizeof(__u32) * type_cnt);
323962306a36Sopenharmony_ci	if (!d->map) {
324062306a36Sopenharmony_ci		err = -ENOMEM;
324162306a36Sopenharmony_ci		goto done;
324262306a36Sopenharmony_ci	}
324362306a36Sopenharmony_ci	/* special BTF "void" type is made canonical immediately */
324462306a36Sopenharmony_ci	d->map[0] = 0;
324562306a36Sopenharmony_ci	for (i = 1; i < type_cnt; i++) {
324662306a36Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, i);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci		/* VAR and DATASEC are never deduped and are self-canonical */
324962306a36Sopenharmony_ci		if (btf_is_var(t) || btf_is_datasec(t))
325062306a36Sopenharmony_ci			d->map[i] = i;
325162306a36Sopenharmony_ci		else
325262306a36Sopenharmony_ci			d->map[i] = BTF_UNPROCESSED_ID;
325362306a36Sopenharmony_ci	}
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	d->hypot_map = malloc(sizeof(__u32) * type_cnt);
325662306a36Sopenharmony_ci	if (!d->hypot_map) {
325762306a36Sopenharmony_ci		err = -ENOMEM;
325862306a36Sopenharmony_ci		goto done;
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci	for (i = 0; i < type_cnt; i++)
326162306a36Sopenharmony_ci		d->hypot_map[i] = BTF_UNPROCESSED_ID;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_cidone:
326462306a36Sopenharmony_ci	if (err) {
326562306a36Sopenharmony_ci		btf_dedup_free(d);
326662306a36Sopenharmony_ci		return ERR_PTR(err);
326762306a36Sopenharmony_ci	}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	return d;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci/*
327362306a36Sopenharmony_ci * Iterate over all possible places in .BTF and .BTF.ext that can reference
327462306a36Sopenharmony_ci * string and pass pointer to it to a provided callback `fn`.
327562306a36Sopenharmony_ci */
327662306a36Sopenharmony_cistatic int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx)
327762306a36Sopenharmony_ci{
327862306a36Sopenharmony_ci	int i, r;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
328162306a36Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci		r = btf_type_visit_str_offs(t, fn, ctx);
328462306a36Sopenharmony_ci		if (r)
328562306a36Sopenharmony_ci			return r;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	if (!d->btf_ext)
328962306a36Sopenharmony_ci		return 0;
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci	r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx);
329262306a36Sopenharmony_ci	if (r)
329362306a36Sopenharmony_ci		return r;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	return 0;
329662306a36Sopenharmony_ci}
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_cistatic int strs_dedup_remap_str_off(__u32 *str_off_ptr, void *ctx)
329962306a36Sopenharmony_ci{
330062306a36Sopenharmony_ci	struct btf_dedup *d = ctx;
330162306a36Sopenharmony_ci	__u32 str_off = *str_off_ptr;
330262306a36Sopenharmony_ci	const char *s;
330362306a36Sopenharmony_ci	int off, err;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	/* don't touch empty string or string in main BTF */
330662306a36Sopenharmony_ci	if (str_off == 0 || str_off < d->btf->start_str_off)
330762306a36Sopenharmony_ci		return 0;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	s = btf__str_by_offset(d->btf, str_off);
331062306a36Sopenharmony_ci	if (d->btf->base_btf) {
331162306a36Sopenharmony_ci		err = btf__find_str(d->btf->base_btf, s);
331262306a36Sopenharmony_ci		if (err >= 0) {
331362306a36Sopenharmony_ci			*str_off_ptr = err;
331462306a36Sopenharmony_ci			return 0;
331562306a36Sopenharmony_ci		}
331662306a36Sopenharmony_ci		if (err != -ENOENT)
331762306a36Sopenharmony_ci			return err;
331862306a36Sopenharmony_ci	}
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	off = strset__add_str(d->strs_set, s);
332162306a36Sopenharmony_ci	if (off < 0)
332262306a36Sopenharmony_ci		return off;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	*str_off_ptr = d->btf->start_str_off + off;
332562306a36Sopenharmony_ci	return 0;
332662306a36Sopenharmony_ci}
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci/*
332962306a36Sopenharmony_ci * Dedup string and filter out those that are not referenced from either .BTF
333062306a36Sopenharmony_ci * or .BTF.ext (if provided) sections.
333162306a36Sopenharmony_ci *
333262306a36Sopenharmony_ci * This is done by building index of all strings in BTF's string section,
333362306a36Sopenharmony_ci * then iterating over all entities that can reference strings (e.g., type
333462306a36Sopenharmony_ci * names, struct field names, .BTF.ext line info, etc) and marking corresponding
333562306a36Sopenharmony_ci * strings as used. After that all used strings are deduped and compacted into
333662306a36Sopenharmony_ci * sequential blob of memory and new offsets are calculated. Then all the string
333762306a36Sopenharmony_ci * references are iterated again and rewritten using new offsets.
333862306a36Sopenharmony_ci */
333962306a36Sopenharmony_cistatic int btf_dedup_strings(struct btf_dedup *d)
334062306a36Sopenharmony_ci{
334162306a36Sopenharmony_ci	int err;
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	if (d->btf->strs_deduped)
334462306a36Sopenharmony_ci		return 0;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	d->strs_set = strset__new(BTF_MAX_STR_OFFSET, NULL, 0);
334762306a36Sopenharmony_ci	if (IS_ERR(d->strs_set)) {
334862306a36Sopenharmony_ci		err = PTR_ERR(d->strs_set);
334962306a36Sopenharmony_ci		goto err_out;
335062306a36Sopenharmony_ci	}
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	if (!d->btf->base_btf) {
335362306a36Sopenharmony_ci		/* insert empty string; we won't be looking it up during strings
335462306a36Sopenharmony_ci		 * dedup, but it's good to have it for generic BTF string lookups
335562306a36Sopenharmony_ci		 */
335662306a36Sopenharmony_ci		err = strset__add_str(d->strs_set, "");
335762306a36Sopenharmony_ci		if (err < 0)
335862306a36Sopenharmony_ci			goto err_out;
335962306a36Sopenharmony_ci	}
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	/* remap string offsets */
336262306a36Sopenharmony_ci	err = btf_for_each_str_off(d, strs_dedup_remap_str_off, d);
336362306a36Sopenharmony_ci	if (err)
336462306a36Sopenharmony_ci		goto err_out;
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci	/* replace BTF string data and hash with deduped ones */
336762306a36Sopenharmony_ci	strset__free(d->btf->strs_set);
336862306a36Sopenharmony_ci	d->btf->hdr->str_len = strset__data_size(d->strs_set);
336962306a36Sopenharmony_ci	d->btf->strs_set = d->strs_set;
337062306a36Sopenharmony_ci	d->strs_set = NULL;
337162306a36Sopenharmony_ci	d->btf->strs_deduped = true;
337262306a36Sopenharmony_ci	return 0;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_cierr_out:
337562306a36Sopenharmony_ci	strset__free(d->strs_set);
337662306a36Sopenharmony_ci	d->strs_set = NULL;
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	return err;
337962306a36Sopenharmony_ci}
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_cistatic long btf_hash_common(struct btf_type *t)
338262306a36Sopenharmony_ci{
338362306a36Sopenharmony_ci	long h;
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	h = hash_combine(0, t->name_off);
338662306a36Sopenharmony_ci	h = hash_combine(h, t->info);
338762306a36Sopenharmony_ci	h = hash_combine(h, t->size);
338862306a36Sopenharmony_ci	return h;
338962306a36Sopenharmony_ci}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_cistatic bool btf_equal_common(struct btf_type *t1, struct btf_type *t2)
339262306a36Sopenharmony_ci{
339362306a36Sopenharmony_ci	return t1->name_off == t2->name_off &&
339462306a36Sopenharmony_ci	       t1->info == t2->info &&
339562306a36Sopenharmony_ci	       t1->size == t2->size;
339662306a36Sopenharmony_ci}
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci/* Calculate type signature hash of INT or TAG. */
339962306a36Sopenharmony_cistatic long btf_hash_int_decl_tag(struct btf_type *t)
340062306a36Sopenharmony_ci{
340162306a36Sopenharmony_ci	__u32 info = *(__u32 *)(t + 1);
340262306a36Sopenharmony_ci	long h;
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci	h = btf_hash_common(t);
340562306a36Sopenharmony_ci	h = hash_combine(h, info);
340662306a36Sopenharmony_ci	return h;
340762306a36Sopenharmony_ci}
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci/* Check structural equality of two INTs or TAGs. */
341062306a36Sopenharmony_cistatic bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
341162306a36Sopenharmony_ci{
341262306a36Sopenharmony_ci	__u32 info1, info2;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
341562306a36Sopenharmony_ci		return false;
341662306a36Sopenharmony_ci	info1 = *(__u32 *)(t1 + 1);
341762306a36Sopenharmony_ci	info2 = *(__u32 *)(t2 + 1);
341862306a36Sopenharmony_ci	return info1 == info2;
341962306a36Sopenharmony_ci}
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci/* Calculate type signature hash of ENUM/ENUM64. */
342262306a36Sopenharmony_cistatic long btf_hash_enum(struct btf_type *t)
342362306a36Sopenharmony_ci{
342462306a36Sopenharmony_ci	long h;
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	/* don't hash vlen, enum members and size to support enum fwd resolving */
342762306a36Sopenharmony_ci	h = hash_combine(0, t->name_off);
342862306a36Sopenharmony_ci	return h;
342962306a36Sopenharmony_ci}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_cistatic bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	const struct btf_enum *m1, *m2;
343462306a36Sopenharmony_ci	__u16 vlen;
343562306a36Sopenharmony_ci	int i;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	vlen = btf_vlen(t1);
343862306a36Sopenharmony_ci	m1 = btf_enum(t1);
343962306a36Sopenharmony_ci	m2 = btf_enum(t2);
344062306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
344162306a36Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->val != m2->val)
344262306a36Sopenharmony_ci			return false;
344362306a36Sopenharmony_ci		m1++;
344462306a36Sopenharmony_ci		m2++;
344562306a36Sopenharmony_ci	}
344662306a36Sopenharmony_ci	return true;
344762306a36Sopenharmony_ci}
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_cistatic bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
345062306a36Sopenharmony_ci{
345162306a36Sopenharmony_ci	const struct btf_enum64 *m1, *m2;
345262306a36Sopenharmony_ci	__u16 vlen;
345362306a36Sopenharmony_ci	int i;
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci	vlen = btf_vlen(t1);
345662306a36Sopenharmony_ci	m1 = btf_enum64(t1);
345762306a36Sopenharmony_ci	m2 = btf_enum64(t2);
345862306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
345962306a36Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
346062306a36Sopenharmony_ci		    m1->val_hi32 != m2->val_hi32)
346162306a36Sopenharmony_ci			return false;
346262306a36Sopenharmony_ci		m1++;
346362306a36Sopenharmony_ci		m2++;
346462306a36Sopenharmony_ci	}
346562306a36Sopenharmony_ci	return true;
346662306a36Sopenharmony_ci}
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci/* Check structural equality of two ENUMs or ENUM64s. */
346962306a36Sopenharmony_cistatic bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
347062306a36Sopenharmony_ci{
347162306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
347262306a36Sopenharmony_ci		return false;
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	/* t1 & t2 kinds are identical because of btf_equal_common */
347562306a36Sopenharmony_ci	if (btf_kind(t1) == BTF_KIND_ENUM)
347662306a36Sopenharmony_ci		return btf_equal_enum_members(t1, t2);
347762306a36Sopenharmony_ci	else
347862306a36Sopenharmony_ci		return btf_equal_enum64_members(t1, t2);
347962306a36Sopenharmony_ci}
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_cistatic inline bool btf_is_enum_fwd(struct btf_type *t)
348262306a36Sopenharmony_ci{
348362306a36Sopenharmony_ci	return btf_is_any_enum(t) && btf_vlen(t) == 0;
348462306a36Sopenharmony_ci}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_cistatic bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
348762306a36Sopenharmony_ci{
348862306a36Sopenharmony_ci	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
348962306a36Sopenharmony_ci		return btf_equal_enum(t1, t2);
349062306a36Sopenharmony_ci	/* At this point either t1 or t2 or both are forward declarations, thus:
349162306a36Sopenharmony_ci	 * - skip comparing vlen because it is zero for forward declarations;
349262306a36Sopenharmony_ci	 * - skip comparing size to allow enum forward declarations
349362306a36Sopenharmony_ci	 *   to be compatible with enum64 full declarations;
349462306a36Sopenharmony_ci	 * - skip comparing kind for the same reason.
349562306a36Sopenharmony_ci	 */
349662306a36Sopenharmony_ci	return t1->name_off == t2->name_off &&
349762306a36Sopenharmony_ci	       btf_is_any_enum(t1) && btf_is_any_enum(t2);
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci/*
350162306a36Sopenharmony_ci * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
350262306a36Sopenharmony_ci * as referenced type IDs equivalence is established separately during type
350362306a36Sopenharmony_ci * graph equivalence check algorithm.
350462306a36Sopenharmony_ci */
350562306a36Sopenharmony_cistatic long btf_hash_struct(struct btf_type *t)
350662306a36Sopenharmony_ci{
350762306a36Sopenharmony_ci	const struct btf_member *member = btf_members(t);
350862306a36Sopenharmony_ci	__u32 vlen = btf_vlen(t);
350962306a36Sopenharmony_ci	long h = btf_hash_common(t);
351062306a36Sopenharmony_ci	int i;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
351362306a36Sopenharmony_ci		h = hash_combine(h, member->name_off);
351462306a36Sopenharmony_ci		h = hash_combine(h, member->offset);
351562306a36Sopenharmony_ci		/* no hashing of referenced type ID, it can be unresolved yet */
351662306a36Sopenharmony_ci		member++;
351762306a36Sopenharmony_ci	}
351862306a36Sopenharmony_ci	return h;
351962306a36Sopenharmony_ci}
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci/*
352262306a36Sopenharmony_ci * Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced
352362306a36Sopenharmony_ci * type IDs. This check is performed during type graph equivalence check and
352462306a36Sopenharmony_ci * referenced types equivalence is checked separately.
352562306a36Sopenharmony_ci */
352662306a36Sopenharmony_cistatic bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
352762306a36Sopenharmony_ci{
352862306a36Sopenharmony_ci	const struct btf_member *m1, *m2;
352962306a36Sopenharmony_ci	__u16 vlen;
353062306a36Sopenharmony_ci	int i;
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
353362306a36Sopenharmony_ci		return false;
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci	vlen = btf_vlen(t1);
353662306a36Sopenharmony_ci	m1 = btf_members(t1);
353762306a36Sopenharmony_ci	m2 = btf_members(t2);
353862306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
353962306a36Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
354062306a36Sopenharmony_ci			return false;
354162306a36Sopenharmony_ci		m1++;
354262306a36Sopenharmony_ci		m2++;
354362306a36Sopenharmony_ci	}
354462306a36Sopenharmony_ci	return true;
354562306a36Sopenharmony_ci}
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci/*
354862306a36Sopenharmony_ci * Calculate type signature hash of ARRAY, including referenced type IDs,
354962306a36Sopenharmony_ci * under assumption that they were already resolved to canonical type IDs and
355062306a36Sopenharmony_ci * are not going to change.
355162306a36Sopenharmony_ci */
355262306a36Sopenharmony_cistatic long btf_hash_array(struct btf_type *t)
355362306a36Sopenharmony_ci{
355462306a36Sopenharmony_ci	const struct btf_array *info = btf_array(t);
355562306a36Sopenharmony_ci	long h = btf_hash_common(t);
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	h = hash_combine(h, info->type);
355862306a36Sopenharmony_ci	h = hash_combine(h, info->index_type);
355962306a36Sopenharmony_ci	h = hash_combine(h, info->nelems);
356062306a36Sopenharmony_ci	return h;
356162306a36Sopenharmony_ci}
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci/*
356462306a36Sopenharmony_ci * Check exact equality of two ARRAYs, taking into account referenced
356562306a36Sopenharmony_ci * type IDs, under assumption that they were already resolved to canonical
356662306a36Sopenharmony_ci * type IDs and are not going to change.
356762306a36Sopenharmony_ci * This function is called during reference types deduplication to compare
356862306a36Sopenharmony_ci * ARRAY to potential canonical representative.
356962306a36Sopenharmony_ci */
357062306a36Sopenharmony_cistatic bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
357162306a36Sopenharmony_ci{
357262306a36Sopenharmony_ci	const struct btf_array *info1, *info2;
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
357562306a36Sopenharmony_ci		return false;
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	info1 = btf_array(t1);
357862306a36Sopenharmony_ci	info2 = btf_array(t2);
357962306a36Sopenharmony_ci	return info1->type == info2->type &&
358062306a36Sopenharmony_ci	       info1->index_type == info2->index_type &&
358162306a36Sopenharmony_ci	       info1->nelems == info2->nelems;
358262306a36Sopenharmony_ci}
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci/*
358562306a36Sopenharmony_ci * Check structural compatibility of two ARRAYs, ignoring referenced type
358662306a36Sopenharmony_ci * IDs. This check is performed during type graph equivalence check and
358762306a36Sopenharmony_ci * referenced types equivalence is checked separately.
358862306a36Sopenharmony_ci */
358962306a36Sopenharmony_cistatic bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
359062306a36Sopenharmony_ci{
359162306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
359262306a36Sopenharmony_ci		return false;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	return btf_array(t1)->nelems == btf_array(t2)->nelems;
359562306a36Sopenharmony_ci}
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci/*
359862306a36Sopenharmony_ci * Calculate type signature hash of FUNC_PROTO, including referenced type IDs,
359962306a36Sopenharmony_ci * under assumption that they were already resolved to canonical type IDs and
360062306a36Sopenharmony_ci * are not going to change.
360162306a36Sopenharmony_ci */
360262306a36Sopenharmony_cistatic long btf_hash_fnproto(struct btf_type *t)
360362306a36Sopenharmony_ci{
360462306a36Sopenharmony_ci	const struct btf_param *member = btf_params(t);
360562306a36Sopenharmony_ci	__u16 vlen = btf_vlen(t);
360662306a36Sopenharmony_ci	long h = btf_hash_common(t);
360762306a36Sopenharmony_ci	int i;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
361062306a36Sopenharmony_ci		h = hash_combine(h, member->name_off);
361162306a36Sopenharmony_ci		h = hash_combine(h, member->type);
361262306a36Sopenharmony_ci		member++;
361362306a36Sopenharmony_ci	}
361462306a36Sopenharmony_ci	return h;
361562306a36Sopenharmony_ci}
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci/*
361862306a36Sopenharmony_ci * Check exact equality of two FUNC_PROTOs, taking into account referenced
361962306a36Sopenharmony_ci * type IDs, under assumption that they were already resolved to canonical
362062306a36Sopenharmony_ci * type IDs and are not going to change.
362162306a36Sopenharmony_ci * This function is called during reference types deduplication to compare
362262306a36Sopenharmony_ci * FUNC_PROTO to potential canonical representative.
362362306a36Sopenharmony_ci */
362462306a36Sopenharmony_cistatic bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
362562306a36Sopenharmony_ci{
362662306a36Sopenharmony_ci	const struct btf_param *m1, *m2;
362762306a36Sopenharmony_ci	__u16 vlen;
362862306a36Sopenharmony_ci	int i;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	if (!btf_equal_common(t1, t2))
363162306a36Sopenharmony_ci		return false;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	vlen = btf_vlen(t1);
363462306a36Sopenharmony_ci	m1 = btf_params(t1);
363562306a36Sopenharmony_ci	m2 = btf_params(t2);
363662306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
363762306a36Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->type != m2->type)
363862306a36Sopenharmony_ci			return false;
363962306a36Sopenharmony_ci		m1++;
364062306a36Sopenharmony_ci		m2++;
364162306a36Sopenharmony_ci	}
364262306a36Sopenharmony_ci	return true;
364362306a36Sopenharmony_ci}
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci/*
364662306a36Sopenharmony_ci * Check structural compatibility of two FUNC_PROTOs, ignoring referenced type
364762306a36Sopenharmony_ci * IDs. This check is performed during type graph equivalence check and
364862306a36Sopenharmony_ci * referenced types equivalence is checked separately.
364962306a36Sopenharmony_ci */
365062306a36Sopenharmony_cistatic bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
365162306a36Sopenharmony_ci{
365262306a36Sopenharmony_ci	const struct btf_param *m1, *m2;
365362306a36Sopenharmony_ci	__u16 vlen;
365462306a36Sopenharmony_ci	int i;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	/* skip return type ID */
365762306a36Sopenharmony_ci	if (t1->name_off != t2->name_off || t1->info != t2->info)
365862306a36Sopenharmony_ci		return false;
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci	vlen = btf_vlen(t1);
366162306a36Sopenharmony_ci	m1 = btf_params(t1);
366262306a36Sopenharmony_ci	m2 = btf_params(t2);
366362306a36Sopenharmony_ci	for (i = 0; i < vlen; i++) {
366462306a36Sopenharmony_ci		if (m1->name_off != m2->name_off)
366562306a36Sopenharmony_ci			return false;
366662306a36Sopenharmony_ci		m1++;
366762306a36Sopenharmony_ci		m2++;
366862306a36Sopenharmony_ci	}
366962306a36Sopenharmony_ci	return true;
367062306a36Sopenharmony_ci}
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci/* Prepare split BTF for deduplication by calculating hashes of base BTF's
367362306a36Sopenharmony_ci * types and initializing the rest of the state (canonical type mapping) for
367462306a36Sopenharmony_ci * the fixed base BTF part.
367562306a36Sopenharmony_ci */
367662306a36Sopenharmony_cistatic int btf_dedup_prep(struct btf_dedup *d)
367762306a36Sopenharmony_ci{
367862306a36Sopenharmony_ci	struct btf_type *t;
367962306a36Sopenharmony_ci	int type_id;
368062306a36Sopenharmony_ci	long h;
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci	if (!d->btf->base_btf)
368362306a36Sopenharmony_ci		return 0;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	for (type_id = 1; type_id < d->btf->start_id; type_id++) {
368662306a36Sopenharmony_ci		t = btf_type_by_id(d->btf, type_id);
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci		/* all base BTF types are self-canonical by definition */
368962306a36Sopenharmony_ci		d->map[type_id] = type_id;
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci		switch (btf_kind(t)) {
369262306a36Sopenharmony_ci		case BTF_KIND_VAR:
369362306a36Sopenharmony_ci		case BTF_KIND_DATASEC:
369462306a36Sopenharmony_ci			/* VAR and DATASEC are never hash/deduplicated */
369562306a36Sopenharmony_ci			continue;
369662306a36Sopenharmony_ci		case BTF_KIND_CONST:
369762306a36Sopenharmony_ci		case BTF_KIND_VOLATILE:
369862306a36Sopenharmony_ci		case BTF_KIND_RESTRICT:
369962306a36Sopenharmony_ci		case BTF_KIND_PTR:
370062306a36Sopenharmony_ci		case BTF_KIND_FWD:
370162306a36Sopenharmony_ci		case BTF_KIND_TYPEDEF:
370262306a36Sopenharmony_ci		case BTF_KIND_FUNC:
370362306a36Sopenharmony_ci		case BTF_KIND_FLOAT:
370462306a36Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
370562306a36Sopenharmony_ci			h = btf_hash_common(t);
370662306a36Sopenharmony_ci			break;
370762306a36Sopenharmony_ci		case BTF_KIND_INT:
370862306a36Sopenharmony_ci		case BTF_KIND_DECL_TAG:
370962306a36Sopenharmony_ci			h = btf_hash_int_decl_tag(t);
371062306a36Sopenharmony_ci			break;
371162306a36Sopenharmony_ci		case BTF_KIND_ENUM:
371262306a36Sopenharmony_ci		case BTF_KIND_ENUM64:
371362306a36Sopenharmony_ci			h = btf_hash_enum(t);
371462306a36Sopenharmony_ci			break;
371562306a36Sopenharmony_ci		case BTF_KIND_STRUCT:
371662306a36Sopenharmony_ci		case BTF_KIND_UNION:
371762306a36Sopenharmony_ci			h = btf_hash_struct(t);
371862306a36Sopenharmony_ci			break;
371962306a36Sopenharmony_ci		case BTF_KIND_ARRAY:
372062306a36Sopenharmony_ci			h = btf_hash_array(t);
372162306a36Sopenharmony_ci			break;
372262306a36Sopenharmony_ci		case BTF_KIND_FUNC_PROTO:
372362306a36Sopenharmony_ci			h = btf_hash_fnproto(t);
372462306a36Sopenharmony_ci			break;
372562306a36Sopenharmony_ci		default:
372662306a36Sopenharmony_ci			pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id);
372762306a36Sopenharmony_ci			return -EINVAL;
372862306a36Sopenharmony_ci		}
372962306a36Sopenharmony_ci		if (btf_dedup_table_add(d, h, type_id))
373062306a36Sopenharmony_ci			return -ENOMEM;
373162306a36Sopenharmony_ci	}
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	return 0;
373462306a36Sopenharmony_ci}
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci/*
373762306a36Sopenharmony_ci * Deduplicate primitive types, that can't reference other types, by calculating
373862306a36Sopenharmony_ci * their type signature hash and comparing them with any possible canonical
373962306a36Sopenharmony_ci * candidate. If no canonical candidate matches, type itself is marked as
374062306a36Sopenharmony_ci * canonical and is added into `btf_dedup->dedup_table` as another candidate.
374162306a36Sopenharmony_ci */
374262306a36Sopenharmony_cistatic int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
374362306a36Sopenharmony_ci{
374462306a36Sopenharmony_ci	struct btf_type *t = btf_type_by_id(d->btf, type_id);
374562306a36Sopenharmony_ci	struct hashmap_entry *hash_entry;
374662306a36Sopenharmony_ci	struct btf_type *cand;
374762306a36Sopenharmony_ci	/* if we don't find equivalent type, then we are canonical */
374862306a36Sopenharmony_ci	__u32 new_id = type_id;
374962306a36Sopenharmony_ci	__u32 cand_id;
375062306a36Sopenharmony_ci	long h;
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	switch (btf_kind(t)) {
375362306a36Sopenharmony_ci	case BTF_KIND_CONST:
375462306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
375562306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
375662306a36Sopenharmony_ci	case BTF_KIND_PTR:
375762306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
375862306a36Sopenharmony_ci	case BTF_KIND_ARRAY:
375962306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
376062306a36Sopenharmony_ci	case BTF_KIND_UNION:
376162306a36Sopenharmony_ci	case BTF_KIND_FUNC:
376262306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
376362306a36Sopenharmony_ci	case BTF_KIND_VAR:
376462306a36Sopenharmony_ci	case BTF_KIND_DATASEC:
376562306a36Sopenharmony_ci	case BTF_KIND_DECL_TAG:
376662306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
376762306a36Sopenharmony_ci		return 0;
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_ci	case BTF_KIND_INT:
377062306a36Sopenharmony_ci		h = btf_hash_int_decl_tag(t);
377162306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
377262306a36Sopenharmony_ci			cand_id = hash_entry->value;
377362306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
377462306a36Sopenharmony_ci			if (btf_equal_int_tag(t, cand)) {
377562306a36Sopenharmony_ci				new_id = cand_id;
377662306a36Sopenharmony_ci				break;
377762306a36Sopenharmony_ci			}
377862306a36Sopenharmony_ci		}
377962306a36Sopenharmony_ci		break;
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	case BTF_KIND_ENUM:
378262306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
378362306a36Sopenharmony_ci		h = btf_hash_enum(t);
378462306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
378562306a36Sopenharmony_ci			cand_id = hash_entry->value;
378662306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
378762306a36Sopenharmony_ci			if (btf_equal_enum(t, cand)) {
378862306a36Sopenharmony_ci				new_id = cand_id;
378962306a36Sopenharmony_ci				break;
379062306a36Sopenharmony_ci			}
379162306a36Sopenharmony_ci			if (btf_compat_enum(t, cand)) {
379262306a36Sopenharmony_ci				if (btf_is_enum_fwd(t)) {
379362306a36Sopenharmony_ci					/* resolve fwd to full enum */
379462306a36Sopenharmony_ci					new_id = cand_id;
379562306a36Sopenharmony_ci					break;
379662306a36Sopenharmony_ci				}
379762306a36Sopenharmony_ci				/* resolve canonical enum fwd to full enum */
379862306a36Sopenharmony_ci				d->map[cand_id] = type_id;
379962306a36Sopenharmony_ci			}
380062306a36Sopenharmony_ci		}
380162306a36Sopenharmony_ci		break;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	case BTF_KIND_FWD:
380462306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
380562306a36Sopenharmony_ci		h = btf_hash_common(t);
380662306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
380762306a36Sopenharmony_ci			cand_id = hash_entry->value;
380862306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
380962306a36Sopenharmony_ci			if (btf_equal_common(t, cand)) {
381062306a36Sopenharmony_ci				new_id = cand_id;
381162306a36Sopenharmony_ci				break;
381262306a36Sopenharmony_ci			}
381362306a36Sopenharmony_ci		}
381462306a36Sopenharmony_ci		break;
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	default:
381762306a36Sopenharmony_ci		return -EINVAL;
381862306a36Sopenharmony_ci	}
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	d->map[type_id] = new_id;
382162306a36Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
382262306a36Sopenharmony_ci		return -ENOMEM;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	return 0;
382562306a36Sopenharmony_ci}
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_cistatic int btf_dedup_prim_types(struct btf_dedup *d)
382862306a36Sopenharmony_ci{
382962306a36Sopenharmony_ci	int i, err;
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
383262306a36Sopenharmony_ci		err = btf_dedup_prim_type(d, d->btf->start_id + i);
383362306a36Sopenharmony_ci		if (err)
383462306a36Sopenharmony_ci			return err;
383562306a36Sopenharmony_ci	}
383662306a36Sopenharmony_ci	return 0;
383762306a36Sopenharmony_ci}
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci/*
384062306a36Sopenharmony_ci * Check whether type is already mapped into canonical one (could be to itself).
384162306a36Sopenharmony_ci */
384262306a36Sopenharmony_cistatic inline bool is_type_mapped(struct btf_dedup *d, uint32_t type_id)
384362306a36Sopenharmony_ci{
384462306a36Sopenharmony_ci	return d->map[type_id] <= BTF_MAX_NR_TYPES;
384562306a36Sopenharmony_ci}
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci/*
384862306a36Sopenharmony_ci * Resolve type ID into its canonical type ID, if any; otherwise return original
384962306a36Sopenharmony_ci * type ID. If type is FWD and is resolved into STRUCT/UNION already, follow
385062306a36Sopenharmony_ci * STRUCT/UNION link and resolve it into canonical type ID as well.
385162306a36Sopenharmony_ci */
385262306a36Sopenharmony_cistatic inline __u32 resolve_type_id(struct btf_dedup *d, __u32 type_id)
385362306a36Sopenharmony_ci{
385462306a36Sopenharmony_ci	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
385562306a36Sopenharmony_ci		type_id = d->map[type_id];
385662306a36Sopenharmony_ci	return type_id;
385762306a36Sopenharmony_ci}
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci/*
386062306a36Sopenharmony_ci * Resolve FWD to underlying STRUCT/UNION, if any; otherwise return original
386162306a36Sopenharmony_ci * type ID.
386262306a36Sopenharmony_ci */
386362306a36Sopenharmony_cistatic uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
386462306a36Sopenharmony_ci{
386562306a36Sopenharmony_ci	__u32 orig_type_id = type_id;
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
386862306a36Sopenharmony_ci		return type_id;
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
387162306a36Sopenharmony_ci		type_id = d->map[type_id];
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
387462306a36Sopenharmony_ci		return type_id;
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	return orig_type_id;
387762306a36Sopenharmony_ci}
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_cistatic inline __u16 btf_fwd_kind(struct btf_type *t)
388162306a36Sopenharmony_ci{
388262306a36Sopenharmony_ci	return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
388362306a36Sopenharmony_ci}
388462306a36Sopenharmony_ci
388562306a36Sopenharmony_ci/* Check if given two types are identical ARRAY definitions */
388662306a36Sopenharmony_cistatic bool btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
388762306a36Sopenharmony_ci{
388862306a36Sopenharmony_ci	struct btf_type *t1, *t2;
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci	t1 = btf_type_by_id(d->btf, id1);
389162306a36Sopenharmony_ci	t2 = btf_type_by_id(d->btf, id2);
389262306a36Sopenharmony_ci	if (!btf_is_array(t1) || !btf_is_array(t2))
389362306a36Sopenharmony_ci		return false;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	return btf_equal_array(t1, t2);
389662306a36Sopenharmony_ci}
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci/* Check if given two types are identical STRUCT/UNION definitions */
389962306a36Sopenharmony_cistatic bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2)
390062306a36Sopenharmony_ci{
390162306a36Sopenharmony_ci	const struct btf_member *m1, *m2;
390262306a36Sopenharmony_ci	struct btf_type *t1, *t2;
390362306a36Sopenharmony_ci	int n, i;
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	t1 = btf_type_by_id(d->btf, id1);
390662306a36Sopenharmony_ci	t2 = btf_type_by_id(d->btf, id2);
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_ci	if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2))
390962306a36Sopenharmony_ci		return false;
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (!btf_shallow_equal_struct(t1, t2))
391262306a36Sopenharmony_ci		return false;
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci	m1 = btf_members(t1);
391562306a36Sopenharmony_ci	m2 = btf_members(t2);
391662306a36Sopenharmony_ci	for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
391762306a36Sopenharmony_ci		if (m1->type != m2->type &&
391862306a36Sopenharmony_ci		    !btf_dedup_identical_arrays(d, m1->type, m2->type) &&
391962306a36Sopenharmony_ci		    !btf_dedup_identical_structs(d, m1->type, m2->type))
392062306a36Sopenharmony_ci			return false;
392162306a36Sopenharmony_ci	}
392262306a36Sopenharmony_ci	return true;
392362306a36Sopenharmony_ci}
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci/*
392662306a36Sopenharmony_ci * Check equivalence of BTF type graph formed by candidate struct/union (we'll
392762306a36Sopenharmony_ci * call it "candidate graph" in this description for brevity) to a type graph
392862306a36Sopenharmony_ci * formed by (potential) canonical struct/union ("canonical graph" for brevity
392962306a36Sopenharmony_ci * here, though keep in mind that not all types in canonical graph are
393062306a36Sopenharmony_ci * necessarily canonical representatives themselves, some of them might be
393162306a36Sopenharmony_ci * duplicates or its uniqueness might not have been established yet).
393262306a36Sopenharmony_ci * Returns:
393362306a36Sopenharmony_ci *  - >0, if type graphs are equivalent;
393462306a36Sopenharmony_ci *  -  0, if not equivalent;
393562306a36Sopenharmony_ci *  - <0, on error.
393662306a36Sopenharmony_ci *
393762306a36Sopenharmony_ci * Algorithm performs side-by-side DFS traversal of both type graphs and checks
393862306a36Sopenharmony_ci * equivalence of BTF types at each step. If at any point BTF types in candidate
393962306a36Sopenharmony_ci * and canonical graphs are not compatible structurally, whole graphs are
394062306a36Sopenharmony_ci * incompatible. If types are structurally equivalent (i.e., all information
394162306a36Sopenharmony_ci * except referenced type IDs is exactly the same), a mapping from `canon_id` to
394262306a36Sopenharmony_ci * a `cand_id` is recored in hypothetical mapping (`btf_dedup->hypot_map`).
394362306a36Sopenharmony_ci * If a type references other types, then those referenced types are checked
394462306a36Sopenharmony_ci * for equivalence recursively.
394562306a36Sopenharmony_ci *
394662306a36Sopenharmony_ci * During DFS traversal, if we find that for current `canon_id` type we
394762306a36Sopenharmony_ci * already have some mapping in hypothetical map, we check for two possible
394862306a36Sopenharmony_ci * situations:
394962306a36Sopenharmony_ci *   - `canon_id` is mapped to exactly the same type as `cand_id`. This will
395062306a36Sopenharmony_ci *     happen when type graphs have cycles. In this case we assume those two
395162306a36Sopenharmony_ci *     types are equivalent.
395262306a36Sopenharmony_ci *   - `canon_id` is mapped to different type. This is contradiction in our
395362306a36Sopenharmony_ci *     hypothetical mapping, because same graph in canonical graph corresponds
395462306a36Sopenharmony_ci *     to two different types in candidate graph, which for equivalent type
395562306a36Sopenharmony_ci *     graphs shouldn't happen. This condition terminates equivalence check
395662306a36Sopenharmony_ci *     with negative result.
395762306a36Sopenharmony_ci *
395862306a36Sopenharmony_ci * If type graphs traversal exhausts types to check and find no contradiction,
395962306a36Sopenharmony_ci * then type graphs are equivalent.
396062306a36Sopenharmony_ci *
396162306a36Sopenharmony_ci * When checking types for equivalence, there is one special case: FWD types.
396262306a36Sopenharmony_ci * If FWD type resolution is allowed and one of the types (either from canonical
396362306a36Sopenharmony_ci * or candidate graph) is FWD and other is STRUCT/UNION (depending on FWD's kind
396462306a36Sopenharmony_ci * flag) and their names match, hypothetical mapping is updated to point from
396562306a36Sopenharmony_ci * FWD to STRUCT/UNION. If graphs will be determined as equivalent successfully,
396662306a36Sopenharmony_ci * this mapping will be used to record FWD -> STRUCT/UNION mapping permanently.
396762306a36Sopenharmony_ci *
396862306a36Sopenharmony_ci * Technically, this could lead to incorrect FWD to STRUCT/UNION resolution,
396962306a36Sopenharmony_ci * if there are two exactly named (or anonymous) structs/unions that are
397062306a36Sopenharmony_ci * compatible structurally, one of which has FWD field, while other is concrete
397162306a36Sopenharmony_ci * STRUCT/UNION, but according to C sources they are different structs/unions
397262306a36Sopenharmony_ci * that are referencing different types with the same name. This is extremely
397362306a36Sopenharmony_ci * unlikely to happen, but btf_dedup API allows to disable FWD resolution if
397462306a36Sopenharmony_ci * this logic is causing problems.
397562306a36Sopenharmony_ci *
397662306a36Sopenharmony_ci * Doing FWD resolution means that both candidate and/or canonical graphs can
397762306a36Sopenharmony_ci * consists of portions of the graph that come from multiple compilation units.
397862306a36Sopenharmony_ci * This is due to the fact that types within single compilation unit are always
397962306a36Sopenharmony_ci * deduplicated and FWDs are already resolved, if referenced struct/union
398062306a36Sopenharmony_ci * definiton is available. So, if we had unresolved FWD and found corresponding
398162306a36Sopenharmony_ci * STRUCT/UNION, they will be from different compilation units. This
398262306a36Sopenharmony_ci * consequently means that when we "link" FWD to corresponding STRUCT/UNION,
398362306a36Sopenharmony_ci * type graph will likely have at least two different BTF types that describe
398462306a36Sopenharmony_ci * same type (e.g., most probably there will be two different BTF types for the
398562306a36Sopenharmony_ci * same 'int' primitive type) and could even have "overlapping" parts of type
398662306a36Sopenharmony_ci * graph that describe same subset of types.
398762306a36Sopenharmony_ci *
398862306a36Sopenharmony_ci * This in turn means that our assumption that each type in canonical graph
398962306a36Sopenharmony_ci * must correspond to exactly one type in candidate graph might not hold
399062306a36Sopenharmony_ci * anymore and will make it harder to detect contradictions using hypothetical
399162306a36Sopenharmony_ci * map. To handle this problem, we allow to follow FWD -> STRUCT/UNION
399262306a36Sopenharmony_ci * resolution only in canonical graph. FWDs in candidate graphs are never
399362306a36Sopenharmony_ci * resolved. To see why it's OK, let's check all possible situations w.r.t. FWDs
399462306a36Sopenharmony_ci * that can occur:
399562306a36Sopenharmony_ci *   - Both types in canonical and candidate graphs are FWDs. If they are
399662306a36Sopenharmony_ci *     structurally equivalent, then they can either be both resolved to the
399762306a36Sopenharmony_ci *     same STRUCT/UNION or not resolved at all. In both cases they are
399862306a36Sopenharmony_ci *     equivalent and there is no need to resolve FWD on candidate side.
399962306a36Sopenharmony_ci *   - Both types in canonical and candidate graphs are concrete STRUCT/UNION,
400062306a36Sopenharmony_ci *     so nothing to resolve as well, algorithm will check equivalence anyway.
400162306a36Sopenharmony_ci *   - Type in canonical graph is FWD, while type in candidate is concrete
400262306a36Sopenharmony_ci *     STRUCT/UNION. In this case candidate graph comes from single compilation
400362306a36Sopenharmony_ci *     unit, so there is exactly one BTF type for each unique C type. After
400462306a36Sopenharmony_ci *     resolving FWD into STRUCT/UNION, there might be more than one BTF type
400562306a36Sopenharmony_ci *     in canonical graph mapping to single BTF type in candidate graph, but
400662306a36Sopenharmony_ci *     because hypothetical mapping maps from canonical to candidate types, it's
400762306a36Sopenharmony_ci *     alright, and we still maintain the property of having single `canon_id`
400862306a36Sopenharmony_ci *     mapping to single `cand_id` (there could be two different `canon_id`
400962306a36Sopenharmony_ci *     mapped to the same `cand_id`, but it's not contradictory).
401062306a36Sopenharmony_ci *   - Type in canonical graph is concrete STRUCT/UNION, while type in candidate
401162306a36Sopenharmony_ci *     graph is FWD. In this case we are just going to check compatibility of
401262306a36Sopenharmony_ci *     STRUCT/UNION and corresponding FWD, and if they are compatible, we'll
401362306a36Sopenharmony_ci *     assume that whatever STRUCT/UNION FWD resolves to must be equivalent to
401462306a36Sopenharmony_ci *     a concrete STRUCT/UNION from canonical graph. If the rest of type graphs
401562306a36Sopenharmony_ci *     turn out equivalent, we'll re-resolve FWD to concrete STRUCT/UNION from
401662306a36Sopenharmony_ci *     canonical graph.
401762306a36Sopenharmony_ci */
401862306a36Sopenharmony_cistatic int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
401962306a36Sopenharmony_ci			      __u32 canon_id)
402062306a36Sopenharmony_ci{
402162306a36Sopenharmony_ci	struct btf_type *cand_type;
402262306a36Sopenharmony_ci	struct btf_type *canon_type;
402362306a36Sopenharmony_ci	__u32 hypot_type_id;
402462306a36Sopenharmony_ci	__u16 cand_kind;
402562306a36Sopenharmony_ci	__u16 canon_kind;
402662306a36Sopenharmony_ci	int i, eq;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	/* if both resolve to the same canonical, they must be equivalent */
402962306a36Sopenharmony_ci	if (resolve_type_id(d, cand_id) == resolve_type_id(d, canon_id))
403062306a36Sopenharmony_ci		return 1;
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	canon_id = resolve_fwd_id(d, canon_id);
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci	hypot_type_id = d->hypot_map[canon_id];
403562306a36Sopenharmony_ci	if (hypot_type_id <= BTF_MAX_NR_TYPES) {
403662306a36Sopenharmony_ci		if (hypot_type_id == cand_id)
403762306a36Sopenharmony_ci			return 1;
403862306a36Sopenharmony_ci		/* In some cases compiler will generate different DWARF types
403962306a36Sopenharmony_ci		 * for *identical* array type definitions and use them for
404062306a36Sopenharmony_ci		 * different fields within the *same* struct. This breaks type
404162306a36Sopenharmony_ci		 * equivalence check, which makes an assumption that candidate
404262306a36Sopenharmony_ci		 * types sub-graph has a consistent and deduped-by-compiler
404362306a36Sopenharmony_ci		 * types within a single CU. So work around that by explicitly
404462306a36Sopenharmony_ci		 * allowing identical array types here.
404562306a36Sopenharmony_ci		 */
404662306a36Sopenharmony_ci		if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id))
404762306a36Sopenharmony_ci			return 1;
404862306a36Sopenharmony_ci		/* It turns out that similar situation can happen with
404962306a36Sopenharmony_ci		 * struct/union sometimes, sigh... Handle the case where
405062306a36Sopenharmony_ci		 * structs/unions are exactly the same, down to the referenced
405162306a36Sopenharmony_ci		 * type IDs. Anything more complicated (e.g., if referenced
405262306a36Sopenharmony_ci		 * types are different, but equivalent) is *way more*
405362306a36Sopenharmony_ci		 * complicated and requires a many-to-many equivalence mapping.
405462306a36Sopenharmony_ci		 */
405562306a36Sopenharmony_ci		if (btf_dedup_identical_structs(d, hypot_type_id, cand_id))
405662306a36Sopenharmony_ci			return 1;
405762306a36Sopenharmony_ci		return 0;
405862306a36Sopenharmony_ci	}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	if (btf_dedup_hypot_map_add(d, canon_id, cand_id))
406162306a36Sopenharmony_ci		return -ENOMEM;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	cand_type = btf_type_by_id(d->btf, cand_id);
406462306a36Sopenharmony_ci	canon_type = btf_type_by_id(d->btf, canon_id);
406562306a36Sopenharmony_ci	cand_kind = btf_kind(cand_type);
406662306a36Sopenharmony_ci	canon_kind = btf_kind(canon_type);
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	if (cand_type->name_off != canon_type->name_off)
406962306a36Sopenharmony_ci		return 0;
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_ci	/* FWD <--> STRUCT/UNION equivalence check, if enabled */
407262306a36Sopenharmony_ci	if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
407362306a36Sopenharmony_ci	    && cand_kind != canon_kind) {
407462306a36Sopenharmony_ci		__u16 real_kind;
407562306a36Sopenharmony_ci		__u16 fwd_kind;
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci		if (cand_kind == BTF_KIND_FWD) {
407862306a36Sopenharmony_ci			real_kind = canon_kind;
407962306a36Sopenharmony_ci			fwd_kind = btf_fwd_kind(cand_type);
408062306a36Sopenharmony_ci		} else {
408162306a36Sopenharmony_ci			real_kind = cand_kind;
408262306a36Sopenharmony_ci			fwd_kind = btf_fwd_kind(canon_type);
408362306a36Sopenharmony_ci			/* we'd need to resolve base FWD to STRUCT/UNION */
408462306a36Sopenharmony_ci			if (fwd_kind == real_kind && canon_id < d->btf->start_id)
408562306a36Sopenharmony_ci				d->hypot_adjust_canon = true;
408662306a36Sopenharmony_ci		}
408762306a36Sopenharmony_ci		return fwd_kind == real_kind;
408862306a36Sopenharmony_ci	}
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	if (cand_kind != canon_kind)
409162306a36Sopenharmony_ci		return 0;
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci	switch (cand_kind) {
409462306a36Sopenharmony_ci	case BTF_KIND_INT:
409562306a36Sopenharmony_ci		return btf_equal_int_tag(cand_type, canon_type);
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	case BTF_KIND_ENUM:
409862306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
409962306a36Sopenharmony_ci		return btf_compat_enum(cand_type, canon_type);
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_ci	case BTF_KIND_FWD:
410262306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
410362306a36Sopenharmony_ci		return btf_equal_common(cand_type, canon_type);
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ci	case BTF_KIND_CONST:
410662306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
410762306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
410862306a36Sopenharmony_ci	case BTF_KIND_PTR:
410962306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
411062306a36Sopenharmony_ci	case BTF_KIND_FUNC:
411162306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
411262306a36Sopenharmony_ci		if (cand_type->info != canon_type->info)
411362306a36Sopenharmony_ci			return 0;
411462306a36Sopenharmony_ci		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	case BTF_KIND_ARRAY: {
411762306a36Sopenharmony_ci		const struct btf_array *cand_arr, *canon_arr;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci		if (!btf_compat_array(cand_type, canon_type))
412062306a36Sopenharmony_ci			return 0;
412162306a36Sopenharmony_ci		cand_arr = btf_array(cand_type);
412262306a36Sopenharmony_ci		canon_arr = btf_array(canon_type);
412362306a36Sopenharmony_ci		eq = btf_dedup_is_equiv(d, cand_arr->index_type, canon_arr->index_type);
412462306a36Sopenharmony_ci		if (eq <= 0)
412562306a36Sopenharmony_ci			return eq;
412662306a36Sopenharmony_ci		return btf_dedup_is_equiv(d, cand_arr->type, canon_arr->type);
412762306a36Sopenharmony_ci	}
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
413062306a36Sopenharmony_ci	case BTF_KIND_UNION: {
413162306a36Sopenharmony_ci		const struct btf_member *cand_m, *canon_m;
413262306a36Sopenharmony_ci		__u16 vlen;
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci		if (!btf_shallow_equal_struct(cand_type, canon_type))
413562306a36Sopenharmony_ci			return 0;
413662306a36Sopenharmony_ci		vlen = btf_vlen(cand_type);
413762306a36Sopenharmony_ci		cand_m = btf_members(cand_type);
413862306a36Sopenharmony_ci		canon_m = btf_members(canon_type);
413962306a36Sopenharmony_ci		for (i = 0; i < vlen; i++) {
414062306a36Sopenharmony_ci			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
414162306a36Sopenharmony_ci			if (eq <= 0)
414262306a36Sopenharmony_ci				return eq;
414362306a36Sopenharmony_ci			cand_m++;
414462306a36Sopenharmony_ci			canon_m++;
414562306a36Sopenharmony_ci		}
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci		return 1;
414862306a36Sopenharmony_ci	}
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
415162306a36Sopenharmony_ci		const struct btf_param *cand_p, *canon_p;
415262306a36Sopenharmony_ci		__u16 vlen;
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci		if (!btf_compat_fnproto(cand_type, canon_type))
415562306a36Sopenharmony_ci			return 0;
415662306a36Sopenharmony_ci		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
415762306a36Sopenharmony_ci		if (eq <= 0)
415862306a36Sopenharmony_ci			return eq;
415962306a36Sopenharmony_ci		vlen = btf_vlen(cand_type);
416062306a36Sopenharmony_ci		cand_p = btf_params(cand_type);
416162306a36Sopenharmony_ci		canon_p = btf_params(canon_type);
416262306a36Sopenharmony_ci		for (i = 0; i < vlen; i++) {
416362306a36Sopenharmony_ci			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
416462306a36Sopenharmony_ci			if (eq <= 0)
416562306a36Sopenharmony_ci				return eq;
416662306a36Sopenharmony_ci			cand_p++;
416762306a36Sopenharmony_ci			canon_p++;
416862306a36Sopenharmony_ci		}
416962306a36Sopenharmony_ci		return 1;
417062306a36Sopenharmony_ci	}
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	default:
417362306a36Sopenharmony_ci		return -EINVAL;
417462306a36Sopenharmony_ci	}
417562306a36Sopenharmony_ci	return 0;
417662306a36Sopenharmony_ci}
417762306a36Sopenharmony_ci
417862306a36Sopenharmony_ci/*
417962306a36Sopenharmony_ci * Use hypothetical mapping, produced by successful type graph equivalence
418062306a36Sopenharmony_ci * check, to augment existing struct/union canonical mapping, where possible.
418162306a36Sopenharmony_ci *
418262306a36Sopenharmony_ci * If BTF_KIND_FWD resolution is allowed, this mapping is also used to record
418362306a36Sopenharmony_ci * FWD -> STRUCT/UNION correspondence as well. FWD resolution is bidirectional:
418462306a36Sopenharmony_ci * it doesn't matter if FWD type was part of canonical graph or candidate one,
418562306a36Sopenharmony_ci * we are recording the mapping anyway. As opposed to carefulness required
418662306a36Sopenharmony_ci * for struct/union correspondence mapping (described below), for FWD resolution
418762306a36Sopenharmony_ci * it's not important, as by the time that FWD type (reference type) will be
418862306a36Sopenharmony_ci * deduplicated all structs/unions will be deduped already anyway.
418962306a36Sopenharmony_ci *
419062306a36Sopenharmony_ci * Recording STRUCT/UNION mapping is purely a performance optimization and is
419162306a36Sopenharmony_ci * not required for correctness. It needs to be done carefully to ensure that
419262306a36Sopenharmony_ci * struct/union from candidate's type graph is not mapped into corresponding
419362306a36Sopenharmony_ci * struct/union from canonical type graph that itself hasn't been resolved into
419462306a36Sopenharmony_ci * canonical representative. The only guarantee we have is that canonical
419562306a36Sopenharmony_ci * struct/union was determined as canonical and that won't change. But any
419662306a36Sopenharmony_ci * types referenced through that struct/union fields could have been not yet
419762306a36Sopenharmony_ci * resolved, so in case like that it's too early to establish any kind of
419862306a36Sopenharmony_ci * correspondence between structs/unions.
419962306a36Sopenharmony_ci *
420062306a36Sopenharmony_ci * No canonical correspondence is derived for primitive types (they are already
420162306a36Sopenharmony_ci * deduplicated completely already anyway) or reference types (they rely on
420262306a36Sopenharmony_ci * stability of struct/union canonical relationship for equivalence checks).
420362306a36Sopenharmony_ci */
420462306a36Sopenharmony_cistatic void btf_dedup_merge_hypot_map(struct btf_dedup *d)
420562306a36Sopenharmony_ci{
420662306a36Sopenharmony_ci	__u32 canon_type_id, targ_type_id;
420762306a36Sopenharmony_ci	__u16 t_kind, c_kind;
420862306a36Sopenharmony_ci	__u32 t_id, c_id;
420962306a36Sopenharmony_ci	int i;
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	for (i = 0; i < d->hypot_cnt; i++) {
421262306a36Sopenharmony_ci		canon_type_id = d->hypot_list[i];
421362306a36Sopenharmony_ci		targ_type_id = d->hypot_map[canon_type_id];
421462306a36Sopenharmony_ci		t_id = resolve_type_id(d, targ_type_id);
421562306a36Sopenharmony_ci		c_id = resolve_type_id(d, canon_type_id);
421662306a36Sopenharmony_ci		t_kind = btf_kind(btf__type_by_id(d->btf, t_id));
421762306a36Sopenharmony_ci		c_kind = btf_kind(btf__type_by_id(d->btf, c_id));
421862306a36Sopenharmony_ci		/*
421962306a36Sopenharmony_ci		 * Resolve FWD into STRUCT/UNION.
422062306a36Sopenharmony_ci		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
422162306a36Sopenharmony_ci		 * mapped to canonical representative (as opposed to
422262306a36Sopenharmony_ci		 * STRUCT/UNION <--> STRUCT/UNION mapping logic below), because
422362306a36Sopenharmony_ci		 * eventually that struct is going to be mapped and all resolved
422462306a36Sopenharmony_ci		 * FWDs will automatically resolve to correct canonical
422562306a36Sopenharmony_ci		 * representative. This will happen before ref type deduping,
422662306a36Sopenharmony_ci		 * which critically depends on stability of these mapping. This
422762306a36Sopenharmony_ci		 * stability is not a requirement for STRUCT/UNION equivalence
422862306a36Sopenharmony_ci		 * checks, though.
422962306a36Sopenharmony_ci		 */
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci		/* if it's the split BTF case, we still need to point base FWD
423262306a36Sopenharmony_ci		 * to STRUCT/UNION in a split BTF, because FWDs from split BTF
423362306a36Sopenharmony_ci		 * will be resolved against base FWD. If we don't point base
423462306a36Sopenharmony_ci		 * canonical FWD to the resolved STRUCT/UNION, then all the
423562306a36Sopenharmony_ci		 * FWDs in split BTF won't be correctly resolved to a proper
423662306a36Sopenharmony_ci		 * STRUCT/UNION.
423762306a36Sopenharmony_ci		 */
423862306a36Sopenharmony_ci		if (t_kind != BTF_KIND_FWD && c_kind == BTF_KIND_FWD)
423962306a36Sopenharmony_ci			d->map[c_id] = t_id;
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci		/* if graph equivalence determined that we'd need to adjust
424262306a36Sopenharmony_ci		 * base canonical types, then we need to only point base FWDs
424362306a36Sopenharmony_ci		 * to STRUCTs/UNIONs and do no more modifications. For all
424462306a36Sopenharmony_ci		 * other purposes the type graphs were not equivalent.
424562306a36Sopenharmony_ci		 */
424662306a36Sopenharmony_ci		if (d->hypot_adjust_canon)
424762306a36Sopenharmony_ci			continue;
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci		if (t_kind == BTF_KIND_FWD && c_kind != BTF_KIND_FWD)
425062306a36Sopenharmony_ci			d->map[t_id] = c_id;
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci		if ((t_kind == BTF_KIND_STRUCT || t_kind == BTF_KIND_UNION) &&
425362306a36Sopenharmony_ci		    c_kind != BTF_KIND_FWD &&
425462306a36Sopenharmony_ci		    is_type_mapped(d, c_id) &&
425562306a36Sopenharmony_ci		    !is_type_mapped(d, t_id)) {
425662306a36Sopenharmony_ci			/*
425762306a36Sopenharmony_ci			 * as a perf optimization, we can map struct/union
425862306a36Sopenharmony_ci			 * that's part of type graph we just verified for
425962306a36Sopenharmony_ci			 * equivalence. We can do that for struct/union that has
426062306a36Sopenharmony_ci			 * canonical representative only, though.
426162306a36Sopenharmony_ci			 */
426262306a36Sopenharmony_ci			d->map[t_id] = c_id;
426362306a36Sopenharmony_ci		}
426462306a36Sopenharmony_ci	}
426562306a36Sopenharmony_ci}
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci/*
426862306a36Sopenharmony_ci * Deduplicate struct/union types.
426962306a36Sopenharmony_ci *
427062306a36Sopenharmony_ci * For each struct/union type its type signature hash is calculated, taking
427162306a36Sopenharmony_ci * into account type's name, size, number, order and names of fields, but
427262306a36Sopenharmony_ci * ignoring type ID's referenced from fields, because they might not be deduped
427362306a36Sopenharmony_ci * completely until after reference types deduplication phase. This type hash
427462306a36Sopenharmony_ci * is used to iterate over all potential canonical types, sharing same hash.
427562306a36Sopenharmony_ci * For each canonical candidate we check whether type graphs that they form
427662306a36Sopenharmony_ci * (through referenced types in fields and so on) are equivalent using algorithm
427762306a36Sopenharmony_ci * implemented in `btf_dedup_is_equiv`. If such equivalence is found and
427862306a36Sopenharmony_ci * BTF_KIND_FWD resolution is allowed, then hypothetical mapping
427962306a36Sopenharmony_ci * (btf_dedup->hypot_map) produced by aforementioned type graph equivalence
428062306a36Sopenharmony_ci * algorithm is used to record FWD -> STRUCT/UNION mapping. It's also used to
428162306a36Sopenharmony_ci * potentially map other structs/unions to their canonical representatives,
428262306a36Sopenharmony_ci * if such relationship hasn't yet been established. This speeds up algorithm
428362306a36Sopenharmony_ci * by eliminating some of the duplicate work.
428462306a36Sopenharmony_ci *
428562306a36Sopenharmony_ci * If no matching canonical representative was found, struct/union is marked
428662306a36Sopenharmony_ci * as canonical for itself and is added into btf_dedup->dedup_table hash map
428762306a36Sopenharmony_ci * for further look ups.
428862306a36Sopenharmony_ci */
428962306a36Sopenharmony_cistatic int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
429062306a36Sopenharmony_ci{
429162306a36Sopenharmony_ci	struct btf_type *cand_type, *t;
429262306a36Sopenharmony_ci	struct hashmap_entry *hash_entry;
429362306a36Sopenharmony_ci	/* if we don't find equivalent type, then we are canonical */
429462306a36Sopenharmony_ci	__u32 new_id = type_id;
429562306a36Sopenharmony_ci	__u16 kind;
429662306a36Sopenharmony_ci	long h;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci	/* already deduped or is in process of deduping (loop detected) */
429962306a36Sopenharmony_ci	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
430062306a36Sopenharmony_ci		return 0;
430162306a36Sopenharmony_ci
430262306a36Sopenharmony_ci	t = btf_type_by_id(d->btf, type_id);
430362306a36Sopenharmony_ci	kind = btf_kind(t);
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
430662306a36Sopenharmony_ci		return 0;
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	h = btf_hash_struct(t);
430962306a36Sopenharmony_ci	for_each_dedup_cand(d, hash_entry, h) {
431062306a36Sopenharmony_ci		__u32 cand_id = hash_entry->value;
431162306a36Sopenharmony_ci		int eq;
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ci		/*
431462306a36Sopenharmony_ci		 * Even though btf_dedup_is_equiv() checks for
431562306a36Sopenharmony_ci		 * btf_shallow_equal_struct() internally when checking two
431662306a36Sopenharmony_ci		 * structs (unions) for equivalence, we need to guard here
431762306a36Sopenharmony_ci		 * from picking matching FWD type as a dedup candidate.
431862306a36Sopenharmony_ci		 * This can happen due to hash collision. In such case just
431962306a36Sopenharmony_ci		 * relying on btf_dedup_is_equiv() would lead to potentially
432062306a36Sopenharmony_ci		 * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because
432162306a36Sopenharmony_ci		 * FWD and compatible STRUCT/UNION are considered equivalent.
432262306a36Sopenharmony_ci		 */
432362306a36Sopenharmony_ci		cand_type = btf_type_by_id(d->btf, cand_id);
432462306a36Sopenharmony_ci		if (!btf_shallow_equal_struct(t, cand_type))
432562306a36Sopenharmony_ci			continue;
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci		btf_dedup_clear_hypot_map(d);
432862306a36Sopenharmony_ci		eq = btf_dedup_is_equiv(d, type_id, cand_id);
432962306a36Sopenharmony_ci		if (eq < 0)
433062306a36Sopenharmony_ci			return eq;
433162306a36Sopenharmony_ci		if (!eq)
433262306a36Sopenharmony_ci			continue;
433362306a36Sopenharmony_ci		btf_dedup_merge_hypot_map(d);
433462306a36Sopenharmony_ci		if (d->hypot_adjust_canon) /* not really equivalent */
433562306a36Sopenharmony_ci			continue;
433662306a36Sopenharmony_ci		new_id = cand_id;
433762306a36Sopenharmony_ci		break;
433862306a36Sopenharmony_ci	}
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci	d->map[type_id] = new_id;
434162306a36Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
434262306a36Sopenharmony_ci		return -ENOMEM;
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	return 0;
434562306a36Sopenharmony_ci}
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_cistatic int btf_dedup_struct_types(struct btf_dedup *d)
434862306a36Sopenharmony_ci{
434962306a36Sopenharmony_ci	int i, err;
435062306a36Sopenharmony_ci
435162306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
435262306a36Sopenharmony_ci		err = btf_dedup_struct_type(d, d->btf->start_id + i);
435362306a36Sopenharmony_ci		if (err)
435462306a36Sopenharmony_ci			return err;
435562306a36Sopenharmony_ci	}
435662306a36Sopenharmony_ci	return 0;
435762306a36Sopenharmony_ci}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci/*
436062306a36Sopenharmony_ci * Deduplicate reference type.
436162306a36Sopenharmony_ci *
436262306a36Sopenharmony_ci * Once all primitive and struct/union types got deduplicated, we can easily
436362306a36Sopenharmony_ci * deduplicate all other (reference) BTF types. This is done in two steps:
436462306a36Sopenharmony_ci *
436562306a36Sopenharmony_ci * 1. Resolve all referenced type IDs into their canonical type IDs. This
436662306a36Sopenharmony_ci * resolution can be done either immediately for primitive or struct/union types
436762306a36Sopenharmony_ci * (because they were deduped in previous two phases) or recursively for
436862306a36Sopenharmony_ci * reference types. Recursion will always terminate at either primitive or
436962306a36Sopenharmony_ci * struct/union type, at which point we can "unwind" chain of reference types
437062306a36Sopenharmony_ci * one by one. There is no danger of encountering cycles because in C type
437162306a36Sopenharmony_ci * system the only way to form type cycle is through struct/union, so any chain
437262306a36Sopenharmony_ci * of reference types, even those taking part in a type cycle, will inevitably
437362306a36Sopenharmony_ci * reach struct/union at some point.
437462306a36Sopenharmony_ci *
437562306a36Sopenharmony_ci * 2. Once all referenced type IDs are resolved into canonical ones, BTF type
437662306a36Sopenharmony_ci * becomes "stable", in the sense that no further deduplication will cause
437762306a36Sopenharmony_ci * any changes to it. With that, it's now possible to calculate type's signature
437862306a36Sopenharmony_ci * hash (this time taking into account referenced type IDs) and loop over all
437962306a36Sopenharmony_ci * potential canonical representatives. If no match was found, current type
438062306a36Sopenharmony_ci * will become canonical representative of itself and will be added into
438162306a36Sopenharmony_ci * btf_dedup->dedup_table as another possible canonical representative.
438262306a36Sopenharmony_ci */
438362306a36Sopenharmony_cistatic int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
438462306a36Sopenharmony_ci{
438562306a36Sopenharmony_ci	struct hashmap_entry *hash_entry;
438662306a36Sopenharmony_ci	__u32 new_id = type_id, cand_id;
438762306a36Sopenharmony_ci	struct btf_type *t, *cand;
438862306a36Sopenharmony_ci	/* if we don't find equivalent type, then we are representative type */
438962306a36Sopenharmony_ci	int ref_type_id;
439062306a36Sopenharmony_ci	long h;
439162306a36Sopenharmony_ci
439262306a36Sopenharmony_ci	if (d->map[type_id] == BTF_IN_PROGRESS_ID)
439362306a36Sopenharmony_ci		return -ELOOP;
439462306a36Sopenharmony_ci	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
439562306a36Sopenharmony_ci		return resolve_type_id(d, type_id);
439662306a36Sopenharmony_ci
439762306a36Sopenharmony_ci	t = btf_type_by_id(d->btf, type_id);
439862306a36Sopenharmony_ci	d->map[type_id] = BTF_IN_PROGRESS_ID;
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	switch (btf_kind(t)) {
440162306a36Sopenharmony_ci	case BTF_KIND_CONST:
440262306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
440362306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
440462306a36Sopenharmony_ci	case BTF_KIND_PTR:
440562306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
440662306a36Sopenharmony_ci	case BTF_KIND_FUNC:
440762306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
440862306a36Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
440962306a36Sopenharmony_ci		if (ref_type_id < 0)
441062306a36Sopenharmony_ci			return ref_type_id;
441162306a36Sopenharmony_ci		t->type = ref_type_id;
441262306a36Sopenharmony_ci
441362306a36Sopenharmony_ci		h = btf_hash_common(t);
441462306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
441562306a36Sopenharmony_ci			cand_id = hash_entry->value;
441662306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
441762306a36Sopenharmony_ci			if (btf_equal_common(t, cand)) {
441862306a36Sopenharmony_ci				new_id = cand_id;
441962306a36Sopenharmony_ci				break;
442062306a36Sopenharmony_ci			}
442162306a36Sopenharmony_ci		}
442262306a36Sopenharmony_ci		break;
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	case BTF_KIND_DECL_TAG:
442562306a36Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
442662306a36Sopenharmony_ci		if (ref_type_id < 0)
442762306a36Sopenharmony_ci			return ref_type_id;
442862306a36Sopenharmony_ci		t->type = ref_type_id;
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_ci		h = btf_hash_int_decl_tag(t);
443162306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
443262306a36Sopenharmony_ci			cand_id = hash_entry->value;
443362306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
443462306a36Sopenharmony_ci			if (btf_equal_int_tag(t, cand)) {
443562306a36Sopenharmony_ci				new_id = cand_id;
443662306a36Sopenharmony_ci				break;
443762306a36Sopenharmony_ci			}
443862306a36Sopenharmony_ci		}
443962306a36Sopenharmony_ci		break;
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_ci	case BTF_KIND_ARRAY: {
444262306a36Sopenharmony_ci		struct btf_array *info = btf_array(t);
444362306a36Sopenharmony_ci
444462306a36Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, info->type);
444562306a36Sopenharmony_ci		if (ref_type_id < 0)
444662306a36Sopenharmony_ci			return ref_type_id;
444762306a36Sopenharmony_ci		info->type = ref_type_id;
444862306a36Sopenharmony_ci
444962306a36Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, info->index_type);
445062306a36Sopenharmony_ci		if (ref_type_id < 0)
445162306a36Sopenharmony_ci			return ref_type_id;
445262306a36Sopenharmony_ci		info->index_type = ref_type_id;
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci		h = btf_hash_array(t);
445562306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
445662306a36Sopenharmony_ci			cand_id = hash_entry->value;
445762306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
445862306a36Sopenharmony_ci			if (btf_equal_array(t, cand)) {
445962306a36Sopenharmony_ci				new_id = cand_id;
446062306a36Sopenharmony_ci				break;
446162306a36Sopenharmony_ci			}
446262306a36Sopenharmony_ci		}
446362306a36Sopenharmony_ci		break;
446462306a36Sopenharmony_ci	}
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
446762306a36Sopenharmony_ci		struct btf_param *param;
446862306a36Sopenharmony_ci		__u16 vlen;
446962306a36Sopenharmony_ci		int i;
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
447262306a36Sopenharmony_ci		if (ref_type_id < 0)
447362306a36Sopenharmony_ci			return ref_type_id;
447462306a36Sopenharmony_ci		t->type = ref_type_id;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci		vlen = btf_vlen(t);
447762306a36Sopenharmony_ci		param = btf_params(t);
447862306a36Sopenharmony_ci		for (i = 0; i < vlen; i++) {
447962306a36Sopenharmony_ci			ref_type_id = btf_dedup_ref_type(d, param->type);
448062306a36Sopenharmony_ci			if (ref_type_id < 0)
448162306a36Sopenharmony_ci				return ref_type_id;
448262306a36Sopenharmony_ci			param->type = ref_type_id;
448362306a36Sopenharmony_ci			param++;
448462306a36Sopenharmony_ci		}
448562306a36Sopenharmony_ci
448662306a36Sopenharmony_ci		h = btf_hash_fnproto(t);
448762306a36Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
448862306a36Sopenharmony_ci			cand_id = hash_entry->value;
448962306a36Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
449062306a36Sopenharmony_ci			if (btf_equal_fnproto(t, cand)) {
449162306a36Sopenharmony_ci				new_id = cand_id;
449262306a36Sopenharmony_ci				break;
449362306a36Sopenharmony_ci			}
449462306a36Sopenharmony_ci		}
449562306a36Sopenharmony_ci		break;
449662306a36Sopenharmony_ci	}
449762306a36Sopenharmony_ci
449862306a36Sopenharmony_ci	default:
449962306a36Sopenharmony_ci		return -EINVAL;
450062306a36Sopenharmony_ci	}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	d->map[type_id] = new_id;
450362306a36Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
450462306a36Sopenharmony_ci		return -ENOMEM;
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci	return new_id;
450762306a36Sopenharmony_ci}
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_cistatic int btf_dedup_ref_types(struct btf_dedup *d)
451062306a36Sopenharmony_ci{
451162306a36Sopenharmony_ci	int i, err;
451262306a36Sopenharmony_ci
451362306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
451462306a36Sopenharmony_ci		err = btf_dedup_ref_type(d, d->btf->start_id + i);
451562306a36Sopenharmony_ci		if (err < 0)
451662306a36Sopenharmony_ci			return err;
451762306a36Sopenharmony_ci	}
451862306a36Sopenharmony_ci	/* we won't need d->dedup_table anymore */
451962306a36Sopenharmony_ci	hashmap__free(d->dedup_table);
452062306a36Sopenharmony_ci	d->dedup_table = NULL;
452162306a36Sopenharmony_ci	return 0;
452262306a36Sopenharmony_ci}
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_ci/*
452562306a36Sopenharmony_ci * Collect a map from type names to type ids for all canonical structs
452662306a36Sopenharmony_ci * and unions. If the same name is shared by several canonical types
452762306a36Sopenharmony_ci * use a special value 0 to indicate this fact.
452862306a36Sopenharmony_ci */
452962306a36Sopenharmony_cistatic int btf_dedup_fill_unique_names_map(struct btf_dedup *d, struct hashmap *names_map)
453062306a36Sopenharmony_ci{
453162306a36Sopenharmony_ci	__u32 nr_types = btf__type_cnt(d->btf);
453262306a36Sopenharmony_ci	struct btf_type *t;
453362306a36Sopenharmony_ci	__u32 type_id;
453462306a36Sopenharmony_ci	__u16 kind;
453562306a36Sopenharmony_ci	int err;
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_ci	/*
453862306a36Sopenharmony_ci	 * Iterate over base and split module ids in order to get all
453962306a36Sopenharmony_ci	 * available structs in the map.
454062306a36Sopenharmony_ci	 */
454162306a36Sopenharmony_ci	for (type_id = 1; type_id < nr_types; ++type_id) {
454262306a36Sopenharmony_ci		t = btf_type_by_id(d->btf, type_id);
454362306a36Sopenharmony_ci		kind = btf_kind(t);
454462306a36Sopenharmony_ci
454562306a36Sopenharmony_ci		if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
454662306a36Sopenharmony_ci			continue;
454762306a36Sopenharmony_ci
454862306a36Sopenharmony_ci		/* Skip non-canonical types */
454962306a36Sopenharmony_ci		if (type_id != d->map[type_id])
455062306a36Sopenharmony_ci			continue;
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci		err = hashmap__add(names_map, t->name_off, type_id);
455362306a36Sopenharmony_ci		if (err == -EEXIST)
455462306a36Sopenharmony_ci			err = hashmap__set(names_map, t->name_off, 0, NULL, NULL);
455562306a36Sopenharmony_ci
455662306a36Sopenharmony_ci		if (err)
455762306a36Sopenharmony_ci			return err;
455862306a36Sopenharmony_ci	}
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	return 0;
456162306a36Sopenharmony_ci}
456262306a36Sopenharmony_ci
456362306a36Sopenharmony_cistatic int btf_dedup_resolve_fwd(struct btf_dedup *d, struct hashmap *names_map, __u32 type_id)
456462306a36Sopenharmony_ci{
456562306a36Sopenharmony_ci	struct btf_type *t = btf_type_by_id(d->btf, type_id);
456662306a36Sopenharmony_ci	enum btf_fwd_kind fwd_kind = btf_kflag(t);
456762306a36Sopenharmony_ci	__u16 cand_kind, kind = btf_kind(t);
456862306a36Sopenharmony_ci	struct btf_type *cand_t;
456962306a36Sopenharmony_ci	uintptr_t cand_id;
457062306a36Sopenharmony_ci
457162306a36Sopenharmony_ci	if (kind != BTF_KIND_FWD)
457262306a36Sopenharmony_ci		return 0;
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_ci	/* Skip if this FWD already has a mapping */
457562306a36Sopenharmony_ci	if (type_id != d->map[type_id])
457662306a36Sopenharmony_ci		return 0;
457762306a36Sopenharmony_ci
457862306a36Sopenharmony_ci	if (!hashmap__find(names_map, t->name_off, &cand_id))
457962306a36Sopenharmony_ci		return 0;
458062306a36Sopenharmony_ci
458162306a36Sopenharmony_ci	/* Zero is a special value indicating that name is not unique */
458262306a36Sopenharmony_ci	if (!cand_id)
458362306a36Sopenharmony_ci		return 0;
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci	cand_t = btf_type_by_id(d->btf, cand_id);
458662306a36Sopenharmony_ci	cand_kind = btf_kind(cand_t);
458762306a36Sopenharmony_ci	if ((cand_kind == BTF_KIND_STRUCT && fwd_kind != BTF_FWD_STRUCT) ||
458862306a36Sopenharmony_ci	    (cand_kind == BTF_KIND_UNION && fwd_kind != BTF_FWD_UNION))
458962306a36Sopenharmony_ci		return 0;
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci	d->map[type_id] = cand_id;
459262306a36Sopenharmony_ci
459362306a36Sopenharmony_ci	return 0;
459462306a36Sopenharmony_ci}
459562306a36Sopenharmony_ci
459662306a36Sopenharmony_ci/*
459762306a36Sopenharmony_ci * Resolve unambiguous forward declarations.
459862306a36Sopenharmony_ci *
459962306a36Sopenharmony_ci * The lion's share of all FWD declarations is resolved during
460062306a36Sopenharmony_ci * `btf_dedup_struct_types` phase when different type graphs are
460162306a36Sopenharmony_ci * compared against each other. However, if in some compilation unit a
460262306a36Sopenharmony_ci * FWD declaration is not a part of a type graph compared against
460362306a36Sopenharmony_ci * another type graph that declaration's canonical type would not be
460462306a36Sopenharmony_ci * changed. Example:
460562306a36Sopenharmony_ci *
460662306a36Sopenharmony_ci * CU #1:
460762306a36Sopenharmony_ci *
460862306a36Sopenharmony_ci * struct foo;
460962306a36Sopenharmony_ci * struct foo *some_global;
461062306a36Sopenharmony_ci *
461162306a36Sopenharmony_ci * CU #2:
461262306a36Sopenharmony_ci *
461362306a36Sopenharmony_ci * struct foo { int u; };
461462306a36Sopenharmony_ci * struct foo *another_global;
461562306a36Sopenharmony_ci *
461662306a36Sopenharmony_ci * After `btf_dedup_struct_types` the BTF looks as follows:
461762306a36Sopenharmony_ci *
461862306a36Sopenharmony_ci * [1] STRUCT 'foo' size=4 vlen=1 ...
461962306a36Sopenharmony_ci * [2] INT 'int' size=4 ...
462062306a36Sopenharmony_ci * [3] PTR '(anon)' type_id=1
462162306a36Sopenharmony_ci * [4] FWD 'foo' fwd_kind=struct
462262306a36Sopenharmony_ci * [5] PTR '(anon)' type_id=4
462362306a36Sopenharmony_ci *
462462306a36Sopenharmony_ci * This pass assumes that such FWD declarations should be mapped to
462562306a36Sopenharmony_ci * structs or unions with identical name in case if the name is not
462662306a36Sopenharmony_ci * ambiguous.
462762306a36Sopenharmony_ci */
462862306a36Sopenharmony_cistatic int btf_dedup_resolve_fwds(struct btf_dedup *d)
462962306a36Sopenharmony_ci{
463062306a36Sopenharmony_ci	int i, err;
463162306a36Sopenharmony_ci	struct hashmap *names_map;
463262306a36Sopenharmony_ci
463362306a36Sopenharmony_ci	names_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
463462306a36Sopenharmony_ci	if (IS_ERR(names_map))
463562306a36Sopenharmony_ci		return PTR_ERR(names_map);
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci	err = btf_dedup_fill_unique_names_map(d, names_map);
463862306a36Sopenharmony_ci	if (err < 0)
463962306a36Sopenharmony_ci		goto exit;
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
464262306a36Sopenharmony_ci		err = btf_dedup_resolve_fwd(d, names_map, d->btf->start_id + i);
464362306a36Sopenharmony_ci		if (err < 0)
464462306a36Sopenharmony_ci			break;
464562306a36Sopenharmony_ci	}
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ciexit:
464862306a36Sopenharmony_ci	hashmap__free(names_map);
464962306a36Sopenharmony_ci	return err;
465062306a36Sopenharmony_ci}
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci/*
465362306a36Sopenharmony_ci * Compact types.
465462306a36Sopenharmony_ci *
465562306a36Sopenharmony_ci * After we established for each type its corresponding canonical representative
465662306a36Sopenharmony_ci * type, we now can eliminate types that are not canonical and leave only
465762306a36Sopenharmony_ci * canonical ones layed out sequentially in memory by copying them over
465862306a36Sopenharmony_ci * duplicates. During compaction btf_dedup->hypot_map array is reused to store
465962306a36Sopenharmony_ci * a map from original type ID to a new compacted type ID, which will be used
466062306a36Sopenharmony_ci * during next phase to "fix up" type IDs, referenced from struct/union and
466162306a36Sopenharmony_ci * reference types.
466262306a36Sopenharmony_ci */
466362306a36Sopenharmony_cistatic int btf_dedup_compact_types(struct btf_dedup *d)
466462306a36Sopenharmony_ci{
466562306a36Sopenharmony_ci	__u32 *new_offs;
466662306a36Sopenharmony_ci	__u32 next_type_id = d->btf->start_id;
466762306a36Sopenharmony_ci	const struct btf_type *t;
466862306a36Sopenharmony_ci	void *p;
466962306a36Sopenharmony_ci	int i, id, len;
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	/* we are going to reuse hypot_map to store compaction remapping */
467262306a36Sopenharmony_ci	d->hypot_map[0] = 0;
467362306a36Sopenharmony_ci	/* base BTF types are not renumbered */
467462306a36Sopenharmony_ci	for (id = 1; id < d->btf->start_id; id++)
467562306a36Sopenharmony_ci		d->hypot_map[id] = id;
467662306a36Sopenharmony_ci	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++)
467762306a36Sopenharmony_ci		d->hypot_map[id] = BTF_UNPROCESSED_ID;
467862306a36Sopenharmony_ci
467962306a36Sopenharmony_ci	p = d->btf->types_data;
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_ci	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) {
468262306a36Sopenharmony_ci		if (d->map[id] != id)
468362306a36Sopenharmony_ci			continue;
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
468662306a36Sopenharmony_ci		len = btf_type_size(t);
468762306a36Sopenharmony_ci		if (len < 0)
468862306a36Sopenharmony_ci			return len;
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci		memmove(p, t, len);
469162306a36Sopenharmony_ci		d->hypot_map[id] = next_type_id;
469262306a36Sopenharmony_ci		d->btf->type_offs[next_type_id - d->btf->start_id] = p - d->btf->types_data;
469362306a36Sopenharmony_ci		p += len;
469462306a36Sopenharmony_ci		next_type_id++;
469562306a36Sopenharmony_ci	}
469662306a36Sopenharmony_ci
469762306a36Sopenharmony_ci	/* shrink struct btf's internal types index and update btf_header */
469862306a36Sopenharmony_ci	d->btf->nr_types = next_type_id - d->btf->start_id;
469962306a36Sopenharmony_ci	d->btf->type_offs_cap = d->btf->nr_types;
470062306a36Sopenharmony_ci	d->btf->hdr->type_len = p - d->btf->types_data;
470162306a36Sopenharmony_ci	new_offs = libbpf_reallocarray(d->btf->type_offs, d->btf->type_offs_cap,
470262306a36Sopenharmony_ci				       sizeof(*new_offs));
470362306a36Sopenharmony_ci	if (d->btf->type_offs_cap && !new_offs)
470462306a36Sopenharmony_ci		return -ENOMEM;
470562306a36Sopenharmony_ci	d->btf->type_offs = new_offs;
470662306a36Sopenharmony_ci	d->btf->hdr->str_off = d->btf->hdr->type_len;
470762306a36Sopenharmony_ci	d->btf->raw_size = d->btf->hdr->hdr_len + d->btf->hdr->type_len + d->btf->hdr->str_len;
470862306a36Sopenharmony_ci	return 0;
470962306a36Sopenharmony_ci}
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci/*
471262306a36Sopenharmony_ci * Figure out final (deduplicated and compacted) type ID for provided original
471362306a36Sopenharmony_ci * `type_id` by first resolving it into corresponding canonical type ID and
471462306a36Sopenharmony_ci * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map,
471562306a36Sopenharmony_ci * which is populated during compaction phase.
471662306a36Sopenharmony_ci */
471762306a36Sopenharmony_cistatic int btf_dedup_remap_type_id(__u32 *type_id, void *ctx)
471862306a36Sopenharmony_ci{
471962306a36Sopenharmony_ci	struct btf_dedup *d = ctx;
472062306a36Sopenharmony_ci	__u32 resolved_type_id, new_type_id;
472162306a36Sopenharmony_ci
472262306a36Sopenharmony_ci	resolved_type_id = resolve_type_id(d, *type_id);
472362306a36Sopenharmony_ci	new_type_id = d->hypot_map[resolved_type_id];
472462306a36Sopenharmony_ci	if (new_type_id > BTF_MAX_NR_TYPES)
472562306a36Sopenharmony_ci		return -EINVAL;
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_ci	*type_id = new_type_id;
472862306a36Sopenharmony_ci	return 0;
472962306a36Sopenharmony_ci}
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci/*
473262306a36Sopenharmony_ci * Remap referenced type IDs into deduped type IDs.
473362306a36Sopenharmony_ci *
473462306a36Sopenharmony_ci * After BTF types are deduplicated and compacted, their final type IDs may
473562306a36Sopenharmony_ci * differ from original ones. The map from original to a corresponding
473662306a36Sopenharmony_ci * deduped type ID is stored in btf_dedup->hypot_map and is populated during
473762306a36Sopenharmony_ci * compaction phase. During remapping phase we are rewriting all type IDs
473862306a36Sopenharmony_ci * referenced from any BTF type (e.g., struct fields, func proto args, etc) to
473962306a36Sopenharmony_ci * their final deduped type IDs.
474062306a36Sopenharmony_ci */
474162306a36Sopenharmony_cistatic int btf_dedup_remap_types(struct btf_dedup *d)
474262306a36Sopenharmony_ci{
474362306a36Sopenharmony_ci	int i, r;
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
474662306a36Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci		r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d);
474962306a36Sopenharmony_ci		if (r)
475062306a36Sopenharmony_ci			return r;
475162306a36Sopenharmony_ci	}
475262306a36Sopenharmony_ci
475362306a36Sopenharmony_ci	if (!d->btf_ext)
475462306a36Sopenharmony_ci		return 0;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d);
475762306a36Sopenharmony_ci	if (r)
475862306a36Sopenharmony_ci		return r;
475962306a36Sopenharmony_ci
476062306a36Sopenharmony_ci	return 0;
476162306a36Sopenharmony_ci}
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci/*
476462306a36Sopenharmony_ci * Probe few well-known locations for vmlinux kernel image and try to load BTF
476562306a36Sopenharmony_ci * data out of it to use for target BTF.
476662306a36Sopenharmony_ci */
476762306a36Sopenharmony_cistruct btf *btf__load_vmlinux_btf(void)
476862306a36Sopenharmony_ci{
476962306a36Sopenharmony_ci	const char *locations[] = {
477062306a36Sopenharmony_ci		/* try canonical vmlinux BTF through sysfs first */
477162306a36Sopenharmony_ci		"/sys/kernel/btf/vmlinux",
477262306a36Sopenharmony_ci		/* fall back to trying to find vmlinux on disk otherwise */
477362306a36Sopenharmony_ci		"/boot/vmlinux-%1$s",
477462306a36Sopenharmony_ci		"/lib/modules/%1$s/vmlinux-%1$s",
477562306a36Sopenharmony_ci		"/lib/modules/%1$s/build/vmlinux",
477662306a36Sopenharmony_ci		"/usr/lib/modules/%1$s/kernel/vmlinux",
477762306a36Sopenharmony_ci		"/usr/lib/debug/boot/vmlinux-%1$s",
477862306a36Sopenharmony_ci		"/usr/lib/debug/boot/vmlinux-%1$s.debug",
477962306a36Sopenharmony_ci		"/usr/lib/debug/lib/modules/%1$s/vmlinux",
478062306a36Sopenharmony_ci	};
478162306a36Sopenharmony_ci	char path[PATH_MAX + 1];
478262306a36Sopenharmony_ci	struct utsname buf;
478362306a36Sopenharmony_ci	struct btf *btf;
478462306a36Sopenharmony_ci	int i, err;
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci	uname(&buf);
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(locations); i++) {
478962306a36Sopenharmony_ci		snprintf(path, PATH_MAX, locations[i], buf.release);
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci		if (faccessat(AT_FDCWD, path, R_OK, AT_EACCESS))
479262306a36Sopenharmony_ci			continue;
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_ci		btf = btf__parse(path, NULL);
479562306a36Sopenharmony_ci		err = libbpf_get_error(btf);
479662306a36Sopenharmony_ci		pr_debug("loading kernel BTF '%s': %d\n", path, err);
479762306a36Sopenharmony_ci		if (err)
479862306a36Sopenharmony_ci			continue;
479962306a36Sopenharmony_ci
480062306a36Sopenharmony_ci		return btf;
480162306a36Sopenharmony_ci	}
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	pr_warn("failed to find valid kernel BTF\n");
480462306a36Sopenharmony_ci	return libbpf_err_ptr(-ESRCH);
480562306a36Sopenharmony_ci}
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_cistruct btf *libbpf_find_kernel_btf(void) __attribute__((alias("btf__load_vmlinux_btf")));
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_cistruct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf)
481062306a36Sopenharmony_ci{
481162306a36Sopenharmony_ci	char path[80];
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	snprintf(path, sizeof(path), "/sys/kernel/btf/%s", module_name);
481462306a36Sopenharmony_ci	return btf__parse_split(path, vmlinux_btf);
481562306a36Sopenharmony_ci}
481662306a36Sopenharmony_ci
481762306a36Sopenharmony_ciint btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx)
481862306a36Sopenharmony_ci{
481962306a36Sopenharmony_ci	int i, n, err;
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	switch (btf_kind(t)) {
482262306a36Sopenharmony_ci	case BTF_KIND_INT:
482362306a36Sopenharmony_ci	case BTF_KIND_FLOAT:
482462306a36Sopenharmony_ci	case BTF_KIND_ENUM:
482562306a36Sopenharmony_ci	case BTF_KIND_ENUM64:
482662306a36Sopenharmony_ci		return 0;
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_ci	case BTF_KIND_FWD:
482962306a36Sopenharmony_ci	case BTF_KIND_CONST:
483062306a36Sopenharmony_ci	case BTF_KIND_VOLATILE:
483162306a36Sopenharmony_ci	case BTF_KIND_RESTRICT:
483262306a36Sopenharmony_ci	case BTF_KIND_PTR:
483362306a36Sopenharmony_ci	case BTF_KIND_TYPEDEF:
483462306a36Sopenharmony_ci	case BTF_KIND_FUNC:
483562306a36Sopenharmony_ci	case BTF_KIND_VAR:
483662306a36Sopenharmony_ci	case BTF_KIND_DECL_TAG:
483762306a36Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
483862306a36Sopenharmony_ci		return visit(&t->type, ctx);
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci	case BTF_KIND_ARRAY: {
484162306a36Sopenharmony_ci		struct btf_array *a = btf_array(t);
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_ci		err = visit(&a->type, ctx);
484462306a36Sopenharmony_ci		err = err ?: visit(&a->index_type, ctx);
484562306a36Sopenharmony_ci		return err;
484662306a36Sopenharmony_ci	}
484762306a36Sopenharmony_ci
484862306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
484962306a36Sopenharmony_ci	case BTF_KIND_UNION: {
485062306a36Sopenharmony_ci		struct btf_member *m = btf_members(t);
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
485362306a36Sopenharmony_ci			err = visit(&m->type, ctx);
485462306a36Sopenharmony_ci			if (err)
485562306a36Sopenharmony_ci				return err;
485662306a36Sopenharmony_ci		}
485762306a36Sopenharmony_ci		return 0;
485862306a36Sopenharmony_ci	}
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
486162306a36Sopenharmony_ci		struct btf_param *m = btf_params(t);
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_ci		err = visit(&t->type, ctx);
486462306a36Sopenharmony_ci		if (err)
486562306a36Sopenharmony_ci			return err;
486662306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
486762306a36Sopenharmony_ci			err = visit(&m->type, ctx);
486862306a36Sopenharmony_ci			if (err)
486962306a36Sopenharmony_ci				return err;
487062306a36Sopenharmony_ci		}
487162306a36Sopenharmony_ci		return 0;
487262306a36Sopenharmony_ci	}
487362306a36Sopenharmony_ci
487462306a36Sopenharmony_ci	case BTF_KIND_DATASEC: {
487562306a36Sopenharmony_ci		struct btf_var_secinfo *m = btf_var_secinfos(t);
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
487862306a36Sopenharmony_ci			err = visit(&m->type, ctx);
487962306a36Sopenharmony_ci			if (err)
488062306a36Sopenharmony_ci				return err;
488162306a36Sopenharmony_ci		}
488262306a36Sopenharmony_ci		return 0;
488362306a36Sopenharmony_ci	}
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci	default:
488662306a36Sopenharmony_ci		return -EINVAL;
488762306a36Sopenharmony_ci	}
488862306a36Sopenharmony_ci}
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ciint btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx)
489162306a36Sopenharmony_ci{
489262306a36Sopenharmony_ci	int i, n, err;
489362306a36Sopenharmony_ci
489462306a36Sopenharmony_ci	err = visit(&t->name_off, ctx);
489562306a36Sopenharmony_ci	if (err)
489662306a36Sopenharmony_ci		return err;
489762306a36Sopenharmony_ci
489862306a36Sopenharmony_ci	switch (btf_kind(t)) {
489962306a36Sopenharmony_ci	case BTF_KIND_STRUCT:
490062306a36Sopenharmony_ci	case BTF_KIND_UNION: {
490162306a36Sopenharmony_ci		struct btf_member *m = btf_members(t);
490262306a36Sopenharmony_ci
490362306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
490462306a36Sopenharmony_ci			err = visit(&m->name_off, ctx);
490562306a36Sopenharmony_ci			if (err)
490662306a36Sopenharmony_ci				return err;
490762306a36Sopenharmony_ci		}
490862306a36Sopenharmony_ci		break;
490962306a36Sopenharmony_ci	}
491062306a36Sopenharmony_ci	case BTF_KIND_ENUM: {
491162306a36Sopenharmony_ci		struct btf_enum *m = btf_enum(t);
491262306a36Sopenharmony_ci
491362306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
491462306a36Sopenharmony_ci			err = visit(&m->name_off, ctx);
491562306a36Sopenharmony_ci			if (err)
491662306a36Sopenharmony_ci				return err;
491762306a36Sopenharmony_ci		}
491862306a36Sopenharmony_ci		break;
491962306a36Sopenharmony_ci	}
492062306a36Sopenharmony_ci	case BTF_KIND_ENUM64: {
492162306a36Sopenharmony_ci		struct btf_enum64 *m = btf_enum64(t);
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
492462306a36Sopenharmony_ci			err = visit(&m->name_off, ctx);
492562306a36Sopenharmony_ci			if (err)
492662306a36Sopenharmony_ci				return err;
492762306a36Sopenharmony_ci		}
492862306a36Sopenharmony_ci		break;
492962306a36Sopenharmony_ci	}
493062306a36Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
493162306a36Sopenharmony_ci		struct btf_param *m = btf_params(t);
493262306a36Sopenharmony_ci
493362306a36Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
493462306a36Sopenharmony_ci			err = visit(&m->name_off, ctx);
493562306a36Sopenharmony_ci			if (err)
493662306a36Sopenharmony_ci				return err;
493762306a36Sopenharmony_ci		}
493862306a36Sopenharmony_ci		break;
493962306a36Sopenharmony_ci	}
494062306a36Sopenharmony_ci	default:
494162306a36Sopenharmony_ci		break;
494262306a36Sopenharmony_ci	}
494362306a36Sopenharmony_ci
494462306a36Sopenharmony_ci	return 0;
494562306a36Sopenharmony_ci}
494662306a36Sopenharmony_ci
494762306a36Sopenharmony_ciint btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx)
494862306a36Sopenharmony_ci{
494962306a36Sopenharmony_ci	const struct btf_ext_info *seg;
495062306a36Sopenharmony_ci	struct btf_ext_info_sec *sec;
495162306a36Sopenharmony_ci	int i, err;
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_ci	seg = &btf_ext->func_info;
495462306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
495562306a36Sopenharmony_ci		struct bpf_func_info_min *rec;
495662306a36Sopenharmony_ci
495762306a36Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
495862306a36Sopenharmony_ci			err = visit(&rec->type_id, ctx);
495962306a36Sopenharmony_ci			if (err < 0)
496062306a36Sopenharmony_ci				return err;
496162306a36Sopenharmony_ci		}
496262306a36Sopenharmony_ci	}
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci	seg = &btf_ext->core_relo_info;
496562306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
496662306a36Sopenharmony_ci		struct bpf_core_relo *rec;
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
496962306a36Sopenharmony_ci			err = visit(&rec->type_id, ctx);
497062306a36Sopenharmony_ci			if (err < 0)
497162306a36Sopenharmony_ci				return err;
497262306a36Sopenharmony_ci		}
497362306a36Sopenharmony_ci	}
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_ci	return 0;
497662306a36Sopenharmony_ci}
497762306a36Sopenharmony_ci
497862306a36Sopenharmony_ciint btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx)
497962306a36Sopenharmony_ci{
498062306a36Sopenharmony_ci	const struct btf_ext_info *seg;
498162306a36Sopenharmony_ci	struct btf_ext_info_sec *sec;
498262306a36Sopenharmony_ci	int i, err;
498362306a36Sopenharmony_ci
498462306a36Sopenharmony_ci	seg = &btf_ext->func_info;
498562306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
498662306a36Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
498762306a36Sopenharmony_ci		if (err)
498862306a36Sopenharmony_ci			return err;
498962306a36Sopenharmony_ci	}
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_ci	seg = &btf_ext->line_info;
499262306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
499362306a36Sopenharmony_ci		struct bpf_line_info_min *rec;
499462306a36Sopenharmony_ci
499562306a36Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
499662306a36Sopenharmony_ci		if (err)
499762306a36Sopenharmony_ci			return err;
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
500062306a36Sopenharmony_ci			err = visit(&rec->file_name_off, ctx);
500162306a36Sopenharmony_ci			if (err)
500262306a36Sopenharmony_ci				return err;
500362306a36Sopenharmony_ci			err = visit(&rec->line_off, ctx);
500462306a36Sopenharmony_ci			if (err)
500562306a36Sopenharmony_ci				return err;
500662306a36Sopenharmony_ci		}
500762306a36Sopenharmony_ci	}
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci	seg = &btf_ext->core_relo_info;
501062306a36Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
501162306a36Sopenharmony_ci		struct bpf_core_relo *rec;
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
501462306a36Sopenharmony_ci		if (err)
501562306a36Sopenharmony_ci			return err;
501662306a36Sopenharmony_ci
501762306a36Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
501862306a36Sopenharmony_ci			err = visit(&rec->access_str_off, ctx);
501962306a36Sopenharmony_ci			if (err)
502062306a36Sopenharmony_ci				return err;
502162306a36Sopenharmony_ci		}
502262306a36Sopenharmony_ci	}
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci	return 0;
502562306a36Sopenharmony_ci}
5026