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