17c2aad20Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
27c2aad20Sopenharmony_ci/* Copyright (c) 2018 Facebook */
37c2aad20Sopenharmony_ci
47c2aad20Sopenharmony_ci#include <byteswap.h>
57c2aad20Sopenharmony_ci#include <endian.h>
67c2aad20Sopenharmony_ci#include <stdio.h>
77c2aad20Sopenharmony_ci#include <stdlib.h>
87c2aad20Sopenharmony_ci#include <string.h>
97c2aad20Sopenharmony_ci#include <fcntl.h>
107c2aad20Sopenharmony_ci#include <unistd.h>
117c2aad20Sopenharmony_ci#include <errno.h>
127c2aad20Sopenharmony_ci#include <sys/utsname.h>
137c2aad20Sopenharmony_ci#include <sys/param.h>
147c2aad20Sopenharmony_ci#include <sys/stat.h>
157c2aad20Sopenharmony_ci#include <linux/kernel.h>
167c2aad20Sopenharmony_ci#include <linux/err.h>
177c2aad20Sopenharmony_ci#include <linux/btf.h>
187c2aad20Sopenharmony_ci
197c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
207c2aad20Sopenharmony_ci#include <gelf.h>
217c2aad20Sopenharmony_ci#endif
227c2aad20Sopenharmony_ci
237c2aad20Sopenharmony_ci#include "btf.h"
247c2aad20Sopenharmony_ci#include "bpf.h"
257c2aad20Sopenharmony_ci#include "libbpf.h"
267c2aad20Sopenharmony_ci#include "libbpf_internal.h"
277c2aad20Sopenharmony_ci#include "hashmap.h"
287c2aad20Sopenharmony_ci#include "strset.h"
297c2aad20Sopenharmony_ci
307c2aad20Sopenharmony_ci#define BTF_MAX_NR_TYPES 0x7fffffffU
317c2aad20Sopenharmony_ci#define BTF_MAX_STR_OFFSET 0x7fffffffU
327c2aad20Sopenharmony_ci
337c2aad20Sopenharmony_cistatic struct btf_type btf_void;
347c2aad20Sopenharmony_ci
357c2aad20Sopenharmony_cistruct btf {
367c2aad20Sopenharmony_ci	/* raw BTF data in native endianness */
377c2aad20Sopenharmony_ci	void *raw_data;
387c2aad20Sopenharmony_ci	/* raw BTF data in non-native endianness */
397c2aad20Sopenharmony_ci	void *raw_data_swapped;
407c2aad20Sopenharmony_ci	__u32 raw_size;
417c2aad20Sopenharmony_ci	/* whether target endianness differs from the native one */
427c2aad20Sopenharmony_ci	bool swapped_endian;
437c2aad20Sopenharmony_ci
447c2aad20Sopenharmony_ci	/*
457c2aad20Sopenharmony_ci	 * When BTF is loaded from an ELF or raw memory it is stored
467c2aad20Sopenharmony_ci	 * in a contiguous memory block. The hdr, type_data, and, strs_data
477c2aad20Sopenharmony_ci	 * point inside that memory region to their respective parts of BTF
487c2aad20Sopenharmony_ci	 * representation:
497c2aad20Sopenharmony_ci	 *
507c2aad20Sopenharmony_ci	 * +--------------------------------+
517c2aad20Sopenharmony_ci	 * |  Header  |  Types  |  Strings  |
527c2aad20Sopenharmony_ci	 * +--------------------------------+
537c2aad20Sopenharmony_ci	 * ^          ^         ^
547c2aad20Sopenharmony_ci	 * |          |         |
557c2aad20Sopenharmony_ci	 * hdr        |         |
567c2aad20Sopenharmony_ci	 * types_data-+         |
577c2aad20Sopenharmony_ci	 * strs_data------------+
587c2aad20Sopenharmony_ci	 *
597c2aad20Sopenharmony_ci	 * If BTF data is later modified, e.g., due to types added or
607c2aad20Sopenharmony_ci	 * removed, BTF deduplication performed, etc, this contiguous
617c2aad20Sopenharmony_ci	 * representation is broken up into three independently allocated
627c2aad20Sopenharmony_ci	 * memory regions to be able to modify them independently.
637c2aad20Sopenharmony_ci	 * raw_data is nulled out at that point, but can be later allocated
647c2aad20Sopenharmony_ci	 * and cached again if user calls btf__raw_data(), at which point
657c2aad20Sopenharmony_ci	 * raw_data will contain a contiguous copy of header, types, and
667c2aad20Sopenharmony_ci	 * strings:
677c2aad20Sopenharmony_ci	 *
687c2aad20Sopenharmony_ci	 * +----------+  +---------+  +-----------+
697c2aad20Sopenharmony_ci	 * |  Header  |  |  Types  |  |  Strings  |
707c2aad20Sopenharmony_ci	 * +----------+  +---------+  +-----------+
717c2aad20Sopenharmony_ci	 * ^             ^            ^
727c2aad20Sopenharmony_ci	 * |             |            |
737c2aad20Sopenharmony_ci	 * hdr           |            |
747c2aad20Sopenharmony_ci	 * types_data----+            |
757c2aad20Sopenharmony_ci	 * strset__data(strs_set)-----+
767c2aad20Sopenharmony_ci	 *
777c2aad20Sopenharmony_ci	 *               +----------+---------+-----------+
787c2aad20Sopenharmony_ci	 *               |  Header  |  Types  |  Strings  |
797c2aad20Sopenharmony_ci	 * raw_data----->+----------+---------+-----------+
807c2aad20Sopenharmony_ci	 */
817c2aad20Sopenharmony_ci	struct btf_header *hdr;
827c2aad20Sopenharmony_ci
837c2aad20Sopenharmony_ci	void *types_data;
847c2aad20Sopenharmony_ci	size_t types_data_cap; /* used size stored in hdr->type_len */
857c2aad20Sopenharmony_ci
867c2aad20Sopenharmony_ci	/* type ID to `struct btf_type *` lookup index
877c2aad20Sopenharmony_ci	 * type_offs[0] corresponds to the first non-VOID type:
887c2aad20Sopenharmony_ci	 *   - for base BTF it's type [1];
897c2aad20Sopenharmony_ci	 *   - for split BTF it's the first non-base BTF type.
907c2aad20Sopenharmony_ci	 */
917c2aad20Sopenharmony_ci	__u32 *type_offs;
927c2aad20Sopenharmony_ci	size_t type_offs_cap;
937c2aad20Sopenharmony_ci	/* number of types in this BTF instance:
947c2aad20Sopenharmony_ci	 *   - doesn't include special [0] void type;
957c2aad20Sopenharmony_ci	 *   - for split BTF counts number of types added on top of base BTF.
967c2aad20Sopenharmony_ci	 */
977c2aad20Sopenharmony_ci	__u32 nr_types;
987c2aad20Sopenharmony_ci	/* if not NULL, points to the base BTF on top of which the current
997c2aad20Sopenharmony_ci	 * split BTF is based
1007c2aad20Sopenharmony_ci	 */
1017c2aad20Sopenharmony_ci	struct btf *base_btf;
1027c2aad20Sopenharmony_ci	/* BTF type ID of the first type in this BTF instance:
1037c2aad20Sopenharmony_ci	 *   - for base BTF it's equal to 1;
1047c2aad20Sopenharmony_ci	 *   - for split BTF it's equal to biggest type ID of base BTF plus 1.
1057c2aad20Sopenharmony_ci	 */
1067c2aad20Sopenharmony_ci	int start_id;
1077c2aad20Sopenharmony_ci	/* logical string offset of this BTF instance:
1087c2aad20Sopenharmony_ci	 *   - for base BTF it's equal to 0;
1097c2aad20Sopenharmony_ci	 *   - for split BTF it's equal to total size of base BTF's string section size.
1107c2aad20Sopenharmony_ci	 */
1117c2aad20Sopenharmony_ci	int start_str_off;
1127c2aad20Sopenharmony_ci
1137c2aad20Sopenharmony_ci	/* only one of strs_data or strs_set can be non-NULL, depending on
1147c2aad20Sopenharmony_ci	 * whether BTF is in a modifiable state (strs_set is used) or not
1157c2aad20Sopenharmony_ci	 * (strs_data points inside raw_data)
1167c2aad20Sopenharmony_ci	 */
1177c2aad20Sopenharmony_ci	void *strs_data;
1187c2aad20Sopenharmony_ci	/* a set of unique strings */
1197c2aad20Sopenharmony_ci	struct strset *strs_set;
1207c2aad20Sopenharmony_ci	/* whether strings are already deduplicated */
1217c2aad20Sopenharmony_ci	bool strs_deduped;
1227c2aad20Sopenharmony_ci
1237c2aad20Sopenharmony_ci	/* BTF object FD, if loaded into kernel */
1247c2aad20Sopenharmony_ci	int fd;
1257c2aad20Sopenharmony_ci
1267c2aad20Sopenharmony_ci	/* Pointer size (in bytes) for a target architecture of this BTF */
1277c2aad20Sopenharmony_ci	int ptr_sz;
1287c2aad20Sopenharmony_ci};
1297c2aad20Sopenharmony_ci
1307c2aad20Sopenharmony_cistatic inline __u64 ptr_to_u64(const void *ptr)
1317c2aad20Sopenharmony_ci{
1327c2aad20Sopenharmony_ci	return (__u64) (unsigned long) ptr;
1337c2aad20Sopenharmony_ci}
1347c2aad20Sopenharmony_ci
1357c2aad20Sopenharmony_ci/* Ensure given dynamically allocated memory region pointed to by *data* with
1367c2aad20Sopenharmony_ci * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough
1377c2aad20Sopenharmony_ci * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements
1387c2aad20Sopenharmony_ci * are already used. At most *max_cnt* elements can be ever allocated.
1397c2aad20Sopenharmony_ci * If necessary, memory is reallocated and all existing data is copied over,
1407c2aad20Sopenharmony_ci * new pointer to the memory region is stored at *data, new memory region
1417c2aad20Sopenharmony_ci * capacity (in number of elements) is stored in *cap.
1427c2aad20Sopenharmony_ci * On success, memory pointer to the beginning of unused memory is returned.
1437c2aad20Sopenharmony_ci * On error, NULL is returned.
1447c2aad20Sopenharmony_ci */
1457c2aad20Sopenharmony_civoid *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
1467c2aad20Sopenharmony_ci		     size_t cur_cnt, size_t max_cnt, size_t add_cnt)
1477c2aad20Sopenharmony_ci{
1487c2aad20Sopenharmony_ci	size_t new_cnt;
1497c2aad20Sopenharmony_ci	void *new_data;
1507c2aad20Sopenharmony_ci
1517c2aad20Sopenharmony_ci	if (cur_cnt + add_cnt <= *cap_cnt)
1527c2aad20Sopenharmony_ci		return *data + cur_cnt * elem_sz;
1537c2aad20Sopenharmony_ci
1547c2aad20Sopenharmony_ci	/* requested more than the set limit */
1557c2aad20Sopenharmony_ci	if (cur_cnt + add_cnt > max_cnt)
1567c2aad20Sopenharmony_ci		return NULL;
1577c2aad20Sopenharmony_ci
1587c2aad20Sopenharmony_ci	new_cnt = *cap_cnt;
1597c2aad20Sopenharmony_ci	new_cnt += new_cnt / 4;		  /* expand by 25% */
1607c2aad20Sopenharmony_ci	if (new_cnt < 16)		  /* but at least 16 elements */
1617c2aad20Sopenharmony_ci		new_cnt = 16;
1627c2aad20Sopenharmony_ci	if (new_cnt > max_cnt)		  /* but not exceeding a set limit */
1637c2aad20Sopenharmony_ci		new_cnt = max_cnt;
1647c2aad20Sopenharmony_ci	if (new_cnt < cur_cnt + add_cnt)  /* also ensure we have enough memory */
1657c2aad20Sopenharmony_ci		new_cnt = cur_cnt + add_cnt;
1667c2aad20Sopenharmony_ci
1677c2aad20Sopenharmony_ci	new_data = libbpf_reallocarray(*data, new_cnt, elem_sz);
1687c2aad20Sopenharmony_ci	if (!new_data)
1697c2aad20Sopenharmony_ci		return NULL;
1707c2aad20Sopenharmony_ci
1717c2aad20Sopenharmony_ci	/* zero out newly allocated portion of memory */
1727c2aad20Sopenharmony_ci	memset(new_data + (*cap_cnt) * elem_sz, 0, (new_cnt - *cap_cnt) * elem_sz);
1737c2aad20Sopenharmony_ci
1747c2aad20Sopenharmony_ci	*data = new_data;
1757c2aad20Sopenharmony_ci	*cap_cnt = new_cnt;
1767c2aad20Sopenharmony_ci	return new_data + cur_cnt * elem_sz;
1777c2aad20Sopenharmony_ci}
1787c2aad20Sopenharmony_ci
1797c2aad20Sopenharmony_ci/* Ensure given dynamically allocated memory region has enough allocated space
1807c2aad20Sopenharmony_ci * to accommodate *need_cnt* elements of size *elem_sz* bytes each
1817c2aad20Sopenharmony_ci */
1827c2aad20Sopenharmony_ciint libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt)
1837c2aad20Sopenharmony_ci{
1847c2aad20Sopenharmony_ci	void *p;
1857c2aad20Sopenharmony_ci
1867c2aad20Sopenharmony_ci	if (need_cnt <= *cap_cnt)
1877c2aad20Sopenharmony_ci		return 0;
1887c2aad20Sopenharmony_ci
1897c2aad20Sopenharmony_ci	p = libbpf_add_mem(data, cap_cnt, elem_sz, *cap_cnt, SIZE_MAX, need_cnt - *cap_cnt);
1907c2aad20Sopenharmony_ci	if (!p)
1917c2aad20Sopenharmony_ci		return -ENOMEM;
1927c2aad20Sopenharmony_ci
1937c2aad20Sopenharmony_ci	return 0;
1947c2aad20Sopenharmony_ci}
1957c2aad20Sopenharmony_ci
1967c2aad20Sopenharmony_cistatic void *btf_add_type_offs_mem(struct btf *btf, size_t add_cnt)
1977c2aad20Sopenharmony_ci{
1987c2aad20Sopenharmony_ci	return libbpf_add_mem((void **)&btf->type_offs, &btf->type_offs_cap, sizeof(__u32),
1997c2aad20Sopenharmony_ci			      btf->nr_types, BTF_MAX_NR_TYPES, add_cnt);
2007c2aad20Sopenharmony_ci}
2017c2aad20Sopenharmony_ci
2027c2aad20Sopenharmony_cistatic int btf_add_type_idx_entry(struct btf *btf, __u32 type_off)
2037c2aad20Sopenharmony_ci{
2047c2aad20Sopenharmony_ci	__u32 *p;
2057c2aad20Sopenharmony_ci
2067c2aad20Sopenharmony_ci	p = btf_add_type_offs_mem(btf, 1);
2077c2aad20Sopenharmony_ci	if (!p)
2087c2aad20Sopenharmony_ci		return -ENOMEM;
2097c2aad20Sopenharmony_ci
2107c2aad20Sopenharmony_ci	*p = type_off;
2117c2aad20Sopenharmony_ci	return 0;
2127c2aad20Sopenharmony_ci}
2137c2aad20Sopenharmony_ci
2147c2aad20Sopenharmony_cistatic void btf_bswap_hdr(struct btf_header *h)
2157c2aad20Sopenharmony_ci{
2167c2aad20Sopenharmony_ci	h->magic = bswap_16(h->magic);
2177c2aad20Sopenharmony_ci	h->hdr_len = bswap_32(h->hdr_len);
2187c2aad20Sopenharmony_ci	h->type_off = bswap_32(h->type_off);
2197c2aad20Sopenharmony_ci	h->type_len = bswap_32(h->type_len);
2207c2aad20Sopenharmony_ci	h->str_off = bswap_32(h->str_off);
2217c2aad20Sopenharmony_ci	h->str_len = bswap_32(h->str_len);
2227c2aad20Sopenharmony_ci}
2237c2aad20Sopenharmony_ci
2247c2aad20Sopenharmony_cistatic int btf_parse_hdr(struct btf *btf)
2257c2aad20Sopenharmony_ci{
2267c2aad20Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
2277c2aad20Sopenharmony_ci	__u32 meta_left;
2287c2aad20Sopenharmony_ci
2297c2aad20Sopenharmony_ci	if (btf->raw_size < sizeof(struct btf_header)) {
2307c2aad20Sopenharmony_ci		pr_debug("BTF header not found\n");
2317c2aad20Sopenharmony_ci		return -EINVAL;
2327c2aad20Sopenharmony_ci	}
2337c2aad20Sopenharmony_ci
2347c2aad20Sopenharmony_ci	if (hdr->magic == bswap_16(BTF_MAGIC)) {
2357c2aad20Sopenharmony_ci		btf->swapped_endian = true;
2367c2aad20Sopenharmony_ci		if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) {
2377c2aad20Sopenharmony_ci			pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n",
2387c2aad20Sopenharmony_ci				bswap_32(hdr->hdr_len));
2397c2aad20Sopenharmony_ci			return -ENOTSUP;
2407c2aad20Sopenharmony_ci		}
2417c2aad20Sopenharmony_ci		btf_bswap_hdr(hdr);
2427c2aad20Sopenharmony_ci	} else if (hdr->magic != BTF_MAGIC) {
2437c2aad20Sopenharmony_ci		pr_debug("Invalid BTF magic: %x\n", hdr->magic);
2447c2aad20Sopenharmony_ci		return -EINVAL;
2457c2aad20Sopenharmony_ci	}
2467c2aad20Sopenharmony_ci
2477c2aad20Sopenharmony_ci	if (btf->raw_size < hdr->hdr_len) {
2487c2aad20Sopenharmony_ci		pr_debug("BTF header len %u larger than data size %u\n",
2497c2aad20Sopenharmony_ci			 hdr->hdr_len, btf->raw_size);
2507c2aad20Sopenharmony_ci		return -EINVAL;
2517c2aad20Sopenharmony_ci	}
2527c2aad20Sopenharmony_ci
2537c2aad20Sopenharmony_ci	meta_left = btf->raw_size - hdr->hdr_len;
2547c2aad20Sopenharmony_ci	if (meta_left < (long long)hdr->str_off + hdr->str_len) {
2557c2aad20Sopenharmony_ci		pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
2567c2aad20Sopenharmony_ci		return -EINVAL;
2577c2aad20Sopenharmony_ci	}
2587c2aad20Sopenharmony_ci
2597c2aad20Sopenharmony_ci	if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
2607c2aad20Sopenharmony_ci		pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
2617c2aad20Sopenharmony_ci			 hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
2627c2aad20Sopenharmony_ci		return -EINVAL;
2637c2aad20Sopenharmony_ci	}
2647c2aad20Sopenharmony_ci
2657c2aad20Sopenharmony_ci	if (hdr->type_off % 4) {
2667c2aad20Sopenharmony_ci		pr_debug("BTF type section is not aligned to 4 bytes\n");
2677c2aad20Sopenharmony_ci		return -EINVAL;
2687c2aad20Sopenharmony_ci	}
2697c2aad20Sopenharmony_ci
2707c2aad20Sopenharmony_ci	return 0;
2717c2aad20Sopenharmony_ci}
2727c2aad20Sopenharmony_ci
2737c2aad20Sopenharmony_cistatic int btf_parse_str_sec(struct btf *btf)
2747c2aad20Sopenharmony_ci{
2757c2aad20Sopenharmony_ci	const struct btf_header *hdr = btf->hdr;
2767c2aad20Sopenharmony_ci	const char *start = btf->strs_data;
2777c2aad20Sopenharmony_ci	const char *end = start + btf->hdr->str_len;
2787c2aad20Sopenharmony_ci
2797c2aad20Sopenharmony_ci	if (btf->base_btf && hdr->str_len == 0)
2807c2aad20Sopenharmony_ci		return 0;
2817c2aad20Sopenharmony_ci	if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_STR_OFFSET || end[-1]) {
2827c2aad20Sopenharmony_ci		pr_debug("Invalid BTF string section\n");
2837c2aad20Sopenharmony_ci		return -EINVAL;
2847c2aad20Sopenharmony_ci	}
2857c2aad20Sopenharmony_ci	if (!btf->base_btf && start[0]) {
2867c2aad20Sopenharmony_ci		pr_debug("Invalid BTF string section\n");
2877c2aad20Sopenharmony_ci		return -EINVAL;
2887c2aad20Sopenharmony_ci	}
2897c2aad20Sopenharmony_ci	return 0;
2907c2aad20Sopenharmony_ci}
2917c2aad20Sopenharmony_ci
2927c2aad20Sopenharmony_cistatic int btf_type_size(const struct btf_type *t)
2937c2aad20Sopenharmony_ci{
2947c2aad20Sopenharmony_ci	const int base_size = sizeof(struct btf_type);
2957c2aad20Sopenharmony_ci	__u16 vlen = btf_vlen(t);
2967c2aad20Sopenharmony_ci
2977c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
2987c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
2997c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
3007c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
3017c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
3027c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
3037c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
3047c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
3057c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
3067c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
3077c2aad20Sopenharmony_ci		return base_size;
3087c2aad20Sopenharmony_ci	case BTF_KIND_INT:
3097c2aad20Sopenharmony_ci		return base_size + sizeof(__u32);
3107c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
3117c2aad20Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_enum);
3127c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
3137c2aad20Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_enum64);
3147c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
3157c2aad20Sopenharmony_ci		return base_size + sizeof(struct btf_array);
3167c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
3177c2aad20Sopenharmony_ci	case BTF_KIND_UNION:
3187c2aad20Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_member);
3197c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
3207c2aad20Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_param);
3217c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
3227c2aad20Sopenharmony_ci		return base_size + sizeof(struct btf_var);
3237c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC:
3247c2aad20Sopenharmony_ci		return base_size + vlen * sizeof(struct btf_var_secinfo);
3257c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
3267c2aad20Sopenharmony_ci		return base_size + sizeof(struct btf_decl_tag);
3277c2aad20Sopenharmony_ci	default:
3287c2aad20Sopenharmony_ci		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
3297c2aad20Sopenharmony_ci		return -EINVAL;
3307c2aad20Sopenharmony_ci	}
3317c2aad20Sopenharmony_ci}
3327c2aad20Sopenharmony_ci
3337c2aad20Sopenharmony_cistatic void btf_bswap_type_base(struct btf_type *t)
3347c2aad20Sopenharmony_ci{
3357c2aad20Sopenharmony_ci	t->name_off = bswap_32(t->name_off);
3367c2aad20Sopenharmony_ci	t->info = bswap_32(t->info);
3377c2aad20Sopenharmony_ci	t->type = bswap_32(t->type);
3387c2aad20Sopenharmony_ci}
3397c2aad20Sopenharmony_ci
3407c2aad20Sopenharmony_cistatic int btf_bswap_type_rest(struct btf_type *t)
3417c2aad20Sopenharmony_ci{
3427c2aad20Sopenharmony_ci	struct btf_var_secinfo *v;
3437c2aad20Sopenharmony_ci	struct btf_enum64 *e64;
3447c2aad20Sopenharmony_ci	struct btf_member *m;
3457c2aad20Sopenharmony_ci	struct btf_array *a;
3467c2aad20Sopenharmony_ci	struct btf_param *p;
3477c2aad20Sopenharmony_ci	struct btf_enum *e;
3487c2aad20Sopenharmony_ci	__u16 vlen = btf_vlen(t);
3497c2aad20Sopenharmony_ci	int i;
3507c2aad20Sopenharmony_ci
3517c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
3527c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
3537c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
3547c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
3557c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
3567c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
3577c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
3587c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
3597c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
3607c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
3617c2aad20Sopenharmony_ci		return 0;
3627c2aad20Sopenharmony_ci	case BTF_KIND_INT:
3637c2aad20Sopenharmony_ci		*(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1));
3647c2aad20Sopenharmony_ci		return 0;
3657c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
3667c2aad20Sopenharmony_ci		for (i = 0, e = btf_enum(t); i < vlen; i++, e++) {
3677c2aad20Sopenharmony_ci			e->name_off = bswap_32(e->name_off);
3687c2aad20Sopenharmony_ci			e->val = bswap_32(e->val);
3697c2aad20Sopenharmony_ci		}
3707c2aad20Sopenharmony_ci		return 0;
3717c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
3727c2aad20Sopenharmony_ci		for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) {
3737c2aad20Sopenharmony_ci			e64->name_off = bswap_32(e64->name_off);
3747c2aad20Sopenharmony_ci			e64->val_lo32 = bswap_32(e64->val_lo32);
3757c2aad20Sopenharmony_ci			e64->val_hi32 = bswap_32(e64->val_hi32);
3767c2aad20Sopenharmony_ci		}
3777c2aad20Sopenharmony_ci		return 0;
3787c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
3797c2aad20Sopenharmony_ci		a = btf_array(t);
3807c2aad20Sopenharmony_ci		a->type = bswap_32(a->type);
3817c2aad20Sopenharmony_ci		a->index_type = bswap_32(a->index_type);
3827c2aad20Sopenharmony_ci		a->nelems = bswap_32(a->nelems);
3837c2aad20Sopenharmony_ci		return 0;
3847c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
3857c2aad20Sopenharmony_ci	case BTF_KIND_UNION:
3867c2aad20Sopenharmony_ci		for (i = 0, m = btf_members(t); i < vlen; i++, m++) {
3877c2aad20Sopenharmony_ci			m->name_off = bswap_32(m->name_off);
3887c2aad20Sopenharmony_ci			m->type = bswap_32(m->type);
3897c2aad20Sopenharmony_ci			m->offset = bswap_32(m->offset);
3907c2aad20Sopenharmony_ci		}
3917c2aad20Sopenharmony_ci		return 0;
3927c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
3937c2aad20Sopenharmony_ci		for (i = 0, p = btf_params(t); i < vlen; i++, p++) {
3947c2aad20Sopenharmony_ci			p->name_off = bswap_32(p->name_off);
3957c2aad20Sopenharmony_ci			p->type = bswap_32(p->type);
3967c2aad20Sopenharmony_ci		}
3977c2aad20Sopenharmony_ci		return 0;
3987c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
3997c2aad20Sopenharmony_ci		btf_var(t)->linkage = bswap_32(btf_var(t)->linkage);
4007c2aad20Sopenharmony_ci		return 0;
4017c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC:
4027c2aad20Sopenharmony_ci		for (i = 0, v = btf_var_secinfos(t); i < vlen; i++, v++) {
4037c2aad20Sopenharmony_ci			v->type = bswap_32(v->type);
4047c2aad20Sopenharmony_ci			v->offset = bswap_32(v->offset);
4057c2aad20Sopenharmony_ci			v->size = bswap_32(v->size);
4067c2aad20Sopenharmony_ci		}
4077c2aad20Sopenharmony_ci		return 0;
4087c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
4097c2aad20Sopenharmony_ci		btf_decl_tag(t)->component_idx = bswap_32(btf_decl_tag(t)->component_idx);
4107c2aad20Sopenharmony_ci		return 0;
4117c2aad20Sopenharmony_ci	default:
4127c2aad20Sopenharmony_ci		pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
4137c2aad20Sopenharmony_ci		return -EINVAL;
4147c2aad20Sopenharmony_ci	}
4157c2aad20Sopenharmony_ci}
4167c2aad20Sopenharmony_ci
4177c2aad20Sopenharmony_cistatic int btf_parse_type_sec(struct btf *btf)
4187c2aad20Sopenharmony_ci{
4197c2aad20Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
4207c2aad20Sopenharmony_ci	void *next_type = btf->types_data;
4217c2aad20Sopenharmony_ci	void *end_type = next_type + hdr->type_len;
4227c2aad20Sopenharmony_ci	int err, type_size;
4237c2aad20Sopenharmony_ci
4247c2aad20Sopenharmony_ci	while (next_type + sizeof(struct btf_type) <= end_type) {
4257c2aad20Sopenharmony_ci		if (btf->swapped_endian)
4267c2aad20Sopenharmony_ci			btf_bswap_type_base(next_type);
4277c2aad20Sopenharmony_ci
4287c2aad20Sopenharmony_ci		type_size = btf_type_size(next_type);
4297c2aad20Sopenharmony_ci		if (type_size < 0)
4307c2aad20Sopenharmony_ci			return type_size;
4317c2aad20Sopenharmony_ci		if (next_type + type_size > end_type) {
4327c2aad20Sopenharmony_ci			pr_warn("BTF type [%d] is malformed\n", btf->start_id + btf->nr_types);
4337c2aad20Sopenharmony_ci			return -EINVAL;
4347c2aad20Sopenharmony_ci		}
4357c2aad20Sopenharmony_ci
4367c2aad20Sopenharmony_ci		if (btf->swapped_endian && btf_bswap_type_rest(next_type))
4377c2aad20Sopenharmony_ci			return -EINVAL;
4387c2aad20Sopenharmony_ci
4397c2aad20Sopenharmony_ci		err = btf_add_type_idx_entry(btf, next_type - btf->types_data);
4407c2aad20Sopenharmony_ci		if (err)
4417c2aad20Sopenharmony_ci			return err;
4427c2aad20Sopenharmony_ci
4437c2aad20Sopenharmony_ci		next_type += type_size;
4447c2aad20Sopenharmony_ci		btf->nr_types++;
4457c2aad20Sopenharmony_ci	}
4467c2aad20Sopenharmony_ci
4477c2aad20Sopenharmony_ci	if (next_type != end_type) {
4487c2aad20Sopenharmony_ci		pr_warn("BTF types data is malformed\n");
4497c2aad20Sopenharmony_ci		return -EINVAL;
4507c2aad20Sopenharmony_ci	}
4517c2aad20Sopenharmony_ci
4527c2aad20Sopenharmony_ci	return 0;
4537c2aad20Sopenharmony_ci}
4547c2aad20Sopenharmony_ci
4557c2aad20Sopenharmony_cistatic int btf_validate_str(const struct btf *btf, __u32 str_off, const char *what, __u32 type_id)
4567c2aad20Sopenharmony_ci{
4577c2aad20Sopenharmony_ci	const char *s;
4587c2aad20Sopenharmony_ci
4597c2aad20Sopenharmony_ci	s = btf__str_by_offset(btf, str_off);
4607c2aad20Sopenharmony_ci	if (!s) {
4617c2aad20Sopenharmony_ci		pr_warn("btf: type [%u]: invalid %s (string offset %u)\n", type_id, what, str_off);
4627c2aad20Sopenharmony_ci		return -EINVAL;
4637c2aad20Sopenharmony_ci	}
4647c2aad20Sopenharmony_ci
4657c2aad20Sopenharmony_ci	return 0;
4667c2aad20Sopenharmony_ci}
4677c2aad20Sopenharmony_ci
4687c2aad20Sopenharmony_cistatic int btf_validate_id(const struct btf *btf, __u32 id, __u32 ctx_id)
4697c2aad20Sopenharmony_ci{
4707c2aad20Sopenharmony_ci	const struct btf_type *t;
4717c2aad20Sopenharmony_ci
4727c2aad20Sopenharmony_ci	t = btf__type_by_id(btf, id);
4737c2aad20Sopenharmony_ci	if (!t) {
4747c2aad20Sopenharmony_ci		pr_warn("btf: type [%u]: invalid referenced type ID %u\n", ctx_id, id);
4757c2aad20Sopenharmony_ci		return -EINVAL;
4767c2aad20Sopenharmony_ci	}
4777c2aad20Sopenharmony_ci
4787c2aad20Sopenharmony_ci	return 0;
4797c2aad20Sopenharmony_ci}
4807c2aad20Sopenharmony_ci
4817c2aad20Sopenharmony_cistatic int btf_validate_type(const struct btf *btf, const struct btf_type *t, __u32 id)
4827c2aad20Sopenharmony_ci{
4837c2aad20Sopenharmony_ci	__u32 kind = btf_kind(t);
4847c2aad20Sopenharmony_ci	int err, i, n;
4857c2aad20Sopenharmony_ci
4867c2aad20Sopenharmony_ci	err = btf_validate_str(btf, t->name_off, "type name", id);
4877c2aad20Sopenharmony_ci	if (err)
4887c2aad20Sopenharmony_ci		return err;
4897c2aad20Sopenharmony_ci
4907c2aad20Sopenharmony_ci	switch (kind) {
4917c2aad20Sopenharmony_ci	case BTF_KIND_UNKN:
4927c2aad20Sopenharmony_ci	case BTF_KIND_INT:
4937c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
4947c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
4957c2aad20Sopenharmony_ci		break;
4967c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
4977c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
4987c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
4997c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
5007c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
5017c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
5027c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
5037c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
5047c2aad20Sopenharmony_ci		err = btf_validate_id(btf, t->type, id);
5057c2aad20Sopenharmony_ci		if (err)
5067c2aad20Sopenharmony_ci			return err;
5077c2aad20Sopenharmony_ci		break;
5087c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY: {
5097c2aad20Sopenharmony_ci		const struct btf_array *a = btf_array(t);
5107c2aad20Sopenharmony_ci
5117c2aad20Sopenharmony_ci		err = btf_validate_id(btf, a->type, id);
5127c2aad20Sopenharmony_ci		err = err ?: btf_validate_id(btf, a->index_type, id);
5137c2aad20Sopenharmony_ci		if (err)
5147c2aad20Sopenharmony_ci			return err;
5157c2aad20Sopenharmony_ci		break;
5167c2aad20Sopenharmony_ci	}
5177c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
5187c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
5197c2aad20Sopenharmony_ci		const struct btf_member *m = btf_members(t);
5207c2aad20Sopenharmony_ci
5217c2aad20Sopenharmony_ci		n = btf_vlen(t);
5227c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
5237c2aad20Sopenharmony_ci			err = btf_validate_str(btf, m->name_off, "field name", id);
5247c2aad20Sopenharmony_ci			err = err ?: btf_validate_id(btf, m->type, id);
5257c2aad20Sopenharmony_ci			if (err)
5267c2aad20Sopenharmony_ci				return err;
5277c2aad20Sopenharmony_ci		}
5287c2aad20Sopenharmony_ci		break;
5297c2aad20Sopenharmony_ci	}
5307c2aad20Sopenharmony_ci	case BTF_KIND_ENUM: {
5317c2aad20Sopenharmony_ci		const struct btf_enum *m = btf_enum(t);
5327c2aad20Sopenharmony_ci
5337c2aad20Sopenharmony_ci		n = btf_vlen(t);
5347c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
5357c2aad20Sopenharmony_ci			err = btf_validate_str(btf, m->name_off, "enum name", id);
5367c2aad20Sopenharmony_ci			if (err)
5377c2aad20Sopenharmony_ci				return err;
5387c2aad20Sopenharmony_ci		}
5397c2aad20Sopenharmony_ci		break;
5407c2aad20Sopenharmony_ci	}
5417c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64: {
5427c2aad20Sopenharmony_ci		const struct btf_enum64 *m = btf_enum64(t);
5437c2aad20Sopenharmony_ci
5447c2aad20Sopenharmony_ci		n = btf_vlen(t);
5457c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
5467c2aad20Sopenharmony_ci			err = btf_validate_str(btf, m->name_off, "enum name", id);
5477c2aad20Sopenharmony_ci			if (err)
5487c2aad20Sopenharmony_ci				return err;
5497c2aad20Sopenharmony_ci		}
5507c2aad20Sopenharmony_ci		break;
5517c2aad20Sopenharmony_ci	}
5527c2aad20Sopenharmony_ci	case BTF_KIND_FUNC: {
5537c2aad20Sopenharmony_ci		const struct btf_type *ft;
5547c2aad20Sopenharmony_ci
5557c2aad20Sopenharmony_ci		err = btf_validate_id(btf, t->type, id);
5567c2aad20Sopenharmony_ci		if (err)
5577c2aad20Sopenharmony_ci			return err;
5587c2aad20Sopenharmony_ci		ft = btf__type_by_id(btf, t->type);
5597c2aad20Sopenharmony_ci		if (btf_kind(ft) != BTF_KIND_FUNC_PROTO) {
5607c2aad20Sopenharmony_ci			pr_warn("btf: type [%u]: referenced type [%u] is not FUNC_PROTO\n", id, t->type);
5617c2aad20Sopenharmony_ci			return -EINVAL;
5627c2aad20Sopenharmony_ci		}
5637c2aad20Sopenharmony_ci		break;
5647c2aad20Sopenharmony_ci	}
5657c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
5667c2aad20Sopenharmony_ci		const struct btf_param *m = btf_params(t);
5677c2aad20Sopenharmony_ci
5687c2aad20Sopenharmony_ci		n = btf_vlen(t);
5697c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
5707c2aad20Sopenharmony_ci			err = btf_validate_str(btf, m->name_off, "param name", id);
5717c2aad20Sopenharmony_ci			err = err ?: btf_validate_id(btf, m->type, id);
5727c2aad20Sopenharmony_ci			if (err)
5737c2aad20Sopenharmony_ci				return err;
5747c2aad20Sopenharmony_ci		}
5757c2aad20Sopenharmony_ci		break;
5767c2aad20Sopenharmony_ci	}
5777c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC: {
5787c2aad20Sopenharmony_ci		const struct btf_var_secinfo *m = btf_var_secinfos(t);
5797c2aad20Sopenharmony_ci
5807c2aad20Sopenharmony_ci		n = btf_vlen(t);
5817c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
5827c2aad20Sopenharmony_ci			err = btf_validate_id(btf, m->type, id);
5837c2aad20Sopenharmony_ci			if (err)
5847c2aad20Sopenharmony_ci				return err;
5857c2aad20Sopenharmony_ci		}
5867c2aad20Sopenharmony_ci		break;
5877c2aad20Sopenharmony_ci	}
5887c2aad20Sopenharmony_ci	default:
5897c2aad20Sopenharmony_ci		pr_warn("btf: type [%u]: unrecognized kind %u\n", id, kind);
5907c2aad20Sopenharmony_ci		return -EINVAL;
5917c2aad20Sopenharmony_ci	}
5927c2aad20Sopenharmony_ci	return 0;
5937c2aad20Sopenharmony_ci}
5947c2aad20Sopenharmony_ci
5957c2aad20Sopenharmony_ci/* Validate basic sanity of BTF. It's intentionally less thorough than
5967c2aad20Sopenharmony_ci * kernel's validation and validates only properties of BTF that libbpf relies
5977c2aad20Sopenharmony_ci * on to be correct (e.g., valid type IDs, valid string offsets, etc)
5987c2aad20Sopenharmony_ci */
5997c2aad20Sopenharmony_cistatic int btf_sanity_check(const struct btf *btf)
6007c2aad20Sopenharmony_ci{
6017c2aad20Sopenharmony_ci	const struct btf_type *t;
6027c2aad20Sopenharmony_ci	__u32 i, n = btf__type_cnt(btf);
6037c2aad20Sopenharmony_ci	int err;
6047c2aad20Sopenharmony_ci
6057c2aad20Sopenharmony_ci	for (i = 1; i < n; i++) {
6067c2aad20Sopenharmony_ci		t = btf_type_by_id(btf, i);
6077c2aad20Sopenharmony_ci		err = btf_validate_type(btf, t, i);
6087c2aad20Sopenharmony_ci		if (err)
6097c2aad20Sopenharmony_ci			return err;
6107c2aad20Sopenharmony_ci	}
6117c2aad20Sopenharmony_ci	return 0;
6127c2aad20Sopenharmony_ci}
6137c2aad20Sopenharmony_ci
6147c2aad20Sopenharmony_ci__u32 btf__type_cnt(const struct btf *btf)
6157c2aad20Sopenharmony_ci{
6167c2aad20Sopenharmony_ci	return btf->start_id + btf->nr_types;
6177c2aad20Sopenharmony_ci}
6187c2aad20Sopenharmony_ci
6197c2aad20Sopenharmony_ciconst struct btf *btf__base_btf(const struct btf *btf)
6207c2aad20Sopenharmony_ci{
6217c2aad20Sopenharmony_ci	return btf->base_btf;
6227c2aad20Sopenharmony_ci}
6237c2aad20Sopenharmony_ci
6247c2aad20Sopenharmony_ci/* internal helper returning non-const pointer to a type */
6257c2aad20Sopenharmony_cistruct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id)
6267c2aad20Sopenharmony_ci{
6277c2aad20Sopenharmony_ci	if (type_id == 0)
6287c2aad20Sopenharmony_ci		return &btf_void;
6297c2aad20Sopenharmony_ci	if (type_id < btf->start_id)
6307c2aad20Sopenharmony_ci		return btf_type_by_id(btf->base_btf, type_id);
6317c2aad20Sopenharmony_ci	return btf->types_data + btf->type_offs[type_id - btf->start_id];
6327c2aad20Sopenharmony_ci}
6337c2aad20Sopenharmony_ci
6347c2aad20Sopenharmony_ciconst struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
6357c2aad20Sopenharmony_ci{
6367c2aad20Sopenharmony_ci	if (type_id >= btf->start_id + btf->nr_types)
6377c2aad20Sopenharmony_ci		return errno = EINVAL, NULL;
6387c2aad20Sopenharmony_ci	return btf_type_by_id((struct btf *)btf, type_id);
6397c2aad20Sopenharmony_ci}
6407c2aad20Sopenharmony_ci
6417c2aad20Sopenharmony_cistatic int determine_ptr_size(const struct btf *btf)
6427c2aad20Sopenharmony_ci{
6437c2aad20Sopenharmony_ci	static const char * const long_aliases[] = {
6447c2aad20Sopenharmony_ci		"long",
6457c2aad20Sopenharmony_ci		"long int",
6467c2aad20Sopenharmony_ci		"int long",
6477c2aad20Sopenharmony_ci		"unsigned long",
6487c2aad20Sopenharmony_ci		"long unsigned",
6497c2aad20Sopenharmony_ci		"unsigned long int",
6507c2aad20Sopenharmony_ci		"unsigned int long",
6517c2aad20Sopenharmony_ci		"long unsigned int",
6527c2aad20Sopenharmony_ci		"long int unsigned",
6537c2aad20Sopenharmony_ci		"int unsigned long",
6547c2aad20Sopenharmony_ci		"int long unsigned",
6557c2aad20Sopenharmony_ci	};
6567c2aad20Sopenharmony_ci	const struct btf_type *t;
6577c2aad20Sopenharmony_ci	const char *name;
6587c2aad20Sopenharmony_ci	int i, j, n;
6597c2aad20Sopenharmony_ci
6607c2aad20Sopenharmony_ci	if (btf->base_btf && btf->base_btf->ptr_sz > 0)
6617c2aad20Sopenharmony_ci		return btf->base_btf->ptr_sz;
6627c2aad20Sopenharmony_ci
6637c2aad20Sopenharmony_ci	n = btf__type_cnt(btf);
6647c2aad20Sopenharmony_ci	for (i = 1; i < n; i++) {
6657c2aad20Sopenharmony_ci		t = btf__type_by_id(btf, i);
6667c2aad20Sopenharmony_ci		if (!btf_is_int(t))
6677c2aad20Sopenharmony_ci			continue;
6687c2aad20Sopenharmony_ci
6697c2aad20Sopenharmony_ci		if (t->size != 4 && t->size != 8)
6707c2aad20Sopenharmony_ci			continue;
6717c2aad20Sopenharmony_ci
6727c2aad20Sopenharmony_ci		name = btf__name_by_offset(btf, t->name_off);
6737c2aad20Sopenharmony_ci		if (!name)
6747c2aad20Sopenharmony_ci			continue;
6757c2aad20Sopenharmony_ci
6767c2aad20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(long_aliases); j++) {
6777c2aad20Sopenharmony_ci			if (strcmp(name, long_aliases[j]) == 0)
6787c2aad20Sopenharmony_ci				return t->size;
6797c2aad20Sopenharmony_ci		}
6807c2aad20Sopenharmony_ci	}
6817c2aad20Sopenharmony_ci
6827c2aad20Sopenharmony_ci	return -1;
6837c2aad20Sopenharmony_ci}
6847c2aad20Sopenharmony_ci
6857c2aad20Sopenharmony_cistatic size_t btf_ptr_sz(const struct btf *btf)
6867c2aad20Sopenharmony_ci{
6877c2aad20Sopenharmony_ci	if (!btf->ptr_sz)
6887c2aad20Sopenharmony_ci		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
6897c2aad20Sopenharmony_ci	return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz;
6907c2aad20Sopenharmony_ci}
6917c2aad20Sopenharmony_ci
6927c2aad20Sopenharmony_ci/* Return pointer size this BTF instance assumes. The size is heuristically
6937c2aad20Sopenharmony_ci * determined by looking for 'long' or 'unsigned long' integer type and
6947c2aad20Sopenharmony_ci * recording its size in bytes. If BTF type information doesn't have any such
6957c2aad20Sopenharmony_ci * type, this function returns 0. In the latter case, native architecture's
6967c2aad20Sopenharmony_ci * pointer size is assumed, so will be either 4 or 8, depending on
6977c2aad20Sopenharmony_ci * architecture that libbpf was compiled for. It's possible to override
6987c2aad20Sopenharmony_ci * guessed value by using btf__set_pointer_size() API.
6997c2aad20Sopenharmony_ci */
7007c2aad20Sopenharmony_cisize_t btf__pointer_size(const struct btf *btf)
7017c2aad20Sopenharmony_ci{
7027c2aad20Sopenharmony_ci	if (!btf->ptr_sz)
7037c2aad20Sopenharmony_ci		((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
7047c2aad20Sopenharmony_ci
7057c2aad20Sopenharmony_ci	if (btf->ptr_sz < 0)
7067c2aad20Sopenharmony_ci		/* not enough BTF type info to guess */
7077c2aad20Sopenharmony_ci		return 0;
7087c2aad20Sopenharmony_ci
7097c2aad20Sopenharmony_ci	return btf->ptr_sz;
7107c2aad20Sopenharmony_ci}
7117c2aad20Sopenharmony_ci
7127c2aad20Sopenharmony_ci/* Override or set pointer size in bytes. Only values of 4 and 8 are
7137c2aad20Sopenharmony_ci * supported.
7147c2aad20Sopenharmony_ci */
7157c2aad20Sopenharmony_ciint btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
7167c2aad20Sopenharmony_ci{
7177c2aad20Sopenharmony_ci	if (ptr_sz != 4 && ptr_sz != 8)
7187c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
7197c2aad20Sopenharmony_ci	btf->ptr_sz = ptr_sz;
7207c2aad20Sopenharmony_ci	return 0;
7217c2aad20Sopenharmony_ci}
7227c2aad20Sopenharmony_ci
7237c2aad20Sopenharmony_cistatic bool is_host_big_endian(void)
7247c2aad20Sopenharmony_ci{
7257c2aad20Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
7267c2aad20Sopenharmony_ci	return false;
7277c2aad20Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
7287c2aad20Sopenharmony_ci	return true;
7297c2aad20Sopenharmony_ci#else
7307c2aad20Sopenharmony_ci# error "Unrecognized __BYTE_ORDER__"
7317c2aad20Sopenharmony_ci#endif
7327c2aad20Sopenharmony_ci}
7337c2aad20Sopenharmony_ci
7347c2aad20Sopenharmony_cienum btf_endianness btf__endianness(const struct btf *btf)
7357c2aad20Sopenharmony_ci{
7367c2aad20Sopenharmony_ci	if (is_host_big_endian())
7377c2aad20Sopenharmony_ci		return btf->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN;
7387c2aad20Sopenharmony_ci	else
7397c2aad20Sopenharmony_ci		return btf->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
7407c2aad20Sopenharmony_ci}
7417c2aad20Sopenharmony_ci
7427c2aad20Sopenharmony_ciint btf__set_endianness(struct btf *btf, enum btf_endianness endian)
7437c2aad20Sopenharmony_ci{
7447c2aad20Sopenharmony_ci	if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN)
7457c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
7467c2aad20Sopenharmony_ci
7477c2aad20Sopenharmony_ci	btf->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN);
7487c2aad20Sopenharmony_ci	if (!btf->swapped_endian) {
7497c2aad20Sopenharmony_ci		free(btf->raw_data_swapped);
7507c2aad20Sopenharmony_ci		btf->raw_data_swapped = NULL;
7517c2aad20Sopenharmony_ci	}
7527c2aad20Sopenharmony_ci	return 0;
7537c2aad20Sopenharmony_ci}
7547c2aad20Sopenharmony_ci
7557c2aad20Sopenharmony_cistatic bool btf_type_is_void(const struct btf_type *t)
7567c2aad20Sopenharmony_ci{
7577c2aad20Sopenharmony_ci	return t == &btf_void || btf_is_fwd(t);
7587c2aad20Sopenharmony_ci}
7597c2aad20Sopenharmony_ci
7607c2aad20Sopenharmony_cistatic bool btf_type_is_void_or_null(const struct btf_type *t)
7617c2aad20Sopenharmony_ci{
7627c2aad20Sopenharmony_ci	return !t || btf_type_is_void(t);
7637c2aad20Sopenharmony_ci}
7647c2aad20Sopenharmony_ci
7657c2aad20Sopenharmony_ci#define MAX_RESOLVE_DEPTH 32
7667c2aad20Sopenharmony_ci
7677c2aad20Sopenharmony_ci__s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
7687c2aad20Sopenharmony_ci{
7697c2aad20Sopenharmony_ci	const struct btf_array *array;
7707c2aad20Sopenharmony_ci	const struct btf_type *t;
7717c2aad20Sopenharmony_ci	__u32 nelems = 1;
7727c2aad20Sopenharmony_ci	__s64 size = -1;
7737c2aad20Sopenharmony_ci	int i;
7747c2aad20Sopenharmony_ci
7757c2aad20Sopenharmony_ci	t = btf__type_by_id(btf, type_id);
7767c2aad20Sopenharmony_ci	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); i++) {
7777c2aad20Sopenharmony_ci		switch (btf_kind(t)) {
7787c2aad20Sopenharmony_ci		case BTF_KIND_INT:
7797c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
7807c2aad20Sopenharmony_ci		case BTF_KIND_UNION:
7817c2aad20Sopenharmony_ci		case BTF_KIND_ENUM:
7827c2aad20Sopenharmony_ci		case BTF_KIND_ENUM64:
7837c2aad20Sopenharmony_ci		case BTF_KIND_DATASEC:
7847c2aad20Sopenharmony_ci		case BTF_KIND_FLOAT:
7857c2aad20Sopenharmony_ci			size = t->size;
7867c2aad20Sopenharmony_ci			goto done;
7877c2aad20Sopenharmony_ci		case BTF_KIND_PTR:
7887c2aad20Sopenharmony_ci			size = btf_ptr_sz(btf);
7897c2aad20Sopenharmony_ci			goto done;
7907c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
7917c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
7927c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
7937c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
7947c2aad20Sopenharmony_ci		case BTF_KIND_VAR:
7957c2aad20Sopenharmony_ci		case BTF_KIND_DECL_TAG:
7967c2aad20Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
7977c2aad20Sopenharmony_ci			type_id = t->type;
7987c2aad20Sopenharmony_ci			break;
7997c2aad20Sopenharmony_ci		case BTF_KIND_ARRAY:
8007c2aad20Sopenharmony_ci			array = btf_array(t);
8017c2aad20Sopenharmony_ci			if (nelems && array->nelems > UINT32_MAX / nelems)
8027c2aad20Sopenharmony_ci				return libbpf_err(-E2BIG);
8037c2aad20Sopenharmony_ci			nelems *= array->nelems;
8047c2aad20Sopenharmony_ci			type_id = array->type;
8057c2aad20Sopenharmony_ci			break;
8067c2aad20Sopenharmony_ci		default:
8077c2aad20Sopenharmony_ci			return libbpf_err(-EINVAL);
8087c2aad20Sopenharmony_ci		}
8097c2aad20Sopenharmony_ci
8107c2aad20Sopenharmony_ci		t = btf__type_by_id(btf, type_id);
8117c2aad20Sopenharmony_ci	}
8127c2aad20Sopenharmony_ci
8137c2aad20Sopenharmony_cidone:
8147c2aad20Sopenharmony_ci	if (size < 0)
8157c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
8167c2aad20Sopenharmony_ci	if (nelems && size > UINT32_MAX / nelems)
8177c2aad20Sopenharmony_ci		return libbpf_err(-E2BIG);
8187c2aad20Sopenharmony_ci
8197c2aad20Sopenharmony_ci	return nelems * size;
8207c2aad20Sopenharmony_ci}
8217c2aad20Sopenharmony_ci
8227c2aad20Sopenharmony_ciint btf__align_of(const struct btf *btf, __u32 id)
8237c2aad20Sopenharmony_ci{
8247c2aad20Sopenharmony_ci	const struct btf_type *t = btf__type_by_id(btf, id);
8257c2aad20Sopenharmony_ci	__u16 kind = btf_kind(t);
8267c2aad20Sopenharmony_ci
8277c2aad20Sopenharmony_ci	switch (kind) {
8287c2aad20Sopenharmony_ci	case BTF_KIND_INT:
8297c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
8307c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
8317c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
8327c2aad20Sopenharmony_ci		return min(btf_ptr_sz(btf), (size_t)t->size);
8337c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
8347c2aad20Sopenharmony_ci		return btf_ptr_sz(btf);
8357c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
8367c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
8377c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
8387c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
8397c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
8407c2aad20Sopenharmony_ci		return btf__align_of(btf, t->type);
8417c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
8427c2aad20Sopenharmony_ci		return btf__align_of(btf, btf_array(t)->type);
8437c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
8447c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
8457c2aad20Sopenharmony_ci		const struct btf_member *m = btf_members(t);
8467c2aad20Sopenharmony_ci		__u16 vlen = btf_vlen(t);
8477c2aad20Sopenharmony_ci		int i, max_align = 1, align;
8487c2aad20Sopenharmony_ci
8497c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++, m++) {
8507c2aad20Sopenharmony_ci			align = btf__align_of(btf, m->type);
8517c2aad20Sopenharmony_ci			if (align <= 0)
8527c2aad20Sopenharmony_ci				return libbpf_err(align);
8537c2aad20Sopenharmony_ci			max_align = max(max_align, align);
8547c2aad20Sopenharmony_ci
8557c2aad20Sopenharmony_ci			/* if field offset isn't aligned according to field
8567c2aad20Sopenharmony_ci			 * type's alignment, then struct must be packed
8577c2aad20Sopenharmony_ci			 */
8587c2aad20Sopenharmony_ci			if (btf_member_bitfield_size(t, i) == 0 &&
8597c2aad20Sopenharmony_ci			    (m->offset % (8 * align)) != 0)
8607c2aad20Sopenharmony_ci				return 1;
8617c2aad20Sopenharmony_ci		}
8627c2aad20Sopenharmony_ci
8637c2aad20Sopenharmony_ci		/* if struct/union size isn't a multiple of its alignment,
8647c2aad20Sopenharmony_ci		 * then struct must be packed
8657c2aad20Sopenharmony_ci		 */
8667c2aad20Sopenharmony_ci		if ((t->size % max_align) != 0)
8677c2aad20Sopenharmony_ci			return 1;
8687c2aad20Sopenharmony_ci
8697c2aad20Sopenharmony_ci		return max_align;
8707c2aad20Sopenharmony_ci	}
8717c2aad20Sopenharmony_ci	default:
8727c2aad20Sopenharmony_ci		pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t));
8737c2aad20Sopenharmony_ci		return errno = EINVAL, 0;
8747c2aad20Sopenharmony_ci	}
8757c2aad20Sopenharmony_ci}
8767c2aad20Sopenharmony_ci
8777c2aad20Sopenharmony_ciint btf__resolve_type(const struct btf *btf, __u32 type_id)
8787c2aad20Sopenharmony_ci{
8797c2aad20Sopenharmony_ci	const struct btf_type *t;
8807c2aad20Sopenharmony_ci	int depth = 0;
8817c2aad20Sopenharmony_ci
8827c2aad20Sopenharmony_ci	t = btf__type_by_id(btf, type_id);
8837c2aad20Sopenharmony_ci	while (depth < MAX_RESOLVE_DEPTH &&
8847c2aad20Sopenharmony_ci	       !btf_type_is_void_or_null(t) &&
8857c2aad20Sopenharmony_ci	       (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
8867c2aad20Sopenharmony_ci		type_id = t->type;
8877c2aad20Sopenharmony_ci		t = btf__type_by_id(btf, type_id);
8887c2aad20Sopenharmony_ci		depth++;
8897c2aad20Sopenharmony_ci	}
8907c2aad20Sopenharmony_ci
8917c2aad20Sopenharmony_ci	if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
8927c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
8937c2aad20Sopenharmony_ci
8947c2aad20Sopenharmony_ci	return type_id;
8957c2aad20Sopenharmony_ci}
8967c2aad20Sopenharmony_ci
8977c2aad20Sopenharmony_ci__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
8987c2aad20Sopenharmony_ci{
8997c2aad20Sopenharmony_ci	__u32 i, nr_types = btf__type_cnt(btf);
9007c2aad20Sopenharmony_ci
9017c2aad20Sopenharmony_ci	if (!strcmp(type_name, "void"))
9027c2aad20Sopenharmony_ci		return 0;
9037c2aad20Sopenharmony_ci
9047c2aad20Sopenharmony_ci	for (i = 1; i < nr_types; i++) {
9057c2aad20Sopenharmony_ci		const struct btf_type *t = btf__type_by_id(btf, i);
9067c2aad20Sopenharmony_ci		const char *name = btf__name_by_offset(btf, t->name_off);
9077c2aad20Sopenharmony_ci
9087c2aad20Sopenharmony_ci		if (name && !strcmp(type_name, name))
9097c2aad20Sopenharmony_ci			return i;
9107c2aad20Sopenharmony_ci	}
9117c2aad20Sopenharmony_ci
9127c2aad20Sopenharmony_ci	return libbpf_err(-ENOENT);
9137c2aad20Sopenharmony_ci}
9147c2aad20Sopenharmony_ci
9157c2aad20Sopenharmony_cistatic __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
9167c2aad20Sopenharmony_ci				   const char *type_name, __u32 kind)
9177c2aad20Sopenharmony_ci{
9187c2aad20Sopenharmony_ci	__u32 i, nr_types = btf__type_cnt(btf);
9197c2aad20Sopenharmony_ci
9207c2aad20Sopenharmony_ci	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
9217c2aad20Sopenharmony_ci		return 0;
9227c2aad20Sopenharmony_ci
9237c2aad20Sopenharmony_ci	for (i = start_id; i < nr_types; i++) {
9247c2aad20Sopenharmony_ci		const struct btf_type *t = btf__type_by_id(btf, i);
9257c2aad20Sopenharmony_ci		const char *name;
9267c2aad20Sopenharmony_ci
9277c2aad20Sopenharmony_ci		if (btf_kind(t) != kind)
9287c2aad20Sopenharmony_ci			continue;
9297c2aad20Sopenharmony_ci		name = btf__name_by_offset(btf, t->name_off);
9307c2aad20Sopenharmony_ci		if (name && !strcmp(type_name, name))
9317c2aad20Sopenharmony_ci			return i;
9327c2aad20Sopenharmony_ci	}
9337c2aad20Sopenharmony_ci
9347c2aad20Sopenharmony_ci	return libbpf_err(-ENOENT);
9357c2aad20Sopenharmony_ci}
9367c2aad20Sopenharmony_ci
9377c2aad20Sopenharmony_ci__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
9387c2aad20Sopenharmony_ci				 __u32 kind)
9397c2aad20Sopenharmony_ci{
9407c2aad20Sopenharmony_ci	return btf_find_by_name_kind(btf, btf->start_id, type_name, kind);
9417c2aad20Sopenharmony_ci}
9427c2aad20Sopenharmony_ci
9437c2aad20Sopenharmony_ci__s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
9447c2aad20Sopenharmony_ci			     __u32 kind)
9457c2aad20Sopenharmony_ci{
9467c2aad20Sopenharmony_ci	return btf_find_by_name_kind(btf, 1, type_name, kind);
9477c2aad20Sopenharmony_ci}
9487c2aad20Sopenharmony_ci
9497c2aad20Sopenharmony_cistatic bool btf_is_modifiable(const struct btf *btf)
9507c2aad20Sopenharmony_ci{
9517c2aad20Sopenharmony_ci	return (void *)btf->hdr != btf->raw_data;
9527c2aad20Sopenharmony_ci}
9537c2aad20Sopenharmony_ci
9547c2aad20Sopenharmony_civoid btf__free(struct btf *btf)
9557c2aad20Sopenharmony_ci{
9567c2aad20Sopenharmony_ci	if (IS_ERR_OR_NULL(btf))
9577c2aad20Sopenharmony_ci		return;
9587c2aad20Sopenharmony_ci
9597c2aad20Sopenharmony_ci	if (btf->fd >= 0)
9607c2aad20Sopenharmony_ci		close(btf->fd);
9617c2aad20Sopenharmony_ci
9627c2aad20Sopenharmony_ci	if (btf_is_modifiable(btf)) {
9637c2aad20Sopenharmony_ci		/* if BTF was modified after loading, it will have a split
9647c2aad20Sopenharmony_ci		 * in-memory representation for header, types, and strings
9657c2aad20Sopenharmony_ci		 * sections, so we need to free all of them individually. It
9667c2aad20Sopenharmony_ci		 * might still have a cached contiguous raw data present,
9677c2aad20Sopenharmony_ci		 * which will be unconditionally freed below.
9687c2aad20Sopenharmony_ci		 */
9697c2aad20Sopenharmony_ci		free(btf->hdr);
9707c2aad20Sopenharmony_ci		free(btf->types_data);
9717c2aad20Sopenharmony_ci		strset__free(btf->strs_set);
9727c2aad20Sopenharmony_ci	}
9737c2aad20Sopenharmony_ci	free(btf->raw_data);
9747c2aad20Sopenharmony_ci	free(btf->raw_data_swapped);
9757c2aad20Sopenharmony_ci	free(btf->type_offs);
9767c2aad20Sopenharmony_ci	free(btf);
9777c2aad20Sopenharmony_ci}
9787c2aad20Sopenharmony_ci
9797c2aad20Sopenharmony_cistatic struct btf *btf_new_empty(struct btf *base_btf)
9807c2aad20Sopenharmony_ci{
9817c2aad20Sopenharmony_ci	struct btf *btf;
9827c2aad20Sopenharmony_ci
9837c2aad20Sopenharmony_ci	btf = calloc(1, sizeof(*btf));
9847c2aad20Sopenharmony_ci	if (!btf)
9857c2aad20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
9867c2aad20Sopenharmony_ci
9877c2aad20Sopenharmony_ci	btf->nr_types = 0;
9887c2aad20Sopenharmony_ci	btf->start_id = 1;
9897c2aad20Sopenharmony_ci	btf->start_str_off = 0;
9907c2aad20Sopenharmony_ci	btf->fd = -1;
9917c2aad20Sopenharmony_ci	btf->ptr_sz = sizeof(void *);
9927c2aad20Sopenharmony_ci	btf->swapped_endian = false;
9937c2aad20Sopenharmony_ci
9947c2aad20Sopenharmony_ci	if (base_btf) {
9957c2aad20Sopenharmony_ci		btf->base_btf = base_btf;
9967c2aad20Sopenharmony_ci		btf->start_id = btf__type_cnt(base_btf);
9977c2aad20Sopenharmony_ci		btf->start_str_off = base_btf->hdr->str_len;
9987c2aad20Sopenharmony_ci	}
9997c2aad20Sopenharmony_ci
10007c2aad20Sopenharmony_ci	/* +1 for empty string at offset 0 */
10017c2aad20Sopenharmony_ci	btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1);
10027c2aad20Sopenharmony_ci	btf->raw_data = calloc(1, btf->raw_size);
10037c2aad20Sopenharmony_ci	if (!btf->raw_data) {
10047c2aad20Sopenharmony_ci		free(btf);
10057c2aad20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10067c2aad20Sopenharmony_ci	}
10077c2aad20Sopenharmony_ci
10087c2aad20Sopenharmony_ci	btf->hdr = btf->raw_data;
10097c2aad20Sopenharmony_ci	btf->hdr->hdr_len = sizeof(struct btf_header);
10107c2aad20Sopenharmony_ci	btf->hdr->magic = BTF_MAGIC;
10117c2aad20Sopenharmony_ci	btf->hdr->version = BTF_VERSION;
10127c2aad20Sopenharmony_ci
10137c2aad20Sopenharmony_ci	btf->types_data = btf->raw_data + btf->hdr->hdr_len;
10147c2aad20Sopenharmony_ci	btf->strs_data = btf->raw_data + btf->hdr->hdr_len;
10157c2aad20Sopenharmony_ci	btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
10167c2aad20Sopenharmony_ci
10177c2aad20Sopenharmony_ci	return btf;
10187c2aad20Sopenharmony_ci}
10197c2aad20Sopenharmony_ci
10207c2aad20Sopenharmony_cistruct btf *btf__new_empty(void)
10217c2aad20Sopenharmony_ci{
10227c2aad20Sopenharmony_ci	return libbpf_ptr(btf_new_empty(NULL));
10237c2aad20Sopenharmony_ci}
10247c2aad20Sopenharmony_ci
10257c2aad20Sopenharmony_cistruct btf *btf__new_empty_split(struct btf *base_btf)
10267c2aad20Sopenharmony_ci{
10277c2aad20Sopenharmony_ci	return libbpf_ptr(btf_new_empty(base_btf));
10287c2aad20Sopenharmony_ci}
10297c2aad20Sopenharmony_ci
10307c2aad20Sopenharmony_cistatic struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
10317c2aad20Sopenharmony_ci{
10327c2aad20Sopenharmony_ci	struct btf *btf;
10337c2aad20Sopenharmony_ci	int err;
10347c2aad20Sopenharmony_ci
10357c2aad20Sopenharmony_ci	btf = calloc(1, sizeof(struct btf));
10367c2aad20Sopenharmony_ci	if (!btf)
10377c2aad20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10387c2aad20Sopenharmony_ci
10397c2aad20Sopenharmony_ci	btf->nr_types = 0;
10407c2aad20Sopenharmony_ci	btf->start_id = 1;
10417c2aad20Sopenharmony_ci	btf->start_str_off = 0;
10427c2aad20Sopenharmony_ci	btf->fd = -1;
10437c2aad20Sopenharmony_ci
10447c2aad20Sopenharmony_ci	if (base_btf) {
10457c2aad20Sopenharmony_ci		btf->base_btf = base_btf;
10467c2aad20Sopenharmony_ci		btf->start_id = btf__type_cnt(base_btf);
10477c2aad20Sopenharmony_ci		btf->start_str_off = base_btf->hdr->str_len;
10487c2aad20Sopenharmony_ci	}
10497c2aad20Sopenharmony_ci
10507c2aad20Sopenharmony_ci	btf->raw_data = malloc(size);
10517c2aad20Sopenharmony_ci	if (!btf->raw_data) {
10527c2aad20Sopenharmony_ci		err = -ENOMEM;
10537c2aad20Sopenharmony_ci		goto done;
10547c2aad20Sopenharmony_ci	}
10557c2aad20Sopenharmony_ci	memcpy(btf->raw_data, data, size);
10567c2aad20Sopenharmony_ci	btf->raw_size = size;
10577c2aad20Sopenharmony_ci
10587c2aad20Sopenharmony_ci	btf->hdr = btf->raw_data;
10597c2aad20Sopenharmony_ci	err = btf_parse_hdr(btf);
10607c2aad20Sopenharmony_ci	if (err)
10617c2aad20Sopenharmony_ci		goto done;
10627c2aad20Sopenharmony_ci
10637c2aad20Sopenharmony_ci	btf->strs_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->str_off;
10647c2aad20Sopenharmony_ci	btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off;
10657c2aad20Sopenharmony_ci
10667c2aad20Sopenharmony_ci	err = btf_parse_str_sec(btf);
10677c2aad20Sopenharmony_ci	err = err ?: btf_parse_type_sec(btf);
10687c2aad20Sopenharmony_ci	err = err ?: btf_sanity_check(btf);
10697c2aad20Sopenharmony_ci	if (err)
10707c2aad20Sopenharmony_ci		goto done;
10717c2aad20Sopenharmony_ci
10727c2aad20Sopenharmony_cidone:
10737c2aad20Sopenharmony_ci	if (err) {
10747c2aad20Sopenharmony_ci		btf__free(btf);
10757c2aad20Sopenharmony_ci		return ERR_PTR(err);
10767c2aad20Sopenharmony_ci	}
10777c2aad20Sopenharmony_ci
10787c2aad20Sopenharmony_ci	return btf;
10797c2aad20Sopenharmony_ci}
10807c2aad20Sopenharmony_ci
10817c2aad20Sopenharmony_cistruct btf *btf__new(const void *data, __u32 size)
10827c2aad20Sopenharmony_ci{
10837c2aad20Sopenharmony_ci	return libbpf_ptr(btf_new(data, size, NULL));
10847c2aad20Sopenharmony_ci}
10857c2aad20Sopenharmony_ci
10867c2aad20Sopenharmony_ci#ifdef HAVE_ELFIO
10877c2aad20Sopenharmony_cistatic Elf64_Shdr *elf_sec_hdr_by_idx(pelfio_t elf, size_t idx, Elf64_Shdr *sheader)
10887c2aad20Sopenharmony_ci{
10897c2aad20Sopenharmony_ci	psection_t psection = elfio_get_section_by_index(elf, idx);
10907c2aad20Sopenharmony_ci
10917c2aad20Sopenharmony_ci	sheader->sh_name = elfio_section_get_name_string_offset(psection);
10927c2aad20Sopenharmony_ci	sheader->sh_type = elfio_section_get_type(psection);
10937c2aad20Sopenharmony_ci	sheader->sh_flags = elfio_section_get_flags(psection);
10947c2aad20Sopenharmony_ci	sheader->sh_addr = elfio_section_get_address(psection);
10957c2aad20Sopenharmony_ci	sheader->sh_offset = elfio_section_get_offset(psection);
10967c2aad20Sopenharmony_ci	sheader->sh_size = elfio_section_get_size(psection);
10977c2aad20Sopenharmony_ci	sheader->sh_link = elfio_section_get_link(psection);
10987c2aad20Sopenharmony_ci	sheader->sh_info = elfio_section_get_info(psection);
10997c2aad20Sopenharmony_ci	sheader->sh_addralign = elfio_section_get_addr_align(psection);
11007c2aad20Sopenharmony_ci	sheader->sh_entsize = elfio_section_get_entry_size(psection);
11017c2aad20Sopenharmony_ci
11027c2aad20Sopenharmony_ci	return sheader;
11037c2aad20Sopenharmony_ci}
11047c2aad20Sopenharmony_ci#endif
11057c2aad20Sopenharmony_ci
11067c2aad20Sopenharmony_cistatic struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
11077c2aad20Sopenharmony_ci				 struct btf_ext **btf_ext)
11087c2aad20Sopenharmony_ci{
11097c2aad20Sopenharmony_ci	Elf_Data *btf_data = NULL, *btf_ext_data = NULL;
11107c2aad20Sopenharmony_ci	int err = 0, fd = -1, idx = 0;
11117c2aad20Sopenharmony_ci	struct btf *btf = NULL;
11127c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11137c2aad20Sopenharmony_ci	Elf_Scn *scn = NULL;
11147c2aad20Sopenharmony_ci	Elf *elf = NULL;
11157c2aad20Sopenharmony_ci	GElf_Ehdr ehdr;
11167c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
11177c2aad20Sopenharmony_ci	pelfio_t elf;
11187c2aad20Sopenharmony_ci	Elf64_Ehdr ehdr;
11197c2aad20Sopenharmony_ci	Elf_Data btf_data_temp, btf_ext_data_temp;
11207c2aad20Sopenharmony_ci#endif
11217c2aad20Sopenharmony_ci	size_t shstrndx;
11227c2aad20Sopenharmony_ci
11237c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11247c2aad20Sopenharmony_ci	if (elf_version(EV_CURRENT) == EV_NONE) {
11257c2aad20Sopenharmony_ci		pr_warn("failed to init libelf for %s\n", path);
11267c2aad20Sopenharmony_ci		return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
11277c2aad20Sopenharmony_ci	}
11287c2aad20Sopenharmony_ci#endif
11297c2aad20Sopenharmony_ci
11307c2aad20Sopenharmony_ci	fd = open(path, O_RDONLY | O_CLOEXEC);
11317c2aad20Sopenharmony_ci	if (fd < 0) {
11327c2aad20Sopenharmony_ci		err = -errno;
11337c2aad20Sopenharmony_ci		pr_warn("failed to open %s: %s\n", path, strerror(errno));
11347c2aad20Sopenharmony_ci		return ERR_PTR(err);
11357c2aad20Sopenharmony_ci	}
11367c2aad20Sopenharmony_ci
11377c2aad20Sopenharmony_ci	err = -LIBBPF_ERRNO__FORMAT;
11387c2aad20Sopenharmony_ci
11397c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11407c2aad20Sopenharmony_ci	elf = elf_begin(fd, ELF_C_READ, NULL);
11417c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
11427c2aad20Sopenharmony_ci	elf = elfio_new();
11437c2aad20Sopenharmony_ci	if (!elfio_load(elf, path)) {
11447c2aad20Sopenharmony_ci		printf( "Can't load ELF file\n" );
11457c2aad20Sopenharmony_ci		goto done;
11467c2aad20Sopenharmony_ci    }
11477c2aad20Sopenharmony_ci#endif
11487c2aad20Sopenharmony_ci	if (!elf) {
11497c2aad20Sopenharmony_ci		pr_warn("failed to open %s as ELF file\n", path);
11507c2aad20Sopenharmony_ci		goto done;
11517c2aad20Sopenharmony_ci	}
11527c2aad20Sopenharmony_ci
11537c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11547c2aad20Sopenharmony_ci	if (!gelf_getehdr(elf, &ehdr)) {
11557c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
11567c2aad20Sopenharmony_ci	ssize_t nread = read(fd, &ehdr, sizeof(Elf64_Ehdr));
11577c2aad20Sopenharmony_ci	if(nread != sizeof(Elf64_Ehdr)) {
11587c2aad20Sopenharmony_ci#endif
11597c2aad20Sopenharmony_ci		pr_warn("failed to get EHDR from %s\n", path);
11607c2aad20Sopenharmony_ci		goto done;
11617c2aad20Sopenharmony_ci	}
11627c2aad20Sopenharmony_ci
11637c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11647c2aad20Sopenharmony_ci	if (elf_getshdrstrndx(elf, &shstrndx)) {
11657c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
11667c2aad20Sopenharmony_ci	shstrndx = elfio_get_section_name_str_index(elf);
11677c2aad20Sopenharmony_ci	if(shstrndx == 0) {
11687c2aad20Sopenharmony_ci#endif
11697c2aad20Sopenharmony_ci		pr_warn("failed to get section names section index for %s\n",
11707c2aad20Sopenharmony_ci			path);
11717c2aad20Sopenharmony_ci		goto done;
11727c2aad20Sopenharmony_ci	}
11737c2aad20Sopenharmony_ci
11747c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
11757c2aad20Sopenharmony_ci	if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) {
11767c2aad20Sopenharmony_ci		pr_warn("failed to get e_shstrndx from %s\n", path);
11777c2aad20Sopenharmony_ci		goto done;
11787c2aad20Sopenharmony_ci	}
11797c2aad20Sopenharmony_ci#endif
11807c2aad20Sopenharmony_ci
11817c2aad20Sopenharmony_ci#if defined HAVE_LIBELF
11827c2aad20Sopenharmony_ci	while ((scn = elf_nextscn(elf, scn)) != NULL) {
11837c2aad20Sopenharmony_ci		GElf_Shdr sh;
11847c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
11857c2aad20Sopenharmony_ci	psection_t psection = elfio_get_section_by_name(elf, ".shstrtab");
11867c2aad20Sopenharmony_ci	if (!psection )
11877c2aad20Sopenharmony_ci		goto done;
11887c2aad20Sopenharmony_ci
11897c2aad20Sopenharmony_ci	pstring_t pstring = elfio_string_section_accessor_new(psection);
11907c2aad20Sopenharmony_ci	if (!pstring )
11917c2aad20Sopenharmony_ci		goto done;
11927c2aad20Sopenharmony_ci
11937c2aad20Sopenharmony_ci	int secno = elfio_get_sections_num(elf);
11947c2aad20Sopenharmony_ci
11957c2aad20Sopenharmony_ci	for ( int i = 0; i < secno; i++ ) {
11967c2aad20Sopenharmony_ci		Elf64_Shdr sh;
11977c2aad20Sopenharmony_ci#endif
11987c2aad20Sopenharmony_ci		char *name;
11997c2aad20Sopenharmony_ci
12007c2aad20Sopenharmony_ci		idx++;
12017c2aad20Sopenharmony_ci#if defined HAVE_LIBELF
12027c2aad20Sopenharmony_ci		if (gelf_getshdr(scn, &sh) != &sh) {
12037c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12047c2aad20Sopenharmony_ci		if (!elf_sec_hdr_by_idx(elf, i, &sh)) {
12057c2aad20Sopenharmony_ci#endif
12067c2aad20Sopenharmony_ci			pr_warn("failed to get section(%d) header from %s\n",
12077c2aad20Sopenharmony_ci				idx, path);
12087c2aad20Sopenharmony_ci			goto done;
12097c2aad20Sopenharmony_ci		}
12107c2aad20Sopenharmony_ci#if defined HAVE_LIBELF
12117c2aad20Sopenharmony_ci		name = elf_strptr(elf, shstrndx, sh.sh_name);
12127c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12137c2aad20Sopenharmony_ci		name = elfio_string_get_string(pstring, sh.sh_name);
12147c2aad20Sopenharmony_ci#endif
12157c2aad20Sopenharmony_ci		if (!name) {
12167c2aad20Sopenharmony_ci			pr_warn("failed to get section(%d) name from %s\n",
12177c2aad20Sopenharmony_ci				idx, path);
12187c2aad20Sopenharmony_ci			goto done;
12197c2aad20Sopenharmony_ci		}
12207c2aad20Sopenharmony_ci		if (strcmp(name, BTF_ELF_SEC) == 0) {
12217c2aad20Sopenharmony_ci#if defined HAVE_LIBELF
12227c2aad20Sopenharmony_ci			btf_data = elf_getdata(scn, 0);
12237c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12247c2aad20Sopenharmony_ci			psection_t psection_index = elfio_get_section_by_index(elf, i);
12257c2aad20Sopenharmony_ci			btf_data_temp.d_buf = (void*)elfio_section_get_data(psection_index);
12267c2aad20Sopenharmony_ci			btf_data_temp.d_size = elfio_section_get_size(psection_index);
12277c2aad20Sopenharmony_ci			btf_data = &btf_data_temp;
12287c2aad20Sopenharmony_ci#endif
12297c2aad20Sopenharmony_ci			if (!btf_data) {
12307c2aad20Sopenharmony_ci				pr_warn("failed to get section(%d, %s) data from %s\n",
12317c2aad20Sopenharmony_ci					idx, name, path);
12327c2aad20Sopenharmony_ci				goto done;
12337c2aad20Sopenharmony_ci			}
12347c2aad20Sopenharmony_ci			continue;
12357c2aad20Sopenharmony_ci		} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
12367c2aad20Sopenharmony_ci#if defined HAVE_LIBELF
12377c2aad20Sopenharmony_ci			btf_ext_data = elf_getdata(scn, 0);
12387c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12397c2aad20Sopenharmony_ci			psection_t psection_index = elfio_get_section_by_index(elf, i);
12407c2aad20Sopenharmony_ci			btf_ext_data_temp.d_buf = (void*)elfio_section_get_data(psection_index);
12417c2aad20Sopenharmony_ci			btf_ext_data_temp.d_size = elfio_section_get_size(psection_index);
12427c2aad20Sopenharmony_ci			btf_ext_data = &btf_ext_data_temp;
12437c2aad20Sopenharmony_ci#endif
12447c2aad20Sopenharmony_ci			if (!btf_ext_data) {
12457c2aad20Sopenharmony_ci				pr_warn("failed to get section(%d, %s) data from %s\n",
12467c2aad20Sopenharmony_ci					idx, name, path);
12477c2aad20Sopenharmony_ci				goto done;
12487c2aad20Sopenharmony_ci			}
12497c2aad20Sopenharmony_ci			continue;
12507c2aad20Sopenharmony_ci		}
12517c2aad20Sopenharmony_ci	}
12527c2aad20Sopenharmony_ci
12537c2aad20Sopenharmony_ci	err = 0;
12547c2aad20Sopenharmony_ci
12557c2aad20Sopenharmony_ci	if (!btf_data) {
12567c2aad20Sopenharmony_ci		pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path);
12577c2aad20Sopenharmony_ci		err = -ENODATA;
12587c2aad20Sopenharmony_ci		goto done;
12597c2aad20Sopenharmony_ci	}
12607c2aad20Sopenharmony_ci	btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
12617c2aad20Sopenharmony_ci	err = libbpf_get_error(btf);
12627c2aad20Sopenharmony_ci	if (err)
12637c2aad20Sopenharmony_ci		goto done;
12647c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
12657c2aad20Sopenharmony_ci	switch (gelf_getclass(elf)) {
12667c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12677c2aad20Sopenharmony_ci	switch (elfio_get_class(elf)) {
12687c2aad20Sopenharmony_ci#endif
12697c2aad20Sopenharmony_ci
12707c2aad20Sopenharmony_ci	case ELFCLASS32:
12717c2aad20Sopenharmony_ci		btf__set_pointer_size(btf, 4);
12727c2aad20Sopenharmony_ci		break;
12737c2aad20Sopenharmony_ci	case ELFCLASS64:
12747c2aad20Sopenharmony_ci		btf__set_pointer_size(btf, 8);
12757c2aad20Sopenharmony_ci		break;
12767c2aad20Sopenharmony_ci	default:
12777c2aad20Sopenharmony_ci		pr_warn("failed to get ELF class (bitness) for %s\n", path);
12787c2aad20Sopenharmony_ci		break;
12797c2aad20Sopenharmony_ci	}
12807c2aad20Sopenharmony_ci
12817c2aad20Sopenharmony_ci	if (btf_ext && btf_ext_data) {
12827c2aad20Sopenharmony_ci		*btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size);
12837c2aad20Sopenharmony_ci		err = libbpf_get_error(*btf_ext);
12847c2aad20Sopenharmony_ci		if (err)
12857c2aad20Sopenharmony_ci			goto done;
12867c2aad20Sopenharmony_ci	} else if (btf_ext) {
12877c2aad20Sopenharmony_ci		*btf_ext = NULL;
12887c2aad20Sopenharmony_ci	}
12897c2aad20Sopenharmony_cidone:
12907c2aad20Sopenharmony_ci	if (elf)
12917c2aad20Sopenharmony_ci#ifdef HAVE_LIBELF
12927c2aad20Sopenharmony_ci		elf_end(elf);
12937c2aad20Sopenharmony_ci#elif defined HAVE_ELFIO
12947c2aad20Sopenharmony_ci		elfio_delete(elf);
12957c2aad20Sopenharmony_ci	if(pstring)
12967c2aad20Sopenharmony_ci		elfio_string_section_accessor_delete(pstring);
12977c2aad20Sopenharmony_ci#endif
12987c2aad20Sopenharmony_ci	close(fd);
12997c2aad20Sopenharmony_ci
13007c2aad20Sopenharmony_ci	if (!err)
13017c2aad20Sopenharmony_ci		return btf;
13027c2aad20Sopenharmony_ci
13037c2aad20Sopenharmony_ci	if (btf_ext)
13047c2aad20Sopenharmony_ci		btf_ext__free(*btf_ext);
13057c2aad20Sopenharmony_ci	btf__free(btf);
13067c2aad20Sopenharmony_ci
13077c2aad20Sopenharmony_ci	return ERR_PTR(err);
13087c2aad20Sopenharmony_ci}
13097c2aad20Sopenharmony_ci
13107c2aad20Sopenharmony_cistruct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
13117c2aad20Sopenharmony_ci{
13127c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext));
13137c2aad20Sopenharmony_ci}
13147c2aad20Sopenharmony_ci
13157c2aad20Sopenharmony_cistruct btf *btf__parse_elf_split(const char *path, struct btf *base_btf)
13167c2aad20Sopenharmony_ci{
13177c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse_elf(path, base_btf, NULL));
13187c2aad20Sopenharmony_ci}
13197c2aad20Sopenharmony_ci
13207c2aad20Sopenharmony_cistatic struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
13217c2aad20Sopenharmony_ci{
13227c2aad20Sopenharmony_ci	struct btf *btf = NULL;
13237c2aad20Sopenharmony_ci	void *data = NULL;
13247c2aad20Sopenharmony_ci	FILE *f = NULL;
13257c2aad20Sopenharmony_ci	__u16 magic;
13267c2aad20Sopenharmony_ci	int err = 0;
13277c2aad20Sopenharmony_ci	long sz;
13287c2aad20Sopenharmony_ci
13297c2aad20Sopenharmony_ci	f = fopen(path, "rbe");
13307c2aad20Sopenharmony_ci	if (!f) {
13317c2aad20Sopenharmony_ci		err = -errno;
13327c2aad20Sopenharmony_ci		goto err_out;
13337c2aad20Sopenharmony_ci	}
13347c2aad20Sopenharmony_ci
13357c2aad20Sopenharmony_ci	/* check BTF magic */
13367c2aad20Sopenharmony_ci	if (fread(&magic, 1, sizeof(magic), f) < sizeof(magic)) {
13377c2aad20Sopenharmony_ci		err = -EIO;
13387c2aad20Sopenharmony_ci		goto err_out;
13397c2aad20Sopenharmony_ci	}
13407c2aad20Sopenharmony_ci	if (magic != BTF_MAGIC && magic != bswap_16(BTF_MAGIC)) {
13417c2aad20Sopenharmony_ci		/* definitely not a raw BTF */
13427c2aad20Sopenharmony_ci		err = -EPROTO;
13437c2aad20Sopenharmony_ci		goto err_out;
13447c2aad20Sopenharmony_ci	}
13457c2aad20Sopenharmony_ci
13467c2aad20Sopenharmony_ci	/* get file size */
13477c2aad20Sopenharmony_ci	if (fseek(f, 0, SEEK_END)) {
13487c2aad20Sopenharmony_ci		err = -errno;
13497c2aad20Sopenharmony_ci		goto err_out;
13507c2aad20Sopenharmony_ci	}
13517c2aad20Sopenharmony_ci	sz = ftell(f);
13527c2aad20Sopenharmony_ci	if (sz < 0) {
13537c2aad20Sopenharmony_ci		err = -errno;
13547c2aad20Sopenharmony_ci		goto err_out;
13557c2aad20Sopenharmony_ci	}
13567c2aad20Sopenharmony_ci	/* rewind to the start */
13577c2aad20Sopenharmony_ci	if (fseek(f, 0, SEEK_SET)) {
13587c2aad20Sopenharmony_ci		err = -errno;
13597c2aad20Sopenharmony_ci		goto err_out;
13607c2aad20Sopenharmony_ci	}
13617c2aad20Sopenharmony_ci
13627c2aad20Sopenharmony_ci	/* pre-alloc memory and read all of BTF data */
13637c2aad20Sopenharmony_ci	data = malloc(sz);
13647c2aad20Sopenharmony_ci	if (!data) {
13657c2aad20Sopenharmony_ci		err = -ENOMEM;
13667c2aad20Sopenharmony_ci		goto err_out;
13677c2aad20Sopenharmony_ci	}
13687c2aad20Sopenharmony_ci	if (fread(data, 1, sz, f) < sz) {
13697c2aad20Sopenharmony_ci		err = -EIO;
13707c2aad20Sopenharmony_ci		goto err_out;
13717c2aad20Sopenharmony_ci	}
13727c2aad20Sopenharmony_ci
13737c2aad20Sopenharmony_ci	/* finally parse BTF data */
13747c2aad20Sopenharmony_ci	btf = btf_new(data, sz, base_btf);
13757c2aad20Sopenharmony_ci
13767c2aad20Sopenharmony_cierr_out:
13777c2aad20Sopenharmony_ci	free(data);
13787c2aad20Sopenharmony_ci	if (f)
13797c2aad20Sopenharmony_ci		fclose(f);
13807c2aad20Sopenharmony_ci	return err ? ERR_PTR(err) : btf;
13817c2aad20Sopenharmony_ci}
13827c2aad20Sopenharmony_ci
13837c2aad20Sopenharmony_cistruct btf *btf__parse_raw(const char *path)
13847c2aad20Sopenharmony_ci{
13857c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse_raw(path, NULL));
13867c2aad20Sopenharmony_ci}
13877c2aad20Sopenharmony_ci
13887c2aad20Sopenharmony_cistruct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
13897c2aad20Sopenharmony_ci{
13907c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse_raw(path, base_btf));
13917c2aad20Sopenharmony_ci}
13927c2aad20Sopenharmony_ci
13937c2aad20Sopenharmony_cistatic struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
13947c2aad20Sopenharmony_ci{
13957c2aad20Sopenharmony_ci	struct btf *btf;
13967c2aad20Sopenharmony_ci	int err;
13977c2aad20Sopenharmony_ci
13987c2aad20Sopenharmony_ci	if (btf_ext)
13997c2aad20Sopenharmony_ci		*btf_ext = NULL;
14007c2aad20Sopenharmony_ci
14017c2aad20Sopenharmony_ci	btf = btf_parse_raw(path, base_btf);
14027c2aad20Sopenharmony_ci	err = libbpf_get_error(btf);
14037c2aad20Sopenharmony_ci	if (!err)
14047c2aad20Sopenharmony_ci		return btf;
14057c2aad20Sopenharmony_ci	if (err != -EPROTO)
14067c2aad20Sopenharmony_ci		return ERR_PTR(err);
14077c2aad20Sopenharmony_ci	return btf_parse_elf(path, base_btf, btf_ext);
14087c2aad20Sopenharmony_ci}
14097c2aad20Sopenharmony_ci
14107c2aad20Sopenharmony_cistruct btf *btf__parse(const char *path, struct btf_ext **btf_ext)
14117c2aad20Sopenharmony_ci{
14127c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse(path, NULL, btf_ext));
14137c2aad20Sopenharmony_ci}
14147c2aad20Sopenharmony_ci
14157c2aad20Sopenharmony_cistruct btf *btf__parse_split(const char *path, struct btf *base_btf)
14167c2aad20Sopenharmony_ci{
14177c2aad20Sopenharmony_ci	return libbpf_ptr(btf_parse(path, base_btf, NULL));
14187c2aad20Sopenharmony_ci}
14197c2aad20Sopenharmony_ci
14207c2aad20Sopenharmony_cistatic void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
14217c2aad20Sopenharmony_ci
14227c2aad20Sopenharmony_ciint btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level)
14237c2aad20Sopenharmony_ci{
14247c2aad20Sopenharmony_ci	LIBBPF_OPTS(bpf_btf_load_opts, opts);
14257c2aad20Sopenharmony_ci	__u32 buf_sz = 0, raw_size;
14267c2aad20Sopenharmony_ci	char *buf = NULL, *tmp;
14277c2aad20Sopenharmony_ci	void *raw_data;
14287c2aad20Sopenharmony_ci	int err = 0;
14297c2aad20Sopenharmony_ci
14307c2aad20Sopenharmony_ci	if (btf->fd >= 0)
14317c2aad20Sopenharmony_ci		return libbpf_err(-EEXIST);
14327c2aad20Sopenharmony_ci	if (log_sz && !log_buf)
14337c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
14347c2aad20Sopenharmony_ci
14357c2aad20Sopenharmony_ci	/* cache native raw data representation */
14367c2aad20Sopenharmony_ci	raw_data = btf_get_raw_data(btf, &raw_size, false);
14377c2aad20Sopenharmony_ci	if (!raw_data) {
14387c2aad20Sopenharmony_ci		err = -ENOMEM;
14397c2aad20Sopenharmony_ci		goto done;
14407c2aad20Sopenharmony_ci	}
14417c2aad20Sopenharmony_ci	btf->raw_size = raw_size;
14427c2aad20Sopenharmony_ci	btf->raw_data = raw_data;
14437c2aad20Sopenharmony_ci
14447c2aad20Sopenharmony_ciretry_load:
14457c2aad20Sopenharmony_ci	/* if log_level is 0, we won't provide log_buf/log_size to the kernel,
14467c2aad20Sopenharmony_ci	 * initially. Only if BTF loading fails, we bump log_level to 1 and
14477c2aad20Sopenharmony_ci	 * retry, using either auto-allocated or custom log_buf. This way
14487c2aad20Sopenharmony_ci	 * non-NULL custom log_buf provides a buffer just in case, but hopes
14497c2aad20Sopenharmony_ci	 * for successful load and no need for log_buf.
14507c2aad20Sopenharmony_ci	 */
14517c2aad20Sopenharmony_ci	if (log_level) {
14527c2aad20Sopenharmony_ci		/* if caller didn't provide custom log_buf, we'll keep
14537c2aad20Sopenharmony_ci		 * allocating our own progressively bigger buffers for BTF
14547c2aad20Sopenharmony_ci		 * verification log
14557c2aad20Sopenharmony_ci		 */
14567c2aad20Sopenharmony_ci		if (!log_buf) {
14577c2aad20Sopenharmony_ci			buf_sz = max((__u32)BPF_LOG_BUF_SIZE, buf_sz * 2);
14587c2aad20Sopenharmony_ci			tmp = realloc(buf, buf_sz);
14597c2aad20Sopenharmony_ci			if (!tmp) {
14607c2aad20Sopenharmony_ci				err = -ENOMEM;
14617c2aad20Sopenharmony_ci				goto done;
14627c2aad20Sopenharmony_ci			}
14637c2aad20Sopenharmony_ci			buf = tmp;
14647c2aad20Sopenharmony_ci			buf[0] = '\0';
14657c2aad20Sopenharmony_ci		}
14667c2aad20Sopenharmony_ci
14677c2aad20Sopenharmony_ci		opts.log_buf = log_buf ? log_buf : buf;
14687c2aad20Sopenharmony_ci		opts.log_size = log_buf ? log_sz : buf_sz;
14697c2aad20Sopenharmony_ci		opts.log_level = log_level;
14707c2aad20Sopenharmony_ci	}
14717c2aad20Sopenharmony_ci
14727c2aad20Sopenharmony_ci	btf->fd = bpf_btf_load(raw_data, raw_size, &opts);
14737c2aad20Sopenharmony_ci	if (btf->fd < 0) {
14747c2aad20Sopenharmony_ci		/* time to turn on verbose mode and try again */
14757c2aad20Sopenharmony_ci		if (log_level == 0) {
14767c2aad20Sopenharmony_ci			log_level = 1;
14777c2aad20Sopenharmony_ci			goto retry_load;
14787c2aad20Sopenharmony_ci		}
14797c2aad20Sopenharmony_ci		/* only retry if caller didn't provide custom log_buf, but
14807c2aad20Sopenharmony_ci		 * make sure we can never overflow buf_sz
14817c2aad20Sopenharmony_ci		 */
14827c2aad20Sopenharmony_ci		if (!log_buf && errno == ENOSPC && buf_sz <= UINT_MAX / 2)
14837c2aad20Sopenharmony_ci			goto retry_load;
14847c2aad20Sopenharmony_ci
14857c2aad20Sopenharmony_ci		err = -errno;
14867c2aad20Sopenharmony_ci		pr_warn("BTF loading error: %d\n", err);
14877c2aad20Sopenharmony_ci		/* don't print out contents of custom log_buf */
14887c2aad20Sopenharmony_ci		if (!log_buf && buf[0])
14897c2aad20Sopenharmony_ci			pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf);
14907c2aad20Sopenharmony_ci	}
14917c2aad20Sopenharmony_ci
14927c2aad20Sopenharmony_cidone:
14937c2aad20Sopenharmony_ci	free(buf);
14947c2aad20Sopenharmony_ci	return libbpf_err(err);
14957c2aad20Sopenharmony_ci}
14967c2aad20Sopenharmony_ci
14977c2aad20Sopenharmony_ciint btf__load_into_kernel(struct btf *btf)
14987c2aad20Sopenharmony_ci{
14997c2aad20Sopenharmony_ci	return btf_load_into_kernel(btf, NULL, 0, 0);
15007c2aad20Sopenharmony_ci}
15017c2aad20Sopenharmony_ci
15027c2aad20Sopenharmony_ciint btf__fd(const struct btf *btf)
15037c2aad20Sopenharmony_ci{
15047c2aad20Sopenharmony_ci	return btf->fd;
15057c2aad20Sopenharmony_ci}
15067c2aad20Sopenharmony_ci
15077c2aad20Sopenharmony_civoid btf__set_fd(struct btf *btf, int fd)
15087c2aad20Sopenharmony_ci{
15097c2aad20Sopenharmony_ci	btf->fd = fd;
15107c2aad20Sopenharmony_ci}
15117c2aad20Sopenharmony_ci
15127c2aad20Sopenharmony_cistatic const void *btf_strs_data(const struct btf *btf)
15137c2aad20Sopenharmony_ci{
15147c2aad20Sopenharmony_ci	return btf->strs_data ? btf->strs_data : strset__data(btf->strs_set);
15157c2aad20Sopenharmony_ci}
15167c2aad20Sopenharmony_ci
15177c2aad20Sopenharmony_cistatic void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian)
15187c2aad20Sopenharmony_ci{
15197c2aad20Sopenharmony_ci	struct btf_header *hdr = btf->hdr;
15207c2aad20Sopenharmony_ci	struct btf_type *t;
15217c2aad20Sopenharmony_ci	void *data, *p;
15227c2aad20Sopenharmony_ci	__u32 data_sz;
15237c2aad20Sopenharmony_ci	int i;
15247c2aad20Sopenharmony_ci
15257c2aad20Sopenharmony_ci	data = swap_endian ? btf->raw_data_swapped : btf->raw_data;
15267c2aad20Sopenharmony_ci	if (data) {
15277c2aad20Sopenharmony_ci		*size = btf->raw_size;
15287c2aad20Sopenharmony_ci		return data;
15297c2aad20Sopenharmony_ci	}
15307c2aad20Sopenharmony_ci
15317c2aad20Sopenharmony_ci	data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len;
15327c2aad20Sopenharmony_ci	data = calloc(1, data_sz);
15337c2aad20Sopenharmony_ci	if (!data)
15347c2aad20Sopenharmony_ci		return NULL;
15357c2aad20Sopenharmony_ci	p = data;
15367c2aad20Sopenharmony_ci
15377c2aad20Sopenharmony_ci	memcpy(p, hdr, hdr->hdr_len);
15387c2aad20Sopenharmony_ci	if (swap_endian)
15397c2aad20Sopenharmony_ci		btf_bswap_hdr(p);
15407c2aad20Sopenharmony_ci	p += hdr->hdr_len;
15417c2aad20Sopenharmony_ci
15427c2aad20Sopenharmony_ci	memcpy(p, btf->types_data, hdr->type_len);
15437c2aad20Sopenharmony_ci	if (swap_endian) {
15447c2aad20Sopenharmony_ci		for (i = 0; i < btf->nr_types; i++) {
15457c2aad20Sopenharmony_ci			t = p + btf->type_offs[i];
15467c2aad20Sopenharmony_ci			/* btf_bswap_type_rest() relies on native t->info, so
15477c2aad20Sopenharmony_ci			 * we swap base type info after we swapped all the
15487c2aad20Sopenharmony_ci			 * additional information
15497c2aad20Sopenharmony_ci			 */
15507c2aad20Sopenharmony_ci			if (btf_bswap_type_rest(t))
15517c2aad20Sopenharmony_ci				goto err_out;
15527c2aad20Sopenharmony_ci			btf_bswap_type_base(t);
15537c2aad20Sopenharmony_ci		}
15547c2aad20Sopenharmony_ci	}
15557c2aad20Sopenharmony_ci	p += hdr->type_len;
15567c2aad20Sopenharmony_ci
15577c2aad20Sopenharmony_ci	memcpy(p, btf_strs_data(btf), hdr->str_len);
15587c2aad20Sopenharmony_ci	p += hdr->str_len;
15597c2aad20Sopenharmony_ci
15607c2aad20Sopenharmony_ci	*size = data_sz;
15617c2aad20Sopenharmony_ci	return data;
15627c2aad20Sopenharmony_cierr_out:
15637c2aad20Sopenharmony_ci	free(data);
15647c2aad20Sopenharmony_ci	return NULL;
15657c2aad20Sopenharmony_ci}
15667c2aad20Sopenharmony_ci
15677c2aad20Sopenharmony_ciconst void *btf__raw_data(const struct btf *btf_ro, __u32 *size)
15687c2aad20Sopenharmony_ci{
15697c2aad20Sopenharmony_ci	struct btf *btf = (struct btf *)btf_ro;
15707c2aad20Sopenharmony_ci	__u32 data_sz;
15717c2aad20Sopenharmony_ci	void *data;
15727c2aad20Sopenharmony_ci
15737c2aad20Sopenharmony_ci	data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian);
15747c2aad20Sopenharmony_ci	if (!data)
15757c2aad20Sopenharmony_ci		return errno = ENOMEM, NULL;
15767c2aad20Sopenharmony_ci
15777c2aad20Sopenharmony_ci	btf->raw_size = data_sz;
15787c2aad20Sopenharmony_ci	if (btf->swapped_endian)
15797c2aad20Sopenharmony_ci		btf->raw_data_swapped = data;
15807c2aad20Sopenharmony_ci	else
15817c2aad20Sopenharmony_ci		btf->raw_data = data;
15827c2aad20Sopenharmony_ci	*size = data_sz;
15837c2aad20Sopenharmony_ci	return data;
15847c2aad20Sopenharmony_ci}
15857c2aad20Sopenharmony_ci
15867c2aad20Sopenharmony_ci__attribute__((alias("btf__raw_data")))
15877c2aad20Sopenharmony_ciconst void *btf__get_raw_data(const struct btf *btf, __u32 *size);
15887c2aad20Sopenharmony_ci
15897c2aad20Sopenharmony_ciconst char *btf__str_by_offset(const struct btf *btf, __u32 offset)
15907c2aad20Sopenharmony_ci{
15917c2aad20Sopenharmony_ci	if (offset < btf->start_str_off)
15927c2aad20Sopenharmony_ci		return btf__str_by_offset(btf->base_btf, offset);
15937c2aad20Sopenharmony_ci	else if (offset - btf->start_str_off < btf->hdr->str_len)
15947c2aad20Sopenharmony_ci		return btf_strs_data(btf) + (offset - btf->start_str_off);
15957c2aad20Sopenharmony_ci	else
15967c2aad20Sopenharmony_ci		return errno = EINVAL, NULL;
15977c2aad20Sopenharmony_ci}
15987c2aad20Sopenharmony_ci
15997c2aad20Sopenharmony_ciconst char *btf__name_by_offset(const struct btf *btf, __u32 offset)
16007c2aad20Sopenharmony_ci{
16017c2aad20Sopenharmony_ci	return btf__str_by_offset(btf, offset);
16027c2aad20Sopenharmony_ci}
16037c2aad20Sopenharmony_ci
16047c2aad20Sopenharmony_cistruct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
16057c2aad20Sopenharmony_ci{
16067c2aad20Sopenharmony_ci	struct bpf_btf_info btf_info;
16077c2aad20Sopenharmony_ci	__u32 len = sizeof(btf_info);
16087c2aad20Sopenharmony_ci	__u32 last_size;
16097c2aad20Sopenharmony_ci	struct btf *btf;
16107c2aad20Sopenharmony_ci	void *ptr;
16117c2aad20Sopenharmony_ci	int err;
16127c2aad20Sopenharmony_ci
16137c2aad20Sopenharmony_ci	/* we won't know btf_size until we call bpf_btf_get_info_by_fd(). so
16147c2aad20Sopenharmony_ci	 * let's start with a sane default - 4KiB here - and resize it only if
16157c2aad20Sopenharmony_ci	 * bpf_btf_get_info_by_fd() needs a bigger buffer.
16167c2aad20Sopenharmony_ci	 */
16177c2aad20Sopenharmony_ci	last_size = 4096;
16187c2aad20Sopenharmony_ci	ptr = malloc(last_size);
16197c2aad20Sopenharmony_ci	if (!ptr)
16207c2aad20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
16217c2aad20Sopenharmony_ci
16227c2aad20Sopenharmony_ci	memset(&btf_info, 0, sizeof(btf_info));
16237c2aad20Sopenharmony_ci	btf_info.btf = ptr_to_u64(ptr);
16247c2aad20Sopenharmony_ci	btf_info.btf_size = last_size;
16257c2aad20Sopenharmony_ci	err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
16267c2aad20Sopenharmony_ci
16277c2aad20Sopenharmony_ci	if (!err && btf_info.btf_size > last_size) {
16287c2aad20Sopenharmony_ci		void *temp_ptr;
16297c2aad20Sopenharmony_ci
16307c2aad20Sopenharmony_ci		last_size = btf_info.btf_size;
16317c2aad20Sopenharmony_ci		temp_ptr = realloc(ptr, last_size);
16327c2aad20Sopenharmony_ci		if (!temp_ptr) {
16337c2aad20Sopenharmony_ci			btf = ERR_PTR(-ENOMEM);
16347c2aad20Sopenharmony_ci			goto exit_free;
16357c2aad20Sopenharmony_ci		}
16367c2aad20Sopenharmony_ci		ptr = temp_ptr;
16377c2aad20Sopenharmony_ci
16387c2aad20Sopenharmony_ci		len = sizeof(btf_info);
16397c2aad20Sopenharmony_ci		memset(&btf_info, 0, sizeof(btf_info));
16407c2aad20Sopenharmony_ci		btf_info.btf = ptr_to_u64(ptr);
16417c2aad20Sopenharmony_ci		btf_info.btf_size = last_size;
16427c2aad20Sopenharmony_ci
16437c2aad20Sopenharmony_ci		err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
16447c2aad20Sopenharmony_ci	}
16457c2aad20Sopenharmony_ci
16467c2aad20Sopenharmony_ci	if (err || btf_info.btf_size > last_size) {
16477c2aad20Sopenharmony_ci		btf = err ? ERR_PTR(-errno) : ERR_PTR(-E2BIG);
16487c2aad20Sopenharmony_ci		goto exit_free;
16497c2aad20Sopenharmony_ci	}
16507c2aad20Sopenharmony_ci
16517c2aad20Sopenharmony_ci	btf = btf_new(ptr, btf_info.btf_size, base_btf);
16527c2aad20Sopenharmony_ci
16537c2aad20Sopenharmony_ciexit_free:
16547c2aad20Sopenharmony_ci	free(ptr);
16557c2aad20Sopenharmony_ci	return btf;
16567c2aad20Sopenharmony_ci}
16577c2aad20Sopenharmony_ci
16587c2aad20Sopenharmony_cistruct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf)
16597c2aad20Sopenharmony_ci{
16607c2aad20Sopenharmony_ci	struct btf *btf;
16617c2aad20Sopenharmony_ci	int btf_fd;
16627c2aad20Sopenharmony_ci
16637c2aad20Sopenharmony_ci	btf_fd = bpf_btf_get_fd_by_id(id);
16647c2aad20Sopenharmony_ci	if (btf_fd < 0)
16657c2aad20Sopenharmony_ci		return libbpf_err_ptr(-errno);
16667c2aad20Sopenharmony_ci
16677c2aad20Sopenharmony_ci	btf = btf_get_from_fd(btf_fd, base_btf);
16687c2aad20Sopenharmony_ci	close(btf_fd);
16697c2aad20Sopenharmony_ci
16707c2aad20Sopenharmony_ci	return libbpf_ptr(btf);
16717c2aad20Sopenharmony_ci}
16727c2aad20Sopenharmony_ci
16737c2aad20Sopenharmony_cistruct btf *btf__load_from_kernel_by_id(__u32 id)
16747c2aad20Sopenharmony_ci{
16757c2aad20Sopenharmony_ci	return btf__load_from_kernel_by_id_split(id, NULL);
16767c2aad20Sopenharmony_ci}
16777c2aad20Sopenharmony_ci
16787c2aad20Sopenharmony_cistatic void btf_invalidate_raw_data(struct btf *btf)
16797c2aad20Sopenharmony_ci{
16807c2aad20Sopenharmony_ci	if (btf->raw_data) {
16817c2aad20Sopenharmony_ci		free(btf->raw_data);
16827c2aad20Sopenharmony_ci		btf->raw_data = NULL;
16837c2aad20Sopenharmony_ci	}
16847c2aad20Sopenharmony_ci	if (btf->raw_data_swapped) {
16857c2aad20Sopenharmony_ci		free(btf->raw_data_swapped);
16867c2aad20Sopenharmony_ci		btf->raw_data_swapped = NULL;
16877c2aad20Sopenharmony_ci	}
16887c2aad20Sopenharmony_ci}
16897c2aad20Sopenharmony_ci
16907c2aad20Sopenharmony_ci/* Ensure BTF is ready to be modified (by splitting into a three memory
16917c2aad20Sopenharmony_ci * regions for header, types, and strings). Also invalidate cached
16927c2aad20Sopenharmony_ci * raw_data, if any.
16937c2aad20Sopenharmony_ci */
16947c2aad20Sopenharmony_cistatic int btf_ensure_modifiable(struct btf *btf)
16957c2aad20Sopenharmony_ci{
16967c2aad20Sopenharmony_ci	void *hdr, *types;
16977c2aad20Sopenharmony_ci	struct strset *set = NULL;
16987c2aad20Sopenharmony_ci	int err = -ENOMEM;
16997c2aad20Sopenharmony_ci
17007c2aad20Sopenharmony_ci	if (btf_is_modifiable(btf)) {
17017c2aad20Sopenharmony_ci		/* any BTF modification invalidates raw_data */
17027c2aad20Sopenharmony_ci		btf_invalidate_raw_data(btf);
17037c2aad20Sopenharmony_ci		return 0;
17047c2aad20Sopenharmony_ci	}
17057c2aad20Sopenharmony_ci
17067c2aad20Sopenharmony_ci	/* split raw data into three memory regions */
17077c2aad20Sopenharmony_ci	hdr = malloc(btf->hdr->hdr_len);
17087c2aad20Sopenharmony_ci	types = malloc(btf->hdr->type_len);
17097c2aad20Sopenharmony_ci	if (!hdr || !types)
17107c2aad20Sopenharmony_ci		goto err_out;
17117c2aad20Sopenharmony_ci
17127c2aad20Sopenharmony_ci	memcpy(hdr, btf->hdr, btf->hdr->hdr_len);
17137c2aad20Sopenharmony_ci	memcpy(types, btf->types_data, btf->hdr->type_len);
17147c2aad20Sopenharmony_ci
17157c2aad20Sopenharmony_ci	/* build lookup index for all strings */
17167c2aad20Sopenharmony_ci	set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len);
17177c2aad20Sopenharmony_ci	if (IS_ERR(set)) {
17187c2aad20Sopenharmony_ci		err = PTR_ERR(set);
17197c2aad20Sopenharmony_ci		goto err_out;
17207c2aad20Sopenharmony_ci	}
17217c2aad20Sopenharmony_ci
17227c2aad20Sopenharmony_ci	/* only when everything was successful, update internal state */
17237c2aad20Sopenharmony_ci	btf->hdr = hdr;
17247c2aad20Sopenharmony_ci	btf->types_data = types;
17257c2aad20Sopenharmony_ci	btf->types_data_cap = btf->hdr->type_len;
17267c2aad20Sopenharmony_ci	btf->strs_data = NULL;
17277c2aad20Sopenharmony_ci	btf->strs_set = set;
17287c2aad20Sopenharmony_ci	/* if BTF was created from scratch, all strings are guaranteed to be
17297c2aad20Sopenharmony_ci	 * unique and deduplicated
17307c2aad20Sopenharmony_ci	 */
17317c2aad20Sopenharmony_ci	if (btf->hdr->str_len == 0)
17327c2aad20Sopenharmony_ci		btf->strs_deduped = true;
17337c2aad20Sopenharmony_ci	if (!btf->base_btf && btf->hdr->str_len == 1)
17347c2aad20Sopenharmony_ci		btf->strs_deduped = true;
17357c2aad20Sopenharmony_ci
17367c2aad20Sopenharmony_ci	/* invalidate raw_data representation */
17377c2aad20Sopenharmony_ci	btf_invalidate_raw_data(btf);
17387c2aad20Sopenharmony_ci
17397c2aad20Sopenharmony_ci	return 0;
17407c2aad20Sopenharmony_ci
17417c2aad20Sopenharmony_cierr_out:
17427c2aad20Sopenharmony_ci	strset__free(set);
17437c2aad20Sopenharmony_ci	free(hdr);
17447c2aad20Sopenharmony_ci	free(types);
17457c2aad20Sopenharmony_ci	return err;
17467c2aad20Sopenharmony_ci}
17477c2aad20Sopenharmony_ci
17487c2aad20Sopenharmony_ci/* Find an offset in BTF string section that corresponds to a given string *s*.
17497c2aad20Sopenharmony_ci * Returns:
17507c2aad20Sopenharmony_ci *   - >0 offset into string section, if string is found;
17517c2aad20Sopenharmony_ci *   - -ENOENT, if string is not in the string section;
17527c2aad20Sopenharmony_ci *   - <0, on any other error.
17537c2aad20Sopenharmony_ci */
17547c2aad20Sopenharmony_ciint btf__find_str(struct btf *btf, const char *s)
17557c2aad20Sopenharmony_ci{
17567c2aad20Sopenharmony_ci	int off;
17577c2aad20Sopenharmony_ci
17587c2aad20Sopenharmony_ci	if (btf->base_btf) {
17597c2aad20Sopenharmony_ci		off = btf__find_str(btf->base_btf, s);
17607c2aad20Sopenharmony_ci		if (off != -ENOENT)
17617c2aad20Sopenharmony_ci			return off;
17627c2aad20Sopenharmony_ci	}
17637c2aad20Sopenharmony_ci
17647c2aad20Sopenharmony_ci	/* BTF needs to be in a modifiable state to build string lookup index */
17657c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
17667c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
17677c2aad20Sopenharmony_ci
17687c2aad20Sopenharmony_ci	off = strset__find_str(btf->strs_set, s);
17697c2aad20Sopenharmony_ci	if (off < 0)
17707c2aad20Sopenharmony_ci		return libbpf_err(off);
17717c2aad20Sopenharmony_ci
17727c2aad20Sopenharmony_ci	return btf->start_str_off + off;
17737c2aad20Sopenharmony_ci}
17747c2aad20Sopenharmony_ci
17757c2aad20Sopenharmony_ci/* Add a string s to the BTF string section.
17767c2aad20Sopenharmony_ci * Returns:
17777c2aad20Sopenharmony_ci *   - > 0 offset into string section, on success;
17787c2aad20Sopenharmony_ci *   - < 0, on error.
17797c2aad20Sopenharmony_ci */
17807c2aad20Sopenharmony_ciint btf__add_str(struct btf *btf, const char *s)
17817c2aad20Sopenharmony_ci{
17827c2aad20Sopenharmony_ci	int off;
17837c2aad20Sopenharmony_ci
17847c2aad20Sopenharmony_ci	if (btf->base_btf) {
17857c2aad20Sopenharmony_ci		off = btf__find_str(btf->base_btf, s);
17867c2aad20Sopenharmony_ci		if (off != -ENOENT)
17877c2aad20Sopenharmony_ci			return off;
17887c2aad20Sopenharmony_ci	}
17897c2aad20Sopenharmony_ci
17907c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
17917c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
17927c2aad20Sopenharmony_ci
17937c2aad20Sopenharmony_ci	off = strset__add_str(btf->strs_set, s);
17947c2aad20Sopenharmony_ci	if (off < 0)
17957c2aad20Sopenharmony_ci		return libbpf_err(off);
17967c2aad20Sopenharmony_ci
17977c2aad20Sopenharmony_ci	btf->hdr->str_len = strset__data_size(btf->strs_set);
17987c2aad20Sopenharmony_ci
17997c2aad20Sopenharmony_ci	return btf->start_str_off + off;
18007c2aad20Sopenharmony_ci}
18017c2aad20Sopenharmony_ci
18027c2aad20Sopenharmony_cistatic void *btf_add_type_mem(struct btf *btf, size_t add_sz)
18037c2aad20Sopenharmony_ci{
18047c2aad20Sopenharmony_ci	return libbpf_add_mem(&btf->types_data, &btf->types_data_cap, 1,
18057c2aad20Sopenharmony_ci			      btf->hdr->type_len, UINT_MAX, add_sz);
18067c2aad20Sopenharmony_ci}
18077c2aad20Sopenharmony_ci
18087c2aad20Sopenharmony_cistatic void btf_type_inc_vlen(struct btf_type *t)
18097c2aad20Sopenharmony_ci{
18107c2aad20Sopenharmony_ci	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
18117c2aad20Sopenharmony_ci}
18127c2aad20Sopenharmony_ci
18137c2aad20Sopenharmony_cistatic int btf_commit_type(struct btf *btf, int data_sz)
18147c2aad20Sopenharmony_ci{
18157c2aad20Sopenharmony_ci	int err;
18167c2aad20Sopenharmony_ci
18177c2aad20Sopenharmony_ci	err = btf_add_type_idx_entry(btf, btf->hdr->type_len);
18187c2aad20Sopenharmony_ci	if (err)
18197c2aad20Sopenharmony_ci		return libbpf_err(err);
18207c2aad20Sopenharmony_ci
18217c2aad20Sopenharmony_ci	btf->hdr->type_len += data_sz;
18227c2aad20Sopenharmony_ci	btf->hdr->str_off += data_sz;
18237c2aad20Sopenharmony_ci	btf->nr_types++;
18247c2aad20Sopenharmony_ci	return btf->start_id + btf->nr_types - 1;
18257c2aad20Sopenharmony_ci}
18267c2aad20Sopenharmony_ci
18277c2aad20Sopenharmony_cistruct btf_pipe {
18287c2aad20Sopenharmony_ci	const struct btf *src;
18297c2aad20Sopenharmony_ci	struct btf *dst;
18307c2aad20Sopenharmony_ci	struct hashmap *str_off_map; /* map string offsets from src to dst */
18317c2aad20Sopenharmony_ci};
18327c2aad20Sopenharmony_ci
18337c2aad20Sopenharmony_cistatic int btf_rewrite_str(__u32 *str_off, void *ctx)
18347c2aad20Sopenharmony_ci{
18357c2aad20Sopenharmony_ci	struct btf_pipe *p = ctx;
18367c2aad20Sopenharmony_ci	long mapped_off;
18377c2aad20Sopenharmony_ci	int off, err;
18387c2aad20Sopenharmony_ci
18397c2aad20Sopenharmony_ci	if (!*str_off) /* nothing to do for empty strings */
18407c2aad20Sopenharmony_ci		return 0;
18417c2aad20Sopenharmony_ci
18427c2aad20Sopenharmony_ci	if (p->str_off_map &&
18437c2aad20Sopenharmony_ci	    hashmap__find(p->str_off_map, *str_off, &mapped_off)) {
18447c2aad20Sopenharmony_ci		*str_off = mapped_off;
18457c2aad20Sopenharmony_ci		return 0;
18467c2aad20Sopenharmony_ci	}
18477c2aad20Sopenharmony_ci
18487c2aad20Sopenharmony_ci	off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off));
18497c2aad20Sopenharmony_ci	if (off < 0)
18507c2aad20Sopenharmony_ci		return off;
18517c2aad20Sopenharmony_ci
18527c2aad20Sopenharmony_ci	/* Remember string mapping from src to dst.  It avoids
18537c2aad20Sopenharmony_ci	 * performing expensive string comparisons.
18547c2aad20Sopenharmony_ci	 */
18557c2aad20Sopenharmony_ci	if (p->str_off_map) {
18567c2aad20Sopenharmony_ci		err = hashmap__append(p->str_off_map, *str_off, off);
18577c2aad20Sopenharmony_ci		if (err)
18587c2aad20Sopenharmony_ci			return err;
18597c2aad20Sopenharmony_ci	}
18607c2aad20Sopenharmony_ci
18617c2aad20Sopenharmony_ci	*str_off = off;
18627c2aad20Sopenharmony_ci	return 0;
18637c2aad20Sopenharmony_ci}
18647c2aad20Sopenharmony_ci
18657c2aad20Sopenharmony_ciint btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type)
18667c2aad20Sopenharmony_ci{
18677c2aad20Sopenharmony_ci	struct btf_pipe p = { .src = src_btf, .dst = btf };
18687c2aad20Sopenharmony_ci	struct btf_type *t;
18697c2aad20Sopenharmony_ci	int sz, err;
18707c2aad20Sopenharmony_ci
18717c2aad20Sopenharmony_ci	sz = btf_type_size(src_type);
18727c2aad20Sopenharmony_ci	if (sz < 0)
18737c2aad20Sopenharmony_ci		return libbpf_err(sz);
18747c2aad20Sopenharmony_ci
18757c2aad20Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
18767c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
18777c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
18787c2aad20Sopenharmony_ci
18797c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
18807c2aad20Sopenharmony_ci	if (!t)
18817c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
18827c2aad20Sopenharmony_ci
18837c2aad20Sopenharmony_ci	memcpy(t, src_type, sz);
18847c2aad20Sopenharmony_ci
18857c2aad20Sopenharmony_ci	err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
18867c2aad20Sopenharmony_ci	if (err)
18877c2aad20Sopenharmony_ci		return libbpf_err(err);
18887c2aad20Sopenharmony_ci
18897c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
18907c2aad20Sopenharmony_ci}
18917c2aad20Sopenharmony_ci
18927c2aad20Sopenharmony_cistatic int btf_rewrite_type_ids(__u32 *type_id, void *ctx)
18937c2aad20Sopenharmony_ci{
18947c2aad20Sopenharmony_ci	struct btf *btf = ctx;
18957c2aad20Sopenharmony_ci
18967c2aad20Sopenharmony_ci	if (!*type_id) /* nothing to do for VOID references */
18977c2aad20Sopenharmony_ci		return 0;
18987c2aad20Sopenharmony_ci
18997c2aad20Sopenharmony_ci	/* we haven't updated btf's type count yet, so
19007c2aad20Sopenharmony_ci	 * btf->start_id + btf->nr_types - 1 is the type ID offset we should
19017c2aad20Sopenharmony_ci	 * add to all newly added BTF types
19027c2aad20Sopenharmony_ci	 */
19037c2aad20Sopenharmony_ci	*type_id += btf->start_id + btf->nr_types - 1;
19047c2aad20Sopenharmony_ci	return 0;
19057c2aad20Sopenharmony_ci}
19067c2aad20Sopenharmony_ci
19077c2aad20Sopenharmony_cistatic size_t btf_dedup_identity_hash_fn(long key, void *ctx);
19087c2aad20Sopenharmony_cistatic bool btf_dedup_equal_fn(long k1, long k2, void *ctx);
19097c2aad20Sopenharmony_ci
19107c2aad20Sopenharmony_ciint btf__add_btf(struct btf *btf, const struct btf *src_btf)
19117c2aad20Sopenharmony_ci{
19127c2aad20Sopenharmony_ci	struct btf_pipe p = { .src = src_btf, .dst = btf };
19137c2aad20Sopenharmony_ci	int data_sz, sz, cnt, i, err, old_strs_len;
19147c2aad20Sopenharmony_ci	__u32 *off;
19157c2aad20Sopenharmony_ci	void *t;
19167c2aad20Sopenharmony_ci
19177c2aad20Sopenharmony_ci	/* appending split BTF isn't supported yet */
19187c2aad20Sopenharmony_ci	if (src_btf->base_btf)
19197c2aad20Sopenharmony_ci		return libbpf_err(-ENOTSUP);
19207c2aad20Sopenharmony_ci
19217c2aad20Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
19227c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
19237c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
19247c2aad20Sopenharmony_ci
19257c2aad20Sopenharmony_ci	/* remember original strings section size if we have to roll back
19267c2aad20Sopenharmony_ci	 * partial strings section changes
19277c2aad20Sopenharmony_ci	 */
19287c2aad20Sopenharmony_ci	old_strs_len = btf->hdr->str_len;
19297c2aad20Sopenharmony_ci
19307c2aad20Sopenharmony_ci	data_sz = src_btf->hdr->type_len;
19317c2aad20Sopenharmony_ci	cnt = btf__type_cnt(src_btf) - 1;
19327c2aad20Sopenharmony_ci
19337c2aad20Sopenharmony_ci	/* pre-allocate enough memory for new types */
19347c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, data_sz);
19357c2aad20Sopenharmony_ci	if (!t)
19367c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
19377c2aad20Sopenharmony_ci
19387c2aad20Sopenharmony_ci	/* pre-allocate enough memory for type offset index for new types */
19397c2aad20Sopenharmony_ci	off = btf_add_type_offs_mem(btf, cnt);
19407c2aad20Sopenharmony_ci	if (!off)
19417c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
19427c2aad20Sopenharmony_ci
19437c2aad20Sopenharmony_ci	/* Map the string offsets from src_btf to the offsets from btf to improve performance */
19447c2aad20Sopenharmony_ci	p.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
19457c2aad20Sopenharmony_ci	if (IS_ERR(p.str_off_map))
19467c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
19477c2aad20Sopenharmony_ci
19487c2aad20Sopenharmony_ci	/* bulk copy types data for all types from src_btf */
19497c2aad20Sopenharmony_ci	memcpy(t, src_btf->types_data, data_sz);
19507c2aad20Sopenharmony_ci
19517c2aad20Sopenharmony_ci	for (i = 0; i < cnt; i++) {
19527c2aad20Sopenharmony_ci		sz = btf_type_size(t);
19537c2aad20Sopenharmony_ci		if (sz < 0) {
19547c2aad20Sopenharmony_ci			/* unlikely, has to be corrupted src_btf */
19557c2aad20Sopenharmony_ci			err = sz;
19567c2aad20Sopenharmony_ci			goto err_out;
19577c2aad20Sopenharmony_ci		}
19587c2aad20Sopenharmony_ci
19597c2aad20Sopenharmony_ci		/* fill out type ID to type offset mapping for lookups by type ID */
19607c2aad20Sopenharmony_ci		*off = t - btf->types_data;
19617c2aad20Sopenharmony_ci
19627c2aad20Sopenharmony_ci		/* add, dedup, and remap strings referenced by this BTF type */
19637c2aad20Sopenharmony_ci		err = btf_type_visit_str_offs(t, btf_rewrite_str, &p);
19647c2aad20Sopenharmony_ci		if (err)
19657c2aad20Sopenharmony_ci			goto err_out;
19667c2aad20Sopenharmony_ci
19677c2aad20Sopenharmony_ci		/* remap all type IDs referenced from this BTF type */
19687c2aad20Sopenharmony_ci		err = btf_type_visit_type_ids(t, btf_rewrite_type_ids, btf);
19697c2aad20Sopenharmony_ci		if (err)
19707c2aad20Sopenharmony_ci			goto err_out;
19717c2aad20Sopenharmony_ci
19727c2aad20Sopenharmony_ci		/* go to next type data and type offset index entry */
19737c2aad20Sopenharmony_ci		t += sz;
19747c2aad20Sopenharmony_ci		off++;
19757c2aad20Sopenharmony_ci	}
19767c2aad20Sopenharmony_ci
19777c2aad20Sopenharmony_ci	/* Up until now any of the copied type data was effectively invisible,
19787c2aad20Sopenharmony_ci	 * so if we exited early before this point due to error, BTF would be
19797c2aad20Sopenharmony_ci	 * effectively unmodified. There would be extra internal memory
19807c2aad20Sopenharmony_ci	 * pre-allocated, but it would not be available for querying.  But now
19817c2aad20Sopenharmony_ci	 * that we've copied and rewritten all the data successfully, we can
19827c2aad20Sopenharmony_ci	 * update type count and various internal offsets and sizes to
19837c2aad20Sopenharmony_ci	 * "commit" the changes and made them visible to the outside world.
19847c2aad20Sopenharmony_ci	 */
19857c2aad20Sopenharmony_ci	btf->hdr->type_len += data_sz;
19867c2aad20Sopenharmony_ci	btf->hdr->str_off += data_sz;
19877c2aad20Sopenharmony_ci	btf->nr_types += cnt;
19887c2aad20Sopenharmony_ci
19897c2aad20Sopenharmony_ci	hashmap__free(p.str_off_map);
19907c2aad20Sopenharmony_ci
19917c2aad20Sopenharmony_ci	/* return type ID of the first added BTF type */
19927c2aad20Sopenharmony_ci	return btf->start_id + btf->nr_types - cnt;
19937c2aad20Sopenharmony_cierr_out:
19947c2aad20Sopenharmony_ci	/* zero out preallocated memory as if it was just allocated with
19957c2aad20Sopenharmony_ci	 * libbpf_add_mem()
19967c2aad20Sopenharmony_ci	 */
19977c2aad20Sopenharmony_ci	memset(btf->types_data + btf->hdr->type_len, 0, data_sz);
19987c2aad20Sopenharmony_ci	memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
19997c2aad20Sopenharmony_ci
20007c2aad20Sopenharmony_ci	/* and now restore original strings section size; types data size
20017c2aad20Sopenharmony_ci	 * wasn't modified, so doesn't need restoring, see big comment above
20027c2aad20Sopenharmony_ci	 */
20037c2aad20Sopenharmony_ci	btf->hdr->str_len = old_strs_len;
20047c2aad20Sopenharmony_ci
20057c2aad20Sopenharmony_ci	hashmap__free(p.str_off_map);
20067c2aad20Sopenharmony_ci
20077c2aad20Sopenharmony_ci	return libbpf_err(err);
20087c2aad20Sopenharmony_ci}
20097c2aad20Sopenharmony_ci
20107c2aad20Sopenharmony_ci/*
20117c2aad20Sopenharmony_ci * Append new BTF_KIND_INT type with:
20127c2aad20Sopenharmony_ci *   - *name* - non-empty, non-NULL type name;
20137c2aad20Sopenharmony_ci *   - *sz* - power-of-2 (1, 2, 4, ..) size of the type, in bytes;
20147c2aad20Sopenharmony_ci *   - encoding is a combination of BTF_INT_SIGNED, BTF_INT_CHAR, BTF_INT_BOOL.
20157c2aad20Sopenharmony_ci * Returns:
20167c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
20177c2aad20Sopenharmony_ci *   - <0, on error.
20187c2aad20Sopenharmony_ci */
20197c2aad20Sopenharmony_ciint btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding)
20207c2aad20Sopenharmony_ci{
20217c2aad20Sopenharmony_ci	struct btf_type *t;
20227c2aad20Sopenharmony_ci	int sz, name_off;
20237c2aad20Sopenharmony_ci
20247c2aad20Sopenharmony_ci	/* non-empty name */
20257c2aad20Sopenharmony_ci	if (!name || !name[0])
20267c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
20277c2aad20Sopenharmony_ci	/* byte_sz must be power of 2 */
20287c2aad20Sopenharmony_ci	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16)
20297c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
20307c2aad20Sopenharmony_ci	if (encoding & ~(BTF_INT_SIGNED | BTF_INT_CHAR | BTF_INT_BOOL))
20317c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
20327c2aad20Sopenharmony_ci
20337c2aad20Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
20347c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
20357c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
20367c2aad20Sopenharmony_ci
20377c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(int);
20387c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
20397c2aad20Sopenharmony_ci	if (!t)
20407c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
20417c2aad20Sopenharmony_ci
20427c2aad20Sopenharmony_ci	/* if something goes wrong later, we might end up with an extra string,
20437c2aad20Sopenharmony_ci	 * but that shouldn't be a problem, because BTF can't be constructed
20447c2aad20Sopenharmony_ci	 * completely anyway and will most probably be just discarded
20457c2aad20Sopenharmony_ci	 */
20467c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
20477c2aad20Sopenharmony_ci	if (name_off < 0)
20487c2aad20Sopenharmony_ci		return name_off;
20497c2aad20Sopenharmony_ci
20507c2aad20Sopenharmony_ci	t->name_off = name_off;
20517c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_INT, 0, 0);
20527c2aad20Sopenharmony_ci	t->size = byte_sz;
20537c2aad20Sopenharmony_ci	/* set INT info, we don't allow setting legacy bit offset/size */
20547c2aad20Sopenharmony_ci	*(__u32 *)(t + 1) = (encoding << 24) | (byte_sz * 8);
20557c2aad20Sopenharmony_ci
20567c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
20577c2aad20Sopenharmony_ci}
20587c2aad20Sopenharmony_ci
20597c2aad20Sopenharmony_ci/*
20607c2aad20Sopenharmony_ci * Append new BTF_KIND_FLOAT type with:
20617c2aad20Sopenharmony_ci *   - *name* - non-empty, non-NULL type name;
20627c2aad20Sopenharmony_ci *   - *sz* - size of the type, in bytes;
20637c2aad20Sopenharmony_ci * Returns:
20647c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
20657c2aad20Sopenharmony_ci *   - <0, on error.
20667c2aad20Sopenharmony_ci */
20677c2aad20Sopenharmony_ciint btf__add_float(struct btf *btf, const char *name, size_t byte_sz)
20687c2aad20Sopenharmony_ci{
20697c2aad20Sopenharmony_ci	struct btf_type *t;
20707c2aad20Sopenharmony_ci	int sz, name_off;
20717c2aad20Sopenharmony_ci
20727c2aad20Sopenharmony_ci	/* non-empty name */
20737c2aad20Sopenharmony_ci	if (!name || !name[0])
20747c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
20757c2aad20Sopenharmony_ci
20767c2aad20Sopenharmony_ci	/* byte_sz must be one of the explicitly allowed values */
20777c2aad20Sopenharmony_ci	if (byte_sz != 2 && byte_sz != 4 && byte_sz != 8 && byte_sz != 12 &&
20787c2aad20Sopenharmony_ci	    byte_sz != 16)
20797c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
20807c2aad20Sopenharmony_ci
20817c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
20827c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
20837c2aad20Sopenharmony_ci
20847c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
20857c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
20867c2aad20Sopenharmony_ci	if (!t)
20877c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
20887c2aad20Sopenharmony_ci
20897c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
20907c2aad20Sopenharmony_ci	if (name_off < 0)
20917c2aad20Sopenharmony_ci		return name_off;
20927c2aad20Sopenharmony_ci
20937c2aad20Sopenharmony_ci	t->name_off = name_off;
20947c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0);
20957c2aad20Sopenharmony_ci	t->size = byte_sz;
20967c2aad20Sopenharmony_ci
20977c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
20987c2aad20Sopenharmony_ci}
20997c2aad20Sopenharmony_ci
21007c2aad20Sopenharmony_ci/* it's completely legal to append BTF types with type IDs pointing forward to
21017c2aad20Sopenharmony_ci * types that haven't been appended yet, so we only make sure that id looks
21027c2aad20Sopenharmony_ci * sane, we can't guarantee that ID will always be valid
21037c2aad20Sopenharmony_ci */
21047c2aad20Sopenharmony_cistatic int validate_type_id(int id)
21057c2aad20Sopenharmony_ci{
21067c2aad20Sopenharmony_ci	if (id < 0 || id > BTF_MAX_NR_TYPES)
21077c2aad20Sopenharmony_ci		return -EINVAL;
21087c2aad20Sopenharmony_ci	return 0;
21097c2aad20Sopenharmony_ci}
21107c2aad20Sopenharmony_ci
21117c2aad20Sopenharmony_ci/* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */
21127c2aad20Sopenharmony_cistatic int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id)
21137c2aad20Sopenharmony_ci{
21147c2aad20Sopenharmony_ci	struct btf_type *t;
21157c2aad20Sopenharmony_ci	int sz, name_off = 0;
21167c2aad20Sopenharmony_ci
21177c2aad20Sopenharmony_ci	if (validate_type_id(ref_type_id))
21187c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
21197c2aad20Sopenharmony_ci
21207c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
21217c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
21227c2aad20Sopenharmony_ci
21237c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
21247c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
21257c2aad20Sopenharmony_ci	if (!t)
21267c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
21277c2aad20Sopenharmony_ci
21287c2aad20Sopenharmony_ci	if (name && name[0]) {
21297c2aad20Sopenharmony_ci		name_off = btf__add_str(btf, name);
21307c2aad20Sopenharmony_ci		if (name_off < 0)
21317c2aad20Sopenharmony_ci			return name_off;
21327c2aad20Sopenharmony_ci	}
21337c2aad20Sopenharmony_ci
21347c2aad20Sopenharmony_ci	t->name_off = name_off;
21357c2aad20Sopenharmony_ci	t->info = btf_type_info(kind, 0, 0);
21367c2aad20Sopenharmony_ci	t->type = ref_type_id;
21377c2aad20Sopenharmony_ci
21387c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
21397c2aad20Sopenharmony_ci}
21407c2aad20Sopenharmony_ci
21417c2aad20Sopenharmony_ci/*
21427c2aad20Sopenharmony_ci * Append new BTF_KIND_PTR type with:
21437c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
21447c2aad20Sopenharmony_ci * Returns:
21457c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
21467c2aad20Sopenharmony_ci *   - <0, on error.
21477c2aad20Sopenharmony_ci */
21487c2aad20Sopenharmony_ciint btf__add_ptr(struct btf *btf, int ref_type_id)
21497c2aad20Sopenharmony_ci{
21507c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id);
21517c2aad20Sopenharmony_ci}
21527c2aad20Sopenharmony_ci
21537c2aad20Sopenharmony_ci/*
21547c2aad20Sopenharmony_ci * Append new BTF_KIND_ARRAY type with:
21557c2aad20Sopenharmony_ci *   - *index_type_id* - type ID of the type describing array index;
21567c2aad20Sopenharmony_ci *   - *elem_type_id* - type ID of the type describing array element;
21577c2aad20Sopenharmony_ci *   - *nr_elems* - the size of the array;
21587c2aad20Sopenharmony_ci * Returns:
21597c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
21607c2aad20Sopenharmony_ci *   - <0, on error.
21617c2aad20Sopenharmony_ci */
21627c2aad20Sopenharmony_ciint btf__add_array(struct btf *btf, int index_type_id, int elem_type_id, __u32 nr_elems)
21637c2aad20Sopenharmony_ci{
21647c2aad20Sopenharmony_ci	struct btf_type *t;
21657c2aad20Sopenharmony_ci	struct btf_array *a;
21667c2aad20Sopenharmony_ci	int sz;
21677c2aad20Sopenharmony_ci
21687c2aad20Sopenharmony_ci	if (validate_type_id(index_type_id) || validate_type_id(elem_type_id))
21697c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
21707c2aad20Sopenharmony_ci
21717c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
21727c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
21737c2aad20Sopenharmony_ci
21747c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_array);
21757c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
21767c2aad20Sopenharmony_ci	if (!t)
21777c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
21787c2aad20Sopenharmony_ci
21797c2aad20Sopenharmony_ci	t->name_off = 0;
21807c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_ARRAY, 0, 0);
21817c2aad20Sopenharmony_ci	t->size = 0;
21827c2aad20Sopenharmony_ci
21837c2aad20Sopenharmony_ci	a = btf_array(t);
21847c2aad20Sopenharmony_ci	a->type = elem_type_id;
21857c2aad20Sopenharmony_ci	a->index_type = index_type_id;
21867c2aad20Sopenharmony_ci	a->nelems = nr_elems;
21877c2aad20Sopenharmony_ci
21887c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
21897c2aad20Sopenharmony_ci}
21907c2aad20Sopenharmony_ci
21917c2aad20Sopenharmony_ci/* generic STRUCT/UNION append function */
21927c2aad20Sopenharmony_cistatic int btf_add_composite(struct btf *btf, int kind, const char *name, __u32 bytes_sz)
21937c2aad20Sopenharmony_ci{
21947c2aad20Sopenharmony_ci	struct btf_type *t;
21957c2aad20Sopenharmony_ci	int sz, name_off = 0;
21967c2aad20Sopenharmony_ci
21977c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
21987c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
21997c2aad20Sopenharmony_ci
22007c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
22017c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
22027c2aad20Sopenharmony_ci	if (!t)
22037c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
22047c2aad20Sopenharmony_ci
22057c2aad20Sopenharmony_ci	if (name && name[0]) {
22067c2aad20Sopenharmony_ci		name_off = btf__add_str(btf, name);
22077c2aad20Sopenharmony_ci		if (name_off < 0)
22087c2aad20Sopenharmony_ci			return name_off;
22097c2aad20Sopenharmony_ci	}
22107c2aad20Sopenharmony_ci
22117c2aad20Sopenharmony_ci	/* start out with vlen=0 and no kflag; this will be adjusted when
22127c2aad20Sopenharmony_ci	 * adding each member
22137c2aad20Sopenharmony_ci	 */
22147c2aad20Sopenharmony_ci	t->name_off = name_off;
22157c2aad20Sopenharmony_ci	t->info = btf_type_info(kind, 0, 0);
22167c2aad20Sopenharmony_ci	t->size = bytes_sz;
22177c2aad20Sopenharmony_ci
22187c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
22197c2aad20Sopenharmony_ci}
22207c2aad20Sopenharmony_ci
22217c2aad20Sopenharmony_ci/*
22227c2aad20Sopenharmony_ci * Append new BTF_KIND_STRUCT type with:
22237c2aad20Sopenharmony_ci *   - *name* - name of the struct, can be NULL or empty for anonymous structs;
22247c2aad20Sopenharmony_ci *   - *byte_sz* - size of the struct, in bytes;
22257c2aad20Sopenharmony_ci *
22267c2aad20Sopenharmony_ci * Struct initially has no fields in it. Fields can be added by
22277c2aad20Sopenharmony_ci * btf__add_field() right after btf__add_struct() succeeds.
22287c2aad20Sopenharmony_ci *
22297c2aad20Sopenharmony_ci * Returns:
22307c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
22317c2aad20Sopenharmony_ci *   - <0, on error.
22327c2aad20Sopenharmony_ci */
22337c2aad20Sopenharmony_ciint btf__add_struct(struct btf *btf, const char *name, __u32 byte_sz)
22347c2aad20Sopenharmony_ci{
22357c2aad20Sopenharmony_ci	return btf_add_composite(btf, BTF_KIND_STRUCT, name, byte_sz);
22367c2aad20Sopenharmony_ci}
22377c2aad20Sopenharmony_ci
22387c2aad20Sopenharmony_ci/*
22397c2aad20Sopenharmony_ci * Append new BTF_KIND_UNION type with:
22407c2aad20Sopenharmony_ci *   - *name* - name of the union, can be NULL or empty for anonymous union;
22417c2aad20Sopenharmony_ci *   - *byte_sz* - size of the union, in bytes;
22427c2aad20Sopenharmony_ci *
22437c2aad20Sopenharmony_ci * Union initially has no fields in it. Fields can be added by
22447c2aad20Sopenharmony_ci * btf__add_field() right after btf__add_union() succeeds. All fields
22457c2aad20Sopenharmony_ci * should have *bit_offset* of 0.
22467c2aad20Sopenharmony_ci *
22477c2aad20Sopenharmony_ci * Returns:
22487c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
22497c2aad20Sopenharmony_ci *   - <0, on error.
22507c2aad20Sopenharmony_ci */
22517c2aad20Sopenharmony_ciint btf__add_union(struct btf *btf, const char *name, __u32 byte_sz)
22527c2aad20Sopenharmony_ci{
22537c2aad20Sopenharmony_ci	return btf_add_composite(btf, BTF_KIND_UNION, name, byte_sz);
22547c2aad20Sopenharmony_ci}
22557c2aad20Sopenharmony_ci
22567c2aad20Sopenharmony_cistatic struct btf_type *btf_last_type(struct btf *btf)
22577c2aad20Sopenharmony_ci{
22587c2aad20Sopenharmony_ci	return btf_type_by_id(btf, btf__type_cnt(btf) - 1);
22597c2aad20Sopenharmony_ci}
22607c2aad20Sopenharmony_ci
22617c2aad20Sopenharmony_ci/*
22627c2aad20Sopenharmony_ci * Append new field for the current STRUCT/UNION type with:
22637c2aad20Sopenharmony_ci *   - *name* - name of the field, can be NULL or empty for anonymous field;
22647c2aad20Sopenharmony_ci *   - *type_id* - type ID for the type describing field type;
22657c2aad20Sopenharmony_ci *   - *bit_offset* - bit offset of the start of the field within struct/union;
22667c2aad20Sopenharmony_ci *   - *bit_size* - bit size of a bitfield, 0 for non-bitfield fields;
22677c2aad20Sopenharmony_ci * Returns:
22687c2aad20Sopenharmony_ci *   -  0, on success;
22697c2aad20Sopenharmony_ci *   - <0, on error.
22707c2aad20Sopenharmony_ci */
22717c2aad20Sopenharmony_ciint btf__add_field(struct btf *btf, const char *name, int type_id,
22727c2aad20Sopenharmony_ci		   __u32 bit_offset, __u32 bit_size)
22737c2aad20Sopenharmony_ci{
22747c2aad20Sopenharmony_ci	struct btf_type *t;
22757c2aad20Sopenharmony_ci	struct btf_member *m;
22767c2aad20Sopenharmony_ci	bool is_bitfield;
22777c2aad20Sopenharmony_ci	int sz, name_off = 0;
22787c2aad20Sopenharmony_ci
22797c2aad20Sopenharmony_ci	/* last type should be union/struct */
22807c2aad20Sopenharmony_ci	if (btf->nr_types == 0)
22817c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
22827c2aad20Sopenharmony_ci	t = btf_last_type(btf);
22837c2aad20Sopenharmony_ci	if (!btf_is_composite(t))
22847c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
22857c2aad20Sopenharmony_ci
22867c2aad20Sopenharmony_ci	if (validate_type_id(type_id))
22877c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
22887c2aad20Sopenharmony_ci	/* best-effort bit field offset/size enforcement */
22897c2aad20Sopenharmony_ci	is_bitfield = bit_size || (bit_offset % 8 != 0);
22907c2aad20Sopenharmony_ci	if (is_bitfield && (bit_size == 0 || bit_size > 255 || bit_offset > 0xffffff))
22917c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
22927c2aad20Sopenharmony_ci
22937c2aad20Sopenharmony_ci	/* only offset 0 is allowed for unions */
22947c2aad20Sopenharmony_ci	if (btf_is_union(t) && bit_offset)
22957c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
22967c2aad20Sopenharmony_ci
22977c2aad20Sopenharmony_ci	/* decompose and invalidate raw data */
22987c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
22997c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
23007c2aad20Sopenharmony_ci
23017c2aad20Sopenharmony_ci	sz = sizeof(struct btf_member);
23027c2aad20Sopenharmony_ci	m = btf_add_type_mem(btf, sz);
23037c2aad20Sopenharmony_ci	if (!m)
23047c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
23057c2aad20Sopenharmony_ci
23067c2aad20Sopenharmony_ci	if (name && name[0]) {
23077c2aad20Sopenharmony_ci		name_off = btf__add_str(btf, name);
23087c2aad20Sopenharmony_ci		if (name_off < 0)
23097c2aad20Sopenharmony_ci			return name_off;
23107c2aad20Sopenharmony_ci	}
23117c2aad20Sopenharmony_ci
23127c2aad20Sopenharmony_ci	m->name_off = name_off;
23137c2aad20Sopenharmony_ci	m->type = type_id;
23147c2aad20Sopenharmony_ci	m->offset = bit_offset | (bit_size << 24);
23157c2aad20Sopenharmony_ci
23167c2aad20Sopenharmony_ci	/* btf_add_type_mem can invalidate t pointer */
23177c2aad20Sopenharmony_ci	t = btf_last_type(btf);
23187c2aad20Sopenharmony_ci	/* update parent type's vlen and kflag */
23197c2aad20Sopenharmony_ci	t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
23207c2aad20Sopenharmony_ci
23217c2aad20Sopenharmony_ci	btf->hdr->type_len += sz;
23227c2aad20Sopenharmony_ci	btf->hdr->str_off += sz;
23237c2aad20Sopenharmony_ci	return 0;
23247c2aad20Sopenharmony_ci}
23257c2aad20Sopenharmony_ci
23267c2aad20Sopenharmony_cistatic int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
23277c2aad20Sopenharmony_ci			       bool is_signed, __u8 kind)
23287c2aad20Sopenharmony_ci{
23297c2aad20Sopenharmony_ci	struct btf_type *t;
23307c2aad20Sopenharmony_ci	int sz, name_off = 0;
23317c2aad20Sopenharmony_ci
23327c2aad20Sopenharmony_ci	/* byte_sz must be power of 2 */
23337c2aad20Sopenharmony_ci	if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 8)
23347c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
23357c2aad20Sopenharmony_ci
23367c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
23377c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
23387c2aad20Sopenharmony_ci
23397c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
23407c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
23417c2aad20Sopenharmony_ci	if (!t)
23427c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
23437c2aad20Sopenharmony_ci
23447c2aad20Sopenharmony_ci	if (name && name[0]) {
23457c2aad20Sopenharmony_ci		name_off = btf__add_str(btf, name);
23467c2aad20Sopenharmony_ci		if (name_off < 0)
23477c2aad20Sopenharmony_ci			return name_off;
23487c2aad20Sopenharmony_ci	}
23497c2aad20Sopenharmony_ci
23507c2aad20Sopenharmony_ci	/* start out with vlen=0; it will be adjusted when adding enum values */
23517c2aad20Sopenharmony_ci	t->name_off = name_off;
23527c2aad20Sopenharmony_ci	t->info = btf_type_info(kind, 0, is_signed);
23537c2aad20Sopenharmony_ci	t->size = byte_sz;
23547c2aad20Sopenharmony_ci
23557c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
23567c2aad20Sopenharmony_ci}
23577c2aad20Sopenharmony_ci
23587c2aad20Sopenharmony_ci/*
23597c2aad20Sopenharmony_ci * Append new BTF_KIND_ENUM type with:
23607c2aad20Sopenharmony_ci *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
23617c2aad20Sopenharmony_ci *   - *byte_sz* - size of the enum, in bytes.
23627c2aad20Sopenharmony_ci *
23637c2aad20Sopenharmony_ci * Enum initially has no enum values in it (and corresponds to enum forward
23647c2aad20Sopenharmony_ci * declaration). Enumerator values can be added by btf__add_enum_value()
23657c2aad20Sopenharmony_ci * immediately after btf__add_enum() succeeds.
23667c2aad20Sopenharmony_ci *
23677c2aad20Sopenharmony_ci * Returns:
23687c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
23697c2aad20Sopenharmony_ci *   - <0, on error.
23707c2aad20Sopenharmony_ci */
23717c2aad20Sopenharmony_ciint btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
23727c2aad20Sopenharmony_ci{
23737c2aad20Sopenharmony_ci	/*
23747c2aad20Sopenharmony_ci	 * set the signedness to be unsigned, it will change to signed
23757c2aad20Sopenharmony_ci	 * if any later enumerator is negative.
23767c2aad20Sopenharmony_ci	 */
23777c2aad20Sopenharmony_ci	return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
23787c2aad20Sopenharmony_ci}
23797c2aad20Sopenharmony_ci
23807c2aad20Sopenharmony_ci/*
23817c2aad20Sopenharmony_ci * Append new enum value for the current ENUM type with:
23827c2aad20Sopenharmony_ci *   - *name* - name of the enumerator value, can't be NULL or empty;
23837c2aad20Sopenharmony_ci *   - *value* - integer value corresponding to enum value *name*;
23847c2aad20Sopenharmony_ci * Returns:
23857c2aad20Sopenharmony_ci *   -  0, on success;
23867c2aad20Sopenharmony_ci *   - <0, on error.
23877c2aad20Sopenharmony_ci */
23887c2aad20Sopenharmony_ciint btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
23897c2aad20Sopenharmony_ci{
23907c2aad20Sopenharmony_ci	struct btf_type *t;
23917c2aad20Sopenharmony_ci	struct btf_enum *v;
23927c2aad20Sopenharmony_ci	int sz, name_off;
23937c2aad20Sopenharmony_ci
23947c2aad20Sopenharmony_ci	/* last type should be BTF_KIND_ENUM */
23957c2aad20Sopenharmony_ci	if (btf->nr_types == 0)
23967c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
23977c2aad20Sopenharmony_ci	t = btf_last_type(btf);
23987c2aad20Sopenharmony_ci	if (!btf_is_enum(t))
23997c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
24007c2aad20Sopenharmony_ci
24017c2aad20Sopenharmony_ci	/* non-empty name */
24027c2aad20Sopenharmony_ci	if (!name || !name[0])
24037c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
24047c2aad20Sopenharmony_ci	if (value < INT_MIN || value > UINT_MAX)
24057c2aad20Sopenharmony_ci		return libbpf_err(-E2BIG);
24067c2aad20Sopenharmony_ci
24077c2aad20Sopenharmony_ci	/* decompose and invalidate raw data */
24087c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
24097c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
24107c2aad20Sopenharmony_ci
24117c2aad20Sopenharmony_ci	sz = sizeof(struct btf_enum);
24127c2aad20Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
24137c2aad20Sopenharmony_ci	if (!v)
24147c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
24157c2aad20Sopenharmony_ci
24167c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
24177c2aad20Sopenharmony_ci	if (name_off < 0)
24187c2aad20Sopenharmony_ci		return name_off;
24197c2aad20Sopenharmony_ci
24207c2aad20Sopenharmony_ci	v->name_off = name_off;
24217c2aad20Sopenharmony_ci	v->val = value;
24227c2aad20Sopenharmony_ci
24237c2aad20Sopenharmony_ci	/* update parent type's vlen */
24247c2aad20Sopenharmony_ci	t = btf_last_type(btf);
24257c2aad20Sopenharmony_ci	btf_type_inc_vlen(t);
24267c2aad20Sopenharmony_ci
24277c2aad20Sopenharmony_ci	/* if negative value, set signedness to signed */
24287c2aad20Sopenharmony_ci	if (value < 0)
24297c2aad20Sopenharmony_ci		t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
24307c2aad20Sopenharmony_ci
24317c2aad20Sopenharmony_ci	btf->hdr->type_len += sz;
24327c2aad20Sopenharmony_ci	btf->hdr->str_off += sz;
24337c2aad20Sopenharmony_ci	return 0;
24347c2aad20Sopenharmony_ci}
24357c2aad20Sopenharmony_ci
24367c2aad20Sopenharmony_ci/*
24377c2aad20Sopenharmony_ci * Append new BTF_KIND_ENUM64 type with:
24387c2aad20Sopenharmony_ci *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
24397c2aad20Sopenharmony_ci *   - *byte_sz* - size of the enum, in bytes.
24407c2aad20Sopenharmony_ci *   - *is_signed* - whether the enum values are signed or not;
24417c2aad20Sopenharmony_ci *
24427c2aad20Sopenharmony_ci * Enum initially has no enum values in it (and corresponds to enum forward
24437c2aad20Sopenharmony_ci * declaration). Enumerator values can be added by btf__add_enum64_value()
24447c2aad20Sopenharmony_ci * immediately after btf__add_enum64() succeeds.
24457c2aad20Sopenharmony_ci *
24467c2aad20Sopenharmony_ci * Returns:
24477c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
24487c2aad20Sopenharmony_ci *   - <0, on error.
24497c2aad20Sopenharmony_ci */
24507c2aad20Sopenharmony_ciint btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
24517c2aad20Sopenharmony_ci		    bool is_signed)
24527c2aad20Sopenharmony_ci{
24537c2aad20Sopenharmony_ci	return btf_add_enum_common(btf, name, byte_sz, is_signed,
24547c2aad20Sopenharmony_ci				   BTF_KIND_ENUM64);
24557c2aad20Sopenharmony_ci}
24567c2aad20Sopenharmony_ci
24577c2aad20Sopenharmony_ci/*
24587c2aad20Sopenharmony_ci * Append new enum value for the current ENUM64 type with:
24597c2aad20Sopenharmony_ci *   - *name* - name of the enumerator value, can't be NULL or empty;
24607c2aad20Sopenharmony_ci *   - *value* - integer value corresponding to enum value *name*;
24617c2aad20Sopenharmony_ci * Returns:
24627c2aad20Sopenharmony_ci *   -  0, on success;
24637c2aad20Sopenharmony_ci *   - <0, on error.
24647c2aad20Sopenharmony_ci */
24657c2aad20Sopenharmony_ciint btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
24667c2aad20Sopenharmony_ci{
24677c2aad20Sopenharmony_ci	struct btf_enum64 *v;
24687c2aad20Sopenharmony_ci	struct btf_type *t;
24697c2aad20Sopenharmony_ci	int sz, name_off;
24707c2aad20Sopenharmony_ci
24717c2aad20Sopenharmony_ci	/* last type should be BTF_KIND_ENUM64 */
24727c2aad20Sopenharmony_ci	if (btf->nr_types == 0)
24737c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
24747c2aad20Sopenharmony_ci	t = btf_last_type(btf);
24757c2aad20Sopenharmony_ci	if (!btf_is_enum64(t))
24767c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
24777c2aad20Sopenharmony_ci
24787c2aad20Sopenharmony_ci	/* non-empty name */
24797c2aad20Sopenharmony_ci	if (!name || !name[0])
24807c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
24817c2aad20Sopenharmony_ci
24827c2aad20Sopenharmony_ci	/* decompose and invalidate raw data */
24837c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
24847c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
24857c2aad20Sopenharmony_ci
24867c2aad20Sopenharmony_ci	sz = sizeof(struct btf_enum64);
24877c2aad20Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
24887c2aad20Sopenharmony_ci	if (!v)
24897c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
24907c2aad20Sopenharmony_ci
24917c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
24927c2aad20Sopenharmony_ci	if (name_off < 0)
24937c2aad20Sopenharmony_ci		return name_off;
24947c2aad20Sopenharmony_ci
24957c2aad20Sopenharmony_ci	v->name_off = name_off;
24967c2aad20Sopenharmony_ci	v->val_lo32 = (__u32)value;
24977c2aad20Sopenharmony_ci	v->val_hi32 = value >> 32;
24987c2aad20Sopenharmony_ci
24997c2aad20Sopenharmony_ci	/* update parent type's vlen */
25007c2aad20Sopenharmony_ci	t = btf_last_type(btf);
25017c2aad20Sopenharmony_ci	btf_type_inc_vlen(t);
25027c2aad20Sopenharmony_ci
25037c2aad20Sopenharmony_ci	btf->hdr->type_len += sz;
25047c2aad20Sopenharmony_ci	btf->hdr->str_off += sz;
25057c2aad20Sopenharmony_ci	return 0;
25067c2aad20Sopenharmony_ci}
25077c2aad20Sopenharmony_ci
25087c2aad20Sopenharmony_ci/*
25097c2aad20Sopenharmony_ci * Append new BTF_KIND_FWD type with:
25107c2aad20Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
25117c2aad20Sopenharmony_ci *   - *fwd_kind*, kind of forward declaration, one of BTF_FWD_STRUCT,
25127c2aad20Sopenharmony_ci *     BTF_FWD_UNION, or BTF_FWD_ENUM;
25137c2aad20Sopenharmony_ci * Returns:
25147c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
25157c2aad20Sopenharmony_ci *   - <0, on error.
25167c2aad20Sopenharmony_ci */
25177c2aad20Sopenharmony_ciint btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind)
25187c2aad20Sopenharmony_ci{
25197c2aad20Sopenharmony_ci	if (!name || !name[0])
25207c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
25217c2aad20Sopenharmony_ci
25227c2aad20Sopenharmony_ci	switch (fwd_kind) {
25237c2aad20Sopenharmony_ci	case BTF_FWD_STRUCT:
25247c2aad20Sopenharmony_ci	case BTF_FWD_UNION: {
25257c2aad20Sopenharmony_ci		struct btf_type *t;
25267c2aad20Sopenharmony_ci		int id;
25277c2aad20Sopenharmony_ci
25287c2aad20Sopenharmony_ci		id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0);
25297c2aad20Sopenharmony_ci		if (id <= 0)
25307c2aad20Sopenharmony_ci			return id;
25317c2aad20Sopenharmony_ci		t = btf_type_by_id(btf, id);
25327c2aad20Sopenharmony_ci		t->info = btf_type_info(BTF_KIND_FWD, 0, fwd_kind == BTF_FWD_UNION);
25337c2aad20Sopenharmony_ci		return id;
25347c2aad20Sopenharmony_ci	}
25357c2aad20Sopenharmony_ci	case BTF_FWD_ENUM:
25367c2aad20Sopenharmony_ci		/* enum forward in BTF currently is just an enum with no enum
25377c2aad20Sopenharmony_ci		 * values; we also assume a standard 4-byte size for it
25387c2aad20Sopenharmony_ci		 */
25397c2aad20Sopenharmony_ci		return btf__add_enum(btf, name, sizeof(int));
25407c2aad20Sopenharmony_ci	default:
25417c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
25427c2aad20Sopenharmony_ci	}
25437c2aad20Sopenharmony_ci}
25447c2aad20Sopenharmony_ci
25457c2aad20Sopenharmony_ci/*
25467c2aad20Sopenharmony_ci * Append new BTF_KING_TYPEDEF type with:
25477c2aad20Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
25487c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
25497c2aad20Sopenharmony_ci * Returns:
25507c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
25517c2aad20Sopenharmony_ci *   - <0, on error.
25527c2aad20Sopenharmony_ci */
25537c2aad20Sopenharmony_ciint btf__add_typedef(struct btf *btf, const char *name, int ref_type_id)
25547c2aad20Sopenharmony_ci{
25557c2aad20Sopenharmony_ci	if (!name || !name[0])
25567c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
25577c2aad20Sopenharmony_ci
25587c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id);
25597c2aad20Sopenharmony_ci}
25607c2aad20Sopenharmony_ci
25617c2aad20Sopenharmony_ci/*
25627c2aad20Sopenharmony_ci * Append new BTF_KIND_VOLATILE type with:
25637c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
25647c2aad20Sopenharmony_ci * Returns:
25657c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
25667c2aad20Sopenharmony_ci *   - <0, on error.
25677c2aad20Sopenharmony_ci */
25687c2aad20Sopenharmony_ciint btf__add_volatile(struct btf *btf, int ref_type_id)
25697c2aad20Sopenharmony_ci{
25707c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id);
25717c2aad20Sopenharmony_ci}
25727c2aad20Sopenharmony_ci
25737c2aad20Sopenharmony_ci/*
25747c2aad20Sopenharmony_ci * Append new BTF_KIND_CONST type with:
25757c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
25767c2aad20Sopenharmony_ci * Returns:
25777c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
25787c2aad20Sopenharmony_ci *   - <0, on error.
25797c2aad20Sopenharmony_ci */
25807c2aad20Sopenharmony_ciint btf__add_const(struct btf *btf, int ref_type_id)
25817c2aad20Sopenharmony_ci{
25827c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id);
25837c2aad20Sopenharmony_ci}
25847c2aad20Sopenharmony_ci
25857c2aad20Sopenharmony_ci/*
25867c2aad20Sopenharmony_ci * Append new BTF_KIND_RESTRICT type with:
25877c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
25887c2aad20Sopenharmony_ci * Returns:
25897c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
25907c2aad20Sopenharmony_ci *   - <0, on error.
25917c2aad20Sopenharmony_ci */
25927c2aad20Sopenharmony_ciint btf__add_restrict(struct btf *btf, int ref_type_id)
25937c2aad20Sopenharmony_ci{
25947c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id);
25957c2aad20Sopenharmony_ci}
25967c2aad20Sopenharmony_ci
25977c2aad20Sopenharmony_ci/*
25987c2aad20Sopenharmony_ci * Append new BTF_KIND_TYPE_TAG type with:
25997c2aad20Sopenharmony_ci *   - *value*, non-empty/non-NULL tag value;
26007c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
26017c2aad20Sopenharmony_ci * Returns:
26027c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
26037c2aad20Sopenharmony_ci *   - <0, on error.
26047c2aad20Sopenharmony_ci */
26057c2aad20Sopenharmony_ciint btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
26067c2aad20Sopenharmony_ci{
26077c2aad20Sopenharmony_ci	if (!value || !value[0])
26087c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26097c2aad20Sopenharmony_ci
26107c2aad20Sopenharmony_ci	return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
26117c2aad20Sopenharmony_ci}
26127c2aad20Sopenharmony_ci
26137c2aad20Sopenharmony_ci/*
26147c2aad20Sopenharmony_ci * Append new BTF_KIND_FUNC type with:
26157c2aad20Sopenharmony_ci *   - *name*, non-empty/non-NULL name;
26167c2aad20Sopenharmony_ci *   - *proto_type_id* - FUNC_PROTO's type ID, it might not exist yet;
26177c2aad20Sopenharmony_ci * Returns:
26187c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
26197c2aad20Sopenharmony_ci *   - <0, on error.
26207c2aad20Sopenharmony_ci */
26217c2aad20Sopenharmony_ciint btf__add_func(struct btf *btf, const char *name,
26227c2aad20Sopenharmony_ci		  enum btf_func_linkage linkage, int proto_type_id)
26237c2aad20Sopenharmony_ci{
26247c2aad20Sopenharmony_ci	int id;
26257c2aad20Sopenharmony_ci
26267c2aad20Sopenharmony_ci	if (!name || !name[0])
26277c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26287c2aad20Sopenharmony_ci	if (linkage != BTF_FUNC_STATIC && linkage != BTF_FUNC_GLOBAL &&
26297c2aad20Sopenharmony_ci	    linkage != BTF_FUNC_EXTERN)
26307c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26317c2aad20Sopenharmony_ci
26327c2aad20Sopenharmony_ci	id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id);
26337c2aad20Sopenharmony_ci	if (id > 0) {
26347c2aad20Sopenharmony_ci		struct btf_type *t = btf_type_by_id(btf, id);
26357c2aad20Sopenharmony_ci
26367c2aad20Sopenharmony_ci		t->info = btf_type_info(BTF_KIND_FUNC, linkage, 0);
26377c2aad20Sopenharmony_ci	}
26387c2aad20Sopenharmony_ci	return libbpf_err(id);
26397c2aad20Sopenharmony_ci}
26407c2aad20Sopenharmony_ci
26417c2aad20Sopenharmony_ci/*
26427c2aad20Sopenharmony_ci * Append new BTF_KIND_FUNC_PROTO with:
26437c2aad20Sopenharmony_ci *   - *ret_type_id* - type ID for return result of a function.
26447c2aad20Sopenharmony_ci *
26457c2aad20Sopenharmony_ci * Function prototype initially has no arguments, but they can be added by
26467c2aad20Sopenharmony_ci * btf__add_func_param() one by one, immediately after
26477c2aad20Sopenharmony_ci * btf__add_func_proto() succeeded.
26487c2aad20Sopenharmony_ci *
26497c2aad20Sopenharmony_ci * Returns:
26507c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
26517c2aad20Sopenharmony_ci *   - <0, on error.
26527c2aad20Sopenharmony_ci */
26537c2aad20Sopenharmony_ciint btf__add_func_proto(struct btf *btf, int ret_type_id)
26547c2aad20Sopenharmony_ci{
26557c2aad20Sopenharmony_ci	struct btf_type *t;
26567c2aad20Sopenharmony_ci	int sz;
26577c2aad20Sopenharmony_ci
26587c2aad20Sopenharmony_ci	if (validate_type_id(ret_type_id))
26597c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26607c2aad20Sopenharmony_ci
26617c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
26627c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
26637c2aad20Sopenharmony_ci
26647c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
26657c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
26667c2aad20Sopenharmony_ci	if (!t)
26677c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
26687c2aad20Sopenharmony_ci
26697c2aad20Sopenharmony_ci	/* start out with vlen=0; this will be adjusted when adding enum
26707c2aad20Sopenharmony_ci	 * values, if necessary
26717c2aad20Sopenharmony_ci	 */
26727c2aad20Sopenharmony_ci	t->name_off = 0;
26737c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_FUNC_PROTO, 0, 0);
26747c2aad20Sopenharmony_ci	t->type = ret_type_id;
26757c2aad20Sopenharmony_ci
26767c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
26777c2aad20Sopenharmony_ci}
26787c2aad20Sopenharmony_ci
26797c2aad20Sopenharmony_ci/*
26807c2aad20Sopenharmony_ci * Append new function parameter for current FUNC_PROTO type with:
26817c2aad20Sopenharmony_ci *   - *name* - parameter name, can be NULL or empty;
26827c2aad20Sopenharmony_ci *   - *type_id* - type ID describing the type of the parameter.
26837c2aad20Sopenharmony_ci * Returns:
26847c2aad20Sopenharmony_ci *   -  0, on success;
26857c2aad20Sopenharmony_ci *   - <0, on error.
26867c2aad20Sopenharmony_ci */
26877c2aad20Sopenharmony_ciint btf__add_func_param(struct btf *btf, const char *name, int type_id)
26887c2aad20Sopenharmony_ci{
26897c2aad20Sopenharmony_ci	struct btf_type *t;
26907c2aad20Sopenharmony_ci	struct btf_param *p;
26917c2aad20Sopenharmony_ci	int sz, name_off = 0;
26927c2aad20Sopenharmony_ci
26937c2aad20Sopenharmony_ci	if (validate_type_id(type_id))
26947c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26957c2aad20Sopenharmony_ci
26967c2aad20Sopenharmony_ci	/* last type should be BTF_KIND_FUNC_PROTO */
26977c2aad20Sopenharmony_ci	if (btf->nr_types == 0)
26987c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
26997c2aad20Sopenharmony_ci	t = btf_last_type(btf);
27007c2aad20Sopenharmony_ci	if (!btf_is_func_proto(t))
27017c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
27027c2aad20Sopenharmony_ci
27037c2aad20Sopenharmony_ci	/* decompose and invalidate raw data */
27047c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
27057c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
27067c2aad20Sopenharmony_ci
27077c2aad20Sopenharmony_ci	sz = sizeof(struct btf_param);
27087c2aad20Sopenharmony_ci	p = btf_add_type_mem(btf, sz);
27097c2aad20Sopenharmony_ci	if (!p)
27107c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
27117c2aad20Sopenharmony_ci
27127c2aad20Sopenharmony_ci	if (name && name[0]) {
27137c2aad20Sopenharmony_ci		name_off = btf__add_str(btf, name);
27147c2aad20Sopenharmony_ci		if (name_off < 0)
27157c2aad20Sopenharmony_ci			return name_off;
27167c2aad20Sopenharmony_ci	}
27177c2aad20Sopenharmony_ci
27187c2aad20Sopenharmony_ci	p->name_off = name_off;
27197c2aad20Sopenharmony_ci	p->type = type_id;
27207c2aad20Sopenharmony_ci
27217c2aad20Sopenharmony_ci	/* update parent type's vlen */
27227c2aad20Sopenharmony_ci	t = btf_last_type(btf);
27237c2aad20Sopenharmony_ci	btf_type_inc_vlen(t);
27247c2aad20Sopenharmony_ci
27257c2aad20Sopenharmony_ci	btf->hdr->type_len += sz;
27267c2aad20Sopenharmony_ci	btf->hdr->str_off += sz;
27277c2aad20Sopenharmony_ci	return 0;
27287c2aad20Sopenharmony_ci}
27297c2aad20Sopenharmony_ci
27307c2aad20Sopenharmony_ci/*
27317c2aad20Sopenharmony_ci * Append new BTF_KIND_VAR type with:
27327c2aad20Sopenharmony_ci *   - *name* - non-empty/non-NULL name;
27337c2aad20Sopenharmony_ci *   - *linkage* - variable linkage, one of BTF_VAR_STATIC,
27347c2aad20Sopenharmony_ci *     BTF_VAR_GLOBAL_ALLOCATED, or BTF_VAR_GLOBAL_EXTERN;
27357c2aad20Sopenharmony_ci *   - *type_id* - type ID of the type describing the type of the variable.
27367c2aad20Sopenharmony_ci * Returns:
27377c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
27387c2aad20Sopenharmony_ci *   - <0, on error.
27397c2aad20Sopenharmony_ci */
27407c2aad20Sopenharmony_ciint btf__add_var(struct btf *btf, const char *name, int linkage, int type_id)
27417c2aad20Sopenharmony_ci{
27427c2aad20Sopenharmony_ci	struct btf_type *t;
27437c2aad20Sopenharmony_ci	struct btf_var *v;
27447c2aad20Sopenharmony_ci	int sz, name_off;
27457c2aad20Sopenharmony_ci
27467c2aad20Sopenharmony_ci	/* non-empty name */
27477c2aad20Sopenharmony_ci	if (!name || !name[0])
27487c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
27497c2aad20Sopenharmony_ci	if (linkage != BTF_VAR_STATIC && linkage != BTF_VAR_GLOBAL_ALLOCATED &&
27507c2aad20Sopenharmony_ci	    linkage != BTF_VAR_GLOBAL_EXTERN)
27517c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
27527c2aad20Sopenharmony_ci	if (validate_type_id(type_id))
27537c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
27547c2aad20Sopenharmony_ci
27557c2aad20Sopenharmony_ci	/* deconstruct BTF, if necessary, and invalidate raw_data */
27567c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
27577c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
27587c2aad20Sopenharmony_ci
27597c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_var);
27607c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
27617c2aad20Sopenharmony_ci	if (!t)
27627c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
27637c2aad20Sopenharmony_ci
27647c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
27657c2aad20Sopenharmony_ci	if (name_off < 0)
27667c2aad20Sopenharmony_ci		return name_off;
27677c2aad20Sopenharmony_ci
27687c2aad20Sopenharmony_ci	t->name_off = name_off;
27697c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_VAR, 0, 0);
27707c2aad20Sopenharmony_ci	t->type = type_id;
27717c2aad20Sopenharmony_ci
27727c2aad20Sopenharmony_ci	v = btf_var(t);
27737c2aad20Sopenharmony_ci	v->linkage = linkage;
27747c2aad20Sopenharmony_ci
27757c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
27767c2aad20Sopenharmony_ci}
27777c2aad20Sopenharmony_ci
27787c2aad20Sopenharmony_ci/*
27797c2aad20Sopenharmony_ci * Append new BTF_KIND_DATASEC type with:
27807c2aad20Sopenharmony_ci *   - *name* - non-empty/non-NULL name;
27817c2aad20Sopenharmony_ci *   - *byte_sz* - data section size, in bytes.
27827c2aad20Sopenharmony_ci *
27837c2aad20Sopenharmony_ci * Data section is initially empty. Variables info can be added with
27847c2aad20Sopenharmony_ci * btf__add_datasec_var_info() calls, after btf__add_datasec() succeeds.
27857c2aad20Sopenharmony_ci *
27867c2aad20Sopenharmony_ci * Returns:
27877c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
27887c2aad20Sopenharmony_ci *   - <0, on error.
27897c2aad20Sopenharmony_ci */
27907c2aad20Sopenharmony_ciint btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz)
27917c2aad20Sopenharmony_ci{
27927c2aad20Sopenharmony_ci	struct btf_type *t;
27937c2aad20Sopenharmony_ci	int sz, name_off;
27947c2aad20Sopenharmony_ci
27957c2aad20Sopenharmony_ci	/* non-empty name */
27967c2aad20Sopenharmony_ci	if (!name || !name[0])
27977c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
27987c2aad20Sopenharmony_ci
27997c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
28007c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28017c2aad20Sopenharmony_ci
28027c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type);
28037c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
28047c2aad20Sopenharmony_ci	if (!t)
28057c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28067c2aad20Sopenharmony_ci
28077c2aad20Sopenharmony_ci	name_off = btf__add_str(btf, name);
28087c2aad20Sopenharmony_ci	if (name_off < 0)
28097c2aad20Sopenharmony_ci		return name_off;
28107c2aad20Sopenharmony_ci
28117c2aad20Sopenharmony_ci	/* start with vlen=0, which will be update as var_secinfos are added */
28127c2aad20Sopenharmony_ci	t->name_off = name_off;
28137c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_DATASEC, 0, 0);
28147c2aad20Sopenharmony_ci	t->size = byte_sz;
28157c2aad20Sopenharmony_ci
28167c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
28177c2aad20Sopenharmony_ci}
28187c2aad20Sopenharmony_ci
28197c2aad20Sopenharmony_ci/*
28207c2aad20Sopenharmony_ci * Append new data section variable information entry for current DATASEC type:
28217c2aad20Sopenharmony_ci *   - *var_type_id* - type ID, describing type of the variable;
28227c2aad20Sopenharmony_ci *   - *offset* - variable offset within data section, in bytes;
28237c2aad20Sopenharmony_ci *   - *byte_sz* - variable size, in bytes.
28247c2aad20Sopenharmony_ci *
28257c2aad20Sopenharmony_ci * Returns:
28267c2aad20Sopenharmony_ci *   -  0, on success;
28277c2aad20Sopenharmony_ci *   - <0, on error.
28287c2aad20Sopenharmony_ci */
28297c2aad20Sopenharmony_ciint btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz)
28307c2aad20Sopenharmony_ci{
28317c2aad20Sopenharmony_ci	struct btf_type *t;
28327c2aad20Sopenharmony_ci	struct btf_var_secinfo *v;
28337c2aad20Sopenharmony_ci	int sz;
28347c2aad20Sopenharmony_ci
28357c2aad20Sopenharmony_ci	/* last type should be BTF_KIND_DATASEC */
28367c2aad20Sopenharmony_ci	if (btf->nr_types == 0)
28377c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
28387c2aad20Sopenharmony_ci	t = btf_last_type(btf);
28397c2aad20Sopenharmony_ci	if (!btf_is_datasec(t))
28407c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
28417c2aad20Sopenharmony_ci
28427c2aad20Sopenharmony_ci	if (validate_type_id(var_type_id))
28437c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
28447c2aad20Sopenharmony_ci
28457c2aad20Sopenharmony_ci	/* decompose and invalidate raw data */
28467c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
28477c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28487c2aad20Sopenharmony_ci
28497c2aad20Sopenharmony_ci	sz = sizeof(struct btf_var_secinfo);
28507c2aad20Sopenharmony_ci	v = btf_add_type_mem(btf, sz);
28517c2aad20Sopenharmony_ci	if (!v)
28527c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28537c2aad20Sopenharmony_ci
28547c2aad20Sopenharmony_ci	v->type = var_type_id;
28557c2aad20Sopenharmony_ci	v->offset = offset;
28567c2aad20Sopenharmony_ci	v->size = byte_sz;
28577c2aad20Sopenharmony_ci
28587c2aad20Sopenharmony_ci	/* update parent type's vlen */
28597c2aad20Sopenharmony_ci	t = btf_last_type(btf);
28607c2aad20Sopenharmony_ci	btf_type_inc_vlen(t);
28617c2aad20Sopenharmony_ci
28627c2aad20Sopenharmony_ci	btf->hdr->type_len += sz;
28637c2aad20Sopenharmony_ci	btf->hdr->str_off += sz;
28647c2aad20Sopenharmony_ci	return 0;
28657c2aad20Sopenharmony_ci}
28667c2aad20Sopenharmony_ci
28677c2aad20Sopenharmony_ci/*
28687c2aad20Sopenharmony_ci * Append new BTF_KIND_DECL_TAG type with:
28697c2aad20Sopenharmony_ci *   - *value* - non-empty/non-NULL string;
28707c2aad20Sopenharmony_ci *   - *ref_type_id* - referenced type ID, it might not exist yet;
28717c2aad20Sopenharmony_ci *   - *component_idx* - -1 for tagging reference type, otherwise struct/union
28727c2aad20Sopenharmony_ci *     member or function argument index;
28737c2aad20Sopenharmony_ci * Returns:
28747c2aad20Sopenharmony_ci *   - >0, type ID of newly added BTF type;
28757c2aad20Sopenharmony_ci *   - <0, on error.
28767c2aad20Sopenharmony_ci */
28777c2aad20Sopenharmony_ciint btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
28787c2aad20Sopenharmony_ci		 int component_idx)
28797c2aad20Sopenharmony_ci{
28807c2aad20Sopenharmony_ci	struct btf_type *t;
28817c2aad20Sopenharmony_ci	int sz, value_off;
28827c2aad20Sopenharmony_ci
28837c2aad20Sopenharmony_ci	if (!value || !value[0] || component_idx < -1)
28847c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
28857c2aad20Sopenharmony_ci
28867c2aad20Sopenharmony_ci	if (validate_type_id(ref_type_id))
28877c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
28887c2aad20Sopenharmony_ci
28897c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf))
28907c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28917c2aad20Sopenharmony_ci
28927c2aad20Sopenharmony_ci	sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag);
28937c2aad20Sopenharmony_ci	t = btf_add_type_mem(btf, sz);
28947c2aad20Sopenharmony_ci	if (!t)
28957c2aad20Sopenharmony_ci		return libbpf_err(-ENOMEM);
28967c2aad20Sopenharmony_ci
28977c2aad20Sopenharmony_ci	value_off = btf__add_str(btf, value);
28987c2aad20Sopenharmony_ci	if (value_off < 0)
28997c2aad20Sopenharmony_ci		return value_off;
29007c2aad20Sopenharmony_ci
29017c2aad20Sopenharmony_ci	t->name_off = value_off;
29027c2aad20Sopenharmony_ci	t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false);
29037c2aad20Sopenharmony_ci	t->type = ref_type_id;
29047c2aad20Sopenharmony_ci	btf_decl_tag(t)->component_idx = component_idx;
29057c2aad20Sopenharmony_ci
29067c2aad20Sopenharmony_ci	return btf_commit_type(btf, sz);
29077c2aad20Sopenharmony_ci}
29087c2aad20Sopenharmony_ci
29097c2aad20Sopenharmony_cistruct btf_ext_sec_setup_param {
29107c2aad20Sopenharmony_ci	__u32 off;
29117c2aad20Sopenharmony_ci	__u32 len;
29127c2aad20Sopenharmony_ci	__u32 min_rec_size;
29137c2aad20Sopenharmony_ci	struct btf_ext_info *ext_info;
29147c2aad20Sopenharmony_ci	const char *desc;
29157c2aad20Sopenharmony_ci};
29167c2aad20Sopenharmony_ci
29177c2aad20Sopenharmony_cistatic int btf_ext_setup_info(struct btf_ext *btf_ext,
29187c2aad20Sopenharmony_ci			      struct btf_ext_sec_setup_param *ext_sec)
29197c2aad20Sopenharmony_ci{
29207c2aad20Sopenharmony_ci	const struct btf_ext_info_sec *sinfo;
29217c2aad20Sopenharmony_ci	struct btf_ext_info *ext_info;
29227c2aad20Sopenharmony_ci	__u32 info_left, record_size;
29237c2aad20Sopenharmony_ci	size_t sec_cnt = 0;
29247c2aad20Sopenharmony_ci	/* The start of the info sec (including the __u32 record_size). */
29257c2aad20Sopenharmony_ci	void *info;
29267c2aad20Sopenharmony_ci
29277c2aad20Sopenharmony_ci	if (ext_sec->len == 0)
29287c2aad20Sopenharmony_ci		return 0;
29297c2aad20Sopenharmony_ci
29307c2aad20Sopenharmony_ci	if (ext_sec->off & 0x03) {
29317c2aad20Sopenharmony_ci		pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
29327c2aad20Sopenharmony_ci		     ext_sec->desc);
29337c2aad20Sopenharmony_ci		return -EINVAL;
29347c2aad20Sopenharmony_ci	}
29357c2aad20Sopenharmony_ci
29367c2aad20Sopenharmony_ci	info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off;
29377c2aad20Sopenharmony_ci	info_left = ext_sec->len;
29387c2aad20Sopenharmony_ci
29397c2aad20Sopenharmony_ci	if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) {
29407c2aad20Sopenharmony_ci		pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
29417c2aad20Sopenharmony_ci			 ext_sec->desc, ext_sec->off, ext_sec->len);
29427c2aad20Sopenharmony_ci		return -EINVAL;
29437c2aad20Sopenharmony_ci	}
29447c2aad20Sopenharmony_ci
29457c2aad20Sopenharmony_ci	/* At least a record size */
29467c2aad20Sopenharmony_ci	if (info_left < sizeof(__u32)) {
29477c2aad20Sopenharmony_ci		pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);
29487c2aad20Sopenharmony_ci		return -EINVAL;
29497c2aad20Sopenharmony_ci	}
29507c2aad20Sopenharmony_ci
29517c2aad20Sopenharmony_ci	/* The record size needs to meet the minimum standard */
29527c2aad20Sopenharmony_ci	record_size = *(__u32 *)info;
29537c2aad20Sopenharmony_ci	if (record_size < ext_sec->min_rec_size ||
29547c2aad20Sopenharmony_ci	    record_size & 0x03) {
29557c2aad20Sopenharmony_ci		pr_debug("%s section in .BTF.ext has invalid record size %u\n",
29567c2aad20Sopenharmony_ci			 ext_sec->desc, record_size);
29577c2aad20Sopenharmony_ci		return -EINVAL;
29587c2aad20Sopenharmony_ci	}
29597c2aad20Sopenharmony_ci
29607c2aad20Sopenharmony_ci	sinfo = info + sizeof(__u32);
29617c2aad20Sopenharmony_ci	info_left -= sizeof(__u32);
29627c2aad20Sopenharmony_ci
29637c2aad20Sopenharmony_ci	/* If no records, return failure now so .BTF.ext won't be used. */
29647c2aad20Sopenharmony_ci	if (!info_left) {
29657c2aad20Sopenharmony_ci		pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);
29667c2aad20Sopenharmony_ci		return -EINVAL;
29677c2aad20Sopenharmony_ci	}
29687c2aad20Sopenharmony_ci
29697c2aad20Sopenharmony_ci	while (info_left) {
29707c2aad20Sopenharmony_ci		unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
29717c2aad20Sopenharmony_ci		__u64 total_record_size;
29727c2aad20Sopenharmony_ci		__u32 num_records;
29737c2aad20Sopenharmony_ci
29747c2aad20Sopenharmony_ci		if (info_left < sec_hdrlen) {
29757c2aad20Sopenharmony_ci			pr_debug("%s section header is not found in .BTF.ext\n",
29767c2aad20Sopenharmony_ci			     ext_sec->desc);
29777c2aad20Sopenharmony_ci			return -EINVAL;
29787c2aad20Sopenharmony_ci		}
29797c2aad20Sopenharmony_ci
29807c2aad20Sopenharmony_ci		num_records = sinfo->num_info;
29817c2aad20Sopenharmony_ci		if (num_records == 0) {
29827c2aad20Sopenharmony_ci			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
29837c2aad20Sopenharmony_ci			     ext_sec->desc);
29847c2aad20Sopenharmony_ci			return -EINVAL;
29857c2aad20Sopenharmony_ci		}
29867c2aad20Sopenharmony_ci
29877c2aad20Sopenharmony_ci		total_record_size = sec_hdrlen + (__u64)num_records * record_size;
29887c2aad20Sopenharmony_ci		if (info_left < total_record_size) {
29897c2aad20Sopenharmony_ci			pr_debug("%s section has incorrect num_records in .BTF.ext\n",
29907c2aad20Sopenharmony_ci			     ext_sec->desc);
29917c2aad20Sopenharmony_ci			return -EINVAL;
29927c2aad20Sopenharmony_ci		}
29937c2aad20Sopenharmony_ci
29947c2aad20Sopenharmony_ci		info_left -= total_record_size;
29957c2aad20Sopenharmony_ci		sinfo = (void *)sinfo + total_record_size;
29967c2aad20Sopenharmony_ci		sec_cnt++;
29977c2aad20Sopenharmony_ci	}
29987c2aad20Sopenharmony_ci
29997c2aad20Sopenharmony_ci	ext_info = ext_sec->ext_info;
30007c2aad20Sopenharmony_ci	ext_info->len = ext_sec->len - sizeof(__u32);
30017c2aad20Sopenharmony_ci	ext_info->rec_size = record_size;
30027c2aad20Sopenharmony_ci	ext_info->info = info + sizeof(__u32);
30037c2aad20Sopenharmony_ci	ext_info->sec_cnt = sec_cnt;
30047c2aad20Sopenharmony_ci
30057c2aad20Sopenharmony_ci	return 0;
30067c2aad20Sopenharmony_ci}
30077c2aad20Sopenharmony_ci
30087c2aad20Sopenharmony_cistatic int btf_ext_setup_func_info(struct btf_ext *btf_ext)
30097c2aad20Sopenharmony_ci{
30107c2aad20Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
30117c2aad20Sopenharmony_ci		.off = btf_ext->hdr->func_info_off,
30127c2aad20Sopenharmony_ci		.len = btf_ext->hdr->func_info_len,
30137c2aad20Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_func_info_min),
30147c2aad20Sopenharmony_ci		.ext_info = &btf_ext->func_info,
30157c2aad20Sopenharmony_ci		.desc = "func_info"
30167c2aad20Sopenharmony_ci	};
30177c2aad20Sopenharmony_ci
30187c2aad20Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
30197c2aad20Sopenharmony_ci}
30207c2aad20Sopenharmony_ci
30217c2aad20Sopenharmony_cistatic int btf_ext_setup_line_info(struct btf_ext *btf_ext)
30227c2aad20Sopenharmony_ci{
30237c2aad20Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
30247c2aad20Sopenharmony_ci		.off = btf_ext->hdr->line_info_off,
30257c2aad20Sopenharmony_ci		.len = btf_ext->hdr->line_info_len,
30267c2aad20Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_line_info_min),
30277c2aad20Sopenharmony_ci		.ext_info = &btf_ext->line_info,
30287c2aad20Sopenharmony_ci		.desc = "line_info",
30297c2aad20Sopenharmony_ci	};
30307c2aad20Sopenharmony_ci
30317c2aad20Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
30327c2aad20Sopenharmony_ci}
30337c2aad20Sopenharmony_ci
30347c2aad20Sopenharmony_cistatic int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
30357c2aad20Sopenharmony_ci{
30367c2aad20Sopenharmony_ci	struct btf_ext_sec_setup_param param = {
30377c2aad20Sopenharmony_ci		.off = btf_ext->hdr->core_relo_off,
30387c2aad20Sopenharmony_ci		.len = btf_ext->hdr->core_relo_len,
30397c2aad20Sopenharmony_ci		.min_rec_size = sizeof(struct bpf_core_relo),
30407c2aad20Sopenharmony_ci		.ext_info = &btf_ext->core_relo_info,
30417c2aad20Sopenharmony_ci		.desc = "core_relo",
30427c2aad20Sopenharmony_ci	};
30437c2aad20Sopenharmony_ci
30447c2aad20Sopenharmony_ci	return btf_ext_setup_info(btf_ext, &param);
30457c2aad20Sopenharmony_ci}
30467c2aad20Sopenharmony_ci
30477c2aad20Sopenharmony_cistatic int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
30487c2aad20Sopenharmony_ci{
30497c2aad20Sopenharmony_ci	const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
30507c2aad20Sopenharmony_ci
30517c2aad20Sopenharmony_ci	if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
30527c2aad20Sopenharmony_ci	    data_size < hdr->hdr_len) {
30537c2aad20Sopenharmony_ci		pr_debug("BTF.ext header not found");
30547c2aad20Sopenharmony_ci		return -EINVAL;
30557c2aad20Sopenharmony_ci	}
30567c2aad20Sopenharmony_ci
30577c2aad20Sopenharmony_ci	if (hdr->magic == bswap_16(BTF_MAGIC)) {
30587c2aad20Sopenharmony_ci		pr_warn("BTF.ext in non-native endianness is not supported\n");
30597c2aad20Sopenharmony_ci		return -ENOTSUP;
30607c2aad20Sopenharmony_ci	} else if (hdr->magic != BTF_MAGIC) {
30617c2aad20Sopenharmony_ci		pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
30627c2aad20Sopenharmony_ci		return -EINVAL;
30637c2aad20Sopenharmony_ci	}
30647c2aad20Sopenharmony_ci
30657c2aad20Sopenharmony_ci	if (hdr->version != BTF_VERSION) {
30667c2aad20Sopenharmony_ci		pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
30677c2aad20Sopenharmony_ci		return -ENOTSUP;
30687c2aad20Sopenharmony_ci	}
30697c2aad20Sopenharmony_ci
30707c2aad20Sopenharmony_ci	if (hdr->flags) {
30717c2aad20Sopenharmony_ci		pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
30727c2aad20Sopenharmony_ci		return -ENOTSUP;
30737c2aad20Sopenharmony_ci	}
30747c2aad20Sopenharmony_ci
30757c2aad20Sopenharmony_ci	if (data_size == hdr->hdr_len) {
30767c2aad20Sopenharmony_ci		pr_debug("BTF.ext has no data\n");
30777c2aad20Sopenharmony_ci		return -EINVAL;
30787c2aad20Sopenharmony_ci	}
30797c2aad20Sopenharmony_ci
30807c2aad20Sopenharmony_ci	return 0;
30817c2aad20Sopenharmony_ci}
30827c2aad20Sopenharmony_ci
30837c2aad20Sopenharmony_civoid btf_ext__free(struct btf_ext *btf_ext)
30847c2aad20Sopenharmony_ci{
30857c2aad20Sopenharmony_ci	if (IS_ERR_OR_NULL(btf_ext))
30867c2aad20Sopenharmony_ci		return;
30877c2aad20Sopenharmony_ci	free(btf_ext->func_info.sec_idxs);
30887c2aad20Sopenharmony_ci	free(btf_ext->line_info.sec_idxs);
30897c2aad20Sopenharmony_ci	free(btf_ext->core_relo_info.sec_idxs);
30907c2aad20Sopenharmony_ci	free(btf_ext->data);
30917c2aad20Sopenharmony_ci	free(btf_ext);
30927c2aad20Sopenharmony_ci}
30937c2aad20Sopenharmony_ci
30947c2aad20Sopenharmony_cistruct btf_ext *btf_ext__new(const __u8 *data, __u32 size)
30957c2aad20Sopenharmony_ci{
30967c2aad20Sopenharmony_ci	struct btf_ext *btf_ext;
30977c2aad20Sopenharmony_ci	int err;
30987c2aad20Sopenharmony_ci
30997c2aad20Sopenharmony_ci	btf_ext = calloc(1, sizeof(struct btf_ext));
31007c2aad20Sopenharmony_ci	if (!btf_ext)
31017c2aad20Sopenharmony_ci		return libbpf_err_ptr(-ENOMEM);
31027c2aad20Sopenharmony_ci
31037c2aad20Sopenharmony_ci	btf_ext->data_size = size;
31047c2aad20Sopenharmony_ci	btf_ext->data = malloc(size);
31057c2aad20Sopenharmony_ci	if (!btf_ext->data) {
31067c2aad20Sopenharmony_ci		err = -ENOMEM;
31077c2aad20Sopenharmony_ci		goto done;
31087c2aad20Sopenharmony_ci	}
31097c2aad20Sopenharmony_ci	memcpy(btf_ext->data, data, size);
31107c2aad20Sopenharmony_ci
31117c2aad20Sopenharmony_ci	err = btf_ext_parse_hdr(btf_ext->data, size);
31127c2aad20Sopenharmony_ci	if (err)
31137c2aad20Sopenharmony_ci		goto done;
31147c2aad20Sopenharmony_ci
31157c2aad20Sopenharmony_ci	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
31167c2aad20Sopenharmony_ci		err = -EINVAL;
31177c2aad20Sopenharmony_ci		goto done;
31187c2aad20Sopenharmony_ci	}
31197c2aad20Sopenharmony_ci
31207c2aad20Sopenharmony_ci	err = btf_ext_setup_func_info(btf_ext);
31217c2aad20Sopenharmony_ci	if (err)
31227c2aad20Sopenharmony_ci		goto done;
31237c2aad20Sopenharmony_ci
31247c2aad20Sopenharmony_ci	err = btf_ext_setup_line_info(btf_ext);
31257c2aad20Sopenharmony_ci	if (err)
31267c2aad20Sopenharmony_ci		goto done;
31277c2aad20Sopenharmony_ci
31287c2aad20Sopenharmony_ci	if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len))
31297c2aad20Sopenharmony_ci		goto done; /* skip core relos parsing */
31307c2aad20Sopenharmony_ci
31317c2aad20Sopenharmony_ci	err = btf_ext_setup_core_relos(btf_ext);
31327c2aad20Sopenharmony_ci	if (err)
31337c2aad20Sopenharmony_ci		goto done;
31347c2aad20Sopenharmony_ci
31357c2aad20Sopenharmony_cidone:
31367c2aad20Sopenharmony_ci	if (err) {
31377c2aad20Sopenharmony_ci		btf_ext__free(btf_ext);
31387c2aad20Sopenharmony_ci		return libbpf_err_ptr(err);
31397c2aad20Sopenharmony_ci	}
31407c2aad20Sopenharmony_ci
31417c2aad20Sopenharmony_ci	return btf_ext;
31427c2aad20Sopenharmony_ci}
31437c2aad20Sopenharmony_ci
31447c2aad20Sopenharmony_ciconst void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)
31457c2aad20Sopenharmony_ci{
31467c2aad20Sopenharmony_ci	*size = btf_ext->data_size;
31477c2aad20Sopenharmony_ci	return btf_ext->data;
31487c2aad20Sopenharmony_ci}
31497c2aad20Sopenharmony_ci
31507c2aad20Sopenharmony_cistruct btf_dedup;
31517c2aad20Sopenharmony_ci
31527c2aad20Sopenharmony_cistatic struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
31537c2aad20Sopenharmony_cistatic void btf_dedup_free(struct btf_dedup *d);
31547c2aad20Sopenharmony_cistatic int btf_dedup_prep(struct btf_dedup *d);
31557c2aad20Sopenharmony_cistatic int btf_dedup_strings(struct btf_dedup *d);
31567c2aad20Sopenharmony_cistatic int btf_dedup_prim_types(struct btf_dedup *d);
31577c2aad20Sopenharmony_cistatic int btf_dedup_struct_types(struct btf_dedup *d);
31587c2aad20Sopenharmony_cistatic int btf_dedup_ref_types(struct btf_dedup *d);
31597c2aad20Sopenharmony_cistatic int btf_dedup_resolve_fwds(struct btf_dedup *d);
31607c2aad20Sopenharmony_cistatic int btf_dedup_compact_types(struct btf_dedup *d);
31617c2aad20Sopenharmony_cistatic int btf_dedup_remap_types(struct btf_dedup *d);
31627c2aad20Sopenharmony_ci
31637c2aad20Sopenharmony_ci/*
31647c2aad20Sopenharmony_ci * Deduplicate BTF types and strings.
31657c2aad20Sopenharmony_ci *
31667c2aad20Sopenharmony_ci * BTF dedup algorithm takes as an input `struct btf` representing `.BTF` ELF
31677c2aad20Sopenharmony_ci * section with all BTF type descriptors and string data. It overwrites that
31687c2aad20Sopenharmony_ci * memory in-place with deduplicated types and strings without any loss of
31697c2aad20Sopenharmony_ci * information. If optional `struct btf_ext` representing '.BTF.ext' ELF section
31707c2aad20Sopenharmony_ci * is provided, all the strings referenced from .BTF.ext section are honored
31717c2aad20Sopenharmony_ci * and updated to point to the right offsets after deduplication.
31727c2aad20Sopenharmony_ci *
31737c2aad20Sopenharmony_ci * If function returns with error, type/string data might be garbled and should
31747c2aad20Sopenharmony_ci * be discarded.
31757c2aad20Sopenharmony_ci *
31767c2aad20Sopenharmony_ci * More verbose and detailed description of both problem btf_dedup is solving,
31777c2aad20Sopenharmony_ci * as well as solution could be found at:
31787c2aad20Sopenharmony_ci * https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html
31797c2aad20Sopenharmony_ci *
31807c2aad20Sopenharmony_ci * Problem description and justification
31817c2aad20Sopenharmony_ci * =====================================
31827c2aad20Sopenharmony_ci *
31837c2aad20Sopenharmony_ci * BTF type information is typically emitted either as a result of conversion
31847c2aad20Sopenharmony_ci * from DWARF to BTF or directly by compiler. In both cases, each compilation
31857c2aad20Sopenharmony_ci * unit contains information about a subset of all the types that are used
31867c2aad20Sopenharmony_ci * in an application. These subsets are frequently overlapping and contain a lot
31877c2aad20Sopenharmony_ci * of duplicated information when later concatenated together into a single
31887c2aad20Sopenharmony_ci * binary. This algorithm ensures that each unique type is represented by single
31897c2aad20Sopenharmony_ci * BTF type descriptor, greatly reducing resulting size of BTF data.
31907c2aad20Sopenharmony_ci *
31917c2aad20Sopenharmony_ci * Compilation unit isolation and subsequent duplication of data is not the only
31927c2aad20Sopenharmony_ci * problem. The same type hierarchy (e.g., struct and all the type that struct
31937c2aad20Sopenharmony_ci * references) in different compilation units can be represented in BTF to
31947c2aad20Sopenharmony_ci * various degrees of completeness (or, rather, incompleteness) due to
31957c2aad20Sopenharmony_ci * struct/union forward declarations.
31967c2aad20Sopenharmony_ci *
31977c2aad20Sopenharmony_ci * Let's take a look at an example, that we'll use to better understand the
31987c2aad20Sopenharmony_ci * problem (and solution). Suppose we have two compilation units, each using
31997c2aad20Sopenharmony_ci * same `struct S`, but each of them having incomplete type information about
32007c2aad20Sopenharmony_ci * struct's fields:
32017c2aad20Sopenharmony_ci *
32027c2aad20Sopenharmony_ci * // CU #1:
32037c2aad20Sopenharmony_ci * struct S;
32047c2aad20Sopenharmony_ci * struct A {
32057c2aad20Sopenharmony_ci *	int a;
32067c2aad20Sopenharmony_ci *	struct A* self;
32077c2aad20Sopenharmony_ci *	struct S* parent;
32087c2aad20Sopenharmony_ci * };
32097c2aad20Sopenharmony_ci * struct B;
32107c2aad20Sopenharmony_ci * struct S {
32117c2aad20Sopenharmony_ci *	struct A* a_ptr;
32127c2aad20Sopenharmony_ci *	struct B* b_ptr;
32137c2aad20Sopenharmony_ci * };
32147c2aad20Sopenharmony_ci *
32157c2aad20Sopenharmony_ci * // CU #2:
32167c2aad20Sopenharmony_ci * struct S;
32177c2aad20Sopenharmony_ci * struct A;
32187c2aad20Sopenharmony_ci * struct B {
32197c2aad20Sopenharmony_ci *	int b;
32207c2aad20Sopenharmony_ci *	struct B* self;
32217c2aad20Sopenharmony_ci *	struct S* parent;
32227c2aad20Sopenharmony_ci * };
32237c2aad20Sopenharmony_ci * struct S {
32247c2aad20Sopenharmony_ci *	struct A* a_ptr;
32257c2aad20Sopenharmony_ci *	struct B* b_ptr;
32267c2aad20Sopenharmony_ci * };
32277c2aad20Sopenharmony_ci *
32287c2aad20Sopenharmony_ci * In case of CU #1, BTF data will know only that `struct B` exist (but no
32297c2aad20Sopenharmony_ci * more), but will know the complete type information about `struct A`. While
32307c2aad20Sopenharmony_ci * for CU #2, it will know full type information about `struct B`, but will
32317c2aad20Sopenharmony_ci * only know about forward declaration of `struct A` (in BTF terms, it will
32327c2aad20Sopenharmony_ci * have `BTF_KIND_FWD` type descriptor with name `B`).
32337c2aad20Sopenharmony_ci *
32347c2aad20Sopenharmony_ci * This compilation unit isolation means that it's possible that there is no
32357c2aad20Sopenharmony_ci * single CU with complete type information describing structs `S`, `A`, and
32367c2aad20Sopenharmony_ci * `B`. Also, we might get tons of duplicated and redundant type information.
32377c2aad20Sopenharmony_ci *
32387c2aad20Sopenharmony_ci * Additional complication we need to keep in mind comes from the fact that
32397c2aad20Sopenharmony_ci * types, in general, can form graphs containing cycles, not just DAGs.
32407c2aad20Sopenharmony_ci *
32417c2aad20Sopenharmony_ci * While algorithm does deduplication, it also merges and resolves type
32427c2aad20Sopenharmony_ci * information (unless disabled throught `struct btf_opts`), whenever possible.
32437c2aad20Sopenharmony_ci * E.g., in the example above with two compilation units having partial type
32447c2aad20Sopenharmony_ci * information for structs `A` and `B`, the output of algorithm will emit
32457c2aad20Sopenharmony_ci * a single copy of each BTF type that describes structs `A`, `B`, and `S`
32467c2aad20Sopenharmony_ci * (as well as type information for `int` and pointers), as if they were defined
32477c2aad20Sopenharmony_ci * in a single compilation unit as:
32487c2aad20Sopenharmony_ci *
32497c2aad20Sopenharmony_ci * struct A {
32507c2aad20Sopenharmony_ci *	int a;
32517c2aad20Sopenharmony_ci *	struct A* self;
32527c2aad20Sopenharmony_ci *	struct S* parent;
32537c2aad20Sopenharmony_ci * };
32547c2aad20Sopenharmony_ci * struct B {
32557c2aad20Sopenharmony_ci *	int b;
32567c2aad20Sopenharmony_ci *	struct B* self;
32577c2aad20Sopenharmony_ci *	struct S* parent;
32587c2aad20Sopenharmony_ci * };
32597c2aad20Sopenharmony_ci * struct S {
32607c2aad20Sopenharmony_ci *	struct A* a_ptr;
32617c2aad20Sopenharmony_ci *	struct B* b_ptr;
32627c2aad20Sopenharmony_ci * };
32637c2aad20Sopenharmony_ci *
32647c2aad20Sopenharmony_ci * Algorithm summary
32657c2aad20Sopenharmony_ci * =================
32667c2aad20Sopenharmony_ci *
32677c2aad20Sopenharmony_ci * Algorithm completes its work in 7 separate passes:
32687c2aad20Sopenharmony_ci *
32697c2aad20Sopenharmony_ci * 1. Strings deduplication.
32707c2aad20Sopenharmony_ci * 2. Primitive types deduplication (int, enum, fwd).
32717c2aad20Sopenharmony_ci * 3. Struct/union types deduplication.
32727c2aad20Sopenharmony_ci * 4. Resolve unambiguous forward declarations.
32737c2aad20Sopenharmony_ci * 5. Reference types deduplication (pointers, typedefs, arrays, funcs, func
32747c2aad20Sopenharmony_ci *    protos, and const/volatile/restrict modifiers).
32757c2aad20Sopenharmony_ci * 6. Types compaction.
32767c2aad20Sopenharmony_ci * 7. Types remapping.
32777c2aad20Sopenharmony_ci *
32787c2aad20Sopenharmony_ci * Algorithm determines canonical type descriptor, which is a single
32797c2aad20Sopenharmony_ci * representative type for each truly unique type. This canonical type is the
32807c2aad20Sopenharmony_ci * one that will go into final deduplicated BTF type information. For
32817c2aad20Sopenharmony_ci * struct/unions, it is also the type that algorithm will merge additional type
32827c2aad20Sopenharmony_ci * information into (while resolving FWDs), as it discovers it from data in
32837c2aad20Sopenharmony_ci * other CUs. Each input BTF type eventually gets either mapped to itself, if
32847c2aad20Sopenharmony_ci * that type is canonical, or to some other type, if that type is equivalent
32857c2aad20Sopenharmony_ci * and was chosen as canonical representative. This mapping is stored in
32867c2aad20Sopenharmony_ci * `btf_dedup->map` array. This map is also used to record STRUCT/UNION that
32877c2aad20Sopenharmony_ci * FWD type got resolved to.
32887c2aad20Sopenharmony_ci *
32897c2aad20Sopenharmony_ci * To facilitate fast discovery of canonical types, we also maintain canonical
32907c2aad20Sopenharmony_ci * index (`btf_dedup->dedup_table`), which maps type descriptor's signature hash
32917c2aad20Sopenharmony_ci * (i.e., hashed kind, name, size, fields, etc) into a list of canonical types
32927c2aad20Sopenharmony_ci * that match that signature. With sufficiently good choice of type signature
32937c2aad20Sopenharmony_ci * hashing function, we can limit number of canonical types for each unique type
32947c2aad20Sopenharmony_ci * signature to a very small number, allowing to find canonical type for any
32957c2aad20Sopenharmony_ci * duplicated type very quickly.
32967c2aad20Sopenharmony_ci *
32977c2aad20Sopenharmony_ci * Struct/union deduplication is the most critical part and algorithm for
32987c2aad20Sopenharmony_ci * deduplicating structs/unions is described in greater details in comments for
32997c2aad20Sopenharmony_ci * `btf_dedup_is_equiv` function.
33007c2aad20Sopenharmony_ci */
33017c2aad20Sopenharmony_ciint btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)
33027c2aad20Sopenharmony_ci{
33037c2aad20Sopenharmony_ci	struct btf_dedup *d;
33047c2aad20Sopenharmony_ci	int err;
33057c2aad20Sopenharmony_ci
33067c2aad20Sopenharmony_ci	if (!OPTS_VALID(opts, btf_dedup_opts))
33077c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
33087c2aad20Sopenharmony_ci
33097c2aad20Sopenharmony_ci	d = btf_dedup_new(btf, opts);
33107c2aad20Sopenharmony_ci	if (IS_ERR(d)) {
33117c2aad20Sopenharmony_ci		pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d));
33127c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
33137c2aad20Sopenharmony_ci	}
33147c2aad20Sopenharmony_ci
33157c2aad20Sopenharmony_ci	if (btf_ensure_modifiable(btf)) {
33167c2aad20Sopenharmony_ci		err = -ENOMEM;
33177c2aad20Sopenharmony_ci		goto done;
33187c2aad20Sopenharmony_ci	}
33197c2aad20Sopenharmony_ci
33207c2aad20Sopenharmony_ci	err = btf_dedup_prep(d);
33217c2aad20Sopenharmony_ci	if (err) {
33227c2aad20Sopenharmony_ci		pr_debug("btf_dedup_prep failed:%d\n", err);
33237c2aad20Sopenharmony_ci		goto done;
33247c2aad20Sopenharmony_ci	}
33257c2aad20Sopenharmony_ci	err = btf_dedup_strings(d);
33267c2aad20Sopenharmony_ci	if (err < 0) {
33277c2aad20Sopenharmony_ci		pr_debug("btf_dedup_strings failed:%d\n", err);
33287c2aad20Sopenharmony_ci		goto done;
33297c2aad20Sopenharmony_ci	}
33307c2aad20Sopenharmony_ci	err = btf_dedup_prim_types(d);
33317c2aad20Sopenharmony_ci	if (err < 0) {
33327c2aad20Sopenharmony_ci		pr_debug("btf_dedup_prim_types failed:%d\n", err);
33337c2aad20Sopenharmony_ci		goto done;
33347c2aad20Sopenharmony_ci	}
33357c2aad20Sopenharmony_ci	err = btf_dedup_struct_types(d);
33367c2aad20Sopenharmony_ci	if (err < 0) {
33377c2aad20Sopenharmony_ci		pr_debug("btf_dedup_struct_types failed:%d\n", err);
33387c2aad20Sopenharmony_ci		goto done;
33397c2aad20Sopenharmony_ci	}
33407c2aad20Sopenharmony_ci	err = btf_dedup_resolve_fwds(d);
33417c2aad20Sopenharmony_ci	if (err < 0) {
33427c2aad20Sopenharmony_ci		pr_debug("btf_dedup_resolve_fwds failed:%d\n", err);
33437c2aad20Sopenharmony_ci		goto done;
33447c2aad20Sopenharmony_ci	}
33457c2aad20Sopenharmony_ci	err = btf_dedup_ref_types(d);
33467c2aad20Sopenharmony_ci	if (err < 0) {
33477c2aad20Sopenharmony_ci		pr_debug("btf_dedup_ref_types failed:%d\n", err);
33487c2aad20Sopenharmony_ci		goto done;
33497c2aad20Sopenharmony_ci	}
33507c2aad20Sopenharmony_ci	err = btf_dedup_compact_types(d);
33517c2aad20Sopenharmony_ci	if (err < 0) {
33527c2aad20Sopenharmony_ci		pr_debug("btf_dedup_compact_types failed:%d\n", err);
33537c2aad20Sopenharmony_ci		goto done;
33547c2aad20Sopenharmony_ci	}
33557c2aad20Sopenharmony_ci	err = btf_dedup_remap_types(d);
33567c2aad20Sopenharmony_ci	if (err < 0) {
33577c2aad20Sopenharmony_ci		pr_debug("btf_dedup_remap_types failed:%d\n", err);
33587c2aad20Sopenharmony_ci		goto done;
33597c2aad20Sopenharmony_ci	}
33607c2aad20Sopenharmony_ci
33617c2aad20Sopenharmony_cidone:
33627c2aad20Sopenharmony_ci	btf_dedup_free(d);
33637c2aad20Sopenharmony_ci	return libbpf_err(err);
33647c2aad20Sopenharmony_ci}
33657c2aad20Sopenharmony_ci
33667c2aad20Sopenharmony_ci#define BTF_UNPROCESSED_ID ((__u32)-1)
33677c2aad20Sopenharmony_ci#define BTF_IN_PROGRESS_ID ((__u32)-2)
33687c2aad20Sopenharmony_ci
33697c2aad20Sopenharmony_cistruct btf_dedup {
33707c2aad20Sopenharmony_ci	/* .BTF section to be deduped in-place */
33717c2aad20Sopenharmony_ci	struct btf *btf;
33727c2aad20Sopenharmony_ci	/*
33737c2aad20Sopenharmony_ci	 * Optional .BTF.ext section. When provided, any strings referenced
33747c2aad20Sopenharmony_ci	 * from it will be taken into account when deduping strings
33757c2aad20Sopenharmony_ci	 */
33767c2aad20Sopenharmony_ci	struct btf_ext *btf_ext;
33777c2aad20Sopenharmony_ci	/*
33787c2aad20Sopenharmony_ci	 * This is a map from any type's signature hash to a list of possible
33797c2aad20Sopenharmony_ci	 * canonical representative type candidates. Hash collisions are
33807c2aad20Sopenharmony_ci	 * ignored, so even types of various kinds can share same list of
33817c2aad20Sopenharmony_ci	 * candidates, which is fine because we rely on subsequent
33827c2aad20Sopenharmony_ci	 * btf_xxx_equal() checks to authoritatively verify type equality.
33837c2aad20Sopenharmony_ci	 */
33847c2aad20Sopenharmony_ci	struct hashmap *dedup_table;
33857c2aad20Sopenharmony_ci	/* Canonical types map */
33867c2aad20Sopenharmony_ci	__u32 *map;
33877c2aad20Sopenharmony_ci	/* Hypothetical mapping, used during type graph equivalence checks */
33887c2aad20Sopenharmony_ci	__u32 *hypot_map;
33897c2aad20Sopenharmony_ci	__u32 *hypot_list;
33907c2aad20Sopenharmony_ci	size_t hypot_cnt;
33917c2aad20Sopenharmony_ci	size_t hypot_cap;
33927c2aad20Sopenharmony_ci	/* Whether hypothetical mapping, if successful, would need to adjust
33937c2aad20Sopenharmony_ci	 * already canonicalized types (due to a new forward declaration to
33947c2aad20Sopenharmony_ci	 * concrete type resolution). In such case, during split BTF dedup
33957c2aad20Sopenharmony_ci	 * candidate type would still be considered as different, because base
33967c2aad20Sopenharmony_ci	 * BTF is considered to be immutable.
33977c2aad20Sopenharmony_ci	 */
33987c2aad20Sopenharmony_ci	bool hypot_adjust_canon;
33997c2aad20Sopenharmony_ci	/* Various option modifying behavior of algorithm */
34007c2aad20Sopenharmony_ci	struct btf_dedup_opts opts;
34017c2aad20Sopenharmony_ci	/* temporary strings deduplication state */
34027c2aad20Sopenharmony_ci	struct strset *strs_set;
34037c2aad20Sopenharmony_ci};
34047c2aad20Sopenharmony_ci
34057c2aad20Sopenharmony_cistatic long hash_combine(long h, long value)
34067c2aad20Sopenharmony_ci{
34077c2aad20Sopenharmony_ci	return h * 31 + value;
34087c2aad20Sopenharmony_ci}
34097c2aad20Sopenharmony_ci
34107c2aad20Sopenharmony_ci#define for_each_dedup_cand(d, node, hash) \
34117c2aad20Sopenharmony_ci	hashmap__for_each_key_entry(d->dedup_table, node, hash)
34127c2aad20Sopenharmony_ci
34137c2aad20Sopenharmony_cistatic int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
34147c2aad20Sopenharmony_ci{
34157c2aad20Sopenharmony_ci	return hashmap__append(d->dedup_table, hash, type_id);
34167c2aad20Sopenharmony_ci}
34177c2aad20Sopenharmony_ci
34187c2aad20Sopenharmony_cistatic int btf_dedup_hypot_map_add(struct btf_dedup *d,
34197c2aad20Sopenharmony_ci				   __u32 from_id, __u32 to_id)
34207c2aad20Sopenharmony_ci{
34217c2aad20Sopenharmony_ci	if (d->hypot_cnt == d->hypot_cap) {
34227c2aad20Sopenharmony_ci		__u32 *new_list;
34237c2aad20Sopenharmony_ci
34247c2aad20Sopenharmony_ci		d->hypot_cap += max((size_t)16, d->hypot_cap / 2);
34257c2aad20Sopenharmony_ci		new_list = libbpf_reallocarray(d->hypot_list, d->hypot_cap, sizeof(__u32));
34267c2aad20Sopenharmony_ci		if (!new_list)
34277c2aad20Sopenharmony_ci			return -ENOMEM;
34287c2aad20Sopenharmony_ci		d->hypot_list = new_list;
34297c2aad20Sopenharmony_ci	}
34307c2aad20Sopenharmony_ci	d->hypot_list[d->hypot_cnt++] = from_id;
34317c2aad20Sopenharmony_ci	d->hypot_map[from_id] = to_id;
34327c2aad20Sopenharmony_ci	return 0;
34337c2aad20Sopenharmony_ci}
34347c2aad20Sopenharmony_ci
34357c2aad20Sopenharmony_cistatic void btf_dedup_clear_hypot_map(struct btf_dedup *d)
34367c2aad20Sopenharmony_ci{
34377c2aad20Sopenharmony_ci	int i;
34387c2aad20Sopenharmony_ci
34397c2aad20Sopenharmony_ci	for (i = 0; i < d->hypot_cnt; i++)
34407c2aad20Sopenharmony_ci		d->hypot_map[d->hypot_list[i]] = BTF_UNPROCESSED_ID;
34417c2aad20Sopenharmony_ci	d->hypot_cnt = 0;
34427c2aad20Sopenharmony_ci	d->hypot_adjust_canon = false;
34437c2aad20Sopenharmony_ci}
34447c2aad20Sopenharmony_ci
34457c2aad20Sopenharmony_cistatic void btf_dedup_free(struct btf_dedup *d)
34467c2aad20Sopenharmony_ci{
34477c2aad20Sopenharmony_ci	hashmap__free(d->dedup_table);
34487c2aad20Sopenharmony_ci	d->dedup_table = NULL;
34497c2aad20Sopenharmony_ci
34507c2aad20Sopenharmony_ci	free(d->map);
34517c2aad20Sopenharmony_ci	d->map = NULL;
34527c2aad20Sopenharmony_ci
34537c2aad20Sopenharmony_ci	free(d->hypot_map);
34547c2aad20Sopenharmony_ci	d->hypot_map = NULL;
34557c2aad20Sopenharmony_ci
34567c2aad20Sopenharmony_ci	free(d->hypot_list);
34577c2aad20Sopenharmony_ci	d->hypot_list = NULL;
34587c2aad20Sopenharmony_ci
34597c2aad20Sopenharmony_ci	free(d);
34607c2aad20Sopenharmony_ci}
34617c2aad20Sopenharmony_ci
34627c2aad20Sopenharmony_cistatic size_t btf_dedup_identity_hash_fn(long key, void *ctx)
34637c2aad20Sopenharmony_ci{
34647c2aad20Sopenharmony_ci	return key;
34657c2aad20Sopenharmony_ci}
34667c2aad20Sopenharmony_ci
34677c2aad20Sopenharmony_cistatic size_t btf_dedup_collision_hash_fn(long key, void *ctx)
34687c2aad20Sopenharmony_ci{
34697c2aad20Sopenharmony_ci	return 0;
34707c2aad20Sopenharmony_ci}
34717c2aad20Sopenharmony_ci
34727c2aad20Sopenharmony_cistatic bool btf_dedup_equal_fn(long k1, long k2, void *ctx)
34737c2aad20Sopenharmony_ci{
34747c2aad20Sopenharmony_ci	return k1 == k2;
34757c2aad20Sopenharmony_ci}
34767c2aad20Sopenharmony_ci
34777c2aad20Sopenharmony_cistatic struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts)
34787c2aad20Sopenharmony_ci{
34797c2aad20Sopenharmony_ci	struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup));
34807c2aad20Sopenharmony_ci	hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn;
34817c2aad20Sopenharmony_ci	int i, err = 0, type_cnt;
34827c2aad20Sopenharmony_ci
34837c2aad20Sopenharmony_ci	if (!d)
34847c2aad20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
34857c2aad20Sopenharmony_ci
34867c2aad20Sopenharmony_ci	if (OPTS_GET(opts, force_collisions, false))
34877c2aad20Sopenharmony_ci		hash_fn = btf_dedup_collision_hash_fn;
34887c2aad20Sopenharmony_ci
34897c2aad20Sopenharmony_ci	d->btf = btf;
34907c2aad20Sopenharmony_ci	d->btf_ext = OPTS_GET(opts, btf_ext, NULL);
34917c2aad20Sopenharmony_ci
34927c2aad20Sopenharmony_ci	d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL);
34937c2aad20Sopenharmony_ci	if (IS_ERR(d->dedup_table)) {
34947c2aad20Sopenharmony_ci		err = PTR_ERR(d->dedup_table);
34957c2aad20Sopenharmony_ci		d->dedup_table = NULL;
34967c2aad20Sopenharmony_ci		goto done;
34977c2aad20Sopenharmony_ci	}
34987c2aad20Sopenharmony_ci
34997c2aad20Sopenharmony_ci	type_cnt = btf__type_cnt(btf);
35007c2aad20Sopenharmony_ci	d->map = malloc(sizeof(__u32) * type_cnt);
35017c2aad20Sopenharmony_ci	if (!d->map) {
35027c2aad20Sopenharmony_ci		err = -ENOMEM;
35037c2aad20Sopenharmony_ci		goto done;
35047c2aad20Sopenharmony_ci	}
35057c2aad20Sopenharmony_ci	/* special BTF "void" type is made canonical immediately */
35067c2aad20Sopenharmony_ci	d->map[0] = 0;
35077c2aad20Sopenharmony_ci	for (i = 1; i < type_cnt; i++) {
35087c2aad20Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, i);
35097c2aad20Sopenharmony_ci
35107c2aad20Sopenharmony_ci		/* VAR and DATASEC are never deduped and are self-canonical */
35117c2aad20Sopenharmony_ci		if (btf_is_var(t) || btf_is_datasec(t))
35127c2aad20Sopenharmony_ci			d->map[i] = i;
35137c2aad20Sopenharmony_ci		else
35147c2aad20Sopenharmony_ci			d->map[i] = BTF_UNPROCESSED_ID;
35157c2aad20Sopenharmony_ci	}
35167c2aad20Sopenharmony_ci
35177c2aad20Sopenharmony_ci	d->hypot_map = malloc(sizeof(__u32) * type_cnt);
35187c2aad20Sopenharmony_ci	if (!d->hypot_map) {
35197c2aad20Sopenharmony_ci		err = -ENOMEM;
35207c2aad20Sopenharmony_ci		goto done;
35217c2aad20Sopenharmony_ci	}
35227c2aad20Sopenharmony_ci	for (i = 0; i < type_cnt; i++)
35237c2aad20Sopenharmony_ci		d->hypot_map[i] = BTF_UNPROCESSED_ID;
35247c2aad20Sopenharmony_ci
35257c2aad20Sopenharmony_cidone:
35267c2aad20Sopenharmony_ci	if (err) {
35277c2aad20Sopenharmony_ci		btf_dedup_free(d);
35287c2aad20Sopenharmony_ci		return ERR_PTR(err);
35297c2aad20Sopenharmony_ci	}
35307c2aad20Sopenharmony_ci
35317c2aad20Sopenharmony_ci	return d;
35327c2aad20Sopenharmony_ci}
35337c2aad20Sopenharmony_ci
35347c2aad20Sopenharmony_ci/*
35357c2aad20Sopenharmony_ci * Iterate over all possible places in .BTF and .BTF.ext that can reference
35367c2aad20Sopenharmony_ci * string and pass pointer to it to a provided callback `fn`.
35377c2aad20Sopenharmony_ci */
35387c2aad20Sopenharmony_cistatic int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx)
35397c2aad20Sopenharmony_ci{
35407c2aad20Sopenharmony_ci	int i, r;
35417c2aad20Sopenharmony_ci
35427c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
35437c2aad20Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
35447c2aad20Sopenharmony_ci
35457c2aad20Sopenharmony_ci		r = btf_type_visit_str_offs(t, fn, ctx);
35467c2aad20Sopenharmony_ci		if (r)
35477c2aad20Sopenharmony_ci			return r;
35487c2aad20Sopenharmony_ci	}
35497c2aad20Sopenharmony_ci
35507c2aad20Sopenharmony_ci	if (!d->btf_ext)
35517c2aad20Sopenharmony_ci		return 0;
35527c2aad20Sopenharmony_ci
35537c2aad20Sopenharmony_ci	r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx);
35547c2aad20Sopenharmony_ci	if (r)
35557c2aad20Sopenharmony_ci		return r;
35567c2aad20Sopenharmony_ci
35577c2aad20Sopenharmony_ci	return 0;
35587c2aad20Sopenharmony_ci}
35597c2aad20Sopenharmony_ci
35607c2aad20Sopenharmony_cistatic int strs_dedup_remap_str_off(__u32 *str_off_ptr, void *ctx)
35617c2aad20Sopenharmony_ci{
35627c2aad20Sopenharmony_ci	struct btf_dedup *d = ctx;
35637c2aad20Sopenharmony_ci	__u32 str_off = *str_off_ptr;
35647c2aad20Sopenharmony_ci	const char *s;
35657c2aad20Sopenharmony_ci	int off, err;
35667c2aad20Sopenharmony_ci
35677c2aad20Sopenharmony_ci	/* don't touch empty string or string in main BTF */
35687c2aad20Sopenharmony_ci	if (str_off == 0 || str_off < d->btf->start_str_off)
35697c2aad20Sopenharmony_ci		return 0;
35707c2aad20Sopenharmony_ci
35717c2aad20Sopenharmony_ci	s = btf__str_by_offset(d->btf, str_off);
35727c2aad20Sopenharmony_ci	if (d->btf->base_btf) {
35737c2aad20Sopenharmony_ci		err = btf__find_str(d->btf->base_btf, s);
35747c2aad20Sopenharmony_ci		if (err >= 0) {
35757c2aad20Sopenharmony_ci			*str_off_ptr = err;
35767c2aad20Sopenharmony_ci			return 0;
35777c2aad20Sopenharmony_ci		}
35787c2aad20Sopenharmony_ci		if (err != -ENOENT)
35797c2aad20Sopenharmony_ci			return err;
35807c2aad20Sopenharmony_ci	}
35817c2aad20Sopenharmony_ci
35827c2aad20Sopenharmony_ci	off = strset__add_str(d->strs_set, s);
35837c2aad20Sopenharmony_ci	if (off < 0)
35847c2aad20Sopenharmony_ci		return off;
35857c2aad20Sopenharmony_ci
35867c2aad20Sopenharmony_ci	*str_off_ptr = d->btf->start_str_off + off;
35877c2aad20Sopenharmony_ci	return 0;
35887c2aad20Sopenharmony_ci}
35897c2aad20Sopenharmony_ci
35907c2aad20Sopenharmony_ci/*
35917c2aad20Sopenharmony_ci * Dedup string and filter out those that are not referenced from either .BTF
35927c2aad20Sopenharmony_ci * or .BTF.ext (if provided) sections.
35937c2aad20Sopenharmony_ci *
35947c2aad20Sopenharmony_ci * This is done by building index of all strings in BTF's string section,
35957c2aad20Sopenharmony_ci * then iterating over all entities that can reference strings (e.g., type
35967c2aad20Sopenharmony_ci * names, struct field names, .BTF.ext line info, etc) and marking corresponding
35977c2aad20Sopenharmony_ci * strings as used. After that all used strings are deduped and compacted into
35987c2aad20Sopenharmony_ci * sequential blob of memory and new offsets are calculated. Then all the string
35997c2aad20Sopenharmony_ci * references are iterated again and rewritten using new offsets.
36007c2aad20Sopenharmony_ci */
36017c2aad20Sopenharmony_cistatic int btf_dedup_strings(struct btf_dedup *d)
36027c2aad20Sopenharmony_ci{
36037c2aad20Sopenharmony_ci	int err;
36047c2aad20Sopenharmony_ci
36057c2aad20Sopenharmony_ci	if (d->btf->strs_deduped)
36067c2aad20Sopenharmony_ci		return 0;
36077c2aad20Sopenharmony_ci
36087c2aad20Sopenharmony_ci	d->strs_set = strset__new(BTF_MAX_STR_OFFSET, NULL, 0);
36097c2aad20Sopenharmony_ci	if (IS_ERR(d->strs_set)) {
36107c2aad20Sopenharmony_ci		err = PTR_ERR(d->strs_set);
36117c2aad20Sopenharmony_ci		goto err_out;
36127c2aad20Sopenharmony_ci	}
36137c2aad20Sopenharmony_ci
36147c2aad20Sopenharmony_ci	if (!d->btf->base_btf) {
36157c2aad20Sopenharmony_ci		/* insert empty string; we won't be looking it up during strings
36167c2aad20Sopenharmony_ci		 * dedup, but it's good to have it for generic BTF string lookups
36177c2aad20Sopenharmony_ci		 */
36187c2aad20Sopenharmony_ci		err = strset__add_str(d->strs_set, "");
36197c2aad20Sopenharmony_ci		if (err < 0)
36207c2aad20Sopenharmony_ci			goto err_out;
36217c2aad20Sopenharmony_ci	}
36227c2aad20Sopenharmony_ci
36237c2aad20Sopenharmony_ci	/* remap string offsets */
36247c2aad20Sopenharmony_ci	err = btf_for_each_str_off(d, strs_dedup_remap_str_off, d);
36257c2aad20Sopenharmony_ci	if (err)
36267c2aad20Sopenharmony_ci		goto err_out;
36277c2aad20Sopenharmony_ci
36287c2aad20Sopenharmony_ci	/* replace BTF string data and hash with deduped ones */
36297c2aad20Sopenharmony_ci	strset__free(d->btf->strs_set);
36307c2aad20Sopenharmony_ci	d->btf->hdr->str_len = strset__data_size(d->strs_set);
36317c2aad20Sopenharmony_ci	d->btf->strs_set = d->strs_set;
36327c2aad20Sopenharmony_ci	d->strs_set = NULL;
36337c2aad20Sopenharmony_ci	d->btf->strs_deduped = true;
36347c2aad20Sopenharmony_ci	return 0;
36357c2aad20Sopenharmony_ci
36367c2aad20Sopenharmony_cierr_out:
36377c2aad20Sopenharmony_ci	strset__free(d->strs_set);
36387c2aad20Sopenharmony_ci	d->strs_set = NULL;
36397c2aad20Sopenharmony_ci
36407c2aad20Sopenharmony_ci	return err;
36417c2aad20Sopenharmony_ci}
36427c2aad20Sopenharmony_ci
36437c2aad20Sopenharmony_cistatic long btf_hash_common(struct btf_type *t)
36447c2aad20Sopenharmony_ci{
36457c2aad20Sopenharmony_ci	long h;
36467c2aad20Sopenharmony_ci
36477c2aad20Sopenharmony_ci	h = hash_combine(0, t->name_off);
36487c2aad20Sopenharmony_ci	h = hash_combine(h, t->info);
36497c2aad20Sopenharmony_ci	h = hash_combine(h, t->size);
36507c2aad20Sopenharmony_ci	return h;
36517c2aad20Sopenharmony_ci}
36527c2aad20Sopenharmony_ci
36537c2aad20Sopenharmony_cistatic bool btf_equal_common(struct btf_type *t1, struct btf_type *t2)
36547c2aad20Sopenharmony_ci{
36557c2aad20Sopenharmony_ci	return t1->name_off == t2->name_off &&
36567c2aad20Sopenharmony_ci	       t1->info == t2->info &&
36577c2aad20Sopenharmony_ci	       t1->size == t2->size;
36587c2aad20Sopenharmony_ci}
36597c2aad20Sopenharmony_ci
36607c2aad20Sopenharmony_ci/* Calculate type signature hash of INT or TAG. */
36617c2aad20Sopenharmony_cistatic long btf_hash_int_decl_tag(struct btf_type *t)
36627c2aad20Sopenharmony_ci{
36637c2aad20Sopenharmony_ci	__u32 info = *(__u32 *)(t + 1);
36647c2aad20Sopenharmony_ci	long h;
36657c2aad20Sopenharmony_ci
36667c2aad20Sopenharmony_ci	h = btf_hash_common(t);
36677c2aad20Sopenharmony_ci	h = hash_combine(h, info);
36687c2aad20Sopenharmony_ci	return h;
36697c2aad20Sopenharmony_ci}
36707c2aad20Sopenharmony_ci
36717c2aad20Sopenharmony_ci/* Check structural equality of two INTs or TAGs. */
36727c2aad20Sopenharmony_cistatic bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
36737c2aad20Sopenharmony_ci{
36747c2aad20Sopenharmony_ci	__u32 info1, info2;
36757c2aad20Sopenharmony_ci
36767c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
36777c2aad20Sopenharmony_ci		return false;
36787c2aad20Sopenharmony_ci	info1 = *(__u32 *)(t1 + 1);
36797c2aad20Sopenharmony_ci	info2 = *(__u32 *)(t2 + 1);
36807c2aad20Sopenharmony_ci	return info1 == info2;
36817c2aad20Sopenharmony_ci}
36827c2aad20Sopenharmony_ci
36837c2aad20Sopenharmony_ci/* Calculate type signature hash of ENUM/ENUM64. */
36847c2aad20Sopenharmony_cistatic long btf_hash_enum(struct btf_type *t)
36857c2aad20Sopenharmony_ci{
36867c2aad20Sopenharmony_ci	long h;
36877c2aad20Sopenharmony_ci
36887c2aad20Sopenharmony_ci	/* don't hash vlen, enum members and size to support enum fwd resolving */
36897c2aad20Sopenharmony_ci	h = hash_combine(0, t->name_off);
36907c2aad20Sopenharmony_ci	return h;
36917c2aad20Sopenharmony_ci}
36927c2aad20Sopenharmony_ci
36937c2aad20Sopenharmony_cistatic bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
36947c2aad20Sopenharmony_ci{
36957c2aad20Sopenharmony_ci	const struct btf_enum *m1, *m2;
36967c2aad20Sopenharmony_ci	__u16 vlen;
36977c2aad20Sopenharmony_ci	int i;
36987c2aad20Sopenharmony_ci
36997c2aad20Sopenharmony_ci	vlen = btf_vlen(t1);
37007c2aad20Sopenharmony_ci	m1 = btf_enum(t1);
37017c2aad20Sopenharmony_ci	m2 = btf_enum(t2);
37027c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
37037c2aad20Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->val != m2->val)
37047c2aad20Sopenharmony_ci			return false;
37057c2aad20Sopenharmony_ci		m1++;
37067c2aad20Sopenharmony_ci		m2++;
37077c2aad20Sopenharmony_ci	}
37087c2aad20Sopenharmony_ci	return true;
37097c2aad20Sopenharmony_ci}
37107c2aad20Sopenharmony_ci
37117c2aad20Sopenharmony_cistatic bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
37127c2aad20Sopenharmony_ci{
37137c2aad20Sopenharmony_ci	const struct btf_enum64 *m1, *m2;
37147c2aad20Sopenharmony_ci	__u16 vlen;
37157c2aad20Sopenharmony_ci	int i;
37167c2aad20Sopenharmony_ci
37177c2aad20Sopenharmony_ci	vlen = btf_vlen(t1);
37187c2aad20Sopenharmony_ci	m1 = btf_enum64(t1);
37197c2aad20Sopenharmony_ci	m2 = btf_enum64(t2);
37207c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
37217c2aad20Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
37227c2aad20Sopenharmony_ci		    m1->val_hi32 != m2->val_hi32)
37237c2aad20Sopenharmony_ci			return false;
37247c2aad20Sopenharmony_ci		m1++;
37257c2aad20Sopenharmony_ci		m2++;
37267c2aad20Sopenharmony_ci	}
37277c2aad20Sopenharmony_ci	return true;
37287c2aad20Sopenharmony_ci}
37297c2aad20Sopenharmony_ci
37307c2aad20Sopenharmony_ci/* Check structural equality of two ENUMs or ENUM64s. */
37317c2aad20Sopenharmony_cistatic bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
37327c2aad20Sopenharmony_ci{
37337c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
37347c2aad20Sopenharmony_ci		return false;
37357c2aad20Sopenharmony_ci
37367c2aad20Sopenharmony_ci	/* t1 & t2 kinds are identical because of btf_equal_common */
37377c2aad20Sopenharmony_ci	if (btf_kind(t1) == BTF_KIND_ENUM)
37387c2aad20Sopenharmony_ci		return btf_equal_enum_members(t1, t2);
37397c2aad20Sopenharmony_ci	else
37407c2aad20Sopenharmony_ci		return btf_equal_enum64_members(t1, t2);
37417c2aad20Sopenharmony_ci}
37427c2aad20Sopenharmony_ci
37437c2aad20Sopenharmony_cistatic inline bool btf_is_enum_fwd(struct btf_type *t)
37447c2aad20Sopenharmony_ci{
37457c2aad20Sopenharmony_ci	return btf_is_any_enum(t) && btf_vlen(t) == 0;
37467c2aad20Sopenharmony_ci}
37477c2aad20Sopenharmony_ci
37487c2aad20Sopenharmony_cistatic bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
37497c2aad20Sopenharmony_ci{
37507c2aad20Sopenharmony_ci	if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
37517c2aad20Sopenharmony_ci		return btf_equal_enum(t1, t2);
37527c2aad20Sopenharmony_ci	/* At this point either t1 or t2 or both are forward declarations, thus:
37537c2aad20Sopenharmony_ci	 * - skip comparing vlen because it is zero for forward declarations;
37547c2aad20Sopenharmony_ci	 * - skip comparing size to allow enum forward declarations
37557c2aad20Sopenharmony_ci	 *   to be compatible with enum64 full declarations;
37567c2aad20Sopenharmony_ci	 * - skip comparing kind for the same reason.
37577c2aad20Sopenharmony_ci	 */
37587c2aad20Sopenharmony_ci	return t1->name_off == t2->name_off &&
37597c2aad20Sopenharmony_ci	       btf_is_any_enum(t1) && btf_is_any_enum(t2);
37607c2aad20Sopenharmony_ci}
37617c2aad20Sopenharmony_ci
37627c2aad20Sopenharmony_ci/*
37637c2aad20Sopenharmony_ci * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
37647c2aad20Sopenharmony_ci * as referenced type IDs equivalence is established separately during type
37657c2aad20Sopenharmony_ci * graph equivalence check algorithm.
37667c2aad20Sopenharmony_ci */
37677c2aad20Sopenharmony_cistatic long btf_hash_struct(struct btf_type *t)
37687c2aad20Sopenharmony_ci{
37697c2aad20Sopenharmony_ci	const struct btf_member *member = btf_members(t);
37707c2aad20Sopenharmony_ci	__u32 vlen = btf_vlen(t);
37717c2aad20Sopenharmony_ci	long h = btf_hash_common(t);
37727c2aad20Sopenharmony_ci	int i;
37737c2aad20Sopenharmony_ci
37747c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
37757c2aad20Sopenharmony_ci		h = hash_combine(h, member->name_off);
37767c2aad20Sopenharmony_ci		h = hash_combine(h, member->offset);
37777c2aad20Sopenharmony_ci		/* no hashing of referenced type ID, it can be unresolved yet */
37787c2aad20Sopenharmony_ci		member++;
37797c2aad20Sopenharmony_ci	}
37807c2aad20Sopenharmony_ci	return h;
37817c2aad20Sopenharmony_ci}
37827c2aad20Sopenharmony_ci
37837c2aad20Sopenharmony_ci/*
37847c2aad20Sopenharmony_ci * Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced
37857c2aad20Sopenharmony_ci * type IDs. This check is performed during type graph equivalence check and
37867c2aad20Sopenharmony_ci * referenced types equivalence is checked separately.
37877c2aad20Sopenharmony_ci */
37887c2aad20Sopenharmony_cistatic bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
37897c2aad20Sopenharmony_ci{
37907c2aad20Sopenharmony_ci	const struct btf_member *m1, *m2;
37917c2aad20Sopenharmony_ci	__u16 vlen;
37927c2aad20Sopenharmony_ci	int i;
37937c2aad20Sopenharmony_ci
37947c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
37957c2aad20Sopenharmony_ci		return false;
37967c2aad20Sopenharmony_ci
37977c2aad20Sopenharmony_ci	vlen = btf_vlen(t1);
37987c2aad20Sopenharmony_ci	m1 = btf_members(t1);
37997c2aad20Sopenharmony_ci	m2 = btf_members(t2);
38007c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
38017c2aad20Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->offset != m2->offset)
38027c2aad20Sopenharmony_ci			return false;
38037c2aad20Sopenharmony_ci		m1++;
38047c2aad20Sopenharmony_ci		m2++;
38057c2aad20Sopenharmony_ci	}
38067c2aad20Sopenharmony_ci	return true;
38077c2aad20Sopenharmony_ci}
38087c2aad20Sopenharmony_ci
38097c2aad20Sopenharmony_ci/*
38107c2aad20Sopenharmony_ci * Calculate type signature hash of ARRAY, including referenced type IDs,
38117c2aad20Sopenharmony_ci * under assumption that they were already resolved to canonical type IDs and
38127c2aad20Sopenharmony_ci * are not going to change.
38137c2aad20Sopenharmony_ci */
38147c2aad20Sopenharmony_cistatic long btf_hash_array(struct btf_type *t)
38157c2aad20Sopenharmony_ci{
38167c2aad20Sopenharmony_ci	const struct btf_array *info = btf_array(t);
38177c2aad20Sopenharmony_ci	long h = btf_hash_common(t);
38187c2aad20Sopenharmony_ci
38197c2aad20Sopenharmony_ci	h = hash_combine(h, info->type);
38207c2aad20Sopenharmony_ci	h = hash_combine(h, info->index_type);
38217c2aad20Sopenharmony_ci	h = hash_combine(h, info->nelems);
38227c2aad20Sopenharmony_ci	return h;
38237c2aad20Sopenharmony_ci}
38247c2aad20Sopenharmony_ci
38257c2aad20Sopenharmony_ci/*
38267c2aad20Sopenharmony_ci * Check exact equality of two ARRAYs, taking into account referenced
38277c2aad20Sopenharmony_ci * type IDs, under assumption that they were already resolved to canonical
38287c2aad20Sopenharmony_ci * type IDs and are not going to change.
38297c2aad20Sopenharmony_ci * This function is called during reference types deduplication to compare
38307c2aad20Sopenharmony_ci * ARRAY to potential canonical representative.
38317c2aad20Sopenharmony_ci */
38327c2aad20Sopenharmony_cistatic bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
38337c2aad20Sopenharmony_ci{
38347c2aad20Sopenharmony_ci	const struct btf_array *info1, *info2;
38357c2aad20Sopenharmony_ci
38367c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
38377c2aad20Sopenharmony_ci		return false;
38387c2aad20Sopenharmony_ci
38397c2aad20Sopenharmony_ci	info1 = btf_array(t1);
38407c2aad20Sopenharmony_ci	info2 = btf_array(t2);
38417c2aad20Sopenharmony_ci	return info1->type == info2->type &&
38427c2aad20Sopenharmony_ci	       info1->index_type == info2->index_type &&
38437c2aad20Sopenharmony_ci	       info1->nelems == info2->nelems;
38447c2aad20Sopenharmony_ci}
38457c2aad20Sopenharmony_ci
38467c2aad20Sopenharmony_ci/*
38477c2aad20Sopenharmony_ci * Check structural compatibility of two ARRAYs, ignoring referenced type
38487c2aad20Sopenharmony_ci * IDs. This check is performed during type graph equivalence check and
38497c2aad20Sopenharmony_ci * referenced types equivalence is checked separately.
38507c2aad20Sopenharmony_ci */
38517c2aad20Sopenharmony_cistatic bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
38527c2aad20Sopenharmony_ci{
38537c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
38547c2aad20Sopenharmony_ci		return false;
38557c2aad20Sopenharmony_ci
38567c2aad20Sopenharmony_ci	return btf_array(t1)->nelems == btf_array(t2)->nelems;
38577c2aad20Sopenharmony_ci}
38587c2aad20Sopenharmony_ci
38597c2aad20Sopenharmony_ci/*
38607c2aad20Sopenharmony_ci * Calculate type signature hash of FUNC_PROTO, including referenced type IDs,
38617c2aad20Sopenharmony_ci * under assumption that they were already resolved to canonical type IDs and
38627c2aad20Sopenharmony_ci * are not going to change.
38637c2aad20Sopenharmony_ci */
38647c2aad20Sopenharmony_cistatic long btf_hash_fnproto(struct btf_type *t)
38657c2aad20Sopenharmony_ci{
38667c2aad20Sopenharmony_ci	const struct btf_param *member = btf_params(t);
38677c2aad20Sopenharmony_ci	__u16 vlen = btf_vlen(t);
38687c2aad20Sopenharmony_ci	long h = btf_hash_common(t);
38697c2aad20Sopenharmony_ci	int i;
38707c2aad20Sopenharmony_ci
38717c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
38727c2aad20Sopenharmony_ci		h = hash_combine(h, member->name_off);
38737c2aad20Sopenharmony_ci		h = hash_combine(h, member->type);
38747c2aad20Sopenharmony_ci		member++;
38757c2aad20Sopenharmony_ci	}
38767c2aad20Sopenharmony_ci	return h;
38777c2aad20Sopenharmony_ci}
38787c2aad20Sopenharmony_ci
38797c2aad20Sopenharmony_ci/*
38807c2aad20Sopenharmony_ci * Check exact equality of two FUNC_PROTOs, taking into account referenced
38817c2aad20Sopenharmony_ci * type IDs, under assumption that they were already resolved to canonical
38827c2aad20Sopenharmony_ci * type IDs and are not going to change.
38837c2aad20Sopenharmony_ci * This function is called during reference types deduplication to compare
38847c2aad20Sopenharmony_ci * FUNC_PROTO to potential canonical representative.
38857c2aad20Sopenharmony_ci */
38867c2aad20Sopenharmony_cistatic bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
38877c2aad20Sopenharmony_ci{
38887c2aad20Sopenharmony_ci	const struct btf_param *m1, *m2;
38897c2aad20Sopenharmony_ci	__u16 vlen;
38907c2aad20Sopenharmony_ci	int i;
38917c2aad20Sopenharmony_ci
38927c2aad20Sopenharmony_ci	if (!btf_equal_common(t1, t2))
38937c2aad20Sopenharmony_ci		return false;
38947c2aad20Sopenharmony_ci
38957c2aad20Sopenharmony_ci	vlen = btf_vlen(t1);
38967c2aad20Sopenharmony_ci	m1 = btf_params(t1);
38977c2aad20Sopenharmony_ci	m2 = btf_params(t2);
38987c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
38997c2aad20Sopenharmony_ci		if (m1->name_off != m2->name_off || m1->type != m2->type)
39007c2aad20Sopenharmony_ci			return false;
39017c2aad20Sopenharmony_ci		m1++;
39027c2aad20Sopenharmony_ci		m2++;
39037c2aad20Sopenharmony_ci	}
39047c2aad20Sopenharmony_ci	return true;
39057c2aad20Sopenharmony_ci}
39067c2aad20Sopenharmony_ci
39077c2aad20Sopenharmony_ci/*
39087c2aad20Sopenharmony_ci * Check structural compatibility of two FUNC_PROTOs, ignoring referenced type
39097c2aad20Sopenharmony_ci * IDs. This check is performed during type graph equivalence check and
39107c2aad20Sopenharmony_ci * referenced types equivalence is checked separately.
39117c2aad20Sopenharmony_ci */
39127c2aad20Sopenharmony_cistatic bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
39137c2aad20Sopenharmony_ci{
39147c2aad20Sopenharmony_ci	const struct btf_param *m1, *m2;
39157c2aad20Sopenharmony_ci	__u16 vlen;
39167c2aad20Sopenharmony_ci	int i;
39177c2aad20Sopenharmony_ci
39187c2aad20Sopenharmony_ci	/* skip return type ID */
39197c2aad20Sopenharmony_ci	if (t1->name_off != t2->name_off || t1->info != t2->info)
39207c2aad20Sopenharmony_ci		return false;
39217c2aad20Sopenharmony_ci
39227c2aad20Sopenharmony_ci	vlen = btf_vlen(t1);
39237c2aad20Sopenharmony_ci	m1 = btf_params(t1);
39247c2aad20Sopenharmony_ci	m2 = btf_params(t2);
39257c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++) {
39267c2aad20Sopenharmony_ci		if (m1->name_off != m2->name_off)
39277c2aad20Sopenharmony_ci			return false;
39287c2aad20Sopenharmony_ci		m1++;
39297c2aad20Sopenharmony_ci		m2++;
39307c2aad20Sopenharmony_ci	}
39317c2aad20Sopenharmony_ci	return true;
39327c2aad20Sopenharmony_ci}
39337c2aad20Sopenharmony_ci
39347c2aad20Sopenharmony_ci/* Prepare split BTF for deduplication by calculating hashes of base BTF's
39357c2aad20Sopenharmony_ci * types and initializing the rest of the state (canonical type mapping) for
39367c2aad20Sopenharmony_ci * the fixed base BTF part.
39377c2aad20Sopenharmony_ci */
39387c2aad20Sopenharmony_cistatic int btf_dedup_prep(struct btf_dedup *d)
39397c2aad20Sopenharmony_ci{
39407c2aad20Sopenharmony_ci	struct btf_type *t;
39417c2aad20Sopenharmony_ci	int type_id;
39427c2aad20Sopenharmony_ci	long h;
39437c2aad20Sopenharmony_ci
39447c2aad20Sopenharmony_ci	if (!d->btf->base_btf)
39457c2aad20Sopenharmony_ci		return 0;
39467c2aad20Sopenharmony_ci
39477c2aad20Sopenharmony_ci	for (type_id = 1; type_id < d->btf->start_id; type_id++) {
39487c2aad20Sopenharmony_ci		t = btf_type_by_id(d->btf, type_id);
39497c2aad20Sopenharmony_ci
39507c2aad20Sopenharmony_ci		/* all base BTF types are self-canonical by definition */
39517c2aad20Sopenharmony_ci		d->map[type_id] = type_id;
39527c2aad20Sopenharmony_ci
39537c2aad20Sopenharmony_ci		switch (btf_kind(t)) {
39547c2aad20Sopenharmony_ci		case BTF_KIND_VAR:
39557c2aad20Sopenharmony_ci		case BTF_KIND_DATASEC:
39567c2aad20Sopenharmony_ci			/* VAR and DATASEC are never hash/deduplicated */
39577c2aad20Sopenharmony_ci			continue;
39587c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
39597c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
39607c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
39617c2aad20Sopenharmony_ci		case BTF_KIND_PTR:
39627c2aad20Sopenharmony_ci		case BTF_KIND_FWD:
39637c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
39647c2aad20Sopenharmony_ci		case BTF_KIND_FUNC:
39657c2aad20Sopenharmony_ci		case BTF_KIND_FLOAT:
39667c2aad20Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
39677c2aad20Sopenharmony_ci			h = btf_hash_common(t);
39687c2aad20Sopenharmony_ci			break;
39697c2aad20Sopenharmony_ci		case BTF_KIND_INT:
39707c2aad20Sopenharmony_ci		case BTF_KIND_DECL_TAG:
39717c2aad20Sopenharmony_ci			h = btf_hash_int_decl_tag(t);
39727c2aad20Sopenharmony_ci			break;
39737c2aad20Sopenharmony_ci		case BTF_KIND_ENUM:
39747c2aad20Sopenharmony_ci		case BTF_KIND_ENUM64:
39757c2aad20Sopenharmony_ci			h = btf_hash_enum(t);
39767c2aad20Sopenharmony_ci			break;
39777c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
39787c2aad20Sopenharmony_ci		case BTF_KIND_UNION:
39797c2aad20Sopenharmony_ci			h = btf_hash_struct(t);
39807c2aad20Sopenharmony_ci			break;
39817c2aad20Sopenharmony_ci		case BTF_KIND_ARRAY:
39827c2aad20Sopenharmony_ci			h = btf_hash_array(t);
39837c2aad20Sopenharmony_ci			break;
39847c2aad20Sopenharmony_ci		case BTF_KIND_FUNC_PROTO:
39857c2aad20Sopenharmony_ci			h = btf_hash_fnproto(t);
39867c2aad20Sopenharmony_ci			break;
39877c2aad20Sopenharmony_ci		default:
39887c2aad20Sopenharmony_ci			pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id);
39897c2aad20Sopenharmony_ci			return -EINVAL;
39907c2aad20Sopenharmony_ci		}
39917c2aad20Sopenharmony_ci		if (btf_dedup_table_add(d, h, type_id))
39927c2aad20Sopenharmony_ci			return -ENOMEM;
39937c2aad20Sopenharmony_ci	}
39947c2aad20Sopenharmony_ci
39957c2aad20Sopenharmony_ci	return 0;
39967c2aad20Sopenharmony_ci}
39977c2aad20Sopenharmony_ci
39987c2aad20Sopenharmony_ci/*
39997c2aad20Sopenharmony_ci * Deduplicate primitive types, that can't reference other types, by calculating
40007c2aad20Sopenharmony_ci * their type signature hash and comparing them with any possible canonical
40017c2aad20Sopenharmony_ci * candidate. If no canonical candidate matches, type itself is marked as
40027c2aad20Sopenharmony_ci * canonical and is added into `btf_dedup->dedup_table` as another candidate.
40037c2aad20Sopenharmony_ci */
40047c2aad20Sopenharmony_cistatic int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
40057c2aad20Sopenharmony_ci{
40067c2aad20Sopenharmony_ci	struct btf_type *t = btf_type_by_id(d->btf, type_id);
40077c2aad20Sopenharmony_ci	struct hashmap_entry *hash_entry;
40087c2aad20Sopenharmony_ci	struct btf_type *cand;
40097c2aad20Sopenharmony_ci	/* if we don't find equivalent type, then we are canonical */
40107c2aad20Sopenharmony_ci	__u32 new_id = type_id;
40117c2aad20Sopenharmony_ci	__u32 cand_id;
40127c2aad20Sopenharmony_ci	long h;
40137c2aad20Sopenharmony_ci
40147c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
40157c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
40167c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
40177c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
40187c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
40197c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
40207c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
40217c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
40227c2aad20Sopenharmony_ci	case BTF_KIND_UNION:
40237c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
40247c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
40257c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
40267c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC:
40277c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
40287c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
40297c2aad20Sopenharmony_ci		return 0;
40307c2aad20Sopenharmony_ci
40317c2aad20Sopenharmony_ci	case BTF_KIND_INT:
40327c2aad20Sopenharmony_ci		h = btf_hash_int_decl_tag(t);
40337c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
40347c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
40357c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
40367c2aad20Sopenharmony_ci			if (btf_equal_int_tag(t, cand)) {
40377c2aad20Sopenharmony_ci				new_id = cand_id;
40387c2aad20Sopenharmony_ci				break;
40397c2aad20Sopenharmony_ci			}
40407c2aad20Sopenharmony_ci		}
40417c2aad20Sopenharmony_ci		break;
40427c2aad20Sopenharmony_ci
40437c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
40447c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
40457c2aad20Sopenharmony_ci		h = btf_hash_enum(t);
40467c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
40477c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
40487c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
40497c2aad20Sopenharmony_ci			if (btf_equal_enum(t, cand)) {
40507c2aad20Sopenharmony_ci				new_id = cand_id;
40517c2aad20Sopenharmony_ci				break;
40527c2aad20Sopenharmony_ci			}
40537c2aad20Sopenharmony_ci			if (btf_compat_enum(t, cand)) {
40547c2aad20Sopenharmony_ci				if (btf_is_enum_fwd(t)) {
40557c2aad20Sopenharmony_ci					/* resolve fwd to full enum */
40567c2aad20Sopenharmony_ci					new_id = cand_id;
40577c2aad20Sopenharmony_ci					break;
40587c2aad20Sopenharmony_ci				}
40597c2aad20Sopenharmony_ci				/* resolve canonical enum fwd to full enum */
40607c2aad20Sopenharmony_ci				d->map[cand_id] = type_id;
40617c2aad20Sopenharmony_ci			}
40627c2aad20Sopenharmony_ci		}
40637c2aad20Sopenharmony_ci		break;
40647c2aad20Sopenharmony_ci
40657c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
40667c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
40677c2aad20Sopenharmony_ci		h = btf_hash_common(t);
40687c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
40697c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
40707c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
40717c2aad20Sopenharmony_ci			if (btf_equal_common(t, cand)) {
40727c2aad20Sopenharmony_ci				new_id = cand_id;
40737c2aad20Sopenharmony_ci				break;
40747c2aad20Sopenharmony_ci			}
40757c2aad20Sopenharmony_ci		}
40767c2aad20Sopenharmony_ci		break;
40777c2aad20Sopenharmony_ci
40787c2aad20Sopenharmony_ci	default:
40797c2aad20Sopenharmony_ci		return -EINVAL;
40807c2aad20Sopenharmony_ci	}
40817c2aad20Sopenharmony_ci
40827c2aad20Sopenharmony_ci	d->map[type_id] = new_id;
40837c2aad20Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
40847c2aad20Sopenharmony_ci		return -ENOMEM;
40857c2aad20Sopenharmony_ci
40867c2aad20Sopenharmony_ci	return 0;
40877c2aad20Sopenharmony_ci}
40887c2aad20Sopenharmony_ci
40897c2aad20Sopenharmony_cistatic int btf_dedup_prim_types(struct btf_dedup *d)
40907c2aad20Sopenharmony_ci{
40917c2aad20Sopenharmony_ci	int i, err;
40927c2aad20Sopenharmony_ci
40937c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
40947c2aad20Sopenharmony_ci		err = btf_dedup_prim_type(d, d->btf->start_id + i);
40957c2aad20Sopenharmony_ci		if (err)
40967c2aad20Sopenharmony_ci			return err;
40977c2aad20Sopenharmony_ci	}
40987c2aad20Sopenharmony_ci	return 0;
40997c2aad20Sopenharmony_ci}
41007c2aad20Sopenharmony_ci
41017c2aad20Sopenharmony_ci/*
41027c2aad20Sopenharmony_ci * Check whether type is already mapped into canonical one (could be to itself).
41037c2aad20Sopenharmony_ci */
41047c2aad20Sopenharmony_cistatic inline bool is_type_mapped(struct btf_dedup *d, uint32_t type_id)
41057c2aad20Sopenharmony_ci{
41067c2aad20Sopenharmony_ci	return d->map[type_id] <= BTF_MAX_NR_TYPES;
41077c2aad20Sopenharmony_ci}
41087c2aad20Sopenharmony_ci
41097c2aad20Sopenharmony_ci/*
41107c2aad20Sopenharmony_ci * Resolve type ID into its canonical type ID, if any; otherwise return original
41117c2aad20Sopenharmony_ci * type ID. If type is FWD and is resolved into STRUCT/UNION already, follow
41127c2aad20Sopenharmony_ci * STRUCT/UNION link and resolve it into canonical type ID as well.
41137c2aad20Sopenharmony_ci */
41147c2aad20Sopenharmony_cistatic inline __u32 resolve_type_id(struct btf_dedup *d, __u32 type_id)
41157c2aad20Sopenharmony_ci{
41167c2aad20Sopenharmony_ci	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
41177c2aad20Sopenharmony_ci		type_id = d->map[type_id];
41187c2aad20Sopenharmony_ci	return type_id;
41197c2aad20Sopenharmony_ci}
41207c2aad20Sopenharmony_ci
41217c2aad20Sopenharmony_ci/*
41227c2aad20Sopenharmony_ci * Resolve FWD to underlying STRUCT/UNION, if any; otherwise return original
41237c2aad20Sopenharmony_ci * type ID.
41247c2aad20Sopenharmony_ci */
41257c2aad20Sopenharmony_cistatic uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
41267c2aad20Sopenharmony_ci{
41277c2aad20Sopenharmony_ci	__u32 orig_type_id = type_id;
41287c2aad20Sopenharmony_ci
41297c2aad20Sopenharmony_ci	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
41307c2aad20Sopenharmony_ci		return type_id;
41317c2aad20Sopenharmony_ci
41327c2aad20Sopenharmony_ci	while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
41337c2aad20Sopenharmony_ci		type_id = d->map[type_id];
41347c2aad20Sopenharmony_ci
41357c2aad20Sopenharmony_ci	if (!btf_is_fwd(btf__type_by_id(d->btf, type_id)))
41367c2aad20Sopenharmony_ci		return type_id;
41377c2aad20Sopenharmony_ci
41387c2aad20Sopenharmony_ci	return orig_type_id;
41397c2aad20Sopenharmony_ci}
41407c2aad20Sopenharmony_ci
41417c2aad20Sopenharmony_ci
41427c2aad20Sopenharmony_cistatic inline __u16 btf_fwd_kind(struct btf_type *t)
41437c2aad20Sopenharmony_ci{
41447c2aad20Sopenharmony_ci	return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
41457c2aad20Sopenharmony_ci}
41467c2aad20Sopenharmony_ci
41477c2aad20Sopenharmony_ci/* Check if given two types are identical ARRAY definitions */
41487c2aad20Sopenharmony_cistatic bool btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
41497c2aad20Sopenharmony_ci{
41507c2aad20Sopenharmony_ci	struct btf_type *t1, *t2;
41517c2aad20Sopenharmony_ci
41527c2aad20Sopenharmony_ci	t1 = btf_type_by_id(d->btf, id1);
41537c2aad20Sopenharmony_ci	t2 = btf_type_by_id(d->btf, id2);
41547c2aad20Sopenharmony_ci	if (!btf_is_array(t1) || !btf_is_array(t2))
41557c2aad20Sopenharmony_ci		return false;
41567c2aad20Sopenharmony_ci
41577c2aad20Sopenharmony_ci	return btf_equal_array(t1, t2);
41587c2aad20Sopenharmony_ci}
41597c2aad20Sopenharmony_ci
41607c2aad20Sopenharmony_ci/* Check if given two types are identical STRUCT/UNION definitions */
41617c2aad20Sopenharmony_cistatic bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2)
41627c2aad20Sopenharmony_ci{
41637c2aad20Sopenharmony_ci	const struct btf_member *m1, *m2;
41647c2aad20Sopenharmony_ci	struct btf_type *t1, *t2;
41657c2aad20Sopenharmony_ci	int n, i;
41667c2aad20Sopenharmony_ci
41677c2aad20Sopenharmony_ci	t1 = btf_type_by_id(d->btf, id1);
41687c2aad20Sopenharmony_ci	t2 = btf_type_by_id(d->btf, id2);
41697c2aad20Sopenharmony_ci
41707c2aad20Sopenharmony_ci	if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2))
41717c2aad20Sopenharmony_ci		return false;
41727c2aad20Sopenharmony_ci
41737c2aad20Sopenharmony_ci	if (!btf_shallow_equal_struct(t1, t2))
41747c2aad20Sopenharmony_ci		return false;
41757c2aad20Sopenharmony_ci
41767c2aad20Sopenharmony_ci	m1 = btf_members(t1);
41777c2aad20Sopenharmony_ci	m2 = btf_members(t2);
41787c2aad20Sopenharmony_ci	for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
41797c2aad20Sopenharmony_ci		if (m1->type != m2->type &&
41807c2aad20Sopenharmony_ci		    !btf_dedup_identical_arrays(d, m1->type, m2->type) &&
41817c2aad20Sopenharmony_ci		    !btf_dedup_identical_structs(d, m1->type, m2->type))
41827c2aad20Sopenharmony_ci			return false;
41837c2aad20Sopenharmony_ci	}
41847c2aad20Sopenharmony_ci	return true;
41857c2aad20Sopenharmony_ci}
41867c2aad20Sopenharmony_ci
41877c2aad20Sopenharmony_ci/*
41887c2aad20Sopenharmony_ci * Check equivalence of BTF type graph formed by candidate struct/union (we'll
41897c2aad20Sopenharmony_ci * call it "candidate graph" in this description for brevity) to a type graph
41907c2aad20Sopenharmony_ci * formed by (potential) canonical struct/union ("canonical graph" for brevity
41917c2aad20Sopenharmony_ci * here, though keep in mind that not all types in canonical graph are
41927c2aad20Sopenharmony_ci * necessarily canonical representatives themselves, some of them might be
41937c2aad20Sopenharmony_ci * duplicates or its uniqueness might not have been established yet).
41947c2aad20Sopenharmony_ci * Returns:
41957c2aad20Sopenharmony_ci *  - >0, if type graphs are equivalent;
41967c2aad20Sopenharmony_ci *  -  0, if not equivalent;
41977c2aad20Sopenharmony_ci *  - <0, on error.
41987c2aad20Sopenharmony_ci *
41997c2aad20Sopenharmony_ci * Algorithm performs side-by-side DFS traversal of both type graphs and checks
42007c2aad20Sopenharmony_ci * equivalence of BTF types at each step. If at any point BTF types in candidate
42017c2aad20Sopenharmony_ci * and canonical graphs are not compatible structurally, whole graphs are
42027c2aad20Sopenharmony_ci * incompatible. If types are structurally equivalent (i.e., all information
42037c2aad20Sopenharmony_ci * except referenced type IDs is exactly the same), a mapping from `canon_id` to
42047c2aad20Sopenharmony_ci * a `cand_id` is recored in hypothetical mapping (`btf_dedup->hypot_map`).
42057c2aad20Sopenharmony_ci * If a type references other types, then those referenced types are checked
42067c2aad20Sopenharmony_ci * for equivalence recursively.
42077c2aad20Sopenharmony_ci *
42087c2aad20Sopenharmony_ci * During DFS traversal, if we find that for current `canon_id` type we
42097c2aad20Sopenharmony_ci * already have some mapping in hypothetical map, we check for two possible
42107c2aad20Sopenharmony_ci * situations:
42117c2aad20Sopenharmony_ci *   - `canon_id` is mapped to exactly the same type as `cand_id`. This will
42127c2aad20Sopenharmony_ci *     happen when type graphs have cycles. In this case we assume those two
42137c2aad20Sopenharmony_ci *     types are equivalent.
42147c2aad20Sopenharmony_ci *   - `canon_id` is mapped to different type. This is contradiction in our
42157c2aad20Sopenharmony_ci *     hypothetical mapping, because same graph in canonical graph corresponds
42167c2aad20Sopenharmony_ci *     to two different types in candidate graph, which for equivalent type
42177c2aad20Sopenharmony_ci *     graphs shouldn't happen. This condition terminates equivalence check
42187c2aad20Sopenharmony_ci *     with negative result.
42197c2aad20Sopenharmony_ci *
42207c2aad20Sopenharmony_ci * If type graphs traversal exhausts types to check and find no contradiction,
42217c2aad20Sopenharmony_ci * then type graphs are equivalent.
42227c2aad20Sopenharmony_ci *
42237c2aad20Sopenharmony_ci * When checking types for equivalence, there is one special case: FWD types.
42247c2aad20Sopenharmony_ci * If FWD type resolution is allowed and one of the types (either from canonical
42257c2aad20Sopenharmony_ci * or candidate graph) is FWD and other is STRUCT/UNION (depending on FWD's kind
42267c2aad20Sopenharmony_ci * flag) and their names match, hypothetical mapping is updated to point from
42277c2aad20Sopenharmony_ci * FWD to STRUCT/UNION. If graphs will be determined as equivalent successfully,
42287c2aad20Sopenharmony_ci * this mapping will be used to record FWD -> STRUCT/UNION mapping permanently.
42297c2aad20Sopenharmony_ci *
42307c2aad20Sopenharmony_ci * Technically, this could lead to incorrect FWD to STRUCT/UNION resolution,
42317c2aad20Sopenharmony_ci * if there are two exactly named (or anonymous) structs/unions that are
42327c2aad20Sopenharmony_ci * compatible structurally, one of which has FWD field, while other is concrete
42337c2aad20Sopenharmony_ci * STRUCT/UNION, but according to C sources they are different structs/unions
42347c2aad20Sopenharmony_ci * that are referencing different types with the same name. This is extremely
42357c2aad20Sopenharmony_ci * unlikely to happen, but btf_dedup API allows to disable FWD resolution if
42367c2aad20Sopenharmony_ci * this logic is causing problems.
42377c2aad20Sopenharmony_ci *
42387c2aad20Sopenharmony_ci * Doing FWD resolution means that both candidate and/or canonical graphs can
42397c2aad20Sopenharmony_ci * consists of portions of the graph that come from multiple compilation units.
42407c2aad20Sopenharmony_ci * This is due to the fact that types within single compilation unit are always
42417c2aad20Sopenharmony_ci * deduplicated and FWDs are already resolved, if referenced struct/union
42427c2aad20Sopenharmony_ci * definiton is available. So, if we had unresolved FWD and found corresponding
42437c2aad20Sopenharmony_ci * STRUCT/UNION, they will be from different compilation units. This
42447c2aad20Sopenharmony_ci * consequently means that when we "link" FWD to corresponding STRUCT/UNION,
42457c2aad20Sopenharmony_ci * type graph will likely have at least two different BTF types that describe
42467c2aad20Sopenharmony_ci * same type (e.g., most probably there will be two different BTF types for the
42477c2aad20Sopenharmony_ci * same 'int' primitive type) and could even have "overlapping" parts of type
42487c2aad20Sopenharmony_ci * graph that describe same subset of types.
42497c2aad20Sopenharmony_ci *
42507c2aad20Sopenharmony_ci * This in turn means that our assumption that each type in canonical graph
42517c2aad20Sopenharmony_ci * must correspond to exactly one type in candidate graph might not hold
42527c2aad20Sopenharmony_ci * anymore and will make it harder to detect contradictions using hypothetical
42537c2aad20Sopenharmony_ci * map. To handle this problem, we allow to follow FWD -> STRUCT/UNION
42547c2aad20Sopenharmony_ci * resolution only in canonical graph. FWDs in candidate graphs are never
42557c2aad20Sopenharmony_ci * resolved. To see why it's OK, let's check all possible situations w.r.t. FWDs
42567c2aad20Sopenharmony_ci * that can occur:
42577c2aad20Sopenharmony_ci *   - Both types in canonical and candidate graphs are FWDs. If they are
42587c2aad20Sopenharmony_ci *     structurally equivalent, then they can either be both resolved to the
42597c2aad20Sopenharmony_ci *     same STRUCT/UNION or not resolved at all. In both cases they are
42607c2aad20Sopenharmony_ci *     equivalent and there is no need to resolve FWD on candidate side.
42617c2aad20Sopenharmony_ci *   - Both types in canonical and candidate graphs are concrete STRUCT/UNION,
42627c2aad20Sopenharmony_ci *     so nothing to resolve as well, algorithm will check equivalence anyway.
42637c2aad20Sopenharmony_ci *   - Type in canonical graph is FWD, while type in candidate is concrete
42647c2aad20Sopenharmony_ci *     STRUCT/UNION. In this case candidate graph comes from single compilation
42657c2aad20Sopenharmony_ci *     unit, so there is exactly one BTF type for each unique C type. After
42667c2aad20Sopenharmony_ci *     resolving FWD into STRUCT/UNION, there might be more than one BTF type
42677c2aad20Sopenharmony_ci *     in canonical graph mapping to single BTF type in candidate graph, but
42687c2aad20Sopenharmony_ci *     because hypothetical mapping maps from canonical to candidate types, it's
42697c2aad20Sopenharmony_ci *     alright, and we still maintain the property of having single `canon_id`
42707c2aad20Sopenharmony_ci *     mapping to single `cand_id` (there could be two different `canon_id`
42717c2aad20Sopenharmony_ci *     mapped to the same `cand_id`, but it's not contradictory).
42727c2aad20Sopenharmony_ci *   - Type in canonical graph is concrete STRUCT/UNION, while type in candidate
42737c2aad20Sopenharmony_ci *     graph is FWD. In this case we are just going to check compatibility of
42747c2aad20Sopenharmony_ci *     STRUCT/UNION and corresponding FWD, and if they are compatible, we'll
42757c2aad20Sopenharmony_ci *     assume that whatever STRUCT/UNION FWD resolves to must be equivalent to
42767c2aad20Sopenharmony_ci *     a concrete STRUCT/UNION from canonical graph. If the rest of type graphs
42777c2aad20Sopenharmony_ci *     turn out equivalent, we'll re-resolve FWD to concrete STRUCT/UNION from
42787c2aad20Sopenharmony_ci *     canonical graph.
42797c2aad20Sopenharmony_ci */
42807c2aad20Sopenharmony_cistatic int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
42817c2aad20Sopenharmony_ci			      __u32 canon_id)
42827c2aad20Sopenharmony_ci{
42837c2aad20Sopenharmony_ci	struct btf_type *cand_type;
42847c2aad20Sopenharmony_ci	struct btf_type *canon_type;
42857c2aad20Sopenharmony_ci	__u32 hypot_type_id;
42867c2aad20Sopenharmony_ci	__u16 cand_kind;
42877c2aad20Sopenharmony_ci	__u16 canon_kind;
42887c2aad20Sopenharmony_ci	int i, eq;
42897c2aad20Sopenharmony_ci
42907c2aad20Sopenharmony_ci	/* if both resolve to the same canonical, they must be equivalent */
42917c2aad20Sopenharmony_ci	if (resolve_type_id(d, cand_id) == resolve_type_id(d, canon_id))
42927c2aad20Sopenharmony_ci		return 1;
42937c2aad20Sopenharmony_ci
42947c2aad20Sopenharmony_ci	canon_id = resolve_fwd_id(d, canon_id);
42957c2aad20Sopenharmony_ci
42967c2aad20Sopenharmony_ci	hypot_type_id = d->hypot_map[canon_id];
42977c2aad20Sopenharmony_ci	if (hypot_type_id <= BTF_MAX_NR_TYPES) {
42987c2aad20Sopenharmony_ci		if (hypot_type_id == cand_id)
42997c2aad20Sopenharmony_ci			return 1;
43007c2aad20Sopenharmony_ci		/* In some cases compiler will generate different DWARF types
43017c2aad20Sopenharmony_ci		 * for *identical* array type definitions and use them for
43027c2aad20Sopenharmony_ci		 * different fields within the *same* struct. This breaks type
43037c2aad20Sopenharmony_ci		 * equivalence check, which makes an assumption that candidate
43047c2aad20Sopenharmony_ci		 * types sub-graph has a consistent and deduped-by-compiler
43057c2aad20Sopenharmony_ci		 * types within a single CU. So work around that by explicitly
43067c2aad20Sopenharmony_ci		 * allowing identical array types here.
43077c2aad20Sopenharmony_ci		 */
43087c2aad20Sopenharmony_ci		if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id))
43097c2aad20Sopenharmony_ci			return 1;
43107c2aad20Sopenharmony_ci		/* It turns out that similar situation can happen with
43117c2aad20Sopenharmony_ci		 * struct/union sometimes, sigh... Handle the case where
43127c2aad20Sopenharmony_ci		 * structs/unions are exactly the same, down to the referenced
43137c2aad20Sopenharmony_ci		 * type IDs. Anything more complicated (e.g., if referenced
43147c2aad20Sopenharmony_ci		 * types are different, but equivalent) is *way more*
43157c2aad20Sopenharmony_ci		 * complicated and requires a many-to-many equivalence mapping.
43167c2aad20Sopenharmony_ci		 */
43177c2aad20Sopenharmony_ci		if (btf_dedup_identical_structs(d, hypot_type_id, cand_id))
43187c2aad20Sopenharmony_ci			return 1;
43197c2aad20Sopenharmony_ci		return 0;
43207c2aad20Sopenharmony_ci	}
43217c2aad20Sopenharmony_ci
43227c2aad20Sopenharmony_ci	if (btf_dedup_hypot_map_add(d, canon_id, cand_id))
43237c2aad20Sopenharmony_ci		return -ENOMEM;
43247c2aad20Sopenharmony_ci
43257c2aad20Sopenharmony_ci	cand_type = btf_type_by_id(d->btf, cand_id);
43267c2aad20Sopenharmony_ci	canon_type = btf_type_by_id(d->btf, canon_id);
43277c2aad20Sopenharmony_ci	cand_kind = btf_kind(cand_type);
43287c2aad20Sopenharmony_ci	canon_kind = btf_kind(canon_type);
43297c2aad20Sopenharmony_ci
43307c2aad20Sopenharmony_ci	if (cand_type->name_off != canon_type->name_off)
43317c2aad20Sopenharmony_ci		return 0;
43327c2aad20Sopenharmony_ci
43337c2aad20Sopenharmony_ci	/* FWD <--> STRUCT/UNION equivalence check, if enabled */
43347c2aad20Sopenharmony_ci	if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
43357c2aad20Sopenharmony_ci	    && cand_kind != canon_kind) {
43367c2aad20Sopenharmony_ci		__u16 real_kind;
43377c2aad20Sopenharmony_ci		__u16 fwd_kind;
43387c2aad20Sopenharmony_ci
43397c2aad20Sopenharmony_ci		if (cand_kind == BTF_KIND_FWD) {
43407c2aad20Sopenharmony_ci			real_kind = canon_kind;
43417c2aad20Sopenharmony_ci			fwd_kind = btf_fwd_kind(cand_type);
43427c2aad20Sopenharmony_ci		} else {
43437c2aad20Sopenharmony_ci			real_kind = cand_kind;
43447c2aad20Sopenharmony_ci			fwd_kind = btf_fwd_kind(canon_type);
43457c2aad20Sopenharmony_ci			/* we'd need to resolve base FWD to STRUCT/UNION */
43467c2aad20Sopenharmony_ci			if (fwd_kind == real_kind && canon_id < d->btf->start_id)
43477c2aad20Sopenharmony_ci				d->hypot_adjust_canon = true;
43487c2aad20Sopenharmony_ci		}
43497c2aad20Sopenharmony_ci		return fwd_kind == real_kind;
43507c2aad20Sopenharmony_ci	}
43517c2aad20Sopenharmony_ci
43527c2aad20Sopenharmony_ci	if (cand_kind != canon_kind)
43537c2aad20Sopenharmony_ci		return 0;
43547c2aad20Sopenharmony_ci
43557c2aad20Sopenharmony_ci	switch (cand_kind) {
43567c2aad20Sopenharmony_ci	case BTF_KIND_INT:
43577c2aad20Sopenharmony_ci		return btf_equal_int_tag(cand_type, canon_type);
43587c2aad20Sopenharmony_ci
43597c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
43607c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
43617c2aad20Sopenharmony_ci		return btf_compat_enum(cand_type, canon_type);
43627c2aad20Sopenharmony_ci
43637c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
43647c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
43657c2aad20Sopenharmony_ci		return btf_equal_common(cand_type, canon_type);
43667c2aad20Sopenharmony_ci
43677c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
43687c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
43697c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
43707c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
43717c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
43727c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
43737c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
43747c2aad20Sopenharmony_ci		if (cand_type->info != canon_type->info)
43757c2aad20Sopenharmony_ci			return 0;
43767c2aad20Sopenharmony_ci		return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
43777c2aad20Sopenharmony_ci
43787c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY: {
43797c2aad20Sopenharmony_ci		const struct btf_array *cand_arr, *canon_arr;
43807c2aad20Sopenharmony_ci
43817c2aad20Sopenharmony_ci		if (!btf_compat_array(cand_type, canon_type))
43827c2aad20Sopenharmony_ci			return 0;
43837c2aad20Sopenharmony_ci		cand_arr = btf_array(cand_type);
43847c2aad20Sopenharmony_ci		canon_arr = btf_array(canon_type);
43857c2aad20Sopenharmony_ci		eq = btf_dedup_is_equiv(d, cand_arr->index_type, canon_arr->index_type);
43867c2aad20Sopenharmony_ci		if (eq <= 0)
43877c2aad20Sopenharmony_ci			return eq;
43887c2aad20Sopenharmony_ci		return btf_dedup_is_equiv(d, cand_arr->type, canon_arr->type);
43897c2aad20Sopenharmony_ci	}
43907c2aad20Sopenharmony_ci
43917c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
43927c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
43937c2aad20Sopenharmony_ci		const struct btf_member *cand_m, *canon_m;
43947c2aad20Sopenharmony_ci		__u16 vlen;
43957c2aad20Sopenharmony_ci
43967c2aad20Sopenharmony_ci		if (!btf_shallow_equal_struct(cand_type, canon_type))
43977c2aad20Sopenharmony_ci			return 0;
43987c2aad20Sopenharmony_ci		vlen = btf_vlen(cand_type);
43997c2aad20Sopenharmony_ci		cand_m = btf_members(cand_type);
44007c2aad20Sopenharmony_ci		canon_m = btf_members(canon_type);
44017c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++) {
44027c2aad20Sopenharmony_ci			eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
44037c2aad20Sopenharmony_ci			if (eq <= 0)
44047c2aad20Sopenharmony_ci				return eq;
44057c2aad20Sopenharmony_ci			cand_m++;
44067c2aad20Sopenharmony_ci			canon_m++;
44077c2aad20Sopenharmony_ci		}
44087c2aad20Sopenharmony_ci
44097c2aad20Sopenharmony_ci		return 1;
44107c2aad20Sopenharmony_ci	}
44117c2aad20Sopenharmony_ci
44127c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
44137c2aad20Sopenharmony_ci		const struct btf_param *cand_p, *canon_p;
44147c2aad20Sopenharmony_ci		__u16 vlen;
44157c2aad20Sopenharmony_ci
44167c2aad20Sopenharmony_ci		if (!btf_compat_fnproto(cand_type, canon_type))
44177c2aad20Sopenharmony_ci			return 0;
44187c2aad20Sopenharmony_ci		eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
44197c2aad20Sopenharmony_ci		if (eq <= 0)
44207c2aad20Sopenharmony_ci			return eq;
44217c2aad20Sopenharmony_ci		vlen = btf_vlen(cand_type);
44227c2aad20Sopenharmony_ci		cand_p = btf_params(cand_type);
44237c2aad20Sopenharmony_ci		canon_p = btf_params(canon_type);
44247c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++) {
44257c2aad20Sopenharmony_ci			eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
44267c2aad20Sopenharmony_ci			if (eq <= 0)
44277c2aad20Sopenharmony_ci				return eq;
44287c2aad20Sopenharmony_ci			cand_p++;
44297c2aad20Sopenharmony_ci			canon_p++;
44307c2aad20Sopenharmony_ci		}
44317c2aad20Sopenharmony_ci		return 1;
44327c2aad20Sopenharmony_ci	}
44337c2aad20Sopenharmony_ci
44347c2aad20Sopenharmony_ci	default:
44357c2aad20Sopenharmony_ci		return -EINVAL;
44367c2aad20Sopenharmony_ci	}
44377c2aad20Sopenharmony_ci	return 0;
44387c2aad20Sopenharmony_ci}
44397c2aad20Sopenharmony_ci
44407c2aad20Sopenharmony_ci/*
44417c2aad20Sopenharmony_ci * Use hypothetical mapping, produced by successful type graph equivalence
44427c2aad20Sopenharmony_ci * check, to augment existing struct/union canonical mapping, where possible.
44437c2aad20Sopenharmony_ci *
44447c2aad20Sopenharmony_ci * If BTF_KIND_FWD resolution is allowed, this mapping is also used to record
44457c2aad20Sopenharmony_ci * FWD -> STRUCT/UNION correspondence as well. FWD resolution is bidirectional:
44467c2aad20Sopenharmony_ci * it doesn't matter if FWD type was part of canonical graph or candidate one,
44477c2aad20Sopenharmony_ci * we are recording the mapping anyway. As opposed to carefulness required
44487c2aad20Sopenharmony_ci * for struct/union correspondence mapping (described below), for FWD resolution
44497c2aad20Sopenharmony_ci * it's not important, as by the time that FWD type (reference type) will be
44507c2aad20Sopenharmony_ci * deduplicated all structs/unions will be deduped already anyway.
44517c2aad20Sopenharmony_ci *
44527c2aad20Sopenharmony_ci * Recording STRUCT/UNION mapping is purely a performance optimization and is
44537c2aad20Sopenharmony_ci * not required for correctness. It needs to be done carefully to ensure that
44547c2aad20Sopenharmony_ci * struct/union from candidate's type graph is not mapped into corresponding
44557c2aad20Sopenharmony_ci * struct/union from canonical type graph that itself hasn't been resolved into
44567c2aad20Sopenharmony_ci * canonical representative. The only guarantee we have is that canonical
44577c2aad20Sopenharmony_ci * struct/union was determined as canonical and that won't change. But any
44587c2aad20Sopenharmony_ci * types referenced through that struct/union fields could have been not yet
44597c2aad20Sopenharmony_ci * resolved, so in case like that it's too early to establish any kind of
44607c2aad20Sopenharmony_ci * correspondence between structs/unions.
44617c2aad20Sopenharmony_ci *
44627c2aad20Sopenharmony_ci * No canonical correspondence is derived for primitive types (they are already
44637c2aad20Sopenharmony_ci * deduplicated completely already anyway) or reference types (they rely on
44647c2aad20Sopenharmony_ci * stability of struct/union canonical relationship for equivalence checks).
44657c2aad20Sopenharmony_ci */
44667c2aad20Sopenharmony_cistatic void btf_dedup_merge_hypot_map(struct btf_dedup *d)
44677c2aad20Sopenharmony_ci{
44687c2aad20Sopenharmony_ci	__u32 canon_type_id, targ_type_id;
44697c2aad20Sopenharmony_ci	__u16 t_kind, c_kind;
44707c2aad20Sopenharmony_ci	__u32 t_id, c_id;
44717c2aad20Sopenharmony_ci	int i;
44727c2aad20Sopenharmony_ci
44737c2aad20Sopenharmony_ci	for (i = 0; i < d->hypot_cnt; i++) {
44747c2aad20Sopenharmony_ci		canon_type_id = d->hypot_list[i];
44757c2aad20Sopenharmony_ci		targ_type_id = d->hypot_map[canon_type_id];
44767c2aad20Sopenharmony_ci		t_id = resolve_type_id(d, targ_type_id);
44777c2aad20Sopenharmony_ci		c_id = resolve_type_id(d, canon_type_id);
44787c2aad20Sopenharmony_ci		t_kind = btf_kind(btf__type_by_id(d->btf, t_id));
44797c2aad20Sopenharmony_ci		c_kind = btf_kind(btf__type_by_id(d->btf, c_id));
44807c2aad20Sopenharmony_ci		/*
44817c2aad20Sopenharmony_ci		 * Resolve FWD into STRUCT/UNION.
44827c2aad20Sopenharmony_ci		 * It's ok to resolve FWD into STRUCT/UNION that's not yet
44837c2aad20Sopenharmony_ci		 * mapped to canonical representative (as opposed to
44847c2aad20Sopenharmony_ci		 * STRUCT/UNION <--> STRUCT/UNION mapping logic below), because
44857c2aad20Sopenharmony_ci		 * eventually that struct is going to be mapped and all resolved
44867c2aad20Sopenharmony_ci		 * FWDs will automatically resolve to correct canonical
44877c2aad20Sopenharmony_ci		 * representative. This will happen before ref type deduping,
44887c2aad20Sopenharmony_ci		 * which critically depends on stability of these mapping. This
44897c2aad20Sopenharmony_ci		 * stability is not a requirement for STRUCT/UNION equivalence
44907c2aad20Sopenharmony_ci		 * checks, though.
44917c2aad20Sopenharmony_ci		 */
44927c2aad20Sopenharmony_ci
44937c2aad20Sopenharmony_ci		/* if it's the split BTF case, we still need to point base FWD
44947c2aad20Sopenharmony_ci		 * to STRUCT/UNION in a split BTF, because FWDs from split BTF
44957c2aad20Sopenharmony_ci		 * will be resolved against base FWD. If we don't point base
44967c2aad20Sopenharmony_ci		 * canonical FWD to the resolved STRUCT/UNION, then all the
44977c2aad20Sopenharmony_ci		 * FWDs in split BTF won't be correctly resolved to a proper
44987c2aad20Sopenharmony_ci		 * STRUCT/UNION.
44997c2aad20Sopenharmony_ci		 */
45007c2aad20Sopenharmony_ci		if (t_kind != BTF_KIND_FWD && c_kind == BTF_KIND_FWD)
45017c2aad20Sopenharmony_ci			d->map[c_id] = t_id;
45027c2aad20Sopenharmony_ci
45037c2aad20Sopenharmony_ci		/* if graph equivalence determined that we'd need to adjust
45047c2aad20Sopenharmony_ci		 * base canonical types, then we need to only point base FWDs
45057c2aad20Sopenharmony_ci		 * to STRUCTs/UNIONs and do no more modifications. For all
45067c2aad20Sopenharmony_ci		 * other purposes the type graphs were not equivalent.
45077c2aad20Sopenharmony_ci		 */
45087c2aad20Sopenharmony_ci		if (d->hypot_adjust_canon)
45097c2aad20Sopenharmony_ci			continue;
45107c2aad20Sopenharmony_ci
45117c2aad20Sopenharmony_ci		if (t_kind == BTF_KIND_FWD && c_kind != BTF_KIND_FWD)
45127c2aad20Sopenharmony_ci			d->map[t_id] = c_id;
45137c2aad20Sopenharmony_ci
45147c2aad20Sopenharmony_ci		if ((t_kind == BTF_KIND_STRUCT || t_kind == BTF_KIND_UNION) &&
45157c2aad20Sopenharmony_ci		    c_kind != BTF_KIND_FWD &&
45167c2aad20Sopenharmony_ci		    is_type_mapped(d, c_id) &&
45177c2aad20Sopenharmony_ci		    !is_type_mapped(d, t_id)) {
45187c2aad20Sopenharmony_ci			/*
45197c2aad20Sopenharmony_ci			 * as a perf optimization, we can map struct/union
45207c2aad20Sopenharmony_ci			 * that's part of type graph we just verified for
45217c2aad20Sopenharmony_ci			 * equivalence. We can do that for struct/union that has
45227c2aad20Sopenharmony_ci			 * canonical representative only, though.
45237c2aad20Sopenharmony_ci			 */
45247c2aad20Sopenharmony_ci			d->map[t_id] = c_id;
45257c2aad20Sopenharmony_ci		}
45267c2aad20Sopenharmony_ci	}
45277c2aad20Sopenharmony_ci}
45287c2aad20Sopenharmony_ci
45297c2aad20Sopenharmony_ci/*
45307c2aad20Sopenharmony_ci * Deduplicate struct/union types.
45317c2aad20Sopenharmony_ci *
45327c2aad20Sopenharmony_ci * For each struct/union type its type signature hash is calculated, taking
45337c2aad20Sopenharmony_ci * into account type's name, size, number, order and names of fields, but
45347c2aad20Sopenharmony_ci * ignoring type ID's referenced from fields, because they might not be deduped
45357c2aad20Sopenharmony_ci * completely until after reference types deduplication phase. This type hash
45367c2aad20Sopenharmony_ci * is used to iterate over all potential canonical types, sharing same hash.
45377c2aad20Sopenharmony_ci * For each canonical candidate we check whether type graphs that they form
45387c2aad20Sopenharmony_ci * (through referenced types in fields and so on) are equivalent using algorithm
45397c2aad20Sopenharmony_ci * implemented in `btf_dedup_is_equiv`. If such equivalence is found and
45407c2aad20Sopenharmony_ci * BTF_KIND_FWD resolution is allowed, then hypothetical mapping
45417c2aad20Sopenharmony_ci * (btf_dedup->hypot_map) produced by aforementioned type graph equivalence
45427c2aad20Sopenharmony_ci * algorithm is used to record FWD -> STRUCT/UNION mapping. It's also used to
45437c2aad20Sopenharmony_ci * potentially map other structs/unions to their canonical representatives,
45447c2aad20Sopenharmony_ci * if such relationship hasn't yet been established. This speeds up algorithm
45457c2aad20Sopenharmony_ci * by eliminating some of the duplicate work.
45467c2aad20Sopenharmony_ci *
45477c2aad20Sopenharmony_ci * If no matching canonical representative was found, struct/union is marked
45487c2aad20Sopenharmony_ci * as canonical for itself and is added into btf_dedup->dedup_table hash map
45497c2aad20Sopenharmony_ci * for further look ups.
45507c2aad20Sopenharmony_ci */
45517c2aad20Sopenharmony_cistatic int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
45527c2aad20Sopenharmony_ci{
45537c2aad20Sopenharmony_ci	struct btf_type *cand_type, *t;
45547c2aad20Sopenharmony_ci	struct hashmap_entry *hash_entry;
45557c2aad20Sopenharmony_ci	/* if we don't find equivalent type, then we are canonical */
45567c2aad20Sopenharmony_ci	__u32 new_id = type_id;
45577c2aad20Sopenharmony_ci	__u16 kind;
45587c2aad20Sopenharmony_ci	long h;
45597c2aad20Sopenharmony_ci
45607c2aad20Sopenharmony_ci	/* already deduped or is in process of deduping (loop detected) */
45617c2aad20Sopenharmony_ci	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
45627c2aad20Sopenharmony_ci		return 0;
45637c2aad20Sopenharmony_ci
45647c2aad20Sopenharmony_ci	t = btf_type_by_id(d->btf, type_id);
45657c2aad20Sopenharmony_ci	kind = btf_kind(t);
45667c2aad20Sopenharmony_ci
45677c2aad20Sopenharmony_ci	if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
45687c2aad20Sopenharmony_ci		return 0;
45697c2aad20Sopenharmony_ci
45707c2aad20Sopenharmony_ci	h = btf_hash_struct(t);
45717c2aad20Sopenharmony_ci	for_each_dedup_cand(d, hash_entry, h) {
45727c2aad20Sopenharmony_ci		__u32 cand_id = hash_entry->value;
45737c2aad20Sopenharmony_ci		int eq;
45747c2aad20Sopenharmony_ci
45757c2aad20Sopenharmony_ci		/*
45767c2aad20Sopenharmony_ci		 * Even though btf_dedup_is_equiv() checks for
45777c2aad20Sopenharmony_ci		 * btf_shallow_equal_struct() internally when checking two
45787c2aad20Sopenharmony_ci		 * structs (unions) for equivalence, we need to guard here
45797c2aad20Sopenharmony_ci		 * from picking matching FWD type as a dedup candidate.
45807c2aad20Sopenharmony_ci		 * This can happen due to hash collision. In such case just
45817c2aad20Sopenharmony_ci		 * relying on btf_dedup_is_equiv() would lead to potentially
45827c2aad20Sopenharmony_ci		 * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because
45837c2aad20Sopenharmony_ci		 * FWD and compatible STRUCT/UNION are considered equivalent.
45847c2aad20Sopenharmony_ci		 */
45857c2aad20Sopenharmony_ci		cand_type = btf_type_by_id(d->btf, cand_id);
45867c2aad20Sopenharmony_ci		if (!btf_shallow_equal_struct(t, cand_type))
45877c2aad20Sopenharmony_ci			continue;
45887c2aad20Sopenharmony_ci
45897c2aad20Sopenharmony_ci		btf_dedup_clear_hypot_map(d);
45907c2aad20Sopenharmony_ci		eq = btf_dedup_is_equiv(d, type_id, cand_id);
45917c2aad20Sopenharmony_ci		if (eq < 0)
45927c2aad20Sopenharmony_ci			return eq;
45937c2aad20Sopenharmony_ci		if (!eq)
45947c2aad20Sopenharmony_ci			continue;
45957c2aad20Sopenharmony_ci		btf_dedup_merge_hypot_map(d);
45967c2aad20Sopenharmony_ci		if (d->hypot_adjust_canon) /* not really equivalent */
45977c2aad20Sopenharmony_ci			continue;
45987c2aad20Sopenharmony_ci		new_id = cand_id;
45997c2aad20Sopenharmony_ci		break;
46007c2aad20Sopenharmony_ci	}
46017c2aad20Sopenharmony_ci
46027c2aad20Sopenharmony_ci	d->map[type_id] = new_id;
46037c2aad20Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
46047c2aad20Sopenharmony_ci		return -ENOMEM;
46057c2aad20Sopenharmony_ci
46067c2aad20Sopenharmony_ci	return 0;
46077c2aad20Sopenharmony_ci}
46087c2aad20Sopenharmony_ci
46097c2aad20Sopenharmony_cistatic int btf_dedup_struct_types(struct btf_dedup *d)
46107c2aad20Sopenharmony_ci{
46117c2aad20Sopenharmony_ci	int i, err;
46127c2aad20Sopenharmony_ci
46137c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
46147c2aad20Sopenharmony_ci		err = btf_dedup_struct_type(d, d->btf->start_id + i);
46157c2aad20Sopenharmony_ci		if (err)
46167c2aad20Sopenharmony_ci			return err;
46177c2aad20Sopenharmony_ci	}
46187c2aad20Sopenharmony_ci	return 0;
46197c2aad20Sopenharmony_ci}
46207c2aad20Sopenharmony_ci
46217c2aad20Sopenharmony_ci/*
46227c2aad20Sopenharmony_ci * Deduplicate reference type.
46237c2aad20Sopenharmony_ci *
46247c2aad20Sopenharmony_ci * Once all primitive and struct/union types got deduplicated, we can easily
46257c2aad20Sopenharmony_ci * deduplicate all other (reference) BTF types. This is done in two steps:
46267c2aad20Sopenharmony_ci *
46277c2aad20Sopenharmony_ci * 1. Resolve all referenced type IDs into their canonical type IDs. This
46287c2aad20Sopenharmony_ci * resolution can be done either immediately for primitive or struct/union types
46297c2aad20Sopenharmony_ci * (because they were deduped in previous two phases) or recursively for
46307c2aad20Sopenharmony_ci * reference types. Recursion will always terminate at either primitive or
46317c2aad20Sopenharmony_ci * struct/union type, at which point we can "unwind" chain of reference types
46327c2aad20Sopenharmony_ci * one by one. There is no danger of encountering cycles because in C type
46337c2aad20Sopenharmony_ci * system the only way to form type cycle is through struct/union, so any chain
46347c2aad20Sopenharmony_ci * of reference types, even those taking part in a type cycle, will inevitably
46357c2aad20Sopenharmony_ci * reach struct/union at some point.
46367c2aad20Sopenharmony_ci *
46377c2aad20Sopenharmony_ci * 2. Once all referenced type IDs are resolved into canonical ones, BTF type
46387c2aad20Sopenharmony_ci * becomes "stable", in the sense that no further deduplication will cause
46397c2aad20Sopenharmony_ci * any changes to it. With that, it's now possible to calculate type's signature
46407c2aad20Sopenharmony_ci * hash (this time taking into account referenced type IDs) and loop over all
46417c2aad20Sopenharmony_ci * potential canonical representatives. If no match was found, current type
46427c2aad20Sopenharmony_ci * will become canonical representative of itself and will be added into
46437c2aad20Sopenharmony_ci * btf_dedup->dedup_table as another possible canonical representative.
46447c2aad20Sopenharmony_ci */
46457c2aad20Sopenharmony_cistatic int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
46467c2aad20Sopenharmony_ci{
46477c2aad20Sopenharmony_ci	struct hashmap_entry *hash_entry;
46487c2aad20Sopenharmony_ci	__u32 new_id = type_id, cand_id;
46497c2aad20Sopenharmony_ci	struct btf_type *t, *cand;
46507c2aad20Sopenharmony_ci	/* if we don't find equivalent type, then we are representative type */
46517c2aad20Sopenharmony_ci	int ref_type_id;
46527c2aad20Sopenharmony_ci	long h;
46537c2aad20Sopenharmony_ci
46547c2aad20Sopenharmony_ci	if (d->map[type_id] == BTF_IN_PROGRESS_ID)
46557c2aad20Sopenharmony_ci		return -ELOOP;
46567c2aad20Sopenharmony_ci	if (d->map[type_id] <= BTF_MAX_NR_TYPES)
46577c2aad20Sopenharmony_ci		return resolve_type_id(d, type_id);
46587c2aad20Sopenharmony_ci
46597c2aad20Sopenharmony_ci	t = btf_type_by_id(d->btf, type_id);
46607c2aad20Sopenharmony_ci	d->map[type_id] = BTF_IN_PROGRESS_ID;
46617c2aad20Sopenharmony_ci
46627c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
46637c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
46647c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
46657c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
46667c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
46677c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
46687c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
46697c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
46707c2aad20Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
46717c2aad20Sopenharmony_ci		if (ref_type_id < 0)
46727c2aad20Sopenharmony_ci			return ref_type_id;
46737c2aad20Sopenharmony_ci		t->type = ref_type_id;
46747c2aad20Sopenharmony_ci
46757c2aad20Sopenharmony_ci		h = btf_hash_common(t);
46767c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
46777c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
46787c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
46797c2aad20Sopenharmony_ci			if (btf_equal_common(t, cand)) {
46807c2aad20Sopenharmony_ci				new_id = cand_id;
46817c2aad20Sopenharmony_ci				break;
46827c2aad20Sopenharmony_ci			}
46837c2aad20Sopenharmony_ci		}
46847c2aad20Sopenharmony_ci		break;
46857c2aad20Sopenharmony_ci
46867c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
46877c2aad20Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
46887c2aad20Sopenharmony_ci		if (ref_type_id < 0)
46897c2aad20Sopenharmony_ci			return ref_type_id;
46907c2aad20Sopenharmony_ci		t->type = ref_type_id;
46917c2aad20Sopenharmony_ci
46927c2aad20Sopenharmony_ci		h = btf_hash_int_decl_tag(t);
46937c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
46947c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
46957c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
46967c2aad20Sopenharmony_ci			if (btf_equal_int_tag(t, cand)) {
46977c2aad20Sopenharmony_ci				new_id = cand_id;
46987c2aad20Sopenharmony_ci				break;
46997c2aad20Sopenharmony_ci			}
47007c2aad20Sopenharmony_ci		}
47017c2aad20Sopenharmony_ci		break;
47027c2aad20Sopenharmony_ci
47037c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY: {
47047c2aad20Sopenharmony_ci		struct btf_array *info = btf_array(t);
47057c2aad20Sopenharmony_ci
47067c2aad20Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, info->type);
47077c2aad20Sopenharmony_ci		if (ref_type_id < 0)
47087c2aad20Sopenharmony_ci			return ref_type_id;
47097c2aad20Sopenharmony_ci		info->type = ref_type_id;
47107c2aad20Sopenharmony_ci
47117c2aad20Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, info->index_type);
47127c2aad20Sopenharmony_ci		if (ref_type_id < 0)
47137c2aad20Sopenharmony_ci			return ref_type_id;
47147c2aad20Sopenharmony_ci		info->index_type = ref_type_id;
47157c2aad20Sopenharmony_ci
47167c2aad20Sopenharmony_ci		h = btf_hash_array(t);
47177c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
47187c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
47197c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
47207c2aad20Sopenharmony_ci			if (btf_equal_array(t, cand)) {
47217c2aad20Sopenharmony_ci				new_id = cand_id;
47227c2aad20Sopenharmony_ci				break;
47237c2aad20Sopenharmony_ci			}
47247c2aad20Sopenharmony_ci		}
47257c2aad20Sopenharmony_ci		break;
47267c2aad20Sopenharmony_ci	}
47277c2aad20Sopenharmony_ci
47287c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
47297c2aad20Sopenharmony_ci		struct btf_param *param;
47307c2aad20Sopenharmony_ci		__u16 vlen;
47317c2aad20Sopenharmony_ci		int i;
47327c2aad20Sopenharmony_ci
47337c2aad20Sopenharmony_ci		ref_type_id = btf_dedup_ref_type(d, t->type);
47347c2aad20Sopenharmony_ci		if (ref_type_id < 0)
47357c2aad20Sopenharmony_ci			return ref_type_id;
47367c2aad20Sopenharmony_ci		t->type = ref_type_id;
47377c2aad20Sopenharmony_ci
47387c2aad20Sopenharmony_ci		vlen = btf_vlen(t);
47397c2aad20Sopenharmony_ci		param = btf_params(t);
47407c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++) {
47417c2aad20Sopenharmony_ci			ref_type_id = btf_dedup_ref_type(d, param->type);
47427c2aad20Sopenharmony_ci			if (ref_type_id < 0)
47437c2aad20Sopenharmony_ci				return ref_type_id;
47447c2aad20Sopenharmony_ci			param->type = ref_type_id;
47457c2aad20Sopenharmony_ci			param++;
47467c2aad20Sopenharmony_ci		}
47477c2aad20Sopenharmony_ci
47487c2aad20Sopenharmony_ci		h = btf_hash_fnproto(t);
47497c2aad20Sopenharmony_ci		for_each_dedup_cand(d, hash_entry, h) {
47507c2aad20Sopenharmony_ci			cand_id = hash_entry->value;
47517c2aad20Sopenharmony_ci			cand = btf_type_by_id(d->btf, cand_id);
47527c2aad20Sopenharmony_ci			if (btf_equal_fnproto(t, cand)) {
47537c2aad20Sopenharmony_ci				new_id = cand_id;
47547c2aad20Sopenharmony_ci				break;
47557c2aad20Sopenharmony_ci			}
47567c2aad20Sopenharmony_ci		}
47577c2aad20Sopenharmony_ci		break;
47587c2aad20Sopenharmony_ci	}
47597c2aad20Sopenharmony_ci
47607c2aad20Sopenharmony_ci	default:
47617c2aad20Sopenharmony_ci		return -EINVAL;
47627c2aad20Sopenharmony_ci	}
47637c2aad20Sopenharmony_ci
47647c2aad20Sopenharmony_ci	d->map[type_id] = new_id;
47657c2aad20Sopenharmony_ci	if (type_id == new_id && btf_dedup_table_add(d, h, type_id))
47667c2aad20Sopenharmony_ci		return -ENOMEM;
47677c2aad20Sopenharmony_ci
47687c2aad20Sopenharmony_ci	return new_id;
47697c2aad20Sopenharmony_ci}
47707c2aad20Sopenharmony_ci
47717c2aad20Sopenharmony_cistatic int btf_dedup_ref_types(struct btf_dedup *d)
47727c2aad20Sopenharmony_ci{
47737c2aad20Sopenharmony_ci	int i, err;
47747c2aad20Sopenharmony_ci
47757c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
47767c2aad20Sopenharmony_ci		err = btf_dedup_ref_type(d, d->btf->start_id + i);
47777c2aad20Sopenharmony_ci		if (err < 0)
47787c2aad20Sopenharmony_ci			return err;
47797c2aad20Sopenharmony_ci	}
47807c2aad20Sopenharmony_ci	/* we won't need d->dedup_table anymore */
47817c2aad20Sopenharmony_ci	hashmap__free(d->dedup_table);
47827c2aad20Sopenharmony_ci	d->dedup_table = NULL;
47837c2aad20Sopenharmony_ci	return 0;
47847c2aad20Sopenharmony_ci}
47857c2aad20Sopenharmony_ci
47867c2aad20Sopenharmony_ci/*
47877c2aad20Sopenharmony_ci * Collect a map from type names to type ids for all canonical structs
47887c2aad20Sopenharmony_ci * and unions. If the same name is shared by several canonical types
47897c2aad20Sopenharmony_ci * use a special value 0 to indicate this fact.
47907c2aad20Sopenharmony_ci */
47917c2aad20Sopenharmony_cistatic int btf_dedup_fill_unique_names_map(struct btf_dedup *d, struct hashmap *names_map)
47927c2aad20Sopenharmony_ci{
47937c2aad20Sopenharmony_ci	__u32 nr_types = btf__type_cnt(d->btf);
47947c2aad20Sopenharmony_ci	struct btf_type *t;
47957c2aad20Sopenharmony_ci	__u32 type_id;
47967c2aad20Sopenharmony_ci	__u16 kind;
47977c2aad20Sopenharmony_ci	int err;
47987c2aad20Sopenharmony_ci
47997c2aad20Sopenharmony_ci	/*
48007c2aad20Sopenharmony_ci	 * Iterate over base and split module ids in order to get all
48017c2aad20Sopenharmony_ci	 * available structs in the map.
48027c2aad20Sopenharmony_ci	 */
48037c2aad20Sopenharmony_ci	for (type_id = 1; type_id < nr_types; ++type_id) {
48047c2aad20Sopenharmony_ci		t = btf_type_by_id(d->btf, type_id);
48057c2aad20Sopenharmony_ci		kind = btf_kind(t);
48067c2aad20Sopenharmony_ci
48077c2aad20Sopenharmony_ci		if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
48087c2aad20Sopenharmony_ci			continue;
48097c2aad20Sopenharmony_ci
48107c2aad20Sopenharmony_ci		/* Skip non-canonical types */
48117c2aad20Sopenharmony_ci		if (type_id != d->map[type_id])
48127c2aad20Sopenharmony_ci			continue;
48137c2aad20Sopenharmony_ci
48147c2aad20Sopenharmony_ci		err = hashmap__add(names_map, t->name_off, type_id);
48157c2aad20Sopenharmony_ci		if (err == -EEXIST)
48167c2aad20Sopenharmony_ci			err = hashmap__set(names_map, t->name_off, 0, NULL, NULL);
48177c2aad20Sopenharmony_ci
48187c2aad20Sopenharmony_ci		if (err)
48197c2aad20Sopenharmony_ci			return err;
48207c2aad20Sopenharmony_ci	}
48217c2aad20Sopenharmony_ci
48227c2aad20Sopenharmony_ci	return 0;
48237c2aad20Sopenharmony_ci}
48247c2aad20Sopenharmony_ci
48257c2aad20Sopenharmony_cistatic int btf_dedup_resolve_fwd(struct btf_dedup *d, struct hashmap *names_map, __u32 type_id)
48267c2aad20Sopenharmony_ci{
48277c2aad20Sopenharmony_ci	struct btf_type *t = btf_type_by_id(d->btf, type_id);
48287c2aad20Sopenharmony_ci	enum btf_fwd_kind fwd_kind = btf_kflag(t);
48297c2aad20Sopenharmony_ci	__u16 cand_kind, kind = btf_kind(t);
48307c2aad20Sopenharmony_ci	struct btf_type *cand_t;
48317c2aad20Sopenharmony_ci	uintptr_t cand_id;
48327c2aad20Sopenharmony_ci
48337c2aad20Sopenharmony_ci	if (kind != BTF_KIND_FWD)
48347c2aad20Sopenharmony_ci		return 0;
48357c2aad20Sopenharmony_ci
48367c2aad20Sopenharmony_ci	/* Skip if this FWD already has a mapping */
48377c2aad20Sopenharmony_ci	if (type_id != d->map[type_id])
48387c2aad20Sopenharmony_ci		return 0;
48397c2aad20Sopenharmony_ci
48407c2aad20Sopenharmony_ci	if (!hashmap__find(names_map, t->name_off, &cand_id))
48417c2aad20Sopenharmony_ci		return 0;
48427c2aad20Sopenharmony_ci
48437c2aad20Sopenharmony_ci	/* Zero is a special value indicating that name is not unique */
48447c2aad20Sopenharmony_ci	if (!cand_id)
48457c2aad20Sopenharmony_ci		return 0;
48467c2aad20Sopenharmony_ci
48477c2aad20Sopenharmony_ci	cand_t = btf_type_by_id(d->btf, cand_id);
48487c2aad20Sopenharmony_ci	cand_kind = btf_kind(cand_t);
48497c2aad20Sopenharmony_ci	if ((cand_kind == BTF_KIND_STRUCT && fwd_kind != BTF_FWD_STRUCT) ||
48507c2aad20Sopenharmony_ci	    (cand_kind == BTF_KIND_UNION && fwd_kind != BTF_FWD_UNION))
48517c2aad20Sopenharmony_ci		return 0;
48527c2aad20Sopenharmony_ci
48537c2aad20Sopenharmony_ci	d->map[type_id] = cand_id;
48547c2aad20Sopenharmony_ci
48557c2aad20Sopenharmony_ci	return 0;
48567c2aad20Sopenharmony_ci}
48577c2aad20Sopenharmony_ci
48587c2aad20Sopenharmony_ci/*
48597c2aad20Sopenharmony_ci * Resolve unambiguous forward declarations.
48607c2aad20Sopenharmony_ci *
48617c2aad20Sopenharmony_ci * The lion's share of all FWD declarations is resolved during
48627c2aad20Sopenharmony_ci * `btf_dedup_struct_types` phase when different type graphs are
48637c2aad20Sopenharmony_ci * compared against each other. However, if in some compilation unit a
48647c2aad20Sopenharmony_ci * FWD declaration is not a part of a type graph compared against
48657c2aad20Sopenharmony_ci * another type graph that declaration's canonical type would not be
48667c2aad20Sopenharmony_ci * changed. Example:
48677c2aad20Sopenharmony_ci *
48687c2aad20Sopenharmony_ci * CU #1:
48697c2aad20Sopenharmony_ci *
48707c2aad20Sopenharmony_ci * struct foo;
48717c2aad20Sopenharmony_ci * struct foo *some_global;
48727c2aad20Sopenharmony_ci *
48737c2aad20Sopenharmony_ci * CU #2:
48747c2aad20Sopenharmony_ci *
48757c2aad20Sopenharmony_ci * struct foo { int u; };
48767c2aad20Sopenharmony_ci * struct foo *another_global;
48777c2aad20Sopenharmony_ci *
48787c2aad20Sopenharmony_ci * After `btf_dedup_struct_types` the BTF looks as follows:
48797c2aad20Sopenharmony_ci *
48807c2aad20Sopenharmony_ci * [1] STRUCT 'foo' size=4 vlen=1 ...
48817c2aad20Sopenharmony_ci * [2] INT 'int' size=4 ...
48827c2aad20Sopenharmony_ci * [3] PTR '(anon)' type_id=1
48837c2aad20Sopenharmony_ci * [4] FWD 'foo' fwd_kind=struct
48847c2aad20Sopenharmony_ci * [5] PTR '(anon)' type_id=4
48857c2aad20Sopenharmony_ci *
48867c2aad20Sopenharmony_ci * This pass assumes that such FWD declarations should be mapped to
48877c2aad20Sopenharmony_ci * structs or unions with identical name in case if the name is not
48887c2aad20Sopenharmony_ci * ambiguous.
48897c2aad20Sopenharmony_ci */
48907c2aad20Sopenharmony_cistatic int btf_dedup_resolve_fwds(struct btf_dedup *d)
48917c2aad20Sopenharmony_ci{
48927c2aad20Sopenharmony_ci	int i, err;
48937c2aad20Sopenharmony_ci	struct hashmap *names_map;
48947c2aad20Sopenharmony_ci
48957c2aad20Sopenharmony_ci	names_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
48967c2aad20Sopenharmony_ci	if (IS_ERR(names_map))
48977c2aad20Sopenharmony_ci		return PTR_ERR(names_map);
48987c2aad20Sopenharmony_ci
48997c2aad20Sopenharmony_ci	err = btf_dedup_fill_unique_names_map(d, names_map);
49007c2aad20Sopenharmony_ci	if (err < 0)
49017c2aad20Sopenharmony_ci		goto exit;
49027c2aad20Sopenharmony_ci
49037c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
49047c2aad20Sopenharmony_ci		err = btf_dedup_resolve_fwd(d, names_map, d->btf->start_id + i);
49057c2aad20Sopenharmony_ci		if (err < 0)
49067c2aad20Sopenharmony_ci			break;
49077c2aad20Sopenharmony_ci	}
49087c2aad20Sopenharmony_ci
49097c2aad20Sopenharmony_ciexit:
49107c2aad20Sopenharmony_ci	hashmap__free(names_map);
49117c2aad20Sopenharmony_ci	return err;
49127c2aad20Sopenharmony_ci}
49137c2aad20Sopenharmony_ci
49147c2aad20Sopenharmony_ci/*
49157c2aad20Sopenharmony_ci * Compact types.
49167c2aad20Sopenharmony_ci *
49177c2aad20Sopenharmony_ci * After we established for each type its corresponding canonical representative
49187c2aad20Sopenharmony_ci * type, we now can eliminate types that are not canonical and leave only
49197c2aad20Sopenharmony_ci * canonical ones layed out sequentially in memory by copying them over
49207c2aad20Sopenharmony_ci * duplicates. During compaction btf_dedup->hypot_map array is reused to store
49217c2aad20Sopenharmony_ci * a map from original type ID to a new compacted type ID, which will be used
49227c2aad20Sopenharmony_ci * during next phase to "fix up" type IDs, referenced from struct/union and
49237c2aad20Sopenharmony_ci * reference types.
49247c2aad20Sopenharmony_ci */
49257c2aad20Sopenharmony_cistatic int btf_dedup_compact_types(struct btf_dedup *d)
49267c2aad20Sopenharmony_ci{
49277c2aad20Sopenharmony_ci	__u32 *new_offs;
49287c2aad20Sopenharmony_ci	__u32 next_type_id = d->btf->start_id;
49297c2aad20Sopenharmony_ci	const struct btf_type *t;
49307c2aad20Sopenharmony_ci	void *p;
49317c2aad20Sopenharmony_ci	int i, id, len;
49327c2aad20Sopenharmony_ci
49337c2aad20Sopenharmony_ci	/* we are going to reuse hypot_map to store compaction remapping */
49347c2aad20Sopenharmony_ci	d->hypot_map[0] = 0;
49357c2aad20Sopenharmony_ci	/* base BTF types are not renumbered */
49367c2aad20Sopenharmony_ci	for (id = 1; id < d->btf->start_id; id++)
49377c2aad20Sopenharmony_ci		d->hypot_map[id] = id;
49387c2aad20Sopenharmony_ci	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++)
49397c2aad20Sopenharmony_ci		d->hypot_map[id] = BTF_UNPROCESSED_ID;
49407c2aad20Sopenharmony_ci
49417c2aad20Sopenharmony_ci	p = d->btf->types_data;
49427c2aad20Sopenharmony_ci
49437c2aad20Sopenharmony_ci	for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) {
49447c2aad20Sopenharmony_ci		if (d->map[id] != id)
49457c2aad20Sopenharmony_ci			continue;
49467c2aad20Sopenharmony_ci
49477c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
49487c2aad20Sopenharmony_ci		len = btf_type_size(t);
49497c2aad20Sopenharmony_ci		if (len < 0)
49507c2aad20Sopenharmony_ci			return len;
49517c2aad20Sopenharmony_ci
49527c2aad20Sopenharmony_ci		memmove(p, t, len);
49537c2aad20Sopenharmony_ci		d->hypot_map[id] = next_type_id;
49547c2aad20Sopenharmony_ci		d->btf->type_offs[next_type_id - d->btf->start_id] = p - d->btf->types_data;
49557c2aad20Sopenharmony_ci		p += len;
49567c2aad20Sopenharmony_ci		next_type_id++;
49577c2aad20Sopenharmony_ci	}
49587c2aad20Sopenharmony_ci
49597c2aad20Sopenharmony_ci	/* shrink struct btf's internal types index and update btf_header */
49607c2aad20Sopenharmony_ci	d->btf->nr_types = next_type_id - d->btf->start_id;
49617c2aad20Sopenharmony_ci	d->btf->type_offs_cap = d->btf->nr_types;
49627c2aad20Sopenharmony_ci	d->btf->hdr->type_len = p - d->btf->types_data;
49637c2aad20Sopenharmony_ci	new_offs = libbpf_reallocarray(d->btf->type_offs, d->btf->type_offs_cap,
49647c2aad20Sopenharmony_ci				       sizeof(*new_offs));
49657c2aad20Sopenharmony_ci	if (d->btf->type_offs_cap && !new_offs)
49667c2aad20Sopenharmony_ci		return -ENOMEM;
49677c2aad20Sopenharmony_ci	d->btf->type_offs = new_offs;
49687c2aad20Sopenharmony_ci	d->btf->hdr->str_off = d->btf->hdr->type_len;
49697c2aad20Sopenharmony_ci	d->btf->raw_size = d->btf->hdr->hdr_len + d->btf->hdr->type_len + d->btf->hdr->str_len;
49707c2aad20Sopenharmony_ci	return 0;
49717c2aad20Sopenharmony_ci}
49727c2aad20Sopenharmony_ci
49737c2aad20Sopenharmony_ci/*
49747c2aad20Sopenharmony_ci * Figure out final (deduplicated and compacted) type ID for provided original
49757c2aad20Sopenharmony_ci * `type_id` by first resolving it into corresponding canonical type ID and
49767c2aad20Sopenharmony_ci * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map,
49777c2aad20Sopenharmony_ci * which is populated during compaction phase.
49787c2aad20Sopenharmony_ci */
49797c2aad20Sopenharmony_cistatic int btf_dedup_remap_type_id(__u32 *type_id, void *ctx)
49807c2aad20Sopenharmony_ci{
49817c2aad20Sopenharmony_ci	struct btf_dedup *d = ctx;
49827c2aad20Sopenharmony_ci	__u32 resolved_type_id, new_type_id;
49837c2aad20Sopenharmony_ci
49847c2aad20Sopenharmony_ci	resolved_type_id = resolve_type_id(d, *type_id);
49857c2aad20Sopenharmony_ci	new_type_id = d->hypot_map[resolved_type_id];
49867c2aad20Sopenharmony_ci	if (new_type_id > BTF_MAX_NR_TYPES)
49877c2aad20Sopenharmony_ci		return -EINVAL;
49887c2aad20Sopenharmony_ci
49897c2aad20Sopenharmony_ci	*type_id = new_type_id;
49907c2aad20Sopenharmony_ci	return 0;
49917c2aad20Sopenharmony_ci}
49927c2aad20Sopenharmony_ci
49937c2aad20Sopenharmony_ci/*
49947c2aad20Sopenharmony_ci * Remap referenced type IDs into deduped type IDs.
49957c2aad20Sopenharmony_ci *
49967c2aad20Sopenharmony_ci * After BTF types are deduplicated and compacted, their final type IDs may
49977c2aad20Sopenharmony_ci * differ from original ones. The map from original to a corresponding
49987c2aad20Sopenharmony_ci * deduped type ID is stored in btf_dedup->hypot_map and is populated during
49997c2aad20Sopenharmony_ci * compaction phase. During remapping phase we are rewriting all type IDs
50007c2aad20Sopenharmony_ci * referenced from any BTF type (e.g., struct fields, func proto args, etc) to
50017c2aad20Sopenharmony_ci * their final deduped type IDs.
50027c2aad20Sopenharmony_ci */
50037c2aad20Sopenharmony_cistatic int btf_dedup_remap_types(struct btf_dedup *d)
50047c2aad20Sopenharmony_ci{
50057c2aad20Sopenharmony_ci	int i, r;
50067c2aad20Sopenharmony_ci
50077c2aad20Sopenharmony_ci	for (i = 0; i < d->btf->nr_types; i++) {
50087c2aad20Sopenharmony_ci		struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
50097c2aad20Sopenharmony_ci
50107c2aad20Sopenharmony_ci		r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d);
50117c2aad20Sopenharmony_ci		if (r)
50127c2aad20Sopenharmony_ci			return r;
50137c2aad20Sopenharmony_ci	}
50147c2aad20Sopenharmony_ci
50157c2aad20Sopenharmony_ci	if (!d->btf_ext)
50167c2aad20Sopenharmony_ci		return 0;
50177c2aad20Sopenharmony_ci
50187c2aad20Sopenharmony_ci	r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d);
50197c2aad20Sopenharmony_ci	if (r)
50207c2aad20Sopenharmony_ci		return r;
50217c2aad20Sopenharmony_ci
50227c2aad20Sopenharmony_ci	return 0;
50237c2aad20Sopenharmony_ci}
50247c2aad20Sopenharmony_ci
50257c2aad20Sopenharmony_ci/*
50267c2aad20Sopenharmony_ci * Probe few well-known locations for vmlinux kernel image and try to load BTF
50277c2aad20Sopenharmony_ci * data out of it to use for target BTF.
50287c2aad20Sopenharmony_ci */
50297c2aad20Sopenharmony_cistruct btf *btf__load_vmlinux_btf(void)
50307c2aad20Sopenharmony_ci{
50317c2aad20Sopenharmony_ci	const char *locations[] = {
50327c2aad20Sopenharmony_ci		/* try canonical vmlinux BTF through sysfs first */
50337c2aad20Sopenharmony_ci		"/sys/kernel/btf/vmlinux",
50347c2aad20Sopenharmony_ci		/* fall back to trying to find vmlinux on disk otherwise */
50357c2aad20Sopenharmony_ci		"/boot/vmlinux-%1$s",
50367c2aad20Sopenharmony_ci		"/lib/modules/%1$s/vmlinux-%1$s",
50377c2aad20Sopenharmony_ci		"/lib/modules/%1$s/build/vmlinux",
50387c2aad20Sopenharmony_ci		"/usr/lib/modules/%1$s/kernel/vmlinux",
50397c2aad20Sopenharmony_ci		"/usr/lib/debug/boot/vmlinux-%1$s",
50407c2aad20Sopenharmony_ci		"/usr/lib/debug/boot/vmlinux-%1$s.debug",
50417c2aad20Sopenharmony_ci		"/usr/lib/debug/lib/modules/%1$s/vmlinux",
50427c2aad20Sopenharmony_ci	};
50437c2aad20Sopenharmony_ci	char path[PATH_MAX + 1];
50447c2aad20Sopenharmony_ci	struct utsname buf;
50457c2aad20Sopenharmony_ci	struct btf *btf;
50467c2aad20Sopenharmony_ci	int i, err;
50477c2aad20Sopenharmony_ci
50487c2aad20Sopenharmony_ci	uname(&buf);
50497c2aad20Sopenharmony_ci
50507c2aad20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(locations); i++) {
50517c2aad20Sopenharmony_ci		snprintf(path, PATH_MAX, locations[i], buf.release);
50527c2aad20Sopenharmony_ci
50537c2aad20Sopenharmony_ci		if (faccessat(AT_FDCWD, path, R_OK, AT_EACCESS))
50547c2aad20Sopenharmony_ci			continue;
50557c2aad20Sopenharmony_ci
50567c2aad20Sopenharmony_ci		btf = btf__parse(path, NULL);
50577c2aad20Sopenharmony_ci		err = libbpf_get_error(btf);
50587c2aad20Sopenharmony_ci		pr_debug("loading kernel BTF '%s': %d\n", path, err);
50597c2aad20Sopenharmony_ci		if (err)
50607c2aad20Sopenharmony_ci			continue;
50617c2aad20Sopenharmony_ci
50627c2aad20Sopenharmony_ci		return btf;
50637c2aad20Sopenharmony_ci	}
50647c2aad20Sopenharmony_ci
50657c2aad20Sopenharmony_ci	pr_warn("failed to find valid kernel BTF\n");
50667c2aad20Sopenharmony_ci	return libbpf_err_ptr(-ESRCH);
50677c2aad20Sopenharmony_ci}
50687c2aad20Sopenharmony_ci
50697c2aad20Sopenharmony_cistruct btf *libbpf_find_kernel_btf(void) __attribute__((alias("btf__load_vmlinux_btf")));
50707c2aad20Sopenharmony_ci
50717c2aad20Sopenharmony_cistruct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf)
50727c2aad20Sopenharmony_ci{
50737c2aad20Sopenharmony_ci	char path[80];
50747c2aad20Sopenharmony_ci
50757c2aad20Sopenharmony_ci	snprintf(path, sizeof(path), "/sys/kernel/btf/%s", module_name);
50767c2aad20Sopenharmony_ci	return btf__parse_split(path, vmlinux_btf);
50777c2aad20Sopenharmony_ci}
50787c2aad20Sopenharmony_ci
50797c2aad20Sopenharmony_ciint btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx)
50807c2aad20Sopenharmony_ci{
50817c2aad20Sopenharmony_ci	int i, n, err;
50827c2aad20Sopenharmony_ci
50837c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
50847c2aad20Sopenharmony_ci	case BTF_KIND_INT:
50857c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
50867c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
50877c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
50887c2aad20Sopenharmony_ci		return 0;
50897c2aad20Sopenharmony_ci
50907c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
50917c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
50927c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
50937c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
50947c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
50957c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
50967c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
50977c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
50987c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
50997c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
51007c2aad20Sopenharmony_ci		return visit(&t->type, ctx);
51017c2aad20Sopenharmony_ci
51027c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY: {
51037c2aad20Sopenharmony_ci		struct btf_array *a = btf_array(t);
51047c2aad20Sopenharmony_ci
51057c2aad20Sopenharmony_ci		err = visit(&a->type, ctx);
51067c2aad20Sopenharmony_ci		err = err ?: visit(&a->index_type, ctx);
51077c2aad20Sopenharmony_ci		return err;
51087c2aad20Sopenharmony_ci	}
51097c2aad20Sopenharmony_ci
51107c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
51117c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
51127c2aad20Sopenharmony_ci		struct btf_member *m = btf_members(t);
51137c2aad20Sopenharmony_ci
51147c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51157c2aad20Sopenharmony_ci			err = visit(&m->type, ctx);
51167c2aad20Sopenharmony_ci			if (err)
51177c2aad20Sopenharmony_ci				return err;
51187c2aad20Sopenharmony_ci		}
51197c2aad20Sopenharmony_ci		return 0;
51207c2aad20Sopenharmony_ci	}
51217c2aad20Sopenharmony_ci
51227c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
51237c2aad20Sopenharmony_ci		struct btf_param *m = btf_params(t);
51247c2aad20Sopenharmony_ci
51257c2aad20Sopenharmony_ci		err = visit(&t->type, ctx);
51267c2aad20Sopenharmony_ci		if (err)
51277c2aad20Sopenharmony_ci			return err;
51287c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51297c2aad20Sopenharmony_ci			err = visit(&m->type, ctx);
51307c2aad20Sopenharmony_ci			if (err)
51317c2aad20Sopenharmony_ci				return err;
51327c2aad20Sopenharmony_ci		}
51337c2aad20Sopenharmony_ci		return 0;
51347c2aad20Sopenharmony_ci	}
51357c2aad20Sopenharmony_ci
51367c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC: {
51377c2aad20Sopenharmony_ci		struct btf_var_secinfo *m = btf_var_secinfos(t);
51387c2aad20Sopenharmony_ci
51397c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51407c2aad20Sopenharmony_ci			err = visit(&m->type, ctx);
51417c2aad20Sopenharmony_ci			if (err)
51427c2aad20Sopenharmony_ci				return err;
51437c2aad20Sopenharmony_ci		}
51447c2aad20Sopenharmony_ci		return 0;
51457c2aad20Sopenharmony_ci	}
51467c2aad20Sopenharmony_ci
51477c2aad20Sopenharmony_ci	default:
51487c2aad20Sopenharmony_ci		return -EINVAL;
51497c2aad20Sopenharmony_ci	}
51507c2aad20Sopenharmony_ci}
51517c2aad20Sopenharmony_ci
51527c2aad20Sopenharmony_ciint btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx)
51537c2aad20Sopenharmony_ci{
51547c2aad20Sopenharmony_ci	int i, n, err;
51557c2aad20Sopenharmony_ci
51567c2aad20Sopenharmony_ci	err = visit(&t->name_off, ctx);
51577c2aad20Sopenharmony_ci	if (err)
51587c2aad20Sopenharmony_ci		return err;
51597c2aad20Sopenharmony_ci
51607c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
51617c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
51627c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
51637c2aad20Sopenharmony_ci		struct btf_member *m = btf_members(t);
51647c2aad20Sopenharmony_ci
51657c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51667c2aad20Sopenharmony_ci			err = visit(&m->name_off, ctx);
51677c2aad20Sopenharmony_ci			if (err)
51687c2aad20Sopenharmony_ci				return err;
51697c2aad20Sopenharmony_ci		}
51707c2aad20Sopenharmony_ci		break;
51717c2aad20Sopenharmony_ci	}
51727c2aad20Sopenharmony_ci	case BTF_KIND_ENUM: {
51737c2aad20Sopenharmony_ci		struct btf_enum *m = btf_enum(t);
51747c2aad20Sopenharmony_ci
51757c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51767c2aad20Sopenharmony_ci			err = visit(&m->name_off, ctx);
51777c2aad20Sopenharmony_ci			if (err)
51787c2aad20Sopenharmony_ci				return err;
51797c2aad20Sopenharmony_ci		}
51807c2aad20Sopenharmony_ci		break;
51817c2aad20Sopenharmony_ci	}
51827c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64: {
51837c2aad20Sopenharmony_ci		struct btf_enum64 *m = btf_enum64(t);
51847c2aad20Sopenharmony_ci
51857c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51867c2aad20Sopenharmony_ci			err = visit(&m->name_off, ctx);
51877c2aad20Sopenharmony_ci			if (err)
51887c2aad20Sopenharmony_ci				return err;
51897c2aad20Sopenharmony_ci		}
51907c2aad20Sopenharmony_ci		break;
51917c2aad20Sopenharmony_ci	}
51927c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
51937c2aad20Sopenharmony_ci		struct btf_param *m = btf_params(t);
51947c2aad20Sopenharmony_ci
51957c2aad20Sopenharmony_ci		for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
51967c2aad20Sopenharmony_ci			err = visit(&m->name_off, ctx);
51977c2aad20Sopenharmony_ci			if (err)
51987c2aad20Sopenharmony_ci				return err;
51997c2aad20Sopenharmony_ci		}
52007c2aad20Sopenharmony_ci		break;
52017c2aad20Sopenharmony_ci	}
52027c2aad20Sopenharmony_ci	default:
52037c2aad20Sopenharmony_ci		break;
52047c2aad20Sopenharmony_ci	}
52057c2aad20Sopenharmony_ci
52067c2aad20Sopenharmony_ci	return 0;
52077c2aad20Sopenharmony_ci}
52087c2aad20Sopenharmony_ci
52097c2aad20Sopenharmony_ciint btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx)
52107c2aad20Sopenharmony_ci{
52117c2aad20Sopenharmony_ci	const struct btf_ext_info *seg;
52127c2aad20Sopenharmony_ci	struct btf_ext_info_sec *sec;
52137c2aad20Sopenharmony_ci	int i, err;
52147c2aad20Sopenharmony_ci
52157c2aad20Sopenharmony_ci	seg = &btf_ext->func_info;
52167c2aad20Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
52177c2aad20Sopenharmony_ci		struct bpf_func_info_min *rec;
52187c2aad20Sopenharmony_ci
52197c2aad20Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
52207c2aad20Sopenharmony_ci			err = visit(&rec->type_id, ctx);
52217c2aad20Sopenharmony_ci			if (err < 0)
52227c2aad20Sopenharmony_ci				return err;
52237c2aad20Sopenharmony_ci		}
52247c2aad20Sopenharmony_ci	}
52257c2aad20Sopenharmony_ci
52267c2aad20Sopenharmony_ci	seg = &btf_ext->core_relo_info;
52277c2aad20Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
52287c2aad20Sopenharmony_ci		struct bpf_core_relo *rec;
52297c2aad20Sopenharmony_ci
52307c2aad20Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
52317c2aad20Sopenharmony_ci			err = visit(&rec->type_id, ctx);
52327c2aad20Sopenharmony_ci			if (err < 0)
52337c2aad20Sopenharmony_ci				return err;
52347c2aad20Sopenharmony_ci		}
52357c2aad20Sopenharmony_ci	}
52367c2aad20Sopenharmony_ci
52377c2aad20Sopenharmony_ci	return 0;
52387c2aad20Sopenharmony_ci}
52397c2aad20Sopenharmony_ci
52407c2aad20Sopenharmony_ciint btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx)
52417c2aad20Sopenharmony_ci{
52427c2aad20Sopenharmony_ci	const struct btf_ext_info *seg;
52437c2aad20Sopenharmony_ci	struct btf_ext_info_sec *sec;
52447c2aad20Sopenharmony_ci	int i, err;
52457c2aad20Sopenharmony_ci
52467c2aad20Sopenharmony_ci	seg = &btf_ext->func_info;
52477c2aad20Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
52487c2aad20Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
52497c2aad20Sopenharmony_ci		if (err)
52507c2aad20Sopenharmony_ci			return err;
52517c2aad20Sopenharmony_ci	}
52527c2aad20Sopenharmony_ci
52537c2aad20Sopenharmony_ci	seg = &btf_ext->line_info;
52547c2aad20Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
52557c2aad20Sopenharmony_ci		struct bpf_line_info_min *rec;
52567c2aad20Sopenharmony_ci
52577c2aad20Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
52587c2aad20Sopenharmony_ci		if (err)
52597c2aad20Sopenharmony_ci			return err;
52607c2aad20Sopenharmony_ci
52617c2aad20Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
52627c2aad20Sopenharmony_ci			err = visit(&rec->file_name_off, ctx);
52637c2aad20Sopenharmony_ci			if (err)
52647c2aad20Sopenharmony_ci				return err;
52657c2aad20Sopenharmony_ci			err = visit(&rec->line_off, ctx);
52667c2aad20Sopenharmony_ci			if (err)
52677c2aad20Sopenharmony_ci				return err;
52687c2aad20Sopenharmony_ci		}
52697c2aad20Sopenharmony_ci	}
52707c2aad20Sopenharmony_ci
52717c2aad20Sopenharmony_ci	seg = &btf_ext->core_relo_info;
52727c2aad20Sopenharmony_ci	for_each_btf_ext_sec(seg, sec) {
52737c2aad20Sopenharmony_ci		struct bpf_core_relo *rec;
52747c2aad20Sopenharmony_ci
52757c2aad20Sopenharmony_ci		err = visit(&sec->sec_name_off, ctx);
52767c2aad20Sopenharmony_ci		if (err)
52777c2aad20Sopenharmony_ci			return err;
52787c2aad20Sopenharmony_ci
52797c2aad20Sopenharmony_ci		for_each_btf_ext_rec(seg, sec, i, rec) {
52807c2aad20Sopenharmony_ci			err = visit(&rec->access_str_off, ctx);
52817c2aad20Sopenharmony_ci			if (err)
52827c2aad20Sopenharmony_ci				return err;
52837c2aad20Sopenharmony_ci		}
52847c2aad20Sopenharmony_ci	}
52857c2aad20Sopenharmony_ci
52867c2aad20Sopenharmony_ci	return 0;
52877c2aad20Sopenharmony_ci}
5288