11bc38b8fSAlexei Starovoitov // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 28a138aedSMartin KaFai Lau /* Copyright (c) 2018 Facebook */ 38a138aedSMartin KaFai Lau 43289959bSAndrii Nakryiko #include <byteswap.h> 5cdb2f920SArnaldo Carvalho de Melo #include <endian.h> 696408c43SYonghong Song #include <stdio.h> 78a138aedSMartin KaFai Lau #include <stdlib.h> 88a138aedSMartin KaFai Lau #include <string.h> 9e6c64855SAndrii Nakryiko #include <fcntl.h> 108a138aedSMartin KaFai Lau #include <unistd.h> 118a138aedSMartin KaFai Lau #include <errno.h> 12fb2426adSMartin KaFai Lau #include <sys/utsname.h> 13fb2426adSMartin KaFai Lau #include <sys/param.h> 14fb2426adSMartin KaFai Lau #include <sys/stat.h> 15fb2426adSMartin KaFai Lau #include <linux/kernel.h> 168a138aedSMartin KaFai Lau #include <linux/err.h> 178a138aedSMartin KaFai Lau #include <linux/btf.h> 18e6c64855SAndrii Nakryiko #include <gelf.h> 198a138aedSMartin KaFai Lau #include "btf.h" 208a138aedSMartin KaFai Lau #include "bpf.h" 218461ef8bSYonghong Song #include "libbpf.h" 22d72386feSAndrii Nakryiko #include "libbpf_internal.h" 232fc3fc0bSAndrii Nakryiko #include "hashmap.h" 2490d76d3eSAndrii Nakryiko #include "strset.h" 258a138aedSMartin KaFai Lau 26fb2426adSMartin KaFai Lau #define BTF_MAX_NR_TYPES 0x7fffffffU 27fb2426adSMartin KaFai Lau #define BTF_MAX_STR_OFFSET 0x7fffffffU 288a138aedSMartin KaFai Lau 298a138aedSMartin KaFai Lau static struct btf_type btf_void; 308a138aedSMartin KaFai Lau 318a138aedSMartin KaFai Lau struct btf { 323289959bSAndrii Nakryiko /* raw BTF data in native endianness */ 33b8604247SAndrii Nakryiko void *raw_data; 343289959bSAndrii Nakryiko /* raw BTF data in non-native endianness */ 353289959bSAndrii Nakryiko void *raw_data_swapped; 36b8604247SAndrii Nakryiko __u32 raw_size; 373289959bSAndrii Nakryiko /* whether target endianness differs from the native one */ 383289959bSAndrii Nakryiko bool swapped_endian; 39b8604247SAndrii Nakryiko 40b8604247SAndrii Nakryiko /* 419141f75aSAndrii Nakryiko * When BTF is loaded from an ELF or raw memory it is stored 429141f75aSAndrii Nakryiko * in a contiguous memory block. The hdr, type_data, and, strs_data 439141f75aSAndrii Nakryiko * point inside that memory region to their respective parts of BTF 449141f75aSAndrii Nakryiko * representation: 45b8604247SAndrii Nakryiko * 46b8604247SAndrii Nakryiko * +--------------------------------+ 47b8604247SAndrii Nakryiko * | Header | Types | Strings | 48b8604247SAndrii Nakryiko * +--------------------------------+ 49b8604247SAndrii Nakryiko * ^ ^ ^ 50b8604247SAndrii Nakryiko * | | | 51b8604247SAndrii Nakryiko * hdr | | 52b8604247SAndrii Nakryiko * types_data-+ | 53b8604247SAndrii Nakryiko * strs_data------------+ 54919d2b1dSAndrii Nakryiko * 55919d2b1dSAndrii Nakryiko * If BTF data is later modified, e.g., due to types added or 56919d2b1dSAndrii Nakryiko * removed, BTF deduplication performed, etc, this contiguous 57919d2b1dSAndrii Nakryiko * representation is broken up into three independently allocated 58919d2b1dSAndrii Nakryiko * memory regions to be able to modify them independently. 59919d2b1dSAndrii Nakryiko * raw_data is nulled out at that point, but can be later allocated 606a886de0SHengqi Chen * and cached again if user calls btf__raw_data(), at which point 61919d2b1dSAndrii Nakryiko * raw_data will contain a contiguous copy of header, types, and 62919d2b1dSAndrii Nakryiko * strings: 63919d2b1dSAndrii Nakryiko * 64919d2b1dSAndrii Nakryiko * +----------+ +---------+ +-----------+ 65919d2b1dSAndrii Nakryiko * | Header | | Types | | Strings | 66919d2b1dSAndrii Nakryiko * +----------+ +---------+ +-----------+ 67919d2b1dSAndrii Nakryiko * ^ ^ ^ 68919d2b1dSAndrii Nakryiko * | | | 69919d2b1dSAndrii Nakryiko * hdr | | 70919d2b1dSAndrii Nakryiko * types_data----+ | 7190d76d3eSAndrii Nakryiko * strset__data(strs_set)-----+ 72919d2b1dSAndrii Nakryiko * 73919d2b1dSAndrii Nakryiko * +----------+---------+-----------+ 74919d2b1dSAndrii Nakryiko * | Header | Types | Strings | 75919d2b1dSAndrii Nakryiko * raw_data----->+----------+---------+-----------+ 76b8604247SAndrii Nakryiko */ 778a138aedSMartin KaFai Lau struct btf_header *hdr; 78919d2b1dSAndrii Nakryiko 79b8604247SAndrii Nakryiko void *types_data; 80919d2b1dSAndrii Nakryiko size_t types_data_cap; /* used size stored in hdr->type_len */ 81b8604247SAndrii Nakryiko 82ba451366SAndrii Nakryiko /* type ID to `struct btf_type *` lookup index 83ba451366SAndrii Nakryiko * type_offs[0] corresponds to the first non-VOID type: 84ba451366SAndrii Nakryiko * - for base BTF it's type [1]; 85ba451366SAndrii Nakryiko * - for split BTF it's the first non-base BTF type. 86ba451366SAndrii Nakryiko */ 87740e69c3SAndrii Nakryiko __u32 *type_offs; 88192f5a1fSAndrii Nakryiko size_t type_offs_cap; 89ba451366SAndrii Nakryiko /* number of types in this BTF instance: 90ba451366SAndrii Nakryiko * - doesn't include special [0] void type; 91ba451366SAndrii Nakryiko * - for split BTF counts number of types added on top of base BTF. 92ba451366SAndrii Nakryiko */ 935b891af7SMartin KaFai Lau __u32 nr_types; 94ba451366SAndrii Nakryiko /* if not NULL, points to the base BTF on top of which the current 95ba451366SAndrii Nakryiko * split BTF is based 96ba451366SAndrii Nakryiko */ 97ba451366SAndrii Nakryiko struct btf *base_btf; 98ba451366SAndrii Nakryiko /* BTF type ID of the first type in this BTF instance: 99ba451366SAndrii Nakryiko * - for base BTF it's equal to 1; 100ba451366SAndrii Nakryiko * - for split BTF it's equal to biggest type ID of base BTF plus 1. 101ba451366SAndrii Nakryiko */ 102ba451366SAndrii Nakryiko int start_id; 103ba451366SAndrii Nakryiko /* logical string offset of this BTF instance: 104ba451366SAndrii Nakryiko * - for base BTF it's equal to 0; 105ba451366SAndrii Nakryiko * - for split BTF it's equal to total size of base BTF's string section size. 106ba451366SAndrii Nakryiko */ 107ba451366SAndrii Nakryiko int start_str_off; 108b8604247SAndrii Nakryiko 10990d76d3eSAndrii Nakryiko /* only one of strs_data or strs_set can be non-NULL, depending on 11090d76d3eSAndrii Nakryiko * whether BTF is in a modifiable state (strs_set is used) or not 11190d76d3eSAndrii Nakryiko * (strs_data points inside raw_data) 11290d76d3eSAndrii Nakryiko */ 113919d2b1dSAndrii Nakryiko void *strs_data; 11490d76d3eSAndrii Nakryiko /* a set of unique strings */ 11590d76d3eSAndrii Nakryiko struct strset *strs_set; 116919d2b1dSAndrii Nakryiko /* whether strings are already deduplicated */ 117919d2b1dSAndrii Nakryiko bool strs_deduped; 11888a82c2aSAndrii Nakryiko 119b8604247SAndrii Nakryiko /* BTF object FD, if loaded into kernel */ 1208a138aedSMartin KaFai Lau int fd; 121b8604247SAndrii Nakryiko 122b8604247SAndrii Nakryiko /* Pointer size (in bytes) for a target architecture of this BTF */ 12344ad23dfSAndrii Nakryiko int ptr_sz; 1248a138aedSMartin KaFai Lau }; 1258a138aedSMartin KaFai Lau 126d7f5b5e0SYonghong Song static inline __u64 ptr_to_u64(const void *ptr) 127d7f5b5e0SYonghong Song { 128d7f5b5e0SYonghong Song return (__u64) (unsigned long) ptr; 129d7f5b5e0SYonghong Song } 130d7f5b5e0SYonghong Song 131192f5a1fSAndrii Nakryiko /* Ensure given dynamically allocated memory region pointed to by *data* with 132192f5a1fSAndrii Nakryiko * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough 133*9bbdfad8SDaniel Müller * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements 134192f5a1fSAndrii Nakryiko * are already used. At most *max_cnt* elements can be ever allocated. 135192f5a1fSAndrii Nakryiko * If necessary, memory is reallocated and all existing data is copied over, 136192f5a1fSAndrii Nakryiko * new pointer to the memory region is stored at *data, new memory region 137192f5a1fSAndrii Nakryiko * capacity (in number of elements) is stored in *cap. 138192f5a1fSAndrii Nakryiko * On success, memory pointer to the beginning of unused memory is returned. 139192f5a1fSAndrii Nakryiko * On error, NULL is returned. 140192f5a1fSAndrii Nakryiko */ 1413b029e06SAndrii Nakryiko void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz, 142192f5a1fSAndrii Nakryiko size_t cur_cnt, size_t max_cnt, size_t add_cnt) 1438a138aedSMartin KaFai Lau { 144192f5a1fSAndrii Nakryiko size_t new_cnt; 145192f5a1fSAndrii Nakryiko void *new_data; 1468a138aedSMartin KaFai Lau 147192f5a1fSAndrii Nakryiko if (cur_cnt + add_cnt <= *cap_cnt) 148192f5a1fSAndrii Nakryiko return *data + cur_cnt * elem_sz; 1498a138aedSMartin KaFai Lau 150192f5a1fSAndrii Nakryiko /* requested more than the set limit */ 151192f5a1fSAndrii Nakryiko if (cur_cnt + add_cnt > max_cnt) 152192f5a1fSAndrii Nakryiko return NULL; 1538a138aedSMartin KaFai Lau 154192f5a1fSAndrii Nakryiko new_cnt = *cap_cnt; 155192f5a1fSAndrii Nakryiko new_cnt += new_cnt / 4; /* expand by 25% */ 156192f5a1fSAndrii Nakryiko if (new_cnt < 16) /* but at least 16 elements */ 157192f5a1fSAndrii Nakryiko new_cnt = 16; 158192f5a1fSAndrii Nakryiko if (new_cnt > max_cnt) /* but not exceeding a set limit */ 159192f5a1fSAndrii Nakryiko new_cnt = max_cnt; 160192f5a1fSAndrii Nakryiko if (new_cnt < cur_cnt + add_cnt) /* also ensure we have enough memory */ 161192f5a1fSAndrii Nakryiko new_cnt = cur_cnt + add_cnt; 1628a138aedSMartin KaFai Lau 163192f5a1fSAndrii Nakryiko new_data = libbpf_reallocarray(*data, new_cnt, elem_sz); 164192f5a1fSAndrii Nakryiko if (!new_data) 165192f5a1fSAndrii Nakryiko return NULL; 1668a138aedSMartin KaFai Lau 167192f5a1fSAndrii Nakryiko /* zero out newly allocated portion of memory */ 168192f5a1fSAndrii Nakryiko memset(new_data + (*cap_cnt) * elem_sz, 0, (new_cnt - *cap_cnt) * elem_sz); 169192f5a1fSAndrii Nakryiko 170192f5a1fSAndrii Nakryiko *data = new_data; 171192f5a1fSAndrii Nakryiko *cap_cnt = new_cnt; 172192f5a1fSAndrii Nakryiko return new_data + cur_cnt * elem_sz; 1738a138aedSMartin KaFai Lau } 1748a138aedSMartin KaFai Lau 1759c6c5c48SAndrii Nakryiko /* Ensure given dynamically allocated memory region has enough allocated space 1769c6c5c48SAndrii Nakryiko * to accommodate *need_cnt* elements of size *elem_sz* bytes each 1779c6c5c48SAndrii Nakryiko */ 1783b029e06SAndrii Nakryiko int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt) 1799c6c5c48SAndrii Nakryiko { 1809c6c5c48SAndrii Nakryiko void *p; 1819c6c5c48SAndrii Nakryiko 1829c6c5c48SAndrii Nakryiko if (need_cnt <= *cap_cnt) 1839c6c5c48SAndrii Nakryiko return 0; 1849c6c5c48SAndrii Nakryiko 1853b029e06SAndrii Nakryiko p = libbpf_add_mem(data, cap_cnt, elem_sz, *cap_cnt, SIZE_MAX, need_cnt - *cap_cnt); 1869c6c5c48SAndrii Nakryiko if (!p) 1879c6c5c48SAndrii Nakryiko return -ENOMEM; 1889c6c5c48SAndrii Nakryiko 1899c6c5c48SAndrii Nakryiko return 0; 1909c6c5c48SAndrii Nakryiko } 1919c6c5c48SAndrii Nakryiko 1927ca61121SAndrii Nakryiko static void *btf_add_type_offs_mem(struct btf *btf, size_t add_cnt) 1937ca61121SAndrii Nakryiko { 1947ca61121SAndrii Nakryiko return libbpf_add_mem((void **)&btf->type_offs, &btf->type_offs_cap, sizeof(__u32), 1957ca61121SAndrii Nakryiko btf->nr_types, BTF_MAX_NR_TYPES, add_cnt); 1967ca61121SAndrii Nakryiko } 1977ca61121SAndrii Nakryiko 198192f5a1fSAndrii Nakryiko static int btf_add_type_idx_entry(struct btf *btf, __u32 type_off) 199192f5a1fSAndrii Nakryiko { 200192f5a1fSAndrii Nakryiko __u32 *p; 2018a138aedSMartin KaFai Lau 2027ca61121SAndrii Nakryiko p = btf_add_type_offs_mem(btf, 1); 203192f5a1fSAndrii Nakryiko if (!p) 204192f5a1fSAndrii Nakryiko return -ENOMEM; 205192f5a1fSAndrii Nakryiko 206192f5a1fSAndrii Nakryiko *p = type_off; 2078a138aedSMartin KaFai Lau return 0; 2088a138aedSMartin KaFai Lau } 2098a138aedSMartin KaFai Lau 2103289959bSAndrii Nakryiko static void btf_bswap_hdr(struct btf_header *h) 2113289959bSAndrii Nakryiko { 2123289959bSAndrii Nakryiko h->magic = bswap_16(h->magic); 2133289959bSAndrii Nakryiko h->hdr_len = bswap_32(h->hdr_len); 2143289959bSAndrii Nakryiko h->type_off = bswap_32(h->type_off); 2153289959bSAndrii Nakryiko h->type_len = bswap_32(h->type_len); 2163289959bSAndrii Nakryiko h->str_off = bswap_32(h->str_off); 2173289959bSAndrii Nakryiko h->str_len = bswap_32(h->str_len); 2183289959bSAndrii Nakryiko } 2193289959bSAndrii Nakryiko 2208461ef8bSYonghong Song static int btf_parse_hdr(struct btf *btf) 2218a138aedSMartin KaFai Lau { 2223289959bSAndrii Nakryiko struct btf_header *hdr = btf->hdr; 2235b891af7SMartin KaFai Lau __u32 meta_left; 2248a138aedSMartin KaFai Lau 225b8604247SAndrii Nakryiko if (btf->raw_size < sizeof(struct btf_header)) { 2268461ef8bSYonghong Song pr_debug("BTF header not found\n"); 2278a138aedSMartin KaFai Lau return -EINVAL; 2288a138aedSMartin KaFai Lau } 2298a138aedSMartin KaFai Lau 2303289959bSAndrii Nakryiko if (hdr->magic == bswap_16(BTF_MAGIC)) { 2313289959bSAndrii Nakryiko btf->swapped_endian = true; 2323289959bSAndrii Nakryiko if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) { 2333289959bSAndrii Nakryiko pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n", 2343289959bSAndrii Nakryiko bswap_32(hdr->hdr_len)); 2353289959bSAndrii Nakryiko return -ENOTSUP; 2363289959bSAndrii Nakryiko } 2373289959bSAndrii Nakryiko btf_bswap_hdr(hdr); 2383289959bSAndrii Nakryiko } else if (hdr->magic != BTF_MAGIC) { 2398461ef8bSYonghong Song pr_debug("Invalid BTF magic: %x\n", hdr->magic); 2408a138aedSMartin KaFai Lau return -EINVAL; 2418a138aedSMartin KaFai Lau } 2428a138aedSMartin KaFai Lau 243c825f5feSAndrii Nakryiko if (btf->raw_size < hdr->hdr_len) { 244c825f5feSAndrii Nakryiko pr_debug("BTF header len %u larger than data size %u\n", 245c825f5feSAndrii Nakryiko hdr->hdr_len, btf->raw_size); 246c825f5feSAndrii Nakryiko return -EINVAL; 247c825f5feSAndrii Nakryiko } 248c825f5feSAndrii Nakryiko 249c825f5feSAndrii Nakryiko meta_left = btf->raw_size - hdr->hdr_len; 2505245dafeSAndrii Nakryiko if (meta_left < (long long)hdr->str_off + hdr->str_len) { 251d8123624SAndrii Nakryiko pr_debug("Invalid BTF total size: %u\n", btf->raw_size); 2528a138aedSMartin KaFai Lau return -EINVAL; 2538a138aedSMartin KaFai Lau } 2548a138aedSMartin KaFai Lau 2555245dafeSAndrii Nakryiko if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) { 256d8123624SAndrii Nakryiko pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n", 257d8123624SAndrii Nakryiko hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len); 2588a138aedSMartin KaFai Lau return -EINVAL; 2598a138aedSMartin KaFai Lau } 2608a138aedSMartin KaFai Lau 261d8123624SAndrii Nakryiko if (hdr->type_off % 4) { 2628461ef8bSYonghong Song pr_debug("BTF type section is not aligned to 4 bytes\n"); 2638a138aedSMartin KaFai Lau return -EINVAL; 2648a138aedSMartin KaFai Lau } 2658a138aedSMartin KaFai Lau 2668a138aedSMartin KaFai Lau return 0; 2678a138aedSMartin KaFai Lau } 2688a138aedSMartin KaFai Lau 2698461ef8bSYonghong Song static int btf_parse_str_sec(struct btf *btf) 2708a138aedSMartin KaFai Lau { 2718a138aedSMartin KaFai Lau const struct btf_header *hdr = btf->hdr; 272b8604247SAndrii Nakryiko const char *start = btf->strs_data; 2738a138aedSMartin KaFai Lau const char *end = start + btf->hdr->str_len; 2748a138aedSMartin KaFai Lau 275ba451366SAndrii Nakryiko if (btf->base_btf && hdr->str_len == 0) 276ba451366SAndrii Nakryiko return 0; 277ba451366SAndrii Nakryiko if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_STR_OFFSET || end[-1]) { 2788461ef8bSYonghong Song pr_debug("Invalid BTF string section\n"); 2798a138aedSMartin KaFai Lau return -EINVAL; 2808a138aedSMartin KaFai Lau } 281ba451366SAndrii Nakryiko if (!btf->base_btf && start[0]) { 282ba451366SAndrii Nakryiko pr_debug("Invalid BTF string section\n"); 283ba451366SAndrii Nakryiko return -EINVAL; 284ba451366SAndrii Nakryiko } 2858a138aedSMartin KaFai Lau return 0; 2868a138aedSMartin KaFai Lau } 2878a138aedSMartin KaFai Lau 288740e69c3SAndrii Nakryiko static int btf_type_size(const struct btf_type *t) 28969eaab04SAndrii Nakryiko { 2903289959bSAndrii Nakryiko const int base_size = sizeof(struct btf_type); 291b03bc685SAndrii Nakryiko __u16 vlen = btf_vlen(t); 29269eaab04SAndrii Nakryiko 293b03bc685SAndrii Nakryiko switch (btf_kind(t)) { 29469eaab04SAndrii Nakryiko case BTF_KIND_FWD: 29569eaab04SAndrii Nakryiko case BTF_KIND_CONST: 29669eaab04SAndrii Nakryiko case BTF_KIND_VOLATILE: 29769eaab04SAndrii Nakryiko case BTF_KIND_RESTRICT: 29869eaab04SAndrii Nakryiko case BTF_KIND_PTR: 29969eaab04SAndrii Nakryiko case BTF_KIND_TYPEDEF: 30069eaab04SAndrii Nakryiko case BTF_KIND_FUNC: 30122541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 3022dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 30369eaab04SAndrii Nakryiko return base_size; 30469eaab04SAndrii Nakryiko case BTF_KIND_INT: 30569eaab04SAndrii Nakryiko return base_size + sizeof(__u32); 30669eaab04SAndrii Nakryiko case BTF_KIND_ENUM: 30769eaab04SAndrii Nakryiko return base_size + vlen * sizeof(struct btf_enum); 30869eaab04SAndrii Nakryiko case BTF_KIND_ARRAY: 30969eaab04SAndrii Nakryiko return base_size + sizeof(struct btf_array); 31069eaab04SAndrii Nakryiko case BTF_KIND_STRUCT: 31169eaab04SAndrii Nakryiko case BTF_KIND_UNION: 31269eaab04SAndrii Nakryiko return base_size + vlen * sizeof(struct btf_member); 31369eaab04SAndrii Nakryiko case BTF_KIND_FUNC_PROTO: 31469eaab04SAndrii Nakryiko return base_size + vlen * sizeof(struct btf_param); 3151713d68bSDaniel Borkmann case BTF_KIND_VAR: 3161713d68bSDaniel Borkmann return base_size + sizeof(struct btf_var); 3171713d68bSDaniel Borkmann case BTF_KIND_DATASEC: 3181713d68bSDaniel Borkmann return base_size + vlen * sizeof(struct btf_var_secinfo); 319223f903eSYonghong Song case BTF_KIND_DECL_TAG: 320223f903eSYonghong Song return base_size + sizeof(struct btf_decl_tag); 32169eaab04SAndrii Nakryiko default: 322b03bc685SAndrii Nakryiko pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); 32369eaab04SAndrii Nakryiko return -EINVAL; 32469eaab04SAndrii Nakryiko } 32569eaab04SAndrii Nakryiko } 32669eaab04SAndrii Nakryiko 3273289959bSAndrii Nakryiko static void btf_bswap_type_base(struct btf_type *t) 3283289959bSAndrii Nakryiko { 3293289959bSAndrii Nakryiko t->name_off = bswap_32(t->name_off); 3303289959bSAndrii Nakryiko t->info = bswap_32(t->info); 3313289959bSAndrii Nakryiko t->type = bswap_32(t->type); 3323289959bSAndrii Nakryiko } 3333289959bSAndrii Nakryiko 3343289959bSAndrii Nakryiko static int btf_bswap_type_rest(struct btf_type *t) 3353289959bSAndrii Nakryiko { 3363289959bSAndrii Nakryiko struct btf_var_secinfo *v; 3373289959bSAndrii Nakryiko struct btf_member *m; 3383289959bSAndrii Nakryiko struct btf_array *a; 3393289959bSAndrii Nakryiko struct btf_param *p; 3403289959bSAndrii Nakryiko struct btf_enum *e; 3413289959bSAndrii Nakryiko __u16 vlen = btf_vlen(t); 3423289959bSAndrii Nakryiko int i; 3433289959bSAndrii Nakryiko 3443289959bSAndrii Nakryiko switch (btf_kind(t)) { 3453289959bSAndrii Nakryiko case BTF_KIND_FWD: 3463289959bSAndrii Nakryiko case BTF_KIND_CONST: 3473289959bSAndrii Nakryiko case BTF_KIND_VOLATILE: 3483289959bSAndrii Nakryiko case BTF_KIND_RESTRICT: 3493289959bSAndrii Nakryiko case BTF_KIND_PTR: 3503289959bSAndrii Nakryiko case BTF_KIND_TYPEDEF: 3513289959bSAndrii Nakryiko case BTF_KIND_FUNC: 35222541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 3532dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 3543289959bSAndrii Nakryiko return 0; 3553289959bSAndrii Nakryiko case BTF_KIND_INT: 3563289959bSAndrii Nakryiko *(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1)); 3573289959bSAndrii Nakryiko return 0; 3583289959bSAndrii Nakryiko case BTF_KIND_ENUM: 3593289959bSAndrii Nakryiko for (i = 0, e = btf_enum(t); i < vlen; i++, e++) { 3603289959bSAndrii Nakryiko e->name_off = bswap_32(e->name_off); 3613289959bSAndrii Nakryiko e->val = bswap_32(e->val); 3623289959bSAndrii Nakryiko } 3633289959bSAndrii Nakryiko return 0; 3643289959bSAndrii Nakryiko case BTF_KIND_ARRAY: 3653289959bSAndrii Nakryiko a = btf_array(t); 3663289959bSAndrii Nakryiko a->type = bswap_32(a->type); 3673289959bSAndrii Nakryiko a->index_type = bswap_32(a->index_type); 3683289959bSAndrii Nakryiko a->nelems = bswap_32(a->nelems); 3693289959bSAndrii Nakryiko return 0; 3703289959bSAndrii Nakryiko case BTF_KIND_STRUCT: 3713289959bSAndrii Nakryiko case BTF_KIND_UNION: 3723289959bSAndrii Nakryiko for (i = 0, m = btf_members(t); i < vlen; i++, m++) { 3733289959bSAndrii Nakryiko m->name_off = bswap_32(m->name_off); 3743289959bSAndrii Nakryiko m->type = bswap_32(m->type); 3753289959bSAndrii Nakryiko m->offset = bswap_32(m->offset); 3763289959bSAndrii Nakryiko } 3773289959bSAndrii Nakryiko return 0; 3783289959bSAndrii Nakryiko case BTF_KIND_FUNC_PROTO: 3793289959bSAndrii Nakryiko for (i = 0, p = btf_params(t); i < vlen; i++, p++) { 3803289959bSAndrii Nakryiko p->name_off = bswap_32(p->name_off); 3813289959bSAndrii Nakryiko p->type = bswap_32(p->type); 3823289959bSAndrii Nakryiko } 3833289959bSAndrii Nakryiko return 0; 3843289959bSAndrii Nakryiko case BTF_KIND_VAR: 3853289959bSAndrii Nakryiko btf_var(t)->linkage = bswap_32(btf_var(t)->linkage); 3863289959bSAndrii Nakryiko return 0; 3873289959bSAndrii Nakryiko case BTF_KIND_DATASEC: 3883289959bSAndrii Nakryiko for (i = 0, v = btf_var_secinfos(t); i < vlen; i++, v++) { 3893289959bSAndrii Nakryiko v->type = bswap_32(v->type); 3903289959bSAndrii Nakryiko v->offset = bswap_32(v->offset); 3913289959bSAndrii Nakryiko v->size = bswap_32(v->size); 3923289959bSAndrii Nakryiko } 3933289959bSAndrii Nakryiko return 0; 394223f903eSYonghong Song case BTF_KIND_DECL_TAG: 395223f903eSYonghong Song btf_decl_tag(t)->component_idx = bswap_32(btf_decl_tag(t)->component_idx); 3965b84bd10SYonghong Song return 0; 3973289959bSAndrii Nakryiko default: 3983289959bSAndrii Nakryiko pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t)); 3993289959bSAndrii Nakryiko return -EINVAL; 4003289959bSAndrii Nakryiko } 4013289959bSAndrii Nakryiko } 4023289959bSAndrii Nakryiko 4038461ef8bSYonghong Song static int btf_parse_type_sec(struct btf *btf) 4048a138aedSMartin KaFai Lau { 4058a138aedSMartin KaFai Lau struct btf_header *hdr = btf->hdr; 406b8604247SAndrii Nakryiko void *next_type = btf->types_data; 407740e69c3SAndrii Nakryiko void *end_type = next_type + hdr->type_len; 408ba451366SAndrii Nakryiko int err, type_size; 409740e69c3SAndrii Nakryiko 4103289959bSAndrii Nakryiko while (next_type + sizeof(struct btf_type) <= end_type) { 4113289959bSAndrii Nakryiko if (btf->swapped_endian) 4123289959bSAndrii Nakryiko btf_bswap_type_base(next_type); 413740e69c3SAndrii Nakryiko 414740e69c3SAndrii Nakryiko type_size = btf_type_size(next_type); 415740e69c3SAndrii Nakryiko if (type_size < 0) 416740e69c3SAndrii Nakryiko return type_size; 4173289959bSAndrii Nakryiko if (next_type + type_size > end_type) { 418ba451366SAndrii Nakryiko pr_warn("BTF type [%d] is malformed\n", btf->start_id + btf->nr_types); 4193289959bSAndrii Nakryiko return -EINVAL; 4203289959bSAndrii Nakryiko } 4213289959bSAndrii Nakryiko 4223289959bSAndrii Nakryiko if (btf->swapped_endian && btf_bswap_type_rest(next_type)) 4233289959bSAndrii Nakryiko return -EINVAL; 4243289959bSAndrii Nakryiko 4253289959bSAndrii Nakryiko err = btf_add_type_idx_entry(btf, next_type - btf->types_data); 4263289959bSAndrii Nakryiko if (err) 4273289959bSAndrii Nakryiko return err; 428740e69c3SAndrii Nakryiko 429740e69c3SAndrii Nakryiko next_type += type_size; 430740e69c3SAndrii Nakryiko btf->nr_types++; 4318a138aedSMartin KaFai Lau } 4328a138aedSMartin KaFai Lau 4333289959bSAndrii Nakryiko if (next_type != end_type) { 4343289959bSAndrii Nakryiko pr_warn("BTF types data is malformed\n"); 4353289959bSAndrii Nakryiko return -EINVAL; 4363289959bSAndrii Nakryiko } 4373289959bSAndrii Nakryiko 4388a138aedSMartin KaFai Lau return 0; 4398a138aedSMartin KaFai Lau } 4408a138aedSMartin KaFai Lau 4419c651127SAndrii Nakryiko __u32 btf__get_nr_types(const struct btf *btf) 4429c651127SAndrii Nakryiko { 443ba451366SAndrii Nakryiko return btf->start_id + btf->nr_types - 1; 4449c651127SAndrii Nakryiko } 4459c651127SAndrii Nakryiko 4466a886de0SHengqi Chen __u32 btf__type_cnt(const struct btf *btf) 4476a886de0SHengqi Chen { 4486a886de0SHengqi Chen return btf->start_id + btf->nr_types; 4496a886de0SHengqi Chen } 4506a886de0SHengqi Chen 4510cfdcd63SAndrii Nakryiko const struct btf *btf__base_btf(const struct btf *btf) 4520cfdcd63SAndrii Nakryiko { 4530cfdcd63SAndrii Nakryiko return btf->base_btf; 4540cfdcd63SAndrii Nakryiko } 4550cfdcd63SAndrii Nakryiko 456740e69c3SAndrii Nakryiko /* internal helper returning non-const pointer to a type */ 45774753e14SAlexei Starovoitov struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id) 458740e69c3SAndrii Nakryiko { 459740e69c3SAndrii Nakryiko if (type_id == 0) 460740e69c3SAndrii Nakryiko return &btf_void; 461ba451366SAndrii Nakryiko if (type_id < btf->start_id) 462ba451366SAndrii Nakryiko return btf_type_by_id(btf->base_btf, type_id); 463ba451366SAndrii Nakryiko return btf->types_data + btf->type_offs[type_id - btf->start_id]; 464740e69c3SAndrii Nakryiko } 465740e69c3SAndrii Nakryiko 46638d5d3b3SMartin KaFai Lau const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id) 4678a138aedSMartin KaFai Lau { 468ba451366SAndrii Nakryiko if (type_id >= btf->start_id + btf->nr_types) 469e9fc3ce9SAndrii Nakryiko return errno = EINVAL, NULL; 470740e69c3SAndrii Nakryiko return btf_type_by_id((struct btf *)btf, type_id); 4718a138aedSMartin KaFai Lau } 4728a138aedSMartin KaFai Lau 47344ad23dfSAndrii Nakryiko static int determine_ptr_size(const struct btf *btf) 47444ad23dfSAndrii Nakryiko { 475610cd93bSDouglas Raillard static const char * const long_aliases[] = { 476610cd93bSDouglas Raillard "long", 477610cd93bSDouglas Raillard "long int", 478610cd93bSDouglas Raillard "int long", 479610cd93bSDouglas Raillard "unsigned long", 480610cd93bSDouglas Raillard "long unsigned", 481610cd93bSDouglas Raillard "unsigned long int", 482610cd93bSDouglas Raillard "unsigned int long", 483610cd93bSDouglas Raillard "long unsigned int", 484610cd93bSDouglas Raillard "long int unsigned", 485610cd93bSDouglas Raillard "int unsigned long", 486610cd93bSDouglas Raillard "int long unsigned", 487610cd93bSDouglas Raillard }; 48844ad23dfSAndrii Nakryiko const struct btf_type *t; 48944ad23dfSAndrii Nakryiko const char *name; 490610cd93bSDouglas Raillard int i, j, n; 49144ad23dfSAndrii Nakryiko 492ba451366SAndrii Nakryiko if (btf->base_btf && btf->base_btf->ptr_sz > 0) 493ba451366SAndrii Nakryiko return btf->base_btf->ptr_sz; 494ba451366SAndrii Nakryiko 4956a886de0SHengqi Chen n = btf__type_cnt(btf); 4966a886de0SHengqi Chen for (i = 1; i < n; i++) { 49744ad23dfSAndrii Nakryiko t = btf__type_by_id(btf, i); 49844ad23dfSAndrii Nakryiko if (!btf_is_int(t)) 49944ad23dfSAndrii Nakryiko continue; 50044ad23dfSAndrii Nakryiko 501610cd93bSDouglas Raillard if (t->size != 4 && t->size != 8) 502610cd93bSDouglas Raillard continue; 503610cd93bSDouglas Raillard 50444ad23dfSAndrii Nakryiko name = btf__name_by_offset(btf, t->name_off); 50544ad23dfSAndrii Nakryiko if (!name) 50644ad23dfSAndrii Nakryiko continue; 50744ad23dfSAndrii Nakryiko 508610cd93bSDouglas Raillard for (j = 0; j < ARRAY_SIZE(long_aliases); j++) { 509610cd93bSDouglas Raillard if (strcmp(name, long_aliases[j]) == 0) 51044ad23dfSAndrii Nakryiko return t->size; 51144ad23dfSAndrii Nakryiko } 51244ad23dfSAndrii Nakryiko } 51344ad23dfSAndrii Nakryiko 51444ad23dfSAndrii Nakryiko return -1; 51544ad23dfSAndrii Nakryiko } 51644ad23dfSAndrii Nakryiko 51744ad23dfSAndrii Nakryiko static size_t btf_ptr_sz(const struct btf *btf) 51844ad23dfSAndrii Nakryiko { 51944ad23dfSAndrii Nakryiko if (!btf->ptr_sz) 52044ad23dfSAndrii Nakryiko ((struct btf *)btf)->ptr_sz = determine_ptr_size(btf); 52144ad23dfSAndrii Nakryiko return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz; 52244ad23dfSAndrii Nakryiko } 52344ad23dfSAndrii Nakryiko 52444ad23dfSAndrii Nakryiko /* Return pointer size this BTF instance assumes. The size is heuristically 52544ad23dfSAndrii Nakryiko * determined by looking for 'long' or 'unsigned long' integer type and 52644ad23dfSAndrii Nakryiko * recording its size in bytes. If BTF type information doesn't have any such 52744ad23dfSAndrii Nakryiko * type, this function returns 0. In the latter case, native architecture's 52844ad23dfSAndrii Nakryiko * pointer size is assumed, so will be either 4 or 8, depending on 52944ad23dfSAndrii Nakryiko * architecture that libbpf was compiled for. It's possible to override 53044ad23dfSAndrii Nakryiko * guessed value by using btf__set_pointer_size() API. 53144ad23dfSAndrii Nakryiko */ 53244ad23dfSAndrii Nakryiko size_t btf__pointer_size(const struct btf *btf) 53344ad23dfSAndrii Nakryiko { 53444ad23dfSAndrii Nakryiko if (!btf->ptr_sz) 53544ad23dfSAndrii Nakryiko ((struct btf *)btf)->ptr_sz = determine_ptr_size(btf); 53644ad23dfSAndrii Nakryiko 53744ad23dfSAndrii Nakryiko if (btf->ptr_sz < 0) 53844ad23dfSAndrii Nakryiko /* not enough BTF type info to guess */ 53944ad23dfSAndrii Nakryiko return 0; 54044ad23dfSAndrii Nakryiko 54144ad23dfSAndrii Nakryiko return btf->ptr_sz; 54244ad23dfSAndrii Nakryiko } 54344ad23dfSAndrii Nakryiko 54444ad23dfSAndrii Nakryiko /* Override or set pointer size in bytes. Only values of 4 and 8 are 54544ad23dfSAndrii Nakryiko * supported. 54644ad23dfSAndrii Nakryiko */ 54744ad23dfSAndrii Nakryiko int btf__set_pointer_size(struct btf *btf, size_t ptr_sz) 54844ad23dfSAndrii Nakryiko { 54944ad23dfSAndrii Nakryiko if (ptr_sz != 4 && ptr_sz != 8) 550e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 55144ad23dfSAndrii Nakryiko btf->ptr_sz = ptr_sz; 55244ad23dfSAndrii Nakryiko return 0; 55344ad23dfSAndrii Nakryiko } 55444ad23dfSAndrii Nakryiko 5553289959bSAndrii Nakryiko static bool is_host_big_endian(void) 5563289959bSAndrii Nakryiko { 5573930198dSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 5583289959bSAndrii Nakryiko return false; 5593930198dSIlya Leoshkevich #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 5603289959bSAndrii Nakryiko return true; 5613289959bSAndrii Nakryiko #else 5623289959bSAndrii Nakryiko # error "Unrecognized __BYTE_ORDER__" 5633289959bSAndrii Nakryiko #endif 5643289959bSAndrii Nakryiko } 5653289959bSAndrii Nakryiko 5663289959bSAndrii Nakryiko enum btf_endianness btf__endianness(const struct btf *btf) 5673289959bSAndrii Nakryiko { 5683289959bSAndrii Nakryiko if (is_host_big_endian()) 5693289959bSAndrii Nakryiko return btf->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN; 5703289959bSAndrii Nakryiko else 5713289959bSAndrii Nakryiko return btf->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN; 5723289959bSAndrii Nakryiko } 5733289959bSAndrii Nakryiko 5743289959bSAndrii Nakryiko int btf__set_endianness(struct btf *btf, enum btf_endianness endian) 5753289959bSAndrii Nakryiko { 5763289959bSAndrii Nakryiko if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN) 577e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 5783289959bSAndrii Nakryiko 5793289959bSAndrii Nakryiko btf->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN); 5803289959bSAndrii Nakryiko if (!btf->swapped_endian) { 5813289959bSAndrii Nakryiko free(btf->raw_data_swapped); 5823289959bSAndrii Nakryiko btf->raw_data_swapped = NULL; 5833289959bSAndrii Nakryiko } 5843289959bSAndrii Nakryiko return 0; 5853289959bSAndrii Nakryiko } 5863289959bSAndrii Nakryiko 5878a138aedSMartin KaFai Lau static bool btf_type_is_void(const struct btf_type *t) 5888a138aedSMartin KaFai Lau { 589b03bc685SAndrii Nakryiko return t == &btf_void || btf_is_fwd(t); 5908a138aedSMartin KaFai Lau } 5918a138aedSMartin KaFai Lau 5928a138aedSMartin KaFai Lau static bool btf_type_is_void_or_null(const struct btf_type *t) 5938a138aedSMartin KaFai Lau { 5948a138aedSMartin KaFai Lau return !t || btf_type_is_void(t); 5958a138aedSMartin KaFai Lau } 5968a138aedSMartin KaFai Lau 5978a138aedSMartin KaFai Lau #define MAX_RESOLVE_DEPTH 32 5988a138aedSMartin KaFai Lau 5995b891af7SMartin KaFai Lau __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) 6008a138aedSMartin KaFai Lau { 6018a138aedSMartin KaFai Lau const struct btf_array *array; 6028a138aedSMartin KaFai Lau const struct btf_type *t; 6035b891af7SMartin KaFai Lau __u32 nelems = 1; 6045b891af7SMartin KaFai Lau __s64 size = -1; 6058a138aedSMartin KaFai Lau int i; 6068a138aedSMartin KaFai Lau 60792b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 608e9fc3ce9SAndrii Nakryiko for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); i++) { 609b03bc685SAndrii Nakryiko switch (btf_kind(t)) { 61069eaab04SAndrii Nakryiko case BTF_KIND_INT: 61169eaab04SAndrii Nakryiko case BTF_KIND_STRUCT: 61269eaab04SAndrii Nakryiko case BTF_KIND_UNION: 61369eaab04SAndrii Nakryiko case BTF_KIND_ENUM: 6141713d68bSDaniel Borkmann case BTF_KIND_DATASEC: 61522541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 61669eaab04SAndrii Nakryiko size = t->size; 61769eaab04SAndrii Nakryiko goto done; 61869eaab04SAndrii Nakryiko case BTF_KIND_PTR: 61944ad23dfSAndrii Nakryiko size = btf_ptr_sz(btf); 62069eaab04SAndrii Nakryiko goto done; 6218a138aedSMartin KaFai Lau case BTF_KIND_TYPEDEF: 6228a138aedSMartin KaFai Lau case BTF_KIND_VOLATILE: 6238a138aedSMartin KaFai Lau case BTF_KIND_CONST: 6248a138aedSMartin KaFai Lau case BTF_KIND_RESTRICT: 6251713d68bSDaniel Borkmann case BTF_KIND_VAR: 626223f903eSYonghong Song case BTF_KIND_DECL_TAG: 62769a055d5SYonghong Song case BTF_KIND_TYPE_TAG: 6288a138aedSMartin KaFai Lau type_id = t->type; 6298a138aedSMartin KaFai Lau break; 6308a138aedSMartin KaFai Lau case BTF_KIND_ARRAY: 631b03bc685SAndrii Nakryiko array = btf_array(t); 6328a138aedSMartin KaFai Lau if (nelems && array->nelems > UINT32_MAX / nelems) 633e9fc3ce9SAndrii Nakryiko return libbpf_err(-E2BIG); 6348a138aedSMartin KaFai Lau nelems *= array->nelems; 6358a138aedSMartin KaFai Lau type_id = array->type; 6368a138aedSMartin KaFai Lau break; 6378a138aedSMartin KaFai Lau default: 638e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 6398a138aedSMartin KaFai Lau } 6408a138aedSMartin KaFai Lau 64192b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 6428a138aedSMartin KaFai Lau } 6438a138aedSMartin KaFai Lau 644994021a7SAndrii Nakryiko done: 6458a138aedSMartin KaFai Lau if (size < 0) 646e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 6478a138aedSMartin KaFai Lau if (nelems && size > UINT32_MAX / nelems) 648e9fc3ce9SAndrii Nakryiko return libbpf_err(-E2BIG); 6498a138aedSMartin KaFai Lau 6508a138aedSMartin KaFai Lau return nelems * size; 6518a138aedSMartin KaFai Lau } 6528a138aedSMartin KaFai Lau 6533d208f4cSAndrii Nakryiko int btf__align_of(const struct btf *btf, __u32 id) 6543d208f4cSAndrii Nakryiko { 6553d208f4cSAndrii Nakryiko const struct btf_type *t = btf__type_by_id(btf, id); 6563d208f4cSAndrii Nakryiko __u16 kind = btf_kind(t); 6573d208f4cSAndrii Nakryiko 6583d208f4cSAndrii Nakryiko switch (kind) { 6593d208f4cSAndrii Nakryiko case BTF_KIND_INT: 6603d208f4cSAndrii Nakryiko case BTF_KIND_ENUM: 66122541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 66244ad23dfSAndrii Nakryiko return min(btf_ptr_sz(btf), (size_t)t->size); 6633d208f4cSAndrii Nakryiko case BTF_KIND_PTR: 66444ad23dfSAndrii Nakryiko return btf_ptr_sz(btf); 6653d208f4cSAndrii Nakryiko case BTF_KIND_TYPEDEF: 6663d208f4cSAndrii Nakryiko case BTF_KIND_VOLATILE: 6673d208f4cSAndrii Nakryiko case BTF_KIND_CONST: 6683d208f4cSAndrii Nakryiko case BTF_KIND_RESTRICT: 6692dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 6703d208f4cSAndrii Nakryiko return btf__align_of(btf, t->type); 6713d208f4cSAndrii Nakryiko case BTF_KIND_ARRAY: 6723d208f4cSAndrii Nakryiko return btf__align_of(btf, btf_array(t)->type); 6733d208f4cSAndrii Nakryiko case BTF_KIND_STRUCT: 6743d208f4cSAndrii Nakryiko case BTF_KIND_UNION: { 6753d208f4cSAndrii Nakryiko const struct btf_member *m = btf_members(t); 6763d208f4cSAndrii Nakryiko __u16 vlen = btf_vlen(t); 677a79ac2d1SPrashant Bhole int i, max_align = 1, align; 6783d208f4cSAndrii Nakryiko 6793d208f4cSAndrii Nakryiko for (i = 0; i < vlen; i++, m++) { 680a79ac2d1SPrashant Bhole align = btf__align_of(btf, m->type); 681a79ac2d1SPrashant Bhole if (align <= 0) 682e9fc3ce9SAndrii Nakryiko return libbpf_err(align); 683a79ac2d1SPrashant Bhole max_align = max(max_align, align); 6843d208f4cSAndrii Nakryiko } 6853d208f4cSAndrii Nakryiko 686a79ac2d1SPrashant Bhole return max_align; 6873d208f4cSAndrii Nakryiko } 6883d208f4cSAndrii Nakryiko default: 6893d208f4cSAndrii Nakryiko pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t)); 690e9fc3ce9SAndrii Nakryiko return errno = EINVAL, 0; 6913d208f4cSAndrii Nakryiko } 6923d208f4cSAndrii Nakryiko } 6933d208f4cSAndrii Nakryiko 69492b57121SOkash Khawaja int btf__resolve_type(const struct btf *btf, __u32 type_id) 69592b57121SOkash Khawaja { 69692b57121SOkash Khawaja const struct btf_type *t; 69792b57121SOkash Khawaja int depth = 0; 69892b57121SOkash Khawaja 69992b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 70092b57121SOkash Khawaja while (depth < MAX_RESOLVE_DEPTH && 70192b57121SOkash Khawaja !btf_type_is_void_or_null(t) && 702b03bc685SAndrii Nakryiko (btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) { 70392b57121SOkash Khawaja type_id = t->type; 70492b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 70592b57121SOkash Khawaja depth++; 70692b57121SOkash Khawaja } 70792b57121SOkash Khawaja 70892b57121SOkash Khawaja if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t)) 709e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 71092b57121SOkash Khawaja 71192b57121SOkash Khawaja return type_id; 71292b57121SOkash Khawaja } 71392b57121SOkash Khawaja 7145b891af7SMartin KaFai Lau __s32 btf__find_by_name(const struct btf *btf, const char *type_name) 7158a138aedSMartin KaFai Lau { 7166a886de0SHengqi Chen __u32 i, nr_types = btf__type_cnt(btf); 7178a138aedSMartin KaFai Lau 7188a138aedSMartin KaFai Lau if (!strcmp(type_name, "void")) 7198a138aedSMartin KaFai Lau return 0; 7208a138aedSMartin KaFai Lau 7216a886de0SHengqi Chen for (i = 1; i < nr_types; i++) { 722740e69c3SAndrii Nakryiko const struct btf_type *t = btf__type_by_id(btf, i); 72392b57121SOkash Khawaja const char *name = btf__name_by_offset(btf, t->name_off); 7248a138aedSMartin KaFai Lau 7258a138aedSMartin KaFai Lau if (name && !strcmp(type_name, name)) 7268a138aedSMartin KaFai Lau return i; 7278a138aedSMartin KaFai Lau } 7288a138aedSMartin KaFai Lau 729e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOENT); 7308a138aedSMartin KaFai Lau } 7318a138aedSMartin KaFai Lau 7329dbe6015SKumar Kartikeya Dwivedi static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id, 7339dbe6015SKumar Kartikeya Dwivedi const char *type_name, __u32 kind) 7341442e287SAlexei Starovoitov { 7356a886de0SHengqi Chen __u32 i, nr_types = btf__type_cnt(btf); 7361442e287SAlexei Starovoitov 7371442e287SAlexei Starovoitov if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void")) 7381442e287SAlexei Starovoitov return 0; 7391442e287SAlexei Starovoitov 7406a886de0SHengqi Chen for (i = start_id; i < nr_types; i++) { 741740e69c3SAndrii Nakryiko const struct btf_type *t = btf__type_by_id(btf, i); 7421442e287SAlexei Starovoitov const char *name; 7431442e287SAlexei Starovoitov 7441442e287SAlexei Starovoitov if (btf_kind(t) != kind) 7451442e287SAlexei Starovoitov continue; 7461442e287SAlexei Starovoitov name = btf__name_by_offset(btf, t->name_off); 7471442e287SAlexei Starovoitov if (name && !strcmp(type_name, name)) 7481442e287SAlexei Starovoitov return i; 7491442e287SAlexei Starovoitov } 7501442e287SAlexei Starovoitov 751e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOENT); 7521442e287SAlexei Starovoitov } 7531442e287SAlexei Starovoitov 7549dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name, 7559dbe6015SKumar Kartikeya Dwivedi __u32 kind) 7569dbe6015SKumar Kartikeya Dwivedi { 7579dbe6015SKumar Kartikeya Dwivedi return btf_find_by_name_kind(btf, btf->start_id, type_name, kind); 7589dbe6015SKumar Kartikeya Dwivedi } 7599dbe6015SKumar Kartikeya Dwivedi 7609dbe6015SKumar Kartikeya Dwivedi __s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name, 7619dbe6015SKumar Kartikeya Dwivedi __u32 kind) 7629dbe6015SKumar Kartikeya Dwivedi { 7639dbe6015SKumar Kartikeya Dwivedi return btf_find_by_name_kind(btf, 1, type_name, kind); 7649dbe6015SKumar Kartikeya Dwivedi } 7659dbe6015SKumar Kartikeya Dwivedi 766919d2b1dSAndrii Nakryiko static bool btf_is_modifiable(const struct btf *btf) 767919d2b1dSAndrii Nakryiko { 768919d2b1dSAndrii Nakryiko return (void *)btf->hdr != btf->raw_data; 769919d2b1dSAndrii Nakryiko } 770919d2b1dSAndrii Nakryiko 7718a138aedSMartin KaFai Lau void btf__free(struct btf *btf) 7728a138aedSMartin KaFai Lau { 77350450fc7SAndrii Nakryiko if (IS_ERR_OR_NULL(btf)) 7748a138aedSMartin KaFai Lau return; 7758a138aedSMartin KaFai Lau 77681372e12SAndrii Nakryiko if (btf->fd >= 0) 7778a138aedSMartin KaFai Lau close(btf->fd); 7788a138aedSMartin KaFai Lau 779919d2b1dSAndrii Nakryiko if (btf_is_modifiable(btf)) { 780919d2b1dSAndrii Nakryiko /* if BTF was modified after loading, it will have a split 781919d2b1dSAndrii Nakryiko * in-memory representation for header, types, and strings 782919d2b1dSAndrii Nakryiko * sections, so we need to free all of them individually. It 783919d2b1dSAndrii Nakryiko * might still have a cached contiguous raw data present, 784919d2b1dSAndrii Nakryiko * which will be unconditionally freed below. 785919d2b1dSAndrii Nakryiko */ 786919d2b1dSAndrii Nakryiko free(btf->hdr); 787919d2b1dSAndrii Nakryiko free(btf->types_data); 78890d76d3eSAndrii Nakryiko strset__free(btf->strs_set); 789919d2b1dSAndrii Nakryiko } 790b8604247SAndrii Nakryiko free(btf->raw_data); 7913289959bSAndrii Nakryiko free(btf->raw_data_swapped); 792740e69c3SAndrii Nakryiko free(btf->type_offs); 7938a138aedSMartin KaFai Lau free(btf); 7948a138aedSMartin KaFai Lau } 7958a138aedSMartin KaFai Lau 796ba451366SAndrii Nakryiko static struct btf *btf_new_empty(struct btf *base_btf) 797a871b043SAndrii Nakryiko { 798a871b043SAndrii Nakryiko struct btf *btf; 799a871b043SAndrii Nakryiko 800a871b043SAndrii Nakryiko btf = calloc(1, sizeof(*btf)); 801a871b043SAndrii Nakryiko if (!btf) 802a871b043SAndrii Nakryiko return ERR_PTR(-ENOMEM); 8033289959bSAndrii Nakryiko 804ba451366SAndrii Nakryiko btf->nr_types = 0; 805ba451366SAndrii Nakryiko btf->start_id = 1; 806ba451366SAndrii Nakryiko btf->start_str_off = 0; 807a871b043SAndrii Nakryiko btf->fd = -1; 808a871b043SAndrii Nakryiko btf->ptr_sz = sizeof(void *); 8093289959bSAndrii Nakryiko btf->swapped_endian = false; 810a871b043SAndrii Nakryiko 811ba451366SAndrii Nakryiko if (base_btf) { 812ba451366SAndrii Nakryiko btf->base_btf = base_btf; 8136a886de0SHengqi Chen btf->start_id = btf__type_cnt(base_btf); 814ba451366SAndrii Nakryiko btf->start_str_off = base_btf->hdr->str_len; 815ba451366SAndrii Nakryiko } 816ba451366SAndrii Nakryiko 817a871b043SAndrii Nakryiko /* +1 for empty string at offset 0 */ 818ba451366SAndrii Nakryiko btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1); 819a871b043SAndrii Nakryiko btf->raw_data = calloc(1, btf->raw_size); 820a871b043SAndrii Nakryiko if (!btf->raw_data) { 821a871b043SAndrii Nakryiko free(btf); 822a871b043SAndrii Nakryiko return ERR_PTR(-ENOMEM); 823a871b043SAndrii Nakryiko } 824a871b043SAndrii Nakryiko 825a871b043SAndrii Nakryiko btf->hdr = btf->raw_data; 826a871b043SAndrii Nakryiko btf->hdr->hdr_len = sizeof(struct btf_header); 827a871b043SAndrii Nakryiko btf->hdr->magic = BTF_MAGIC; 828a871b043SAndrii Nakryiko btf->hdr->version = BTF_VERSION; 829a871b043SAndrii Nakryiko 830a871b043SAndrii Nakryiko btf->types_data = btf->raw_data + btf->hdr->hdr_len; 831a871b043SAndrii Nakryiko btf->strs_data = btf->raw_data + btf->hdr->hdr_len; 832ba451366SAndrii Nakryiko btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */ 833a871b043SAndrii Nakryiko 834a871b043SAndrii Nakryiko return btf; 835a871b043SAndrii Nakryiko } 836a871b043SAndrii Nakryiko 837ba451366SAndrii Nakryiko struct btf *btf__new_empty(void) 838ba451366SAndrii Nakryiko { 839e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_new_empty(NULL)); 840ba451366SAndrii Nakryiko } 841ba451366SAndrii Nakryiko 842ba451366SAndrii Nakryiko struct btf *btf__new_empty_split(struct btf *base_btf) 843ba451366SAndrii Nakryiko { 844e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_new_empty(base_btf)); 845ba451366SAndrii Nakryiko } 846ba451366SAndrii Nakryiko 847ba451366SAndrii Nakryiko static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf) 8488a138aedSMartin KaFai Lau { 8498a138aedSMartin KaFai Lau struct btf *btf; 8508a138aedSMartin KaFai Lau int err; 8518a138aedSMartin KaFai Lau 8528a138aedSMartin KaFai Lau btf = calloc(1, sizeof(struct btf)); 8538a138aedSMartin KaFai Lau if (!btf) 8548a138aedSMartin KaFai Lau return ERR_PTR(-ENOMEM); 8558a138aedSMartin KaFai Lau 856ba451366SAndrii Nakryiko btf->nr_types = 0; 857ba451366SAndrii Nakryiko btf->start_id = 1; 858ba451366SAndrii Nakryiko btf->start_str_off = 0; 859c34c338aSDaniel Xu btf->fd = -1; 860ba451366SAndrii Nakryiko 861ba451366SAndrii Nakryiko if (base_btf) { 862ba451366SAndrii Nakryiko btf->base_btf = base_btf; 8636a886de0SHengqi Chen btf->start_id = btf__type_cnt(base_btf); 864ba451366SAndrii Nakryiko btf->start_str_off = base_btf->hdr->str_len; 865ba451366SAndrii Nakryiko } 866ba451366SAndrii Nakryiko 867b8604247SAndrii Nakryiko btf->raw_data = malloc(size); 868b8604247SAndrii Nakryiko if (!btf->raw_data) { 8698a138aedSMartin KaFai Lau err = -ENOMEM; 8708a138aedSMartin KaFai Lau goto done; 8718a138aedSMartin KaFai Lau } 872b8604247SAndrii Nakryiko memcpy(btf->raw_data, data, size); 873b8604247SAndrii Nakryiko btf->raw_size = size; 8748a138aedSMartin KaFai Lau 875b8604247SAndrii Nakryiko btf->hdr = btf->raw_data; 8768461ef8bSYonghong Song err = btf_parse_hdr(btf); 8778a138aedSMartin KaFai Lau if (err) 8788a138aedSMartin KaFai Lau goto done; 8798a138aedSMartin KaFai Lau 880b8604247SAndrii Nakryiko btf->strs_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->str_off; 881b8604247SAndrii Nakryiko btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off; 8828a138aedSMartin KaFai Lau 883b8604247SAndrii Nakryiko err = btf_parse_str_sec(btf); 884b8604247SAndrii Nakryiko err = err ?: btf_parse_type_sec(btf); 8853289959bSAndrii Nakryiko if (err) 8863289959bSAndrii Nakryiko goto done; 8873289959bSAndrii Nakryiko 8888a138aedSMartin KaFai Lau done: 8898a138aedSMartin KaFai Lau if (err) { 8908a138aedSMartin KaFai Lau btf__free(btf); 8918a138aedSMartin KaFai Lau return ERR_PTR(err); 8928a138aedSMartin KaFai Lau } 8938a138aedSMartin KaFai Lau 8948a138aedSMartin KaFai Lau return btf; 8958a138aedSMartin KaFai Lau } 8968a138aedSMartin KaFai Lau 897ba451366SAndrii Nakryiko struct btf *btf__new(const void *data, __u32 size) 898ba451366SAndrii Nakryiko { 899e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_new(data, size, NULL)); 900ba451366SAndrii Nakryiko } 901ba451366SAndrii Nakryiko 902ba451366SAndrii Nakryiko static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, 903ba451366SAndrii Nakryiko struct btf_ext **btf_ext) 904e6c64855SAndrii Nakryiko { 905e6c64855SAndrii Nakryiko Elf_Data *btf_data = NULL, *btf_ext_data = NULL; 906e6c64855SAndrii Nakryiko int err = 0, fd = -1, idx = 0; 907e6c64855SAndrii Nakryiko struct btf *btf = NULL; 908e6c64855SAndrii Nakryiko Elf_Scn *scn = NULL; 909e6c64855SAndrii Nakryiko Elf *elf = NULL; 910e6c64855SAndrii Nakryiko GElf_Ehdr ehdr; 9116095d5a2SJiri Olsa size_t shstrndx; 912e6c64855SAndrii Nakryiko 913e6c64855SAndrii Nakryiko if (elf_version(EV_CURRENT) == EV_NONE) { 914be18010eSKefeng Wang pr_warn("failed to init libelf for %s\n", path); 915e6c64855SAndrii Nakryiko return ERR_PTR(-LIBBPF_ERRNO__LIBELF); 916e6c64855SAndrii Nakryiko } 917e6c64855SAndrii Nakryiko 91892274e24SKumar Kartikeya Dwivedi fd = open(path, O_RDONLY | O_CLOEXEC); 919e6c64855SAndrii Nakryiko if (fd < 0) { 920e6c64855SAndrii Nakryiko err = -errno; 921be18010eSKefeng Wang pr_warn("failed to open %s: %s\n", path, strerror(errno)); 922e6c64855SAndrii Nakryiko return ERR_PTR(err); 923e6c64855SAndrii Nakryiko } 924e6c64855SAndrii Nakryiko 925e6c64855SAndrii Nakryiko err = -LIBBPF_ERRNO__FORMAT; 926e6c64855SAndrii Nakryiko 927e6c64855SAndrii Nakryiko elf = elf_begin(fd, ELF_C_READ, NULL); 928e6c64855SAndrii Nakryiko if (!elf) { 929be18010eSKefeng Wang pr_warn("failed to open %s as ELF file\n", path); 930e6c64855SAndrii Nakryiko goto done; 931e6c64855SAndrii Nakryiko } 932e6c64855SAndrii Nakryiko if (!gelf_getehdr(elf, &ehdr)) { 933be18010eSKefeng Wang pr_warn("failed to get EHDR from %s\n", path); 934e6c64855SAndrii Nakryiko goto done; 935e6c64855SAndrii Nakryiko } 9366095d5a2SJiri Olsa 9376095d5a2SJiri Olsa if (elf_getshdrstrndx(elf, &shstrndx)) { 9386095d5a2SJiri Olsa pr_warn("failed to get section names section index for %s\n", 9396095d5a2SJiri Olsa path); 9406095d5a2SJiri Olsa goto done; 9416095d5a2SJiri Olsa } 9426095d5a2SJiri Olsa 9436095d5a2SJiri Olsa if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) { 944be18010eSKefeng Wang pr_warn("failed to get e_shstrndx from %s\n", path); 945e6c64855SAndrii Nakryiko goto done; 946e6c64855SAndrii Nakryiko } 947e6c64855SAndrii Nakryiko 948e6c64855SAndrii Nakryiko while ((scn = elf_nextscn(elf, scn)) != NULL) { 949e6c64855SAndrii Nakryiko GElf_Shdr sh; 950e6c64855SAndrii Nakryiko char *name; 951e6c64855SAndrii Nakryiko 952e6c64855SAndrii Nakryiko idx++; 953e6c64855SAndrii Nakryiko if (gelf_getshdr(scn, &sh) != &sh) { 954be18010eSKefeng Wang pr_warn("failed to get section(%d) header from %s\n", 955e6c64855SAndrii Nakryiko idx, path); 956e6c64855SAndrii Nakryiko goto done; 957e6c64855SAndrii Nakryiko } 9586095d5a2SJiri Olsa name = elf_strptr(elf, shstrndx, sh.sh_name); 959e6c64855SAndrii Nakryiko if (!name) { 960be18010eSKefeng Wang pr_warn("failed to get section(%d) name from %s\n", 961e6c64855SAndrii Nakryiko idx, path); 962e6c64855SAndrii Nakryiko goto done; 963e6c64855SAndrii Nakryiko } 964e6c64855SAndrii Nakryiko if (strcmp(name, BTF_ELF_SEC) == 0) { 965e6c64855SAndrii Nakryiko btf_data = elf_getdata(scn, 0); 966e6c64855SAndrii Nakryiko if (!btf_data) { 967be18010eSKefeng Wang pr_warn("failed to get section(%d, %s) data from %s\n", 968e6c64855SAndrii Nakryiko idx, name, path); 969e6c64855SAndrii Nakryiko goto done; 970e6c64855SAndrii Nakryiko } 971e6c64855SAndrii Nakryiko continue; 972e6c64855SAndrii Nakryiko } else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) { 973e6c64855SAndrii Nakryiko btf_ext_data = elf_getdata(scn, 0); 974e6c64855SAndrii Nakryiko if (!btf_ext_data) { 975be18010eSKefeng Wang pr_warn("failed to get section(%d, %s) data from %s\n", 976e6c64855SAndrii Nakryiko idx, name, path); 977e6c64855SAndrii Nakryiko goto done; 978e6c64855SAndrii Nakryiko } 979e6c64855SAndrii Nakryiko continue; 980e6c64855SAndrii Nakryiko } 981e6c64855SAndrii Nakryiko } 982e6c64855SAndrii Nakryiko 983e6c64855SAndrii Nakryiko err = 0; 984e6c64855SAndrii Nakryiko 985e6c64855SAndrii Nakryiko if (!btf_data) { 986e6c64855SAndrii Nakryiko err = -ENOENT; 987e6c64855SAndrii Nakryiko goto done; 988e6c64855SAndrii Nakryiko } 989ba451366SAndrii Nakryiko btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf); 990e9fc3ce9SAndrii Nakryiko err = libbpf_get_error(btf); 991e9fc3ce9SAndrii Nakryiko if (err) 992e6c64855SAndrii Nakryiko goto done; 993e6c64855SAndrii Nakryiko 99444ad23dfSAndrii Nakryiko switch (gelf_getclass(elf)) { 99544ad23dfSAndrii Nakryiko case ELFCLASS32: 99644ad23dfSAndrii Nakryiko btf__set_pointer_size(btf, 4); 99744ad23dfSAndrii Nakryiko break; 99844ad23dfSAndrii Nakryiko case ELFCLASS64: 99944ad23dfSAndrii Nakryiko btf__set_pointer_size(btf, 8); 100044ad23dfSAndrii Nakryiko break; 100144ad23dfSAndrii Nakryiko default: 100244ad23dfSAndrii Nakryiko pr_warn("failed to get ELF class (bitness) for %s\n", path); 100344ad23dfSAndrii Nakryiko break; 100444ad23dfSAndrii Nakryiko } 100544ad23dfSAndrii Nakryiko 1006e6c64855SAndrii Nakryiko if (btf_ext && btf_ext_data) { 1007e9fc3ce9SAndrii Nakryiko *btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size); 1008e9fc3ce9SAndrii Nakryiko err = libbpf_get_error(*btf_ext); 1009e9fc3ce9SAndrii Nakryiko if (err) 1010e6c64855SAndrii Nakryiko goto done; 1011e6c64855SAndrii Nakryiko } else if (btf_ext) { 1012e6c64855SAndrii Nakryiko *btf_ext = NULL; 1013e6c64855SAndrii Nakryiko } 1014e6c64855SAndrii Nakryiko done: 1015e6c64855SAndrii Nakryiko if (elf) 1016e6c64855SAndrii Nakryiko elf_end(elf); 1017e6c64855SAndrii Nakryiko close(fd); 1018e6c64855SAndrii Nakryiko 1019e9fc3ce9SAndrii Nakryiko if (!err) 1020e6c64855SAndrii Nakryiko return btf; 1021e9fc3ce9SAndrii Nakryiko 1022e9fc3ce9SAndrii Nakryiko if (btf_ext) 1023e9fc3ce9SAndrii Nakryiko btf_ext__free(*btf_ext); 1024e6c64855SAndrii Nakryiko btf__free(btf); 1025e9fc3ce9SAndrii Nakryiko 1026e6c64855SAndrii Nakryiko return ERR_PTR(err); 1027e6c64855SAndrii Nakryiko } 1028e6c64855SAndrii Nakryiko 1029ba451366SAndrii Nakryiko struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext) 1030ba451366SAndrii Nakryiko { 1031e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse_elf(path, NULL, btf_ext)); 1032ba451366SAndrii Nakryiko } 1033ba451366SAndrii Nakryiko 1034ba451366SAndrii Nakryiko struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf) 1035ba451366SAndrii Nakryiko { 1036e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse_elf(path, base_btf, NULL)); 1037ba451366SAndrii Nakryiko } 1038ba451366SAndrii Nakryiko 1039ba451366SAndrii Nakryiko static struct btf *btf_parse_raw(const char *path, struct btf *base_btf) 104094a1feddSAndrii Nakryiko { 1041932ac54aSDaniel T. Lee struct btf *btf = NULL; 104294a1feddSAndrii Nakryiko void *data = NULL; 104394a1feddSAndrii Nakryiko FILE *f = NULL; 104494a1feddSAndrii Nakryiko __u16 magic; 104594a1feddSAndrii Nakryiko int err = 0; 104694a1feddSAndrii Nakryiko long sz; 104794a1feddSAndrii Nakryiko 104894a1feddSAndrii Nakryiko f = fopen(path, "rb"); 104994a1feddSAndrii Nakryiko if (!f) { 105094a1feddSAndrii Nakryiko err = -errno; 105194a1feddSAndrii Nakryiko goto err_out; 105294a1feddSAndrii Nakryiko } 105394a1feddSAndrii Nakryiko 105494a1feddSAndrii Nakryiko /* check BTF magic */ 105594a1feddSAndrii Nakryiko if (fread(&magic, 1, sizeof(magic), f) < sizeof(magic)) { 105694a1feddSAndrii Nakryiko err = -EIO; 105794a1feddSAndrii Nakryiko goto err_out; 105894a1feddSAndrii Nakryiko } 10593289959bSAndrii Nakryiko if (magic != BTF_MAGIC && magic != bswap_16(BTF_MAGIC)) { 106094a1feddSAndrii Nakryiko /* definitely not a raw BTF */ 106194a1feddSAndrii Nakryiko err = -EPROTO; 106294a1feddSAndrii Nakryiko goto err_out; 106394a1feddSAndrii Nakryiko } 106494a1feddSAndrii Nakryiko 106594a1feddSAndrii Nakryiko /* get file size */ 106694a1feddSAndrii Nakryiko if (fseek(f, 0, SEEK_END)) { 106794a1feddSAndrii Nakryiko err = -errno; 106894a1feddSAndrii Nakryiko goto err_out; 106994a1feddSAndrii Nakryiko } 107094a1feddSAndrii Nakryiko sz = ftell(f); 107194a1feddSAndrii Nakryiko if (sz < 0) { 107294a1feddSAndrii Nakryiko err = -errno; 107394a1feddSAndrii Nakryiko goto err_out; 107494a1feddSAndrii Nakryiko } 107594a1feddSAndrii Nakryiko /* rewind to the start */ 107694a1feddSAndrii Nakryiko if (fseek(f, 0, SEEK_SET)) { 107794a1feddSAndrii Nakryiko err = -errno; 107894a1feddSAndrii Nakryiko goto err_out; 107994a1feddSAndrii Nakryiko } 108094a1feddSAndrii Nakryiko 108194a1feddSAndrii Nakryiko /* pre-alloc memory and read all of BTF data */ 108294a1feddSAndrii Nakryiko data = malloc(sz); 108394a1feddSAndrii Nakryiko if (!data) { 108494a1feddSAndrii Nakryiko err = -ENOMEM; 108594a1feddSAndrii Nakryiko goto err_out; 108694a1feddSAndrii Nakryiko } 108794a1feddSAndrii Nakryiko if (fread(data, 1, sz, f) < sz) { 108894a1feddSAndrii Nakryiko err = -EIO; 108994a1feddSAndrii Nakryiko goto err_out; 109094a1feddSAndrii Nakryiko } 109194a1feddSAndrii Nakryiko 109294a1feddSAndrii Nakryiko /* finally parse BTF data */ 1093ba451366SAndrii Nakryiko btf = btf_new(data, sz, base_btf); 109494a1feddSAndrii Nakryiko 109594a1feddSAndrii Nakryiko err_out: 109694a1feddSAndrii Nakryiko free(data); 109794a1feddSAndrii Nakryiko if (f) 109894a1feddSAndrii Nakryiko fclose(f); 109994a1feddSAndrii Nakryiko return err ? ERR_PTR(err) : btf; 110094a1feddSAndrii Nakryiko } 110194a1feddSAndrii Nakryiko 1102ba451366SAndrii Nakryiko struct btf *btf__parse_raw(const char *path) 1103ba451366SAndrii Nakryiko { 1104e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse_raw(path, NULL)); 1105ba451366SAndrii Nakryiko } 1106ba451366SAndrii Nakryiko 1107ba451366SAndrii Nakryiko struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf) 1108ba451366SAndrii Nakryiko { 1109e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse_raw(path, base_btf)); 1110ba451366SAndrii Nakryiko } 1111ba451366SAndrii Nakryiko 1112ba451366SAndrii Nakryiko static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext) 111394a1feddSAndrii Nakryiko { 111494a1feddSAndrii Nakryiko struct btf *btf; 1115e9fc3ce9SAndrii Nakryiko int err; 111694a1feddSAndrii Nakryiko 111794a1feddSAndrii Nakryiko if (btf_ext) 111894a1feddSAndrii Nakryiko *btf_ext = NULL; 111994a1feddSAndrii Nakryiko 1120ba451366SAndrii Nakryiko btf = btf_parse_raw(path, base_btf); 1121e9fc3ce9SAndrii Nakryiko err = libbpf_get_error(btf); 1122e9fc3ce9SAndrii Nakryiko if (!err) 112394a1feddSAndrii Nakryiko return btf; 1124e9fc3ce9SAndrii Nakryiko if (err != -EPROTO) 1125e9fc3ce9SAndrii Nakryiko return ERR_PTR(err); 1126ba451366SAndrii Nakryiko return btf_parse_elf(path, base_btf, btf_ext); 1127ba451366SAndrii Nakryiko } 1128ba451366SAndrii Nakryiko 1129ba451366SAndrii Nakryiko struct btf *btf__parse(const char *path, struct btf_ext **btf_ext) 1130ba451366SAndrii Nakryiko { 1131e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse(path, NULL, btf_ext)); 1132ba451366SAndrii Nakryiko } 1133ba451366SAndrii Nakryiko 1134ba451366SAndrii Nakryiko struct btf *btf__parse_split(const char *path, struct btf *base_btf) 1135ba451366SAndrii Nakryiko { 1136e9fc3ce9SAndrii Nakryiko return libbpf_ptr(btf_parse(path, base_btf, NULL)); 113794a1feddSAndrii Nakryiko } 113894a1feddSAndrii Nakryiko 11393289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian); 11403289959bSAndrii Nakryiko 11411a190d1eSAndrii Nakryiko int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level) 1142d29d87f7SAndrii Nakryiko { 11431a190d1eSAndrii Nakryiko LIBBPF_OPTS(bpf_btf_load_opts, opts); 11441a190d1eSAndrii Nakryiko __u32 buf_sz = 0, raw_size; 11451a190d1eSAndrii Nakryiko char *buf = NULL, *tmp; 11463289959bSAndrii Nakryiko void *raw_data; 1147d29d87f7SAndrii Nakryiko int err = 0; 1148d29d87f7SAndrii Nakryiko 1149d29d87f7SAndrii Nakryiko if (btf->fd >= 0) 1150e9fc3ce9SAndrii Nakryiko return libbpf_err(-EEXIST); 11511a190d1eSAndrii Nakryiko if (log_sz && !log_buf) 11521a190d1eSAndrii Nakryiko return libbpf_err(-EINVAL); 1153d29d87f7SAndrii Nakryiko 11541a190d1eSAndrii Nakryiko /* cache native raw data representation */ 11553289959bSAndrii Nakryiko raw_data = btf_get_raw_data(btf, &raw_size, false); 1156b8604247SAndrii Nakryiko if (!raw_data) { 1157b8604247SAndrii Nakryiko err = -ENOMEM; 1158b8604247SAndrii Nakryiko goto done; 1159b8604247SAndrii Nakryiko } 11603289959bSAndrii Nakryiko btf->raw_size = raw_size; 11613289959bSAndrii Nakryiko btf->raw_data = raw_data; 1162b8604247SAndrii Nakryiko 11631a190d1eSAndrii Nakryiko retry_load: 11641a190d1eSAndrii Nakryiko /* if log_level is 0, we won't provide log_buf/log_size to the kernel, 11651a190d1eSAndrii Nakryiko * initially. Only if BTF loading fails, we bump log_level to 1 and 11661a190d1eSAndrii Nakryiko * retry, using either auto-allocated or custom log_buf. This way 11671a190d1eSAndrii Nakryiko * non-NULL custom log_buf provides a buffer just in case, but hopes 11681a190d1eSAndrii Nakryiko * for successful load and no need for log_buf. 11691a190d1eSAndrii Nakryiko */ 11701a190d1eSAndrii Nakryiko if (log_level) { 11711a190d1eSAndrii Nakryiko /* if caller didn't provide custom log_buf, we'll keep 11721a190d1eSAndrii Nakryiko * allocating our own progressively bigger buffers for BTF 11731a190d1eSAndrii Nakryiko * verification log 11741a190d1eSAndrii Nakryiko */ 11751a190d1eSAndrii Nakryiko if (!log_buf) { 11761a190d1eSAndrii Nakryiko buf_sz = max((__u32)BPF_LOG_BUF_SIZE, buf_sz * 2); 11771a190d1eSAndrii Nakryiko tmp = realloc(buf, buf_sz); 11781a190d1eSAndrii Nakryiko if (!tmp) { 11791a190d1eSAndrii Nakryiko err = -ENOMEM; 11801a190d1eSAndrii Nakryiko goto done; 11811a190d1eSAndrii Nakryiko } 11821a190d1eSAndrii Nakryiko buf = tmp; 11831a190d1eSAndrii Nakryiko buf[0] = '\0'; 11848395f320SStanislav Fomichev } 11858395f320SStanislav Fomichev 11861a190d1eSAndrii Nakryiko opts.log_buf = log_buf ? log_buf : buf; 11871a190d1eSAndrii Nakryiko opts.log_size = log_buf ? log_sz : buf_sz; 11881a190d1eSAndrii Nakryiko opts.log_level = log_level; 11891a190d1eSAndrii Nakryiko } 11901a190d1eSAndrii Nakryiko 11911a190d1eSAndrii Nakryiko btf->fd = bpf_btf_load(raw_data, raw_size, &opts); 11921a190d1eSAndrii Nakryiko if (btf->fd < 0) { 11931a190d1eSAndrii Nakryiko /* time to turn on verbose mode and try again */ 11941a190d1eSAndrii Nakryiko if (log_level == 0) { 11951a190d1eSAndrii Nakryiko log_level = 1; 11961a190d1eSAndrii Nakryiko goto retry_load; 11971a190d1eSAndrii Nakryiko } 11981a190d1eSAndrii Nakryiko /* only retry if caller didn't provide custom log_buf, but 11991a190d1eSAndrii Nakryiko * make sure we can never overflow buf_sz 12001a190d1eSAndrii Nakryiko */ 12011a190d1eSAndrii Nakryiko if (!log_buf && errno == ENOSPC && buf_sz <= UINT_MAX / 2) 12021a190d1eSAndrii Nakryiko goto retry_load; 12031a190d1eSAndrii Nakryiko 1204d29d87f7SAndrii Nakryiko err = -errno; 12051a190d1eSAndrii Nakryiko pr_warn("BTF loading error: %d\n", err); 12061a190d1eSAndrii Nakryiko /* don't print out contents of custom log_buf */ 12071a190d1eSAndrii Nakryiko if (!log_buf && buf[0]) 12081a190d1eSAndrii Nakryiko pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf); 1209d29d87f7SAndrii Nakryiko } 1210d29d87f7SAndrii Nakryiko 1211d29d87f7SAndrii Nakryiko done: 12121a190d1eSAndrii Nakryiko free(buf); 1213e9fc3ce9SAndrii Nakryiko return libbpf_err(err); 1214d29d87f7SAndrii Nakryiko } 12151a190d1eSAndrii Nakryiko 12161a190d1eSAndrii Nakryiko int btf__load_into_kernel(struct btf *btf) 12171a190d1eSAndrii Nakryiko { 12181a190d1eSAndrii Nakryiko return btf_load_into_kernel(btf, NULL, 0, 0); 12191a190d1eSAndrii Nakryiko } 12201a190d1eSAndrii Nakryiko 12213c7e5859SQuentin Monnet int btf__load(struct btf *) __attribute__((alias("btf__load_into_kernel"))); 1222d29d87f7SAndrii Nakryiko 12238a138aedSMartin KaFai Lau int btf__fd(const struct btf *btf) 12248a138aedSMartin KaFai Lau { 12258a138aedSMartin KaFai Lau return btf->fd; 12268a138aedSMartin KaFai Lau } 122792b57121SOkash Khawaja 122881372e12SAndrii Nakryiko void btf__set_fd(struct btf *btf, int fd) 122981372e12SAndrii Nakryiko { 123081372e12SAndrii Nakryiko btf->fd = fd; 123181372e12SAndrii Nakryiko } 123281372e12SAndrii Nakryiko 123390d76d3eSAndrii Nakryiko static const void *btf_strs_data(const struct btf *btf) 123490d76d3eSAndrii Nakryiko { 123590d76d3eSAndrii Nakryiko return btf->strs_data ? btf->strs_data : strset__data(btf->strs_set); 123690d76d3eSAndrii Nakryiko } 123790d76d3eSAndrii Nakryiko 12383289959bSAndrii Nakryiko static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian) 12393289959bSAndrii Nakryiko { 12403289959bSAndrii Nakryiko struct btf_header *hdr = btf->hdr; 12413289959bSAndrii Nakryiko struct btf_type *t; 12423289959bSAndrii Nakryiko void *data, *p; 12433289959bSAndrii Nakryiko __u32 data_sz; 12443289959bSAndrii Nakryiko int i; 12453289959bSAndrii Nakryiko 12463289959bSAndrii Nakryiko data = swap_endian ? btf->raw_data_swapped : btf->raw_data; 12473289959bSAndrii Nakryiko if (data) { 12483289959bSAndrii Nakryiko *size = btf->raw_size; 12493289959bSAndrii Nakryiko return data; 12503289959bSAndrii Nakryiko } 12513289959bSAndrii Nakryiko 12523289959bSAndrii Nakryiko data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len; 12533289959bSAndrii Nakryiko data = calloc(1, data_sz); 12543289959bSAndrii Nakryiko if (!data) 12553289959bSAndrii Nakryiko return NULL; 12563289959bSAndrii Nakryiko p = data; 12573289959bSAndrii Nakryiko 12583289959bSAndrii Nakryiko memcpy(p, hdr, hdr->hdr_len); 12593289959bSAndrii Nakryiko if (swap_endian) 12603289959bSAndrii Nakryiko btf_bswap_hdr(p); 12613289959bSAndrii Nakryiko p += hdr->hdr_len; 12623289959bSAndrii Nakryiko 12633289959bSAndrii Nakryiko memcpy(p, btf->types_data, hdr->type_len); 12643289959bSAndrii Nakryiko if (swap_endian) { 1265ba451366SAndrii Nakryiko for (i = 0; i < btf->nr_types; i++) { 12663289959bSAndrii Nakryiko t = p + btf->type_offs[i]; 12673289959bSAndrii Nakryiko /* btf_bswap_type_rest() relies on native t->info, so 12683289959bSAndrii Nakryiko * we swap base type info after we swapped all the 12693289959bSAndrii Nakryiko * additional information 12703289959bSAndrii Nakryiko */ 12713289959bSAndrii Nakryiko if (btf_bswap_type_rest(t)) 12723289959bSAndrii Nakryiko goto err_out; 12733289959bSAndrii Nakryiko btf_bswap_type_base(t); 12743289959bSAndrii Nakryiko } 12753289959bSAndrii Nakryiko } 12763289959bSAndrii Nakryiko p += hdr->type_len; 12773289959bSAndrii Nakryiko 127890d76d3eSAndrii Nakryiko memcpy(p, btf_strs_data(btf), hdr->str_len); 12793289959bSAndrii Nakryiko p += hdr->str_len; 12803289959bSAndrii Nakryiko 12813289959bSAndrii Nakryiko *size = data_sz; 12823289959bSAndrii Nakryiko return data; 12833289959bSAndrii Nakryiko err_out: 12843289959bSAndrii Nakryiko free(data); 12853289959bSAndrii Nakryiko return NULL; 12863289959bSAndrii Nakryiko } 12873289959bSAndrii Nakryiko 12886a886de0SHengqi Chen const void *btf__raw_data(const struct btf *btf_ro, __u32 *size) 128902c87446SAndrii Nakryiko { 1290919d2b1dSAndrii Nakryiko struct btf *btf = (struct btf *)btf_ro; 12913289959bSAndrii Nakryiko __u32 data_sz; 1292919d2b1dSAndrii Nakryiko void *data; 1293919d2b1dSAndrii Nakryiko 12943289959bSAndrii Nakryiko data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian); 12953289959bSAndrii Nakryiko if (!data) 12966a886de0SHengqi Chen return errno = ENOMEM, NULL; 1297919d2b1dSAndrii Nakryiko 12983289959bSAndrii Nakryiko btf->raw_size = data_sz; 12993289959bSAndrii Nakryiko if (btf->swapped_endian) 13003289959bSAndrii Nakryiko btf->raw_data_swapped = data; 13013289959bSAndrii Nakryiko else 13023289959bSAndrii Nakryiko btf->raw_data = data; 13033289959bSAndrii Nakryiko *size = data_sz; 13043289959bSAndrii Nakryiko return data; 130502c87446SAndrii Nakryiko } 130602c87446SAndrii Nakryiko 13076a886de0SHengqi Chen __attribute__((alias("btf__raw_data"))) 13086a886de0SHengqi Chen const void *btf__get_raw_data(const struct btf *btf, __u32 *size); 13096a886de0SHengqi Chen 1310f86ed050SAndrii Nakryiko const char *btf__str_by_offset(const struct btf *btf, __u32 offset) 131192b57121SOkash Khawaja { 1312ba451366SAndrii Nakryiko if (offset < btf->start_str_off) 1313ba451366SAndrii Nakryiko return btf__str_by_offset(btf->base_btf, offset); 1314ba451366SAndrii Nakryiko else if (offset - btf->start_str_off < btf->hdr->str_len) 131590d76d3eSAndrii Nakryiko return btf_strs_data(btf) + (offset - btf->start_str_off); 131692b57121SOkash Khawaja else 1317e9fc3ce9SAndrii Nakryiko return errno = EINVAL, NULL; 131892b57121SOkash Khawaja } 13192993e051SYonghong Song 1320f86ed050SAndrii Nakryiko const char *btf__name_by_offset(const struct btf *btf, __u32 offset) 1321f86ed050SAndrii Nakryiko { 1322f86ed050SAndrii Nakryiko return btf__str_by_offset(btf, offset); 1323f86ed050SAndrii Nakryiko } 1324f86ed050SAndrii Nakryiko 1325a19f93cfSAndrii Nakryiko struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf) 1326d7f5b5e0SYonghong Song { 1327a19f93cfSAndrii Nakryiko struct bpf_btf_info btf_info; 1328d7f5b5e0SYonghong Song __u32 len = sizeof(btf_info); 1329d7f5b5e0SYonghong Song __u32 last_size; 1330a19f93cfSAndrii Nakryiko struct btf *btf; 1331d7f5b5e0SYonghong Song void *ptr; 1332d7f5b5e0SYonghong Song int err; 1333d7f5b5e0SYonghong Song 1334d7f5b5e0SYonghong Song /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so 1335d7f5b5e0SYonghong Song * let's start with a sane default - 4KiB here - and resize it only if 1336d7f5b5e0SYonghong Song * bpf_obj_get_info_by_fd() needs a bigger buffer. 1337d7f5b5e0SYonghong Song */ 1338a19f93cfSAndrii Nakryiko last_size = 4096; 1339d7f5b5e0SYonghong Song ptr = malloc(last_size); 1340a19f93cfSAndrii Nakryiko if (!ptr) 1341a19f93cfSAndrii Nakryiko return ERR_PTR(-ENOMEM); 1342d7f5b5e0SYonghong Song 1343a19f93cfSAndrii Nakryiko memset(&btf_info, 0, sizeof(btf_info)); 1344d7f5b5e0SYonghong Song btf_info.btf = ptr_to_u64(ptr); 1345a19f93cfSAndrii Nakryiko btf_info.btf_size = last_size; 1346d7f5b5e0SYonghong Song err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); 1347d7f5b5e0SYonghong Song 1348d7f5b5e0SYonghong Song if (!err && btf_info.btf_size > last_size) { 1349d7f5b5e0SYonghong Song void *temp_ptr; 1350d7f5b5e0SYonghong Song 1351d7f5b5e0SYonghong Song last_size = btf_info.btf_size; 1352d7f5b5e0SYonghong Song temp_ptr = realloc(ptr, last_size); 1353d7f5b5e0SYonghong Song if (!temp_ptr) { 1354a19f93cfSAndrii Nakryiko btf = ERR_PTR(-ENOMEM); 1355d7f5b5e0SYonghong Song goto exit_free; 1356d7f5b5e0SYonghong Song } 1357d7f5b5e0SYonghong Song ptr = temp_ptr; 1358a19f93cfSAndrii Nakryiko 1359a19f93cfSAndrii Nakryiko len = sizeof(btf_info); 1360a19f93cfSAndrii Nakryiko memset(&btf_info, 0, sizeof(btf_info)); 1361d7f5b5e0SYonghong Song btf_info.btf = ptr_to_u64(ptr); 1362a19f93cfSAndrii Nakryiko btf_info.btf_size = last_size; 1363a19f93cfSAndrii Nakryiko 1364d7f5b5e0SYonghong Song err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); 1365d7f5b5e0SYonghong Song } 1366d7f5b5e0SYonghong Song 1367d7f5b5e0SYonghong Song if (err || btf_info.btf_size > last_size) { 1368a19f93cfSAndrii Nakryiko btf = err ? ERR_PTR(-errno) : ERR_PTR(-E2BIG); 1369d7f5b5e0SYonghong Song goto exit_free; 1370d7f5b5e0SYonghong Song } 1371d7f5b5e0SYonghong Song 1372a19f93cfSAndrii Nakryiko btf = btf_new(ptr, btf_info.btf_size, base_btf); 1373d7f5b5e0SYonghong Song 1374d7f5b5e0SYonghong Song exit_free: 1375d7f5b5e0SYonghong Song free(ptr); 1376a19f93cfSAndrii Nakryiko return btf; 1377a19f93cfSAndrii Nakryiko } 1378d7f5b5e0SYonghong Song 137961fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf) 13806cc93e2fSQuentin Monnet { 13816cc93e2fSQuentin Monnet struct btf *btf; 13826cc93e2fSQuentin Monnet int btf_fd; 13836cc93e2fSQuentin Monnet 13846cc93e2fSQuentin Monnet btf_fd = bpf_btf_get_fd_by_id(id); 13856cc93e2fSQuentin Monnet if (btf_fd < 0) 13866cc93e2fSQuentin Monnet return libbpf_err_ptr(-errno); 13876cc93e2fSQuentin Monnet 138861fc51b1SQuentin Monnet btf = btf_get_from_fd(btf_fd, base_btf); 13896cc93e2fSQuentin Monnet close(btf_fd); 13906cc93e2fSQuentin Monnet 13916cc93e2fSQuentin Monnet return libbpf_ptr(btf); 13926cc93e2fSQuentin Monnet } 13936cc93e2fSQuentin Monnet 139461fc51b1SQuentin Monnet struct btf *btf__load_from_kernel_by_id(__u32 id) 139561fc51b1SQuentin Monnet { 139661fc51b1SQuentin Monnet return btf__load_from_kernel_by_id_split(id, NULL); 139761fc51b1SQuentin Monnet } 139861fc51b1SQuentin Monnet 1399a19f93cfSAndrii Nakryiko int btf__get_from_id(__u32 id, struct btf **btf) 1400a19f93cfSAndrii Nakryiko { 1401a19f93cfSAndrii Nakryiko struct btf *res; 14026cc93e2fSQuentin Monnet int err; 1403a19f93cfSAndrii Nakryiko 1404a19f93cfSAndrii Nakryiko *btf = NULL; 14056cc93e2fSQuentin Monnet res = btf__load_from_kernel_by_id(id); 1406e9fc3ce9SAndrii Nakryiko err = libbpf_get_error(res); 1407e9fc3ce9SAndrii Nakryiko 1408e9fc3ce9SAndrii Nakryiko if (err) 1409e9fc3ce9SAndrii Nakryiko return libbpf_err(err); 1410a19f93cfSAndrii Nakryiko 1411a19f93cfSAndrii Nakryiko *btf = res; 1412a19f93cfSAndrii Nakryiko return 0; 1413d7f5b5e0SYonghong Song } 1414d7f5b5e0SYonghong Song 1415a6c109a6SYonghong Song int btf__get_map_kv_tids(const struct btf *btf, const char *map_name, 141696408c43SYonghong Song __u32 expected_key_size, __u32 expected_value_size, 141796408c43SYonghong Song __u32 *key_type_id, __u32 *value_type_id) 141896408c43SYonghong Song { 141996408c43SYonghong Song const struct btf_type *container_type; 142096408c43SYonghong Song const struct btf_member *key, *value; 142196408c43SYonghong Song const size_t max_name = 256; 142296408c43SYonghong Song char container_name[max_name]; 142396408c43SYonghong Song __s64 key_size, value_size; 142496408c43SYonghong Song __s32 container_id; 142596408c43SYonghong Song 1426e9fc3ce9SAndrii Nakryiko if (snprintf(container_name, max_name, "____btf_map_%s", map_name) == max_name) { 1427be18010eSKefeng Wang pr_warn("map:%s length of '____btf_map_%s' is too long\n", 142896408c43SYonghong Song map_name, map_name); 1429e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 143096408c43SYonghong Song } 143196408c43SYonghong Song 143296408c43SYonghong Song container_id = btf__find_by_name(btf, container_name); 143396408c43SYonghong Song if (container_id < 0) { 1434f7748e29SYonghong Song pr_debug("map:%s container_name:%s cannot be found in BTF. Missing BPF_ANNOTATE_KV_PAIR?\n", 143596408c43SYonghong Song map_name, container_name); 1436e9fc3ce9SAndrii Nakryiko return libbpf_err(container_id); 143796408c43SYonghong Song } 143896408c43SYonghong Song 143996408c43SYonghong Song container_type = btf__type_by_id(btf, container_id); 144096408c43SYonghong Song if (!container_type) { 1441be18010eSKefeng Wang pr_warn("map:%s cannot find BTF type for container_id:%u\n", 144296408c43SYonghong Song map_name, container_id); 1443e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 144496408c43SYonghong Song } 144596408c43SYonghong Song 1446b03bc685SAndrii Nakryiko if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) { 1447be18010eSKefeng Wang pr_warn("map:%s container_name:%s is an invalid container struct\n", 144896408c43SYonghong Song map_name, container_name); 1449e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 145096408c43SYonghong Song } 145196408c43SYonghong Song 1452b03bc685SAndrii Nakryiko key = btf_members(container_type); 145396408c43SYonghong Song value = key + 1; 145496408c43SYonghong Song 145596408c43SYonghong Song key_size = btf__resolve_size(btf, key->type); 145696408c43SYonghong Song if (key_size < 0) { 1457be18010eSKefeng Wang pr_warn("map:%s invalid BTF key_type_size\n", map_name); 1458e9fc3ce9SAndrii Nakryiko return libbpf_err(key_size); 145996408c43SYonghong Song } 146096408c43SYonghong Song 146196408c43SYonghong Song if (expected_key_size != key_size) { 1462be18010eSKefeng Wang pr_warn("map:%s btf_key_type_size:%u != map_def_key_size:%u\n", 146396408c43SYonghong Song map_name, (__u32)key_size, expected_key_size); 1464e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 146596408c43SYonghong Song } 146696408c43SYonghong Song 146796408c43SYonghong Song value_size = btf__resolve_size(btf, value->type); 146896408c43SYonghong Song if (value_size < 0) { 1469be18010eSKefeng Wang pr_warn("map:%s invalid BTF value_type_size\n", map_name); 1470e9fc3ce9SAndrii Nakryiko return libbpf_err(value_size); 147196408c43SYonghong Song } 147296408c43SYonghong Song 147396408c43SYonghong Song if (expected_value_size != value_size) { 1474be18010eSKefeng Wang pr_warn("map:%s btf_value_type_size:%u != map_def_value_size:%u\n", 147596408c43SYonghong Song map_name, (__u32)value_size, expected_value_size); 1476e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 147796408c43SYonghong Song } 147896408c43SYonghong Song 147996408c43SYonghong Song *key_type_id = key->type; 148096408c43SYonghong Song *value_type_id = value->type; 148196408c43SYonghong Song 148296408c43SYonghong Song return 0; 148396408c43SYonghong Song } 148496408c43SYonghong Song 14853289959bSAndrii Nakryiko static void btf_invalidate_raw_data(struct btf *btf) 14863289959bSAndrii Nakryiko { 14873289959bSAndrii Nakryiko if (btf->raw_data) { 14883289959bSAndrii Nakryiko free(btf->raw_data); 14893289959bSAndrii Nakryiko btf->raw_data = NULL; 14903289959bSAndrii Nakryiko } 14913289959bSAndrii Nakryiko if (btf->raw_data_swapped) { 14923289959bSAndrii Nakryiko free(btf->raw_data_swapped); 14933289959bSAndrii Nakryiko btf->raw_data_swapped = NULL; 14943289959bSAndrii Nakryiko } 14953289959bSAndrii Nakryiko } 14963289959bSAndrii Nakryiko 1497919d2b1dSAndrii Nakryiko /* Ensure BTF is ready to be modified (by splitting into a three memory 1498919d2b1dSAndrii Nakryiko * regions for header, types, and strings). Also invalidate cached 1499919d2b1dSAndrii Nakryiko * raw_data, if any. 1500919d2b1dSAndrii Nakryiko */ 1501919d2b1dSAndrii Nakryiko static int btf_ensure_modifiable(struct btf *btf) 1502919d2b1dSAndrii Nakryiko { 150390d76d3eSAndrii Nakryiko void *hdr, *types; 150490d76d3eSAndrii Nakryiko struct strset *set = NULL; 150590d76d3eSAndrii Nakryiko int err = -ENOMEM; 1506919d2b1dSAndrii Nakryiko 1507919d2b1dSAndrii Nakryiko if (btf_is_modifiable(btf)) { 1508919d2b1dSAndrii Nakryiko /* any BTF modification invalidates raw_data */ 15093289959bSAndrii Nakryiko btf_invalidate_raw_data(btf); 1510919d2b1dSAndrii Nakryiko return 0; 1511919d2b1dSAndrii Nakryiko } 1512919d2b1dSAndrii Nakryiko 1513919d2b1dSAndrii Nakryiko /* split raw data into three memory regions */ 1514919d2b1dSAndrii Nakryiko hdr = malloc(btf->hdr->hdr_len); 1515919d2b1dSAndrii Nakryiko types = malloc(btf->hdr->type_len); 151690d76d3eSAndrii Nakryiko if (!hdr || !types) 1517919d2b1dSAndrii Nakryiko goto err_out; 1518919d2b1dSAndrii Nakryiko 1519919d2b1dSAndrii Nakryiko memcpy(hdr, btf->hdr, btf->hdr->hdr_len); 1520919d2b1dSAndrii Nakryiko memcpy(types, btf->types_data, btf->hdr->type_len); 152188a82c2aSAndrii Nakryiko 1522919d2b1dSAndrii Nakryiko /* build lookup index for all strings */ 152390d76d3eSAndrii Nakryiko set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len); 152490d76d3eSAndrii Nakryiko if (IS_ERR(set)) { 152590d76d3eSAndrii Nakryiko err = PTR_ERR(set); 1526919d2b1dSAndrii Nakryiko goto err_out; 1527919d2b1dSAndrii Nakryiko } 1528919d2b1dSAndrii Nakryiko 1529919d2b1dSAndrii Nakryiko /* only when everything was successful, update internal state */ 1530919d2b1dSAndrii Nakryiko btf->hdr = hdr; 1531919d2b1dSAndrii Nakryiko btf->types_data = types; 1532919d2b1dSAndrii Nakryiko btf->types_data_cap = btf->hdr->type_len; 153390d76d3eSAndrii Nakryiko btf->strs_data = NULL; 153490d76d3eSAndrii Nakryiko btf->strs_set = set; 1535919d2b1dSAndrii Nakryiko /* if BTF was created from scratch, all strings are guaranteed to be 1536919d2b1dSAndrii Nakryiko * unique and deduplicated 1537919d2b1dSAndrii Nakryiko */ 1538ba451366SAndrii Nakryiko if (btf->hdr->str_len == 0) 1539ba451366SAndrii Nakryiko btf->strs_deduped = true; 1540ba451366SAndrii Nakryiko if (!btf->base_btf && btf->hdr->str_len == 1) 1541ba451366SAndrii Nakryiko btf->strs_deduped = true; 1542919d2b1dSAndrii Nakryiko 1543919d2b1dSAndrii Nakryiko /* invalidate raw_data representation */ 15443289959bSAndrii Nakryiko btf_invalidate_raw_data(btf); 1545919d2b1dSAndrii Nakryiko 1546919d2b1dSAndrii Nakryiko return 0; 1547919d2b1dSAndrii Nakryiko 1548919d2b1dSAndrii Nakryiko err_out: 154990d76d3eSAndrii Nakryiko strset__free(set); 1550919d2b1dSAndrii Nakryiko free(hdr); 1551919d2b1dSAndrii Nakryiko free(types); 155290d76d3eSAndrii Nakryiko return err; 1553919d2b1dSAndrii Nakryiko } 1554919d2b1dSAndrii Nakryiko 1555919d2b1dSAndrii Nakryiko /* Find an offset in BTF string section that corresponds to a given string *s*. 1556919d2b1dSAndrii Nakryiko * Returns: 1557919d2b1dSAndrii Nakryiko * - >0 offset into string section, if string is found; 1558919d2b1dSAndrii Nakryiko * - -ENOENT, if string is not in the string section; 1559919d2b1dSAndrii Nakryiko * - <0, on any other error. 1560919d2b1dSAndrii Nakryiko */ 1561919d2b1dSAndrii Nakryiko int btf__find_str(struct btf *btf, const char *s) 1562919d2b1dSAndrii Nakryiko { 156390d76d3eSAndrii Nakryiko int off; 1564919d2b1dSAndrii Nakryiko 1565ba451366SAndrii Nakryiko if (btf->base_btf) { 156690d76d3eSAndrii Nakryiko off = btf__find_str(btf->base_btf, s); 156790d76d3eSAndrii Nakryiko if (off != -ENOENT) 156890d76d3eSAndrii Nakryiko return off; 1569ba451366SAndrii Nakryiko } 1570ba451366SAndrii Nakryiko 1571919d2b1dSAndrii Nakryiko /* BTF needs to be in a modifiable state to build string lookup index */ 1572919d2b1dSAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1573e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 1574919d2b1dSAndrii Nakryiko 157590d76d3eSAndrii Nakryiko off = strset__find_str(btf->strs_set, s); 157690d76d3eSAndrii Nakryiko if (off < 0) 1577e9fc3ce9SAndrii Nakryiko return libbpf_err(off); 1578919d2b1dSAndrii Nakryiko 157990d76d3eSAndrii Nakryiko return btf->start_str_off + off; 1580919d2b1dSAndrii Nakryiko } 1581919d2b1dSAndrii Nakryiko 1582919d2b1dSAndrii Nakryiko /* Add a string s to the BTF string section. 1583919d2b1dSAndrii Nakryiko * Returns: 1584919d2b1dSAndrii Nakryiko * - > 0 offset into string section, on success; 1585919d2b1dSAndrii Nakryiko * - < 0, on error. 1586919d2b1dSAndrii Nakryiko */ 1587919d2b1dSAndrii Nakryiko int btf__add_str(struct btf *btf, const char *s) 1588919d2b1dSAndrii Nakryiko { 158990d76d3eSAndrii Nakryiko int off; 1590919d2b1dSAndrii Nakryiko 1591ba451366SAndrii Nakryiko if (btf->base_btf) { 159290d76d3eSAndrii Nakryiko off = btf__find_str(btf->base_btf, s); 159390d76d3eSAndrii Nakryiko if (off != -ENOENT) 159490d76d3eSAndrii Nakryiko return off; 1595ba451366SAndrii Nakryiko } 1596ba451366SAndrii Nakryiko 1597919d2b1dSAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1598e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 1599919d2b1dSAndrii Nakryiko 160090d76d3eSAndrii Nakryiko off = strset__add_str(btf->strs_set, s); 160190d76d3eSAndrii Nakryiko if (off < 0) 1602e9fc3ce9SAndrii Nakryiko return libbpf_err(off); 1603919d2b1dSAndrii Nakryiko 160490d76d3eSAndrii Nakryiko btf->hdr->str_len = strset__data_size(btf->strs_set); 1605919d2b1dSAndrii Nakryiko 160690d76d3eSAndrii Nakryiko return btf->start_str_off + off; 1607919d2b1dSAndrii Nakryiko } 1608919d2b1dSAndrii Nakryiko 16094a3b33f8SAndrii Nakryiko static void *btf_add_type_mem(struct btf *btf, size_t add_sz) 16104a3b33f8SAndrii Nakryiko { 16113b029e06SAndrii Nakryiko return libbpf_add_mem(&btf->types_data, &btf->types_data_cap, 1, 16124a3b33f8SAndrii Nakryiko btf->hdr->type_len, UINT_MAX, add_sz); 16134a3b33f8SAndrii Nakryiko } 16144a3b33f8SAndrii Nakryiko 16154a3b33f8SAndrii Nakryiko static void btf_type_inc_vlen(struct btf_type *t) 16164a3b33f8SAndrii Nakryiko { 16174a3b33f8SAndrii Nakryiko t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t)); 16184a3b33f8SAndrii Nakryiko } 16194a3b33f8SAndrii Nakryiko 1620c81ed6d8SAndrii Nakryiko static int btf_commit_type(struct btf *btf, int data_sz) 1621c81ed6d8SAndrii Nakryiko { 1622c81ed6d8SAndrii Nakryiko int err; 1623c81ed6d8SAndrii Nakryiko 1624c81ed6d8SAndrii Nakryiko err = btf_add_type_idx_entry(btf, btf->hdr->type_len); 1625c81ed6d8SAndrii Nakryiko if (err) 1626e9fc3ce9SAndrii Nakryiko return libbpf_err(err); 1627c81ed6d8SAndrii Nakryiko 1628c81ed6d8SAndrii Nakryiko btf->hdr->type_len += data_sz; 1629c81ed6d8SAndrii Nakryiko btf->hdr->str_off += data_sz; 1630c81ed6d8SAndrii Nakryiko btf->nr_types++; 1631ba451366SAndrii Nakryiko return btf->start_id + btf->nr_types - 1; 1632c81ed6d8SAndrii Nakryiko } 1633c81ed6d8SAndrii Nakryiko 16349af44bc5SAndrii Nakryiko struct btf_pipe { 16359af44bc5SAndrii Nakryiko const struct btf *src; 16369af44bc5SAndrii Nakryiko struct btf *dst; 1637d81283d2SKui-Feng Lee struct hashmap *str_off_map; /* map string offsets from src to dst */ 16389af44bc5SAndrii Nakryiko }; 16399af44bc5SAndrii Nakryiko 16409af44bc5SAndrii Nakryiko static int btf_rewrite_str(__u32 *str_off, void *ctx) 16419af44bc5SAndrii Nakryiko { 16429af44bc5SAndrii Nakryiko struct btf_pipe *p = ctx; 1643d81283d2SKui-Feng Lee void *mapped_off; 1644d81283d2SKui-Feng Lee int off, err; 16459af44bc5SAndrii Nakryiko 16469af44bc5SAndrii Nakryiko if (!*str_off) /* nothing to do for empty strings */ 16479af44bc5SAndrii Nakryiko return 0; 16489af44bc5SAndrii Nakryiko 1649d81283d2SKui-Feng Lee if (p->str_off_map && 1650d81283d2SKui-Feng Lee hashmap__find(p->str_off_map, (void *)(long)*str_off, &mapped_off)) { 1651d81283d2SKui-Feng Lee *str_off = (__u32)(long)mapped_off; 1652d81283d2SKui-Feng Lee return 0; 1653d81283d2SKui-Feng Lee } 1654d81283d2SKui-Feng Lee 16559af44bc5SAndrii Nakryiko off = btf__add_str(p->dst, btf__str_by_offset(p->src, *str_off)); 16569af44bc5SAndrii Nakryiko if (off < 0) 16579af44bc5SAndrii Nakryiko return off; 16589af44bc5SAndrii Nakryiko 1659d81283d2SKui-Feng Lee /* Remember string mapping from src to dst. It avoids 1660d81283d2SKui-Feng Lee * performing expensive string comparisons. 1661d81283d2SKui-Feng Lee */ 1662d81283d2SKui-Feng Lee if (p->str_off_map) { 1663d81283d2SKui-Feng Lee err = hashmap__append(p->str_off_map, (void *)(long)*str_off, (void *)(long)off); 1664d81283d2SKui-Feng Lee if (err) 1665d81283d2SKui-Feng Lee return err; 1666d81283d2SKui-Feng Lee } 1667d81283d2SKui-Feng Lee 16689af44bc5SAndrii Nakryiko *str_off = off; 16699af44bc5SAndrii Nakryiko return 0; 16709af44bc5SAndrii Nakryiko } 16719af44bc5SAndrii Nakryiko 16729af44bc5SAndrii Nakryiko int btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type) 16739af44bc5SAndrii Nakryiko { 16749af44bc5SAndrii Nakryiko struct btf_pipe p = { .src = src_btf, .dst = btf }; 16759af44bc5SAndrii Nakryiko struct btf_type *t; 16769af44bc5SAndrii Nakryiko int sz, err; 16779af44bc5SAndrii Nakryiko 16789af44bc5SAndrii Nakryiko sz = btf_type_size(src_type); 16799af44bc5SAndrii Nakryiko if (sz < 0) 1680e9fc3ce9SAndrii Nakryiko return libbpf_err(sz); 16819af44bc5SAndrii Nakryiko 16829af44bc5SAndrii Nakryiko /* deconstruct BTF, if necessary, and invalidate raw_data */ 16839af44bc5SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1684e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 16859af44bc5SAndrii Nakryiko 16869af44bc5SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 16879af44bc5SAndrii Nakryiko if (!t) 1688e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 16899af44bc5SAndrii Nakryiko 16909af44bc5SAndrii Nakryiko memcpy(t, src_type, sz); 16919af44bc5SAndrii Nakryiko 16929af44bc5SAndrii Nakryiko err = btf_type_visit_str_offs(t, btf_rewrite_str, &p); 16939af44bc5SAndrii Nakryiko if (err) 1694e9fc3ce9SAndrii Nakryiko return libbpf_err(err); 16959af44bc5SAndrii Nakryiko 16969af44bc5SAndrii Nakryiko return btf_commit_type(btf, sz); 16979af44bc5SAndrii Nakryiko } 16989af44bc5SAndrii Nakryiko 16997ca61121SAndrii Nakryiko static int btf_rewrite_type_ids(__u32 *type_id, void *ctx) 17007ca61121SAndrii Nakryiko { 17017ca61121SAndrii Nakryiko struct btf *btf = ctx; 17027ca61121SAndrii Nakryiko 17037ca61121SAndrii Nakryiko if (!*type_id) /* nothing to do for VOID references */ 17047ca61121SAndrii Nakryiko return 0; 17057ca61121SAndrii Nakryiko 17067ca61121SAndrii Nakryiko /* we haven't updated btf's type count yet, so 17077ca61121SAndrii Nakryiko * btf->start_id + btf->nr_types - 1 is the type ID offset we should 17087ca61121SAndrii Nakryiko * add to all newly added BTF types 17097ca61121SAndrii Nakryiko */ 17107ca61121SAndrii Nakryiko *type_id += btf->start_id + btf->nr_types - 1; 17117ca61121SAndrii Nakryiko return 0; 17127ca61121SAndrii Nakryiko } 17137ca61121SAndrii Nakryiko 1714d81283d2SKui-Feng Lee static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx); 1715d81283d2SKui-Feng Lee static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx); 1716d81283d2SKui-Feng Lee 17177ca61121SAndrii Nakryiko int btf__add_btf(struct btf *btf, const struct btf *src_btf) 17187ca61121SAndrii Nakryiko { 17197ca61121SAndrii Nakryiko struct btf_pipe p = { .src = src_btf, .dst = btf }; 17207ca61121SAndrii Nakryiko int data_sz, sz, cnt, i, err, old_strs_len; 17217ca61121SAndrii Nakryiko __u32 *off; 17227ca61121SAndrii Nakryiko void *t; 17237ca61121SAndrii Nakryiko 17247ca61121SAndrii Nakryiko /* appending split BTF isn't supported yet */ 17257ca61121SAndrii Nakryiko if (src_btf->base_btf) 17267ca61121SAndrii Nakryiko return libbpf_err(-ENOTSUP); 17277ca61121SAndrii Nakryiko 17287ca61121SAndrii Nakryiko /* deconstruct BTF, if necessary, and invalidate raw_data */ 17297ca61121SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 17307ca61121SAndrii Nakryiko return libbpf_err(-ENOMEM); 17317ca61121SAndrii Nakryiko 17327ca61121SAndrii Nakryiko /* remember original strings section size if we have to roll back 17337ca61121SAndrii Nakryiko * partial strings section changes 17347ca61121SAndrii Nakryiko */ 17357ca61121SAndrii Nakryiko old_strs_len = btf->hdr->str_len; 17367ca61121SAndrii Nakryiko 17377ca61121SAndrii Nakryiko data_sz = src_btf->hdr->type_len; 17386a886de0SHengqi Chen cnt = btf__type_cnt(src_btf) - 1; 17397ca61121SAndrii Nakryiko 17407ca61121SAndrii Nakryiko /* pre-allocate enough memory for new types */ 17417ca61121SAndrii Nakryiko t = btf_add_type_mem(btf, data_sz); 17427ca61121SAndrii Nakryiko if (!t) 17437ca61121SAndrii Nakryiko return libbpf_err(-ENOMEM); 17447ca61121SAndrii Nakryiko 17457ca61121SAndrii Nakryiko /* pre-allocate enough memory for type offset index for new types */ 17467ca61121SAndrii Nakryiko off = btf_add_type_offs_mem(btf, cnt); 17477ca61121SAndrii Nakryiko if (!off) 17487ca61121SAndrii Nakryiko return libbpf_err(-ENOMEM); 17497ca61121SAndrii Nakryiko 1750d81283d2SKui-Feng Lee /* Map the string offsets from src_btf to the offsets from btf to improve performance */ 1751d81283d2SKui-Feng Lee p.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL); 1752d81283d2SKui-Feng Lee if (IS_ERR(p.str_off_map)) 1753d81283d2SKui-Feng Lee return libbpf_err(-ENOMEM); 1754d81283d2SKui-Feng Lee 17557ca61121SAndrii Nakryiko /* bulk copy types data for all types from src_btf */ 17567ca61121SAndrii Nakryiko memcpy(t, src_btf->types_data, data_sz); 17577ca61121SAndrii Nakryiko 17587ca61121SAndrii Nakryiko for (i = 0; i < cnt; i++) { 17597ca61121SAndrii Nakryiko sz = btf_type_size(t); 17607ca61121SAndrii Nakryiko if (sz < 0) { 17617ca61121SAndrii Nakryiko /* unlikely, has to be corrupted src_btf */ 17627ca61121SAndrii Nakryiko err = sz; 17637ca61121SAndrii Nakryiko goto err_out; 17647ca61121SAndrii Nakryiko } 17657ca61121SAndrii Nakryiko 17667ca61121SAndrii Nakryiko /* fill out type ID to type offset mapping for lookups by type ID */ 17677ca61121SAndrii Nakryiko *off = t - btf->types_data; 17687ca61121SAndrii Nakryiko 17697ca61121SAndrii Nakryiko /* add, dedup, and remap strings referenced by this BTF type */ 17707ca61121SAndrii Nakryiko err = btf_type_visit_str_offs(t, btf_rewrite_str, &p); 17717ca61121SAndrii Nakryiko if (err) 17727ca61121SAndrii Nakryiko goto err_out; 17737ca61121SAndrii Nakryiko 17747ca61121SAndrii Nakryiko /* remap all type IDs referenced from this BTF type */ 17757ca61121SAndrii Nakryiko err = btf_type_visit_type_ids(t, btf_rewrite_type_ids, btf); 17767ca61121SAndrii Nakryiko if (err) 17777ca61121SAndrii Nakryiko goto err_out; 17787ca61121SAndrii Nakryiko 17797ca61121SAndrii Nakryiko /* go to next type data and type offset index entry */ 17807ca61121SAndrii Nakryiko t += sz; 17817ca61121SAndrii Nakryiko off++; 17827ca61121SAndrii Nakryiko } 17837ca61121SAndrii Nakryiko 17847ca61121SAndrii Nakryiko /* Up until now any of the copied type data was effectively invisible, 17857ca61121SAndrii Nakryiko * so if we exited early before this point due to error, BTF would be 17867ca61121SAndrii Nakryiko * effectively unmodified. There would be extra internal memory 17877ca61121SAndrii Nakryiko * pre-allocated, but it would not be available for querying. But now 17887ca61121SAndrii Nakryiko * that we've copied and rewritten all the data successfully, we can 17897ca61121SAndrii Nakryiko * update type count and various internal offsets and sizes to 17907ca61121SAndrii Nakryiko * "commit" the changes and made them visible to the outside world. 17917ca61121SAndrii Nakryiko */ 17927ca61121SAndrii Nakryiko btf->hdr->type_len += data_sz; 17937ca61121SAndrii Nakryiko btf->hdr->str_off += data_sz; 17947ca61121SAndrii Nakryiko btf->nr_types += cnt; 17957ca61121SAndrii Nakryiko 1796d81283d2SKui-Feng Lee hashmap__free(p.str_off_map); 1797d81283d2SKui-Feng Lee 17987ca61121SAndrii Nakryiko /* return type ID of the first added BTF type */ 17997ca61121SAndrii Nakryiko return btf->start_id + btf->nr_types - cnt; 18007ca61121SAndrii Nakryiko err_out: 18017ca61121SAndrii Nakryiko /* zero out preallocated memory as if it was just allocated with 18027ca61121SAndrii Nakryiko * libbpf_add_mem() 18037ca61121SAndrii Nakryiko */ 18047ca61121SAndrii Nakryiko memset(btf->types_data + btf->hdr->type_len, 0, data_sz); 18057ca61121SAndrii Nakryiko memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len); 18067ca61121SAndrii Nakryiko 18077ca61121SAndrii Nakryiko /* and now restore original strings section size; types data size 18087ca61121SAndrii Nakryiko * wasn't modified, so doesn't need restoring, see big comment above */ 18097ca61121SAndrii Nakryiko btf->hdr->str_len = old_strs_len; 18107ca61121SAndrii Nakryiko 1811d81283d2SKui-Feng Lee hashmap__free(p.str_off_map); 1812d81283d2SKui-Feng Lee 18137ca61121SAndrii Nakryiko return libbpf_err(err); 18147ca61121SAndrii Nakryiko } 18157ca61121SAndrii Nakryiko 18164a3b33f8SAndrii Nakryiko /* 18174a3b33f8SAndrii Nakryiko * Append new BTF_KIND_INT type with: 18184a3b33f8SAndrii Nakryiko * - *name* - non-empty, non-NULL type name; 18194a3b33f8SAndrii Nakryiko * - *sz* - power-of-2 (1, 2, 4, ..) size of the type, in bytes; 18204a3b33f8SAndrii Nakryiko * - encoding is a combination of BTF_INT_SIGNED, BTF_INT_CHAR, BTF_INT_BOOL. 18214a3b33f8SAndrii Nakryiko * Returns: 18224a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 18234a3b33f8SAndrii Nakryiko * - <0, on error. 18244a3b33f8SAndrii Nakryiko */ 18254a3b33f8SAndrii Nakryiko int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding) 18264a3b33f8SAndrii Nakryiko { 18274a3b33f8SAndrii Nakryiko struct btf_type *t; 1828c81ed6d8SAndrii Nakryiko int sz, name_off; 18294a3b33f8SAndrii Nakryiko 18304a3b33f8SAndrii Nakryiko /* non-empty name */ 18314a3b33f8SAndrii Nakryiko if (!name || !name[0]) 1832e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 18334a3b33f8SAndrii Nakryiko /* byte_sz must be power of 2 */ 18344a3b33f8SAndrii Nakryiko if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 16) 1835e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 18364a3b33f8SAndrii Nakryiko if (encoding & ~(BTF_INT_SIGNED | BTF_INT_CHAR | BTF_INT_BOOL)) 1837e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 18384a3b33f8SAndrii Nakryiko 18394a3b33f8SAndrii Nakryiko /* deconstruct BTF, if necessary, and invalidate raw_data */ 18404a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1841e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 18424a3b33f8SAndrii Nakryiko 18434a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type) + sizeof(int); 18444a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 18454a3b33f8SAndrii Nakryiko if (!t) 1846e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 18474a3b33f8SAndrii Nakryiko 18484a3b33f8SAndrii Nakryiko /* if something goes wrong later, we might end up with an extra string, 18494a3b33f8SAndrii Nakryiko * but that shouldn't be a problem, because BTF can't be constructed 18504a3b33f8SAndrii Nakryiko * completely anyway and will most probably be just discarded 18514a3b33f8SAndrii Nakryiko */ 18524a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 18534a3b33f8SAndrii Nakryiko if (name_off < 0) 18544a3b33f8SAndrii Nakryiko return name_off; 18554a3b33f8SAndrii Nakryiko 18564a3b33f8SAndrii Nakryiko t->name_off = name_off; 18574a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_INT, 0, 0); 18584a3b33f8SAndrii Nakryiko t->size = byte_sz; 18594a3b33f8SAndrii Nakryiko /* set INT info, we don't allow setting legacy bit offset/size */ 18604a3b33f8SAndrii Nakryiko *(__u32 *)(t + 1) = (encoding << 24) | (byte_sz * 8); 18614a3b33f8SAndrii Nakryiko 1862c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 18634a3b33f8SAndrii Nakryiko } 18644a3b33f8SAndrii Nakryiko 186522541a9eSIlya Leoshkevich /* 186622541a9eSIlya Leoshkevich * Append new BTF_KIND_FLOAT type with: 186722541a9eSIlya Leoshkevich * - *name* - non-empty, non-NULL type name; 186822541a9eSIlya Leoshkevich * - *sz* - size of the type, in bytes; 186922541a9eSIlya Leoshkevich * Returns: 187022541a9eSIlya Leoshkevich * - >0, type ID of newly added BTF type; 187122541a9eSIlya Leoshkevich * - <0, on error. 187222541a9eSIlya Leoshkevich */ 187322541a9eSIlya Leoshkevich int btf__add_float(struct btf *btf, const char *name, size_t byte_sz) 187422541a9eSIlya Leoshkevich { 187522541a9eSIlya Leoshkevich struct btf_type *t; 187622541a9eSIlya Leoshkevich int sz, name_off; 187722541a9eSIlya Leoshkevich 187822541a9eSIlya Leoshkevich /* non-empty name */ 187922541a9eSIlya Leoshkevich if (!name || !name[0]) 1880e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 188122541a9eSIlya Leoshkevich 188222541a9eSIlya Leoshkevich /* byte_sz must be one of the explicitly allowed values */ 188322541a9eSIlya Leoshkevich if (byte_sz != 2 && byte_sz != 4 && byte_sz != 8 && byte_sz != 12 && 188422541a9eSIlya Leoshkevich byte_sz != 16) 1885e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 188622541a9eSIlya Leoshkevich 188722541a9eSIlya Leoshkevich if (btf_ensure_modifiable(btf)) 1888e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 188922541a9eSIlya Leoshkevich 189022541a9eSIlya Leoshkevich sz = sizeof(struct btf_type); 189122541a9eSIlya Leoshkevich t = btf_add_type_mem(btf, sz); 189222541a9eSIlya Leoshkevich if (!t) 1893e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 189422541a9eSIlya Leoshkevich 189522541a9eSIlya Leoshkevich name_off = btf__add_str(btf, name); 189622541a9eSIlya Leoshkevich if (name_off < 0) 189722541a9eSIlya Leoshkevich return name_off; 189822541a9eSIlya Leoshkevich 189922541a9eSIlya Leoshkevich t->name_off = name_off; 190022541a9eSIlya Leoshkevich t->info = btf_type_info(BTF_KIND_FLOAT, 0, 0); 190122541a9eSIlya Leoshkevich t->size = byte_sz; 190222541a9eSIlya Leoshkevich 190322541a9eSIlya Leoshkevich return btf_commit_type(btf, sz); 190422541a9eSIlya Leoshkevich } 190522541a9eSIlya Leoshkevich 19064a3b33f8SAndrii Nakryiko /* it's completely legal to append BTF types with type IDs pointing forward to 19074a3b33f8SAndrii Nakryiko * types that haven't been appended yet, so we only make sure that id looks 19084a3b33f8SAndrii Nakryiko * sane, we can't guarantee that ID will always be valid 19094a3b33f8SAndrii Nakryiko */ 19104a3b33f8SAndrii Nakryiko static int validate_type_id(int id) 19114a3b33f8SAndrii Nakryiko { 19124a3b33f8SAndrii Nakryiko if (id < 0 || id > BTF_MAX_NR_TYPES) 19134a3b33f8SAndrii Nakryiko return -EINVAL; 19144a3b33f8SAndrii Nakryiko return 0; 19154a3b33f8SAndrii Nakryiko } 19164a3b33f8SAndrii Nakryiko 19174a3b33f8SAndrii Nakryiko /* generic append function for PTR, TYPEDEF, CONST/VOLATILE/RESTRICT */ 19184a3b33f8SAndrii Nakryiko static int btf_add_ref_kind(struct btf *btf, int kind, const char *name, int ref_type_id) 19194a3b33f8SAndrii Nakryiko { 19204a3b33f8SAndrii Nakryiko struct btf_type *t; 1921c81ed6d8SAndrii Nakryiko int sz, name_off = 0; 19224a3b33f8SAndrii Nakryiko 19234a3b33f8SAndrii Nakryiko if (validate_type_id(ref_type_id)) 1924e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 19254a3b33f8SAndrii Nakryiko 19264a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1927e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 19284a3b33f8SAndrii Nakryiko 19294a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type); 19304a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 19314a3b33f8SAndrii Nakryiko if (!t) 1932e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 19334a3b33f8SAndrii Nakryiko 19344a3b33f8SAndrii Nakryiko if (name && name[0]) { 19354a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 19364a3b33f8SAndrii Nakryiko if (name_off < 0) 19374a3b33f8SAndrii Nakryiko return name_off; 19384a3b33f8SAndrii Nakryiko } 19394a3b33f8SAndrii Nakryiko 19404a3b33f8SAndrii Nakryiko t->name_off = name_off; 19414a3b33f8SAndrii Nakryiko t->info = btf_type_info(kind, 0, 0); 19424a3b33f8SAndrii Nakryiko t->type = ref_type_id; 19434a3b33f8SAndrii Nakryiko 1944c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 19454a3b33f8SAndrii Nakryiko } 19464a3b33f8SAndrii Nakryiko 19474a3b33f8SAndrii Nakryiko /* 19484a3b33f8SAndrii Nakryiko * Append new BTF_KIND_PTR type with: 19494a3b33f8SAndrii Nakryiko * - *ref_type_id* - referenced type ID, it might not exist yet; 19504a3b33f8SAndrii Nakryiko * Returns: 19514a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 19524a3b33f8SAndrii Nakryiko * - <0, on error. 19534a3b33f8SAndrii Nakryiko */ 19544a3b33f8SAndrii Nakryiko int btf__add_ptr(struct btf *btf, int ref_type_id) 19554a3b33f8SAndrii Nakryiko { 19564a3b33f8SAndrii Nakryiko return btf_add_ref_kind(btf, BTF_KIND_PTR, NULL, ref_type_id); 19574a3b33f8SAndrii Nakryiko } 19584a3b33f8SAndrii Nakryiko 19594a3b33f8SAndrii Nakryiko /* 19604a3b33f8SAndrii Nakryiko * Append new BTF_KIND_ARRAY type with: 19614a3b33f8SAndrii Nakryiko * - *index_type_id* - type ID of the type describing array index; 19624a3b33f8SAndrii Nakryiko * - *elem_type_id* - type ID of the type describing array element; 19634a3b33f8SAndrii Nakryiko * - *nr_elems* - the size of the array; 19644a3b33f8SAndrii Nakryiko * Returns: 19654a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 19664a3b33f8SAndrii Nakryiko * - <0, on error. 19674a3b33f8SAndrii Nakryiko */ 19684a3b33f8SAndrii Nakryiko int btf__add_array(struct btf *btf, int index_type_id, int elem_type_id, __u32 nr_elems) 19694a3b33f8SAndrii Nakryiko { 19704a3b33f8SAndrii Nakryiko struct btf_type *t; 19714a3b33f8SAndrii Nakryiko struct btf_array *a; 1972c81ed6d8SAndrii Nakryiko int sz; 19734a3b33f8SAndrii Nakryiko 19744a3b33f8SAndrii Nakryiko if (validate_type_id(index_type_id) || validate_type_id(elem_type_id)) 1975e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 19764a3b33f8SAndrii Nakryiko 19774a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 1978e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 19794a3b33f8SAndrii Nakryiko 19804a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type) + sizeof(struct btf_array); 19814a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 19824a3b33f8SAndrii Nakryiko if (!t) 1983e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 19844a3b33f8SAndrii Nakryiko 19854a3b33f8SAndrii Nakryiko t->name_off = 0; 19864a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_ARRAY, 0, 0); 19874a3b33f8SAndrii Nakryiko t->size = 0; 19884a3b33f8SAndrii Nakryiko 19894a3b33f8SAndrii Nakryiko a = btf_array(t); 19904a3b33f8SAndrii Nakryiko a->type = elem_type_id; 19914a3b33f8SAndrii Nakryiko a->index_type = index_type_id; 19924a3b33f8SAndrii Nakryiko a->nelems = nr_elems; 19934a3b33f8SAndrii Nakryiko 1994c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 19954a3b33f8SAndrii Nakryiko } 19964a3b33f8SAndrii Nakryiko 19974a3b33f8SAndrii Nakryiko /* generic STRUCT/UNION append function */ 19984a3b33f8SAndrii Nakryiko static int btf_add_composite(struct btf *btf, int kind, const char *name, __u32 bytes_sz) 19994a3b33f8SAndrii Nakryiko { 20004a3b33f8SAndrii Nakryiko struct btf_type *t; 2001c81ed6d8SAndrii Nakryiko int sz, name_off = 0; 20024a3b33f8SAndrii Nakryiko 20034a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2004e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 20054a3b33f8SAndrii Nakryiko 20064a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type); 20074a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 20084a3b33f8SAndrii Nakryiko if (!t) 2009e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 20104a3b33f8SAndrii Nakryiko 20114a3b33f8SAndrii Nakryiko if (name && name[0]) { 20124a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 20134a3b33f8SAndrii Nakryiko if (name_off < 0) 20144a3b33f8SAndrii Nakryiko return name_off; 20154a3b33f8SAndrii Nakryiko } 20164a3b33f8SAndrii Nakryiko 20174a3b33f8SAndrii Nakryiko /* start out with vlen=0 and no kflag; this will be adjusted when 20184a3b33f8SAndrii Nakryiko * adding each member 20194a3b33f8SAndrii Nakryiko */ 20204a3b33f8SAndrii Nakryiko t->name_off = name_off; 20214a3b33f8SAndrii Nakryiko t->info = btf_type_info(kind, 0, 0); 20224a3b33f8SAndrii Nakryiko t->size = bytes_sz; 20234a3b33f8SAndrii Nakryiko 2024c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 20254a3b33f8SAndrii Nakryiko } 20264a3b33f8SAndrii Nakryiko 20274a3b33f8SAndrii Nakryiko /* 20284a3b33f8SAndrii Nakryiko * Append new BTF_KIND_STRUCT type with: 20294a3b33f8SAndrii Nakryiko * - *name* - name of the struct, can be NULL or empty for anonymous structs; 20304a3b33f8SAndrii Nakryiko * - *byte_sz* - size of the struct, in bytes; 20314a3b33f8SAndrii Nakryiko * 20324a3b33f8SAndrii Nakryiko * Struct initially has no fields in it. Fields can be added by 20334a3b33f8SAndrii Nakryiko * btf__add_field() right after btf__add_struct() succeeds. 20344a3b33f8SAndrii Nakryiko * 20354a3b33f8SAndrii Nakryiko * Returns: 20364a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 20374a3b33f8SAndrii Nakryiko * - <0, on error. 20384a3b33f8SAndrii Nakryiko */ 20394a3b33f8SAndrii Nakryiko int btf__add_struct(struct btf *btf, const char *name, __u32 byte_sz) 20404a3b33f8SAndrii Nakryiko { 20414a3b33f8SAndrii Nakryiko return btf_add_composite(btf, BTF_KIND_STRUCT, name, byte_sz); 20424a3b33f8SAndrii Nakryiko } 20434a3b33f8SAndrii Nakryiko 20444a3b33f8SAndrii Nakryiko /* 20454a3b33f8SAndrii Nakryiko * Append new BTF_KIND_UNION type with: 20464a3b33f8SAndrii Nakryiko * - *name* - name of the union, can be NULL or empty for anonymous union; 20474a3b33f8SAndrii Nakryiko * - *byte_sz* - size of the union, in bytes; 20484a3b33f8SAndrii Nakryiko * 20494a3b33f8SAndrii Nakryiko * Union initially has no fields in it. Fields can be added by 20504a3b33f8SAndrii Nakryiko * btf__add_field() right after btf__add_union() succeeds. All fields 20514a3b33f8SAndrii Nakryiko * should have *bit_offset* of 0. 20524a3b33f8SAndrii Nakryiko * 20534a3b33f8SAndrii Nakryiko * Returns: 20544a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 20554a3b33f8SAndrii Nakryiko * - <0, on error. 20564a3b33f8SAndrii Nakryiko */ 20574a3b33f8SAndrii Nakryiko int btf__add_union(struct btf *btf, const char *name, __u32 byte_sz) 20584a3b33f8SAndrii Nakryiko { 20594a3b33f8SAndrii Nakryiko return btf_add_composite(btf, BTF_KIND_UNION, name, byte_sz); 20604a3b33f8SAndrii Nakryiko } 20614a3b33f8SAndrii Nakryiko 2062c81ed6d8SAndrii Nakryiko static struct btf_type *btf_last_type(struct btf *btf) 2063c81ed6d8SAndrii Nakryiko { 20646a886de0SHengqi Chen return btf_type_by_id(btf, btf__type_cnt(btf) - 1); 2065c81ed6d8SAndrii Nakryiko } 2066c81ed6d8SAndrii Nakryiko 20674a3b33f8SAndrii Nakryiko /* 20684a3b33f8SAndrii Nakryiko * Append new field for the current STRUCT/UNION type with: 20694a3b33f8SAndrii Nakryiko * - *name* - name of the field, can be NULL or empty for anonymous field; 20704a3b33f8SAndrii Nakryiko * - *type_id* - type ID for the type describing field type; 20714a3b33f8SAndrii Nakryiko * - *bit_offset* - bit offset of the start of the field within struct/union; 20724a3b33f8SAndrii Nakryiko * - *bit_size* - bit size of a bitfield, 0 for non-bitfield fields; 20734a3b33f8SAndrii Nakryiko * Returns: 20744a3b33f8SAndrii Nakryiko * - 0, on success; 20754a3b33f8SAndrii Nakryiko * - <0, on error. 20764a3b33f8SAndrii Nakryiko */ 20774a3b33f8SAndrii Nakryiko int btf__add_field(struct btf *btf, const char *name, int type_id, 20784a3b33f8SAndrii Nakryiko __u32 bit_offset, __u32 bit_size) 20794a3b33f8SAndrii Nakryiko { 20804a3b33f8SAndrii Nakryiko struct btf_type *t; 20814a3b33f8SAndrii Nakryiko struct btf_member *m; 20824a3b33f8SAndrii Nakryiko bool is_bitfield; 20834a3b33f8SAndrii Nakryiko int sz, name_off = 0; 20844a3b33f8SAndrii Nakryiko 20854a3b33f8SAndrii Nakryiko /* last type should be union/struct */ 20864a3b33f8SAndrii Nakryiko if (btf->nr_types == 0) 2087e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 2088c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 20894a3b33f8SAndrii Nakryiko if (!btf_is_composite(t)) 2090e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 20914a3b33f8SAndrii Nakryiko 20924a3b33f8SAndrii Nakryiko if (validate_type_id(type_id)) 2093e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 20944a3b33f8SAndrii Nakryiko /* best-effort bit field offset/size enforcement */ 20954a3b33f8SAndrii Nakryiko is_bitfield = bit_size || (bit_offset % 8 != 0); 20964a3b33f8SAndrii Nakryiko if (is_bitfield && (bit_size == 0 || bit_size > 255 || bit_offset > 0xffffff)) 2097e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 20984a3b33f8SAndrii Nakryiko 20994a3b33f8SAndrii Nakryiko /* only offset 0 is allowed for unions */ 21004a3b33f8SAndrii Nakryiko if (btf_is_union(t) && bit_offset) 2101e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 21024a3b33f8SAndrii Nakryiko 21034a3b33f8SAndrii Nakryiko /* decompose and invalidate raw data */ 21044a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2105e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 21064a3b33f8SAndrii Nakryiko 21074a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_member); 21084a3b33f8SAndrii Nakryiko m = btf_add_type_mem(btf, sz); 21094a3b33f8SAndrii Nakryiko if (!m) 2110e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 21114a3b33f8SAndrii Nakryiko 21124a3b33f8SAndrii Nakryiko if (name && name[0]) { 21134a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 21144a3b33f8SAndrii Nakryiko if (name_off < 0) 21154a3b33f8SAndrii Nakryiko return name_off; 21164a3b33f8SAndrii Nakryiko } 21174a3b33f8SAndrii Nakryiko 21184a3b33f8SAndrii Nakryiko m->name_off = name_off; 21194a3b33f8SAndrii Nakryiko m->type = type_id; 21204a3b33f8SAndrii Nakryiko m->offset = bit_offset | (bit_size << 24); 21214a3b33f8SAndrii Nakryiko 21224a3b33f8SAndrii Nakryiko /* btf_add_type_mem can invalidate t pointer */ 2123c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 21244a3b33f8SAndrii Nakryiko /* update parent type's vlen and kflag */ 21254a3b33f8SAndrii Nakryiko t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t)); 21264a3b33f8SAndrii Nakryiko 21274a3b33f8SAndrii Nakryiko btf->hdr->type_len += sz; 21284a3b33f8SAndrii Nakryiko btf->hdr->str_off += sz; 21294a3b33f8SAndrii Nakryiko return 0; 21304a3b33f8SAndrii Nakryiko } 21314a3b33f8SAndrii Nakryiko 21324a3b33f8SAndrii Nakryiko /* 21334a3b33f8SAndrii Nakryiko * Append new BTF_KIND_ENUM type with: 21344a3b33f8SAndrii Nakryiko * - *name* - name of the enum, can be NULL or empty for anonymous enums; 21354a3b33f8SAndrii Nakryiko * - *byte_sz* - size of the enum, in bytes. 21364a3b33f8SAndrii Nakryiko * 21374a3b33f8SAndrii Nakryiko * Enum initially has no enum values in it (and corresponds to enum forward 21384a3b33f8SAndrii Nakryiko * declaration). Enumerator values can be added by btf__add_enum_value() 21394a3b33f8SAndrii Nakryiko * immediately after btf__add_enum() succeeds. 21404a3b33f8SAndrii Nakryiko * 21414a3b33f8SAndrii Nakryiko * Returns: 21424a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 21434a3b33f8SAndrii Nakryiko * - <0, on error. 21444a3b33f8SAndrii Nakryiko */ 21454a3b33f8SAndrii Nakryiko int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz) 21464a3b33f8SAndrii Nakryiko { 21474a3b33f8SAndrii Nakryiko struct btf_type *t; 2148c81ed6d8SAndrii Nakryiko int sz, name_off = 0; 21494a3b33f8SAndrii Nakryiko 21504a3b33f8SAndrii Nakryiko /* byte_sz must be power of 2 */ 21514a3b33f8SAndrii Nakryiko if (!byte_sz || (byte_sz & (byte_sz - 1)) || byte_sz > 8) 2152e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 21534a3b33f8SAndrii Nakryiko 21544a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2155e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 21564a3b33f8SAndrii Nakryiko 21574a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type); 21584a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 21594a3b33f8SAndrii Nakryiko if (!t) 2160e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 21614a3b33f8SAndrii Nakryiko 21624a3b33f8SAndrii Nakryiko if (name && name[0]) { 21634a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 21644a3b33f8SAndrii Nakryiko if (name_off < 0) 21654a3b33f8SAndrii Nakryiko return name_off; 21664a3b33f8SAndrii Nakryiko } 21674a3b33f8SAndrii Nakryiko 21684a3b33f8SAndrii Nakryiko /* start out with vlen=0; it will be adjusted when adding enum values */ 21694a3b33f8SAndrii Nakryiko t->name_off = name_off; 21704a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_ENUM, 0, 0); 21714a3b33f8SAndrii Nakryiko t->size = byte_sz; 21724a3b33f8SAndrii Nakryiko 2173c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 21744a3b33f8SAndrii Nakryiko } 21754a3b33f8SAndrii Nakryiko 21764a3b33f8SAndrii Nakryiko /* 21774a3b33f8SAndrii Nakryiko * Append new enum value for the current ENUM type with: 21784a3b33f8SAndrii Nakryiko * - *name* - name of the enumerator value, can't be NULL or empty; 21794a3b33f8SAndrii Nakryiko * - *value* - integer value corresponding to enum value *name*; 21804a3b33f8SAndrii Nakryiko * Returns: 21814a3b33f8SAndrii Nakryiko * - 0, on success; 21824a3b33f8SAndrii Nakryiko * - <0, on error. 21834a3b33f8SAndrii Nakryiko */ 21844a3b33f8SAndrii Nakryiko int btf__add_enum_value(struct btf *btf, const char *name, __s64 value) 21854a3b33f8SAndrii Nakryiko { 21864a3b33f8SAndrii Nakryiko struct btf_type *t; 21874a3b33f8SAndrii Nakryiko struct btf_enum *v; 21884a3b33f8SAndrii Nakryiko int sz, name_off; 21894a3b33f8SAndrii Nakryiko 21904a3b33f8SAndrii Nakryiko /* last type should be BTF_KIND_ENUM */ 21914a3b33f8SAndrii Nakryiko if (btf->nr_types == 0) 2192e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 2193c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 21944a3b33f8SAndrii Nakryiko if (!btf_is_enum(t)) 2195e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 21964a3b33f8SAndrii Nakryiko 21974a3b33f8SAndrii Nakryiko /* non-empty name */ 21984a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2199e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 22004a3b33f8SAndrii Nakryiko if (value < INT_MIN || value > UINT_MAX) 2201e9fc3ce9SAndrii Nakryiko return libbpf_err(-E2BIG); 22024a3b33f8SAndrii Nakryiko 22034a3b33f8SAndrii Nakryiko /* decompose and invalidate raw data */ 22044a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2205e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 22064a3b33f8SAndrii Nakryiko 22074a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_enum); 22084a3b33f8SAndrii Nakryiko v = btf_add_type_mem(btf, sz); 22094a3b33f8SAndrii Nakryiko if (!v) 2210e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 22114a3b33f8SAndrii Nakryiko 22124a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 22134a3b33f8SAndrii Nakryiko if (name_off < 0) 22144a3b33f8SAndrii Nakryiko return name_off; 22154a3b33f8SAndrii Nakryiko 22164a3b33f8SAndrii Nakryiko v->name_off = name_off; 22174a3b33f8SAndrii Nakryiko v->val = value; 22184a3b33f8SAndrii Nakryiko 22194a3b33f8SAndrii Nakryiko /* update parent type's vlen */ 2220c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 22214a3b33f8SAndrii Nakryiko btf_type_inc_vlen(t); 22224a3b33f8SAndrii Nakryiko 22234a3b33f8SAndrii Nakryiko btf->hdr->type_len += sz; 22244a3b33f8SAndrii Nakryiko btf->hdr->str_off += sz; 22254a3b33f8SAndrii Nakryiko return 0; 22264a3b33f8SAndrii Nakryiko } 22274a3b33f8SAndrii Nakryiko 22284a3b33f8SAndrii Nakryiko /* 22294a3b33f8SAndrii Nakryiko * Append new BTF_KIND_FWD type with: 22304a3b33f8SAndrii Nakryiko * - *name*, non-empty/non-NULL name; 22314a3b33f8SAndrii Nakryiko * - *fwd_kind*, kind of forward declaration, one of BTF_FWD_STRUCT, 22324a3b33f8SAndrii Nakryiko * BTF_FWD_UNION, or BTF_FWD_ENUM; 22334a3b33f8SAndrii Nakryiko * Returns: 22344a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 22354a3b33f8SAndrii Nakryiko * - <0, on error. 22364a3b33f8SAndrii Nakryiko */ 22374a3b33f8SAndrii Nakryiko int btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind) 22384a3b33f8SAndrii Nakryiko { 22394a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2240e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 22414a3b33f8SAndrii Nakryiko 22424a3b33f8SAndrii Nakryiko switch (fwd_kind) { 22434a3b33f8SAndrii Nakryiko case BTF_FWD_STRUCT: 22444a3b33f8SAndrii Nakryiko case BTF_FWD_UNION: { 22454a3b33f8SAndrii Nakryiko struct btf_type *t; 22464a3b33f8SAndrii Nakryiko int id; 22474a3b33f8SAndrii Nakryiko 22484a3b33f8SAndrii Nakryiko id = btf_add_ref_kind(btf, BTF_KIND_FWD, name, 0); 22494a3b33f8SAndrii Nakryiko if (id <= 0) 22504a3b33f8SAndrii Nakryiko return id; 22514a3b33f8SAndrii Nakryiko t = btf_type_by_id(btf, id); 22524a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_FWD, 0, fwd_kind == BTF_FWD_UNION); 22534a3b33f8SAndrii Nakryiko return id; 22544a3b33f8SAndrii Nakryiko } 22554a3b33f8SAndrii Nakryiko case BTF_FWD_ENUM: 22564a3b33f8SAndrii Nakryiko /* enum forward in BTF currently is just an enum with no enum 22574a3b33f8SAndrii Nakryiko * values; we also assume a standard 4-byte size for it 22584a3b33f8SAndrii Nakryiko */ 22594a3b33f8SAndrii Nakryiko return btf__add_enum(btf, name, sizeof(int)); 22604a3b33f8SAndrii Nakryiko default: 2261e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 22624a3b33f8SAndrii Nakryiko } 22634a3b33f8SAndrii Nakryiko } 22644a3b33f8SAndrii Nakryiko 22654a3b33f8SAndrii Nakryiko /* 22664a3b33f8SAndrii Nakryiko * Append new BTF_KING_TYPEDEF type with: 22674a3b33f8SAndrii Nakryiko * - *name*, non-empty/non-NULL name; 22684a3b33f8SAndrii Nakryiko * - *ref_type_id* - referenced type ID, it might not exist yet; 22694a3b33f8SAndrii Nakryiko * Returns: 22704a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 22714a3b33f8SAndrii Nakryiko * - <0, on error. 22724a3b33f8SAndrii Nakryiko */ 22734a3b33f8SAndrii Nakryiko int btf__add_typedef(struct btf *btf, const char *name, int ref_type_id) 22744a3b33f8SAndrii Nakryiko { 22754a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2276e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 22774a3b33f8SAndrii Nakryiko 22784a3b33f8SAndrii Nakryiko return btf_add_ref_kind(btf, BTF_KIND_TYPEDEF, name, ref_type_id); 22794a3b33f8SAndrii Nakryiko } 22804a3b33f8SAndrii Nakryiko 22814a3b33f8SAndrii Nakryiko /* 22824a3b33f8SAndrii Nakryiko * Append new BTF_KIND_VOLATILE type with: 22834a3b33f8SAndrii Nakryiko * - *ref_type_id* - referenced type ID, it might not exist yet; 22844a3b33f8SAndrii Nakryiko * Returns: 22854a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 22864a3b33f8SAndrii Nakryiko * - <0, on error. 22874a3b33f8SAndrii Nakryiko */ 22884a3b33f8SAndrii Nakryiko int btf__add_volatile(struct btf *btf, int ref_type_id) 22894a3b33f8SAndrii Nakryiko { 22904a3b33f8SAndrii Nakryiko return btf_add_ref_kind(btf, BTF_KIND_VOLATILE, NULL, ref_type_id); 22914a3b33f8SAndrii Nakryiko } 22924a3b33f8SAndrii Nakryiko 22934a3b33f8SAndrii Nakryiko /* 22944a3b33f8SAndrii Nakryiko * Append new BTF_KIND_CONST type with: 22954a3b33f8SAndrii Nakryiko * - *ref_type_id* - referenced type ID, it might not exist yet; 22964a3b33f8SAndrii Nakryiko * Returns: 22974a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 22984a3b33f8SAndrii Nakryiko * - <0, on error. 22994a3b33f8SAndrii Nakryiko */ 23004a3b33f8SAndrii Nakryiko int btf__add_const(struct btf *btf, int ref_type_id) 23014a3b33f8SAndrii Nakryiko { 23024a3b33f8SAndrii Nakryiko return btf_add_ref_kind(btf, BTF_KIND_CONST, NULL, ref_type_id); 23034a3b33f8SAndrii Nakryiko } 23044a3b33f8SAndrii Nakryiko 23054a3b33f8SAndrii Nakryiko /* 23064a3b33f8SAndrii Nakryiko * Append new BTF_KIND_RESTRICT type with: 23074a3b33f8SAndrii Nakryiko * - *ref_type_id* - referenced type ID, it might not exist yet; 23084a3b33f8SAndrii Nakryiko * Returns: 23094a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 23104a3b33f8SAndrii Nakryiko * - <0, on error. 23114a3b33f8SAndrii Nakryiko */ 23124a3b33f8SAndrii Nakryiko int btf__add_restrict(struct btf *btf, int ref_type_id) 23134a3b33f8SAndrii Nakryiko { 23144a3b33f8SAndrii Nakryiko return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id); 23154a3b33f8SAndrii Nakryiko } 23164a3b33f8SAndrii Nakryiko 23174a3b33f8SAndrii Nakryiko /* 23182dc1e488SYonghong Song * Append new BTF_KIND_TYPE_TAG type with: 23192dc1e488SYonghong Song * - *value*, non-empty/non-NULL tag value; 23202dc1e488SYonghong Song * - *ref_type_id* - referenced type ID, it might not exist yet; 23212dc1e488SYonghong Song * Returns: 23222dc1e488SYonghong Song * - >0, type ID of newly added BTF type; 23232dc1e488SYonghong Song * - <0, on error. 23242dc1e488SYonghong Song */ 23252dc1e488SYonghong Song int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id) 23262dc1e488SYonghong Song { 23272dc1e488SYonghong Song if (!value|| !value[0]) 23282dc1e488SYonghong Song return libbpf_err(-EINVAL); 23292dc1e488SYonghong Song 23302dc1e488SYonghong Song return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id); 23312dc1e488SYonghong Song } 23322dc1e488SYonghong Song 23332dc1e488SYonghong Song /* 23344a3b33f8SAndrii Nakryiko * Append new BTF_KIND_FUNC type with: 23354a3b33f8SAndrii Nakryiko * - *name*, non-empty/non-NULL name; 23364a3b33f8SAndrii Nakryiko * - *proto_type_id* - FUNC_PROTO's type ID, it might not exist yet; 23374a3b33f8SAndrii Nakryiko * Returns: 23384a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 23394a3b33f8SAndrii Nakryiko * - <0, on error. 23404a3b33f8SAndrii Nakryiko */ 23414a3b33f8SAndrii Nakryiko int btf__add_func(struct btf *btf, const char *name, 23424a3b33f8SAndrii Nakryiko enum btf_func_linkage linkage, int proto_type_id) 23434a3b33f8SAndrii Nakryiko { 23444a3b33f8SAndrii Nakryiko int id; 23454a3b33f8SAndrii Nakryiko 23464a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2347e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 23484a3b33f8SAndrii Nakryiko if (linkage != BTF_FUNC_STATIC && linkage != BTF_FUNC_GLOBAL && 23494a3b33f8SAndrii Nakryiko linkage != BTF_FUNC_EXTERN) 2350e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 23514a3b33f8SAndrii Nakryiko 23524a3b33f8SAndrii Nakryiko id = btf_add_ref_kind(btf, BTF_KIND_FUNC, name, proto_type_id); 23534a3b33f8SAndrii Nakryiko if (id > 0) { 23544a3b33f8SAndrii Nakryiko struct btf_type *t = btf_type_by_id(btf, id); 23554a3b33f8SAndrii Nakryiko 23564a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_FUNC, linkage, 0); 23574a3b33f8SAndrii Nakryiko } 2358e9fc3ce9SAndrii Nakryiko return libbpf_err(id); 23594a3b33f8SAndrii Nakryiko } 23604a3b33f8SAndrii Nakryiko 23614a3b33f8SAndrii Nakryiko /* 23624a3b33f8SAndrii Nakryiko * Append new BTF_KIND_FUNC_PROTO with: 23634a3b33f8SAndrii Nakryiko * - *ret_type_id* - type ID for return result of a function. 23644a3b33f8SAndrii Nakryiko * 23654a3b33f8SAndrii Nakryiko * Function prototype initially has no arguments, but they can be added by 23664a3b33f8SAndrii Nakryiko * btf__add_func_param() one by one, immediately after 23674a3b33f8SAndrii Nakryiko * btf__add_func_proto() succeeded. 23684a3b33f8SAndrii Nakryiko * 23694a3b33f8SAndrii Nakryiko * Returns: 23704a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 23714a3b33f8SAndrii Nakryiko * - <0, on error. 23724a3b33f8SAndrii Nakryiko */ 23734a3b33f8SAndrii Nakryiko int btf__add_func_proto(struct btf *btf, int ret_type_id) 23744a3b33f8SAndrii Nakryiko { 23754a3b33f8SAndrii Nakryiko struct btf_type *t; 2376c81ed6d8SAndrii Nakryiko int sz; 23774a3b33f8SAndrii Nakryiko 23784a3b33f8SAndrii Nakryiko if (validate_type_id(ret_type_id)) 2379e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 23804a3b33f8SAndrii Nakryiko 23814a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2382e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 23834a3b33f8SAndrii Nakryiko 23844a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type); 23854a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 23864a3b33f8SAndrii Nakryiko if (!t) 2387e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 23884a3b33f8SAndrii Nakryiko 23894a3b33f8SAndrii Nakryiko /* start out with vlen=0; this will be adjusted when adding enum 23904a3b33f8SAndrii Nakryiko * values, if necessary 23914a3b33f8SAndrii Nakryiko */ 23924a3b33f8SAndrii Nakryiko t->name_off = 0; 23934a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_FUNC_PROTO, 0, 0); 23944a3b33f8SAndrii Nakryiko t->type = ret_type_id; 23954a3b33f8SAndrii Nakryiko 2396c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 23974a3b33f8SAndrii Nakryiko } 23984a3b33f8SAndrii Nakryiko 23994a3b33f8SAndrii Nakryiko /* 24004a3b33f8SAndrii Nakryiko * Append new function parameter for current FUNC_PROTO type with: 24014a3b33f8SAndrii Nakryiko * - *name* - parameter name, can be NULL or empty; 24024a3b33f8SAndrii Nakryiko * - *type_id* - type ID describing the type of the parameter. 24034a3b33f8SAndrii Nakryiko * Returns: 24044a3b33f8SAndrii Nakryiko * - 0, on success; 24054a3b33f8SAndrii Nakryiko * - <0, on error. 24064a3b33f8SAndrii Nakryiko */ 24074a3b33f8SAndrii Nakryiko int btf__add_func_param(struct btf *btf, const char *name, int type_id) 24084a3b33f8SAndrii Nakryiko { 24094a3b33f8SAndrii Nakryiko struct btf_type *t; 24104a3b33f8SAndrii Nakryiko struct btf_param *p; 24114a3b33f8SAndrii Nakryiko int sz, name_off = 0; 24124a3b33f8SAndrii Nakryiko 24134a3b33f8SAndrii Nakryiko if (validate_type_id(type_id)) 2414e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 24154a3b33f8SAndrii Nakryiko 24164a3b33f8SAndrii Nakryiko /* last type should be BTF_KIND_FUNC_PROTO */ 24174a3b33f8SAndrii Nakryiko if (btf->nr_types == 0) 2418e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 2419c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 24204a3b33f8SAndrii Nakryiko if (!btf_is_func_proto(t)) 2421e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 24224a3b33f8SAndrii Nakryiko 24234a3b33f8SAndrii Nakryiko /* decompose and invalidate raw data */ 24244a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2425e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 24264a3b33f8SAndrii Nakryiko 24274a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_param); 24284a3b33f8SAndrii Nakryiko p = btf_add_type_mem(btf, sz); 24294a3b33f8SAndrii Nakryiko if (!p) 2430e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 24314a3b33f8SAndrii Nakryiko 24324a3b33f8SAndrii Nakryiko if (name && name[0]) { 24334a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 24344a3b33f8SAndrii Nakryiko if (name_off < 0) 24354a3b33f8SAndrii Nakryiko return name_off; 24364a3b33f8SAndrii Nakryiko } 24374a3b33f8SAndrii Nakryiko 24384a3b33f8SAndrii Nakryiko p->name_off = name_off; 24394a3b33f8SAndrii Nakryiko p->type = type_id; 24404a3b33f8SAndrii Nakryiko 24414a3b33f8SAndrii Nakryiko /* update parent type's vlen */ 2442c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 24434a3b33f8SAndrii Nakryiko btf_type_inc_vlen(t); 24444a3b33f8SAndrii Nakryiko 24454a3b33f8SAndrii Nakryiko btf->hdr->type_len += sz; 24464a3b33f8SAndrii Nakryiko btf->hdr->str_off += sz; 24474a3b33f8SAndrii Nakryiko return 0; 24484a3b33f8SAndrii Nakryiko } 24494a3b33f8SAndrii Nakryiko 24504a3b33f8SAndrii Nakryiko /* 24514a3b33f8SAndrii Nakryiko * Append new BTF_KIND_VAR type with: 24524a3b33f8SAndrii Nakryiko * - *name* - non-empty/non-NULL name; 24534a3b33f8SAndrii Nakryiko * - *linkage* - variable linkage, one of BTF_VAR_STATIC, 24544a3b33f8SAndrii Nakryiko * BTF_VAR_GLOBAL_ALLOCATED, or BTF_VAR_GLOBAL_EXTERN; 24554a3b33f8SAndrii Nakryiko * - *type_id* - type ID of the type describing the type of the variable. 24564a3b33f8SAndrii Nakryiko * Returns: 24574a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 24584a3b33f8SAndrii Nakryiko * - <0, on error. 24594a3b33f8SAndrii Nakryiko */ 24604a3b33f8SAndrii Nakryiko int btf__add_var(struct btf *btf, const char *name, int linkage, int type_id) 24614a3b33f8SAndrii Nakryiko { 24624a3b33f8SAndrii Nakryiko struct btf_type *t; 24634a3b33f8SAndrii Nakryiko struct btf_var *v; 2464c81ed6d8SAndrii Nakryiko int sz, name_off; 24654a3b33f8SAndrii Nakryiko 24664a3b33f8SAndrii Nakryiko /* non-empty name */ 24674a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2468e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 24694a3b33f8SAndrii Nakryiko if (linkage != BTF_VAR_STATIC && linkage != BTF_VAR_GLOBAL_ALLOCATED && 24704a3b33f8SAndrii Nakryiko linkage != BTF_VAR_GLOBAL_EXTERN) 2471e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 24724a3b33f8SAndrii Nakryiko if (validate_type_id(type_id)) 2473e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 24744a3b33f8SAndrii Nakryiko 24754a3b33f8SAndrii Nakryiko /* deconstruct BTF, if necessary, and invalidate raw_data */ 24764a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2477e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 24784a3b33f8SAndrii Nakryiko 24794a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type) + sizeof(struct btf_var); 24804a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 24814a3b33f8SAndrii Nakryiko if (!t) 2482e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 24834a3b33f8SAndrii Nakryiko 24844a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 24854a3b33f8SAndrii Nakryiko if (name_off < 0) 24864a3b33f8SAndrii Nakryiko return name_off; 24874a3b33f8SAndrii Nakryiko 24884a3b33f8SAndrii Nakryiko t->name_off = name_off; 24894a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_VAR, 0, 0); 24904a3b33f8SAndrii Nakryiko t->type = type_id; 24914a3b33f8SAndrii Nakryiko 24924a3b33f8SAndrii Nakryiko v = btf_var(t); 24934a3b33f8SAndrii Nakryiko v->linkage = linkage; 24944a3b33f8SAndrii Nakryiko 2495c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 24964a3b33f8SAndrii Nakryiko } 24974a3b33f8SAndrii Nakryiko 24984a3b33f8SAndrii Nakryiko /* 24994a3b33f8SAndrii Nakryiko * Append new BTF_KIND_DATASEC type with: 25004a3b33f8SAndrii Nakryiko * - *name* - non-empty/non-NULL name; 25014a3b33f8SAndrii Nakryiko * - *byte_sz* - data section size, in bytes. 25024a3b33f8SAndrii Nakryiko * 25034a3b33f8SAndrii Nakryiko * Data section is initially empty. Variables info can be added with 25044a3b33f8SAndrii Nakryiko * btf__add_datasec_var_info() calls, after btf__add_datasec() succeeds. 25054a3b33f8SAndrii Nakryiko * 25064a3b33f8SAndrii Nakryiko * Returns: 25074a3b33f8SAndrii Nakryiko * - >0, type ID of newly added BTF type; 25084a3b33f8SAndrii Nakryiko * - <0, on error. 25094a3b33f8SAndrii Nakryiko */ 25104a3b33f8SAndrii Nakryiko int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz) 25114a3b33f8SAndrii Nakryiko { 25124a3b33f8SAndrii Nakryiko struct btf_type *t; 2513c81ed6d8SAndrii Nakryiko int sz, name_off; 25144a3b33f8SAndrii Nakryiko 25154a3b33f8SAndrii Nakryiko /* non-empty name */ 25164a3b33f8SAndrii Nakryiko if (!name || !name[0]) 2517e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 25184a3b33f8SAndrii Nakryiko 25194a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2520e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 25214a3b33f8SAndrii Nakryiko 25224a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_type); 25234a3b33f8SAndrii Nakryiko t = btf_add_type_mem(btf, sz); 25244a3b33f8SAndrii Nakryiko if (!t) 2525e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 25264a3b33f8SAndrii Nakryiko 25274a3b33f8SAndrii Nakryiko name_off = btf__add_str(btf, name); 25284a3b33f8SAndrii Nakryiko if (name_off < 0) 25294a3b33f8SAndrii Nakryiko return name_off; 25304a3b33f8SAndrii Nakryiko 25314a3b33f8SAndrii Nakryiko /* start with vlen=0, which will be update as var_secinfos are added */ 25324a3b33f8SAndrii Nakryiko t->name_off = name_off; 25334a3b33f8SAndrii Nakryiko t->info = btf_type_info(BTF_KIND_DATASEC, 0, 0); 25344a3b33f8SAndrii Nakryiko t->size = byte_sz; 25354a3b33f8SAndrii Nakryiko 2536c81ed6d8SAndrii Nakryiko return btf_commit_type(btf, sz); 25374a3b33f8SAndrii Nakryiko } 25384a3b33f8SAndrii Nakryiko 25394a3b33f8SAndrii Nakryiko /* 25404a3b33f8SAndrii Nakryiko * Append new data section variable information entry for current DATASEC type: 25414a3b33f8SAndrii Nakryiko * - *var_type_id* - type ID, describing type of the variable; 25424a3b33f8SAndrii Nakryiko * - *offset* - variable offset within data section, in bytes; 25434a3b33f8SAndrii Nakryiko * - *byte_sz* - variable size, in bytes. 25444a3b33f8SAndrii Nakryiko * 25454a3b33f8SAndrii Nakryiko * Returns: 25464a3b33f8SAndrii Nakryiko * - 0, on success; 25474a3b33f8SAndrii Nakryiko * - <0, on error. 25484a3b33f8SAndrii Nakryiko */ 25494a3b33f8SAndrii Nakryiko int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __u32 byte_sz) 25504a3b33f8SAndrii Nakryiko { 25514a3b33f8SAndrii Nakryiko struct btf_type *t; 25524a3b33f8SAndrii Nakryiko struct btf_var_secinfo *v; 25534a3b33f8SAndrii Nakryiko int sz; 25544a3b33f8SAndrii Nakryiko 25554a3b33f8SAndrii Nakryiko /* last type should be BTF_KIND_DATASEC */ 25564a3b33f8SAndrii Nakryiko if (btf->nr_types == 0) 2557e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 2558c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 25594a3b33f8SAndrii Nakryiko if (!btf_is_datasec(t)) 2560e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 25614a3b33f8SAndrii Nakryiko 25624a3b33f8SAndrii Nakryiko if (validate_type_id(var_type_id)) 2563e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 25644a3b33f8SAndrii Nakryiko 25654a3b33f8SAndrii Nakryiko /* decompose and invalidate raw data */ 25664a3b33f8SAndrii Nakryiko if (btf_ensure_modifiable(btf)) 2567e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 25684a3b33f8SAndrii Nakryiko 25694a3b33f8SAndrii Nakryiko sz = sizeof(struct btf_var_secinfo); 25704a3b33f8SAndrii Nakryiko v = btf_add_type_mem(btf, sz); 25714a3b33f8SAndrii Nakryiko if (!v) 2572e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 25734a3b33f8SAndrii Nakryiko 25744a3b33f8SAndrii Nakryiko v->type = var_type_id; 25754a3b33f8SAndrii Nakryiko v->offset = offset; 25764a3b33f8SAndrii Nakryiko v->size = byte_sz; 25774a3b33f8SAndrii Nakryiko 25784a3b33f8SAndrii Nakryiko /* update parent type's vlen */ 2579c81ed6d8SAndrii Nakryiko t = btf_last_type(btf); 25804a3b33f8SAndrii Nakryiko btf_type_inc_vlen(t); 25814a3b33f8SAndrii Nakryiko 25824a3b33f8SAndrii Nakryiko btf->hdr->type_len += sz; 25834a3b33f8SAndrii Nakryiko btf->hdr->str_off += sz; 25844a3b33f8SAndrii Nakryiko return 0; 25854a3b33f8SAndrii Nakryiko } 25864a3b33f8SAndrii Nakryiko 25875b84bd10SYonghong Song /* 2588223f903eSYonghong Song * Append new BTF_KIND_DECL_TAG type with: 25895b84bd10SYonghong Song * - *value* - non-empty/non-NULL string; 25905b84bd10SYonghong Song * - *ref_type_id* - referenced type ID, it might not exist yet; 25915b84bd10SYonghong Song * - *component_idx* - -1 for tagging reference type, otherwise struct/union 25925b84bd10SYonghong Song * member or function argument index; 25935b84bd10SYonghong Song * Returns: 25945b84bd10SYonghong Song * - >0, type ID of newly added BTF type; 25955b84bd10SYonghong Song * - <0, on error. 25965b84bd10SYonghong Song */ 2597223f903eSYonghong Song int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id, 25985b84bd10SYonghong Song int component_idx) 25995b84bd10SYonghong Song { 26005b84bd10SYonghong Song struct btf_type *t; 26015b84bd10SYonghong Song int sz, value_off; 26025b84bd10SYonghong Song 26035b84bd10SYonghong Song if (!value || !value[0] || component_idx < -1) 26045b84bd10SYonghong Song return libbpf_err(-EINVAL); 26055b84bd10SYonghong Song 26065b84bd10SYonghong Song if (validate_type_id(ref_type_id)) 26075b84bd10SYonghong Song return libbpf_err(-EINVAL); 26085b84bd10SYonghong Song 26095b84bd10SYonghong Song if (btf_ensure_modifiable(btf)) 26105b84bd10SYonghong Song return libbpf_err(-ENOMEM); 26115b84bd10SYonghong Song 2612223f903eSYonghong Song sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag); 26135b84bd10SYonghong Song t = btf_add_type_mem(btf, sz); 26145b84bd10SYonghong Song if (!t) 26155b84bd10SYonghong Song return libbpf_err(-ENOMEM); 26165b84bd10SYonghong Song 26175b84bd10SYonghong Song value_off = btf__add_str(btf, value); 26185b84bd10SYonghong Song if (value_off < 0) 26195b84bd10SYonghong Song return value_off; 26205b84bd10SYonghong Song 26215b84bd10SYonghong Song t->name_off = value_off; 2622223f903eSYonghong Song t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false); 26235b84bd10SYonghong Song t->type = ref_type_id; 2624223f903eSYonghong Song btf_decl_tag(t)->component_idx = component_idx; 26255b84bd10SYonghong Song 26265b84bd10SYonghong Song return btf_commit_type(btf, sz); 26275b84bd10SYonghong Song } 26285b84bd10SYonghong Song 2629ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param { 26303d650141SMartin KaFai Lau __u32 off; 26313d650141SMartin KaFai Lau __u32 len; 26323d650141SMartin KaFai Lau __u32 min_rec_size; 26333d650141SMartin KaFai Lau struct btf_ext_info *ext_info; 26343d650141SMartin KaFai Lau const char *desc; 26353d650141SMartin KaFai Lau }; 26363d650141SMartin KaFai Lau 2637ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_info(struct btf_ext *btf_ext, 2638ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param *ext_sec) 26392993e051SYonghong Song { 26403d650141SMartin KaFai Lau const struct btf_ext_info_sec *sinfo; 26413d650141SMartin KaFai Lau struct btf_ext_info *ext_info; 2642f0187f0bSMartin KaFai Lau __u32 info_left, record_size; 264311d5daa8SAndrii Nakryiko size_t sec_cnt = 0; 2644f0187f0bSMartin KaFai Lau /* The start of the info sec (including the __u32 record_size). */ 2645ae4ab4b4SAndrii Nakryiko void *info; 2646f0187f0bSMartin KaFai Lau 26474cedc0daSAndrii Nakryiko if (ext_sec->len == 0) 26484cedc0daSAndrii Nakryiko return 0; 26494cedc0daSAndrii Nakryiko 26503d650141SMartin KaFai Lau if (ext_sec->off & 0x03) { 26518461ef8bSYonghong Song pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n", 26523d650141SMartin KaFai Lau ext_sec->desc); 2653f0187f0bSMartin KaFai Lau return -EINVAL; 2654f0187f0bSMartin KaFai Lau } 2655f0187f0bSMartin KaFai Lau 2656ae4ab4b4SAndrii Nakryiko info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off; 2657ae4ab4b4SAndrii Nakryiko info_left = ext_sec->len; 2658ae4ab4b4SAndrii Nakryiko 2659ae4ab4b4SAndrii Nakryiko if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) { 26608461ef8bSYonghong Song pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n", 26613d650141SMartin KaFai Lau ext_sec->desc, ext_sec->off, ext_sec->len); 2662f0187f0bSMartin KaFai Lau return -EINVAL; 2663f0187f0bSMartin KaFai Lau } 2664f0187f0bSMartin KaFai Lau 26653d650141SMartin KaFai Lau /* At least a record size */ 2666f0187f0bSMartin KaFai Lau if (info_left < sizeof(__u32)) { 26678461ef8bSYonghong Song pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc); 26682993e051SYonghong Song return -EINVAL; 26692993e051SYonghong Song } 26702993e051SYonghong Song 2671f0187f0bSMartin KaFai Lau /* The record size needs to meet the minimum standard */ 2672f0187f0bSMartin KaFai Lau record_size = *(__u32 *)info; 26733d650141SMartin KaFai Lau if (record_size < ext_sec->min_rec_size || 2674f0187f0bSMartin KaFai Lau record_size & 0x03) { 26758461ef8bSYonghong Song pr_debug("%s section in .BTF.ext has invalid record size %u\n", 26763d650141SMartin KaFai Lau ext_sec->desc, record_size); 26772993e051SYonghong Song return -EINVAL; 26782993e051SYonghong Song } 26792993e051SYonghong Song 2680f0187f0bSMartin KaFai Lau sinfo = info + sizeof(__u32); 2681f0187f0bSMartin KaFai Lau info_left -= sizeof(__u32); 26822993e051SYonghong Song 26833d650141SMartin KaFai Lau /* If no records, return failure now so .BTF.ext won't be used. */ 2684f0187f0bSMartin KaFai Lau if (!info_left) { 26858461ef8bSYonghong Song pr_debug("%s section in .BTF.ext has no records", ext_sec->desc); 26862993e051SYonghong Song return -EINVAL; 26872993e051SYonghong Song } 26882993e051SYonghong Song 2689f0187f0bSMartin KaFai Lau while (info_left) { 26903d650141SMartin KaFai Lau unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec); 2691f0187f0bSMartin KaFai Lau __u64 total_record_size; 2692f0187f0bSMartin KaFai Lau __u32 num_records; 2693f0187f0bSMartin KaFai Lau 2694f0187f0bSMartin KaFai Lau if (info_left < sec_hdrlen) { 26958461ef8bSYonghong Song pr_debug("%s section header is not found in .BTF.ext\n", 26963d650141SMartin KaFai Lau ext_sec->desc); 26972993e051SYonghong Song return -EINVAL; 26982993e051SYonghong Song } 26992993e051SYonghong Song 27003d650141SMartin KaFai Lau num_records = sinfo->num_info; 27012993e051SYonghong Song if (num_records == 0) { 27028461ef8bSYonghong Song pr_debug("%s section has incorrect num_records in .BTF.ext\n", 27033d650141SMartin KaFai Lau ext_sec->desc); 27042993e051SYonghong Song return -EINVAL; 27052993e051SYonghong Song } 27062993e051SYonghong Song 270711d5daa8SAndrii Nakryiko total_record_size = sec_hdrlen + (__u64)num_records * record_size; 2708f0187f0bSMartin KaFai Lau if (info_left < total_record_size) { 27098461ef8bSYonghong Song pr_debug("%s section has incorrect num_records in .BTF.ext\n", 27103d650141SMartin KaFai Lau ext_sec->desc); 27112993e051SYonghong Song return -EINVAL; 27122993e051SYonghong Song } 27132993e051SYonghong Song 2714f0187f0bSMartin KaFai Lau info_left -= total_record_size; 27152993e051SYonghong Song sinfo = (void *)sinfo + total_record_size; 271611d5daa8SAndrii Nakryiko sec_cnt++; 27172993e051SYonghong Song } 27182993e051SYonghong Song 27193d650141SMartin KaFai Lau ext_info = ext_sec->ext_info; 27203d650141SMartin KaFai Lau ext_info->len = ext_sec->len - sizeof(__u32); 27213d650141SMartin KaFai Lau ext_info->rec_size = record_size; 2722ae4ab4b4SAndrii Nakryiko ext_info->info = info + sizeof(__u32); 272311d5daa8SAndrii Nakryiko ext_info->sec_cnt = sec_cnt; 2724f0187f0bSMartin KaFai Lau 27252993e051SYonghong Song return 0; 27262993e051SYonghong Song } 27272993e051SYonghong Song 2728ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_func_info(struct btf_ext *btf_ext) 27293d650141SMartin KaFai Lau { 2730ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param param = { 2731ae4ab4b4SAndrii Nakryiko .off = btf_ext->hdr->func_info_off, 2732ae4ab4b4SAndrii Nakryiko .len = btf_ext->hdr->func_info_len, 27333d650141SMartin KaFai Lau .min_rec_size = sizeof(struct bpf_func_info_min), 27343d650141SMartin KaFai Lau .ext_info = &btf_ext->func_info, 27353d650141SMartin KaFai Lau .desc = "func_info" 27363d650141SMartin KaFai Lau }; 27373d650141SMartin KaFai Lau 2738ae4ab4b4SAndrii Nakryiko return btf_ext_setup_info(btf_ext, ¶m); 27393d650141SMartin KaFai Lau } 27403d650141SMartin KaFai Lau 2741ae4ab4b4SAndrii Nakryiko static int btf_ext_setup_line_info(struct btf_ext *btf_ext) 27423d650141SMartin KaFai Lau { 2743ae4ab4b4SAndrii Nakryiko struct btf_ext_sec_setup_param param = { 2744ae4ab4b4SAndrii Nakryiko .off = btf_ext->hdr->line_info_off, 2745ae4ab4b4SAndrii Nakryiko .len = btf_ext->hdr->line_info_len, 27463d650141SMartin KaFai Lau .min_rec_size = sizeof(struct bpf_line_info_min), 27473d650141SMartin KaFai Lau .ext_info = &btf_ext->line_info, 27483d650141SMartin KaFai Lau .desc = "line_info", 27493d650141SMartin KaFai Lau }; 27503d650141SMartin KaFai Lau 2751ae4ab4b4SAndrii Nakryiko return btf_ext_setup_info(btf_ext, ¶m); 27523d650141SMartin KaFai Lau } 27533d650141SMartin KaFai Lau 275428b93c64SAndrii Nakryiko static int btf_ext_setup_core_relos(struct btf_ext *btf_ext) 27554cedc0daSAndrii Nakryiko { 27564cedc0daSAndrii Nakryiko struct btf_ext_sec_setup_param param = { 275728b93c64SAndrii Nakryiko .off = btf_ext->hdr->core_relo_off, 275828b93c64SAndrii Nakryiko .len = btf_ext->hdr->core_relo_len, 275928b93c64SAndrii Nakryiko .min_rec_size = sizeof(struct bpf_core_relo), 276028b93c64SAndrii Nakryiko .ext_info = &btf_ext->core_relo_info, 276128b93c64SAndrii Nakryiko .desc = "core_relo", 27624cedc0daSAndrii Nakryiko }; 27634cedc0daSAndrii Nakryiko 27644cedc0daSAndrii Nakryiko return btf_ext_setup_info(btf_ext, ¶m); 27654cedc0daSAndrii Nakryiko } 27664cedc0daSAndrii Nakryiko 27678461ef8bSYonghong Song static int btf_ext_parse_hdr(__u8 *data, __u32 data_size) 27682993e051SYonghong Song { 27692993e051SYonghong Song const struct btf_ext_header *hdr = (struct btf_ext_header *)data; 27702993e051SYonghong Song 27714cedc0daSAndrii Nakryiko if (data_size < offsetofend(struct btf_ext_header, hdr_len) || 27722993e051SYonghong Song data_size < hdr->hdr_len) { 27738461ef8bSYonghong Song pr_debug("BTF.ext header not found"); 27742993e051SYonghong Song return -EINVAL; 27752993e051SYonghong Song } 27762993e051SYonghong Song 27773289959bSAndrii Nakryiko if (hdr->magic == bswap_16(BTF_MAGIC)) { 27783289959bSAndrii Nakryiko pr_warn("BTF.ext in non-native endianness is not supported\n"); 27793289959bSAndrii Nakryiko return -ENOTSUP; 27803289959bSAndrii Nakryiko } else if (hdr->magic != BTF_MAGIC) { 27818461ef8bSYonghong Song pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic); 27822993e051SYonghong Song return -EINVAL; 27832993e051SYonghong Song } 27842993e051SYonghong Song 27852993e051SYonghong Song if (hdr->version != BTF_VERSION) { 27868461ef8bSYonghong Song pr_debug("Unsupported BTF.ext version:%u\n", hdr->version); 27872993e051SYonghong Song return -ENOTSUP; 27882993e051SYonghong Song } 27892993e051SYonghong Song 27902993e051SYonghong Song if (hdr->flags) { 27918461ef8bSYonghong Song pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags); 27922993e051SYonghong Song return -ENOTSUP; 27932993e051SYonghong Song } 27942993e051SYonghong Song 2795f0187f0bSMartin KaFai Lau if (data_size == hdr->hdr_len) { 27968461ef8bSYonghong Song pr_debug("BTF.ext has no data\n"); 27972993e051SYonghong Song return -EINVAL; 27982993e051SYonghong Song } 27992993e051SYonghong Song 2800f0187f0bSMartin KaFai Lau return 0; 28012993e051SYonghong Song } 28022993e051SYonghong Song 28032993e051SYonghong Song void btf_ext__free(struct btf_ext *btf_ext) 28042993e051SYonghong Song { 280550450fc7SAndrii Nakryiko if (IS_ERR_OR_NULL(btf_ext)) 28062993e051SYonghong Song return; 280711d5daa8SAndrii Nakryiko free(btf_ext->func_info.sec_idxs); 280811d5daa8SAndrii Nakryiko free(btf_ext->line_info.sec_idxs); 280911d5daa8SAndrii Nakryiko free(btf_ext->core_relo_info.sec_idxs); 2810ae4ab4b4SAndrii Nakryiko free(btf_ext->data); 28112993e051SYonghong Song free(btf_ext); 28122993e051SYonghong Song } 28132993e051SYonghong Song 2814401891a9SAndrii Nakryiko struct btf_ext *btf_ext__new(const __u8 *data, __u32 size) 28152993e051SYonghong Song { 28162993e051SYonghong Song struct btf_ext *btf_ext; 28172993e051SYonghong Song int err; 28182993e051SYonghong Song 28192993e051SYonghong Song btf_ext = calloc(1, sizeof(struct btf_ext)); 28202993e051SYonghong Song if (!btf_ext) 2821e9fc3ce9SAndrii Nakryiko return libbpf_err_ptr(-ENOMEM); 28222993e051SYonghong Song 2823ae4ab4b4SAndrii Nakryiko btf_ext->data_size = size; 2824ae4ab4b4SAndrii Nakryiko btf_ext->data = malloc(size); 2825ae4ab4b4SAndrii Nakryiko if (!btf_ext->data) { 2826ae4ab4b4SAndrii Nakryiko err = -ENOMEM; 2827ae4ab4b4SAndrii Nakryiko goto done; 28282993e051SYonghong Song } 2829ae4ab4b4SAndrii Nakryiko memcpy(btf_ext->data, data, size); 28302993e051SYonghong Song 2831401891a9SAndrii Nakryiko err = btf_ext_parse_hdr(btf_ext->data, size); 2832401891a9SAndrii Nakryiko if (err) 2833401891a9SAndrii Nakryiko goto done; 2834401891a9SAndrii Nakryiko 2835e9fc3ce9SAndrii Nakryiko if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) { 2836e9fc3ce9SAndrii Nakryiko err = -EINVAL; 28374cedc0daSAndrii Nakryiko goto done; 2838e9fc3ce9SAndrii Nakryiko } 2839e9fc3ce9SAndrii Nakryiko 2840ae4ab4b4SAndrii Nakryiko err = btf_ext_setup_func_info(btf_ext); 2841ae4ab4b4SAndrii Nakryiko if (err) 2842ae4ab4b4SAndrii Nakryiko goto done; 2843ae4ab4b4SAndrii Nakryiko 2844ae4ab4b4SAndrii Nakryiko err = btf_ext_setup_line_info(btf_ext); 2845ae4ab4b4SAndrii Nakryiko if (err) 2846ae4ab4b4SAndrii Nakryiko goto done; 2847ae4ab4b4SAndrii Nakryiko 2848e93f3999SYuntao Wang if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) 2849e93f3999SYuntao Wang goto done; /* skip core relos parsing */ 2850e9fc3ce9SAndrii Nakryiko 285128b93c64SAndrii Nakryiko err = btf_ext_setup_core_relos(btf_ext); 28524cedc0daSAndrii Nakryiko if (err) 28534cedc0daSAndrii Nakryiko goto done; 28544cedc0daSAndrii Nakryiko 2855ae4ab4b4SAndrii Nakryiko done: 28563d650141SMartin KaFai Lau if (err) { 28573d650141SMartin KaFai Lau btf_ext__free(btf_ext); 2858e9fc3ce9SAndrii Nakryiko return libbpf_err_ptr(err); 28593d650141SMartin KaFai Lau } 28603d650141SMartin KaFai Lau 28612993e051SYonghong Song return btf_ext; 28622993e051SYonghong Song } 28632993e051SYonghong Song 2864ae4ab4b4SAndrii Nakryiko const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size) 2865ae4ab4b4SAndrii Nakryiko { 2866ae4ab4b4SAndrii Nakryiko *size = btf_ext->data_size; 2867ae4ab4b4SAndrii Nakryiko return btf_ext->data; 2868ae4ab4b4SAndrii Nakryiko } 2869ae4ab4b4SAndrii Nakryiko 28703d650141SMartin KaFai Lau static int btf_ext_reloc_info(const struct btf *btf, 28713d650141SMartin KaFai Lau const struct btf_ext_info *ext_info, 28722993e051SYonghong Song const char *sec_name, __u32 insns_cnt, 28733d650141SMartin KaFai Lau void **info, __u32 *cnt) 28742993e051SYonghong Song { 28753d650141SMartin KaFai Lau __u32 sec_hdrlen = sizeof(struct btf_ext_info_sec); 28763d650141SMartin KaFai Lau __u32 i, record_size, existing_len, records_len; 28773d650141SMartin KaFai Lau struct btf_ext_info_sec *sinfo; 28782993e051SYonghong Song const char *info_sec_name; 28792993e051SYonghong Song __u64 remain_len; 28802993e051SYonghong Song void *data; 28812993e051SYonghong Song 28823d650141SMartin KaFai Lau record_size = ext_info->rec_size; 28833d650141SMartin KaFai Lau sinfo = ext_info->info; 28843d650141SMartin KaFai Lau remain_len = ext_info->len; 28852993e051SYonghong Song while (remain_len > 0) { 28863d650141SMartin KaFai Lau records_len = sinfo->num_info * record_size; 28872993e051SYonghong Song info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); 28882993e051SYonghong Song if (strcmp(info_sec_name, sec_name)) { 28892993e051SYonghong Song remain_len -= sec_hdrlen + records_len; 28902993e051SYonghong Song sinfo = (void *)sinfo + sec_hdrlen + records_len; 28912993e051SYonghong Song continue; 28922993e051SYonghong Song } 28932993e051SYonghong Song 28943d650141SMartin KaFai Lau existing_len = (*cnt) * record_size; 28953d650141SMartin KaFai Lau data = realloc(*info, existing_len + records_len); 28962993e051SYonghong Song if (!data) 2897e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOMEM); 28982993e051SYonghong Song 28993d650141SMartin KaFai Lau memcpy(data + existing_len, sinfo->data, records_len); 290084ecc1f9SMartin KaFai Lau /* adjust insn_off only, the rest data will be passed 29012993e051SYonghong Song * to the kernel. 29022993e051SYonghong Song */ 29033d650141SMartin KaFai Lau for (i = 0; i < sinfo->num_info; i++) { 29043d650141SMartin KaFai Lau __u32 *insn_off; 29052993e051SYonghong Song 29063d650141SMartin KaFai Lau insn_off = data + existing_len + (i * record_size); 2907e9fc3ce9SAndrii Nakryiko *insn_off = *insn_off / sizeof(struct bpf_insn) + insns_cnt; 29082993e051SYonghong Song } 29093d650141SMartin KaFai Lau *info = data; 29103d650141SMartin KaFai Lau *cnt += sinfo->num_info; 29112993e051SYonghong Song return 0; 29122993e051SYonghong Song } 29132993e051SYonghong Song 2914e9fc3ce9SAndrii Nakryiko return libbpf_err(-ENOENT); 2915f0187f0bSMartin KaFai Lau } 2916f0187f0bSMartin KaFai Lau 2917ae4ab4b4SAndrii Nakryiko int btf_ext__reloc_func_info(const struct btf *btf, 2918ae4ab4b4SAndrii Nakryiko const struct btf_ext *btf_ext, 29193d650141SMartin KaFai Lau const char *sec_name, __u32 insns_cnt, 29203d650141SMartin KaFai Lau void **func_info, __u32 *cnt) 29213d650141SMartin KaFai Lau { 29223d650141SMartin KaFai Lau return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name, 29233d650141SMartin KaFai Lau insns_cnt, func_info, cnt); 29243d650141SMartin KaFai Lau } 29253d650141SMartin KaFai Lau 2926ae4ab4b4SAndrii Nakryiko int btf_ext__reloc_line_info(const struct btf *btf, 2927ae4ab4b4SAndrii Nakryiko const struct btf_ext *btf_ext, 29283d650141SMartin KaFai Lau const char *sec_name, __u32 insns_cnt, 29293d650141SMartin KaFai Lau void **line_info, __u32 *cnt) 29303d650141SMartin KaFai Lau { 29313d650141SMartin KaFai Lau return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name, 29323d650141SMartin KaFai Lau insns_cnt, line_info, cnt); 29333d650141SMartin KaFai Lau } 29343d650141SMartin KaFai Lau 2935f0187f0bSMartin KaFai Lau __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext) 2936f0187f0bSMartin KaFai Lau { 29373d650141SMartin KaFai Lau return btf_ext->func_info.rec_size; 29383d650141SMartin KaFai Lau } 29393d650141SMartin KaFai Lau 29403d650141SMartin KaFai Lau __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext) 29413d650141SMartin KaFai Lau { 29423d650141SMartin KaFai Lau return btf_ext->line_info.rec_size; 29432993e051SYonghong Song } 2944d5caef5bSAndrii Nakryiko 2945d5caef5bSAndrii Nakryiko struct btf_dedup; 2946d5caef5bSAndrii Nakryiko 2947957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts); 2948d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d); 2949f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d); 2950d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d); 2951d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d); 2952d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d); 2953d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d); 2954d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d); 2955d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d); 2956d5caef5bSAndrii Nakryiko 2957d5caef5bSAndrii Nakryiko /* 2958d5caef5bSAndrii Nakryiko * Deduplicate BTF types and strings. 2959d5caef5bSAndrii Nakryiko * 2960d5caef5bSAndrii Nakryiko * BTF dedup algorithm takes as an input `struct btf` representing `.BTF` ELF 2961d5caef5bSAndrii Nakryiko * section with all BTF type descriptors and string data. It overwrites that 2962d5caef5bSAndrii Nakryiko * memory in-place with deduplicated types and strings without any loss of 2963d5caef5bSAndrii Nakryiko * information. If optional `struct btf_ext` representing '.BTF.ext' ELF section 2964d5caef5bSAndrii Nakryiko * is provided, all the strings referenced from .BTF.ext section are honored 2965d5caef5bSAndrii Nakryiko * and updated to point to the right offsets after deduplication. 2966d5caef5bSAndrii Nakryiko * 2967d5caef5bSAndrii Nakryiko * If function returns with error, type/string data might be garbled and should 2968d5caef5bSAndrii Nakryiko * be discarded. 2969d5caef5bSAndrii Nakryiko * 2970d5caef5bSAndrii Nakryiko * More verbose and detailed description of both problem btf_dedup is solving, 2971d5caef5bSAndrii Nakryiko * as well as solution could be found at: 2972d5caef5bSAndrii Nakryiko * https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html 2973d5caef5bSAndrii Nakryiko * 2974d5caef5bSAndrii Nakryiko * Problem description and justification 2975d5caef5bSAndrii Nakryiko * ===================================== 2976d5caef5bSAndrii Nakryiko * 2977d5caef5bSAndrii Nakryiko * BTF type information is typically emitted either as a result of conversion 2978d5caef5bSAndrii Nakryiko * from DWARF to BTF or directly by compiler. In both cases, each compilation 2979d5caef5bSAndrii Nakryiko * unit contains information about a subset of all the types that are used 2980d5caef5bSAndrii Nakryiko * in an application. These subsets are frequently overlapping and contain a lot 2981d5caef5bSAndrii Nakryiko * of duplicated information when later concatenated together into a single 2982d5caef5bSAndrii Nakryiko * binary. This algorithm ensures that each unique type is represented by single 2983d5caef5bSAndrii Nakryiko * BTF type descriptor, greatly reducing resulting size of BTF data. 2984d5caef5bSAndrii Nakryiko * 2985d5caef5bSAndrii Nakryiko * Compilation unit isolation and subsequent duplication of data is not the only 2986d5caef5bSAndrii Nakryiko * problem. The same type hierarchy (e.g., struct and all the type that struct 2987d5caef5bSAndrii Nakryiko * references) in different compilation units can be represented in BTF to 2988d5caef5bSAndrii Nakryiko * various degrees of completeness (or, rather, incompleteness) due to 2989d5caef5bSAndrii Nakryiko * struct/union forward declarations. 2990d5caef5bSAndrii Nakryiko * 2991d5caef5bSAndrii Nakryiko * Let's take a look at an example, that we'll use to better understand the 2992d5caef5bSAndrii Nakryiko * problem (and solution). Suppose we have two compilation units, each using 2993d5caef5bSAndrii Nakryiko * same `struct S`, but each of them having incomplete type information about 2994d5caef5bSAndrii Nakryiko * struct's fields: 2995d5caef5bSAndrii Nakryiko * 2996d5caef5bSAndrii Nakryiko * // CU #1: 2997d5caef5bSAndrii Nakryiko * struct S; 2998d5caef5bSAndrii Nakryiko * struct A { 2999d5caef5bSAndrii Nakryiko * int a; 3000d5caef5bSAndrii Nakryiko * struct A* self; 3001d5caef5bSAndrii Nakryiko * struct S* parent; 3002d5caef5bSAndrii Nakryiko * }; 3003d5caef5bSAndrii Nakryiko * struct B; 3004d5caef5bSAndrii Nakryiko * struct S { 3005d5caef5bSAndrii Nakryiko * struct A* a_ptr; 3006d5caef5bSAndrii Nakryiko * struct B* b_ptr; 3007d5caef5bSAndrii Nakryiko * }; 3008d5caef5bSAndrii Nakryiko * 3009d5caef5bSAndrii Nakryiko * // CU #2: 3010d5caef5bSAndrii Nakryiko * struct S; 3011d5caef5bSAndrii Nakryiko * struct A; 3012d5caef5bSAndrii Nakryiko * struct B { 3013d5caef5bSAndrii Nakryiko * int b; 3014d5caef5bSAndrii Nakryiko * struct B* self; 3015d5caef5bSAndrii Nakryiko * struct S* parent; 3016d5caef5bSAndrii Nakryiko * }; 3017d5caef5bSAndrii Nakryiko * struct S { 3018d5caef5bSAndrii Nakryiko * struct A* a_ptr; 3019d5caef5bSAndrii Nakryiko * struct B* b_ptr; 3020d5caef5bSAndrii Nakryiko * }; 3021d5caef5bSAndrii Nakryiko * 3022d5caef5bSAndrii Nakryiko * In case of CU #1, BTF data will know only that `struct B` exist (but no 3023d5caef5bSAndrii Nakryiko * more), but will know the complete type information about `struct A`. While 3024d5caef5bSAndrii Nakryiko * for CU #2, it will know full type information about `struct B`, but will 3025d5caef5bSAndrii Nakryiko * only know about forward declaration of `struct A` (in BTF terms, it will 3026d5caef5bSAndrii Nakryiko * have `BTF_KIND_FWD` type descriptor with name `B`). 3027d5caef5bSAndrii Nakryiko * 3028d5caef5bSAndrii Nakryiko * This compilation unit isolation means that it's possible that there is no 3029d5caef5bSAndrii Nakryiko * single CU with complete type information describing structs `S`, `A`, and 3030d5caef5bSAndrii Nakryiko * `B`. Also, we might get tons of duplicated and redundant type information. 3031d5caef5bSAndrii Nakryiko * 3032d5caef5bSAndrii Nakryiko * Additional complication we need to keep in mind comes from the fact that 3033d5caef5bSAndrii Nakryiko * types, in general, can form graphs containing cycles, not just DAGs. 3034d5caef5bSAndrii Nakryiko * 3035d5caef5bSAndrii Nakryiko * While algorithm does deduplication, it also merges and resolves type 3036d5caef5bSAndrii Nakryiko * information (unless disabled throught `struct btf_opts`), whenever possible. 3037d5caef5bSAndrii Nakryiko * E.g., in the example above with two compilation units having partial type 3038d5caef5bSAndrii Nakryiko * information for structs `A` and `B`, the output of algorithm will emit 3039d5caef5bSAndrii Nakryiko * a single copy of each BTF type that describes structs `A`, `B`, and `S` 3040d5caef5bSAndrii Nakryiko * (as well as type information for `int` and pointers), as if they were defined 3041d5caef5bSAndrii Nakryiko * in a single compilation unit as: 3042d5caef5bSAndrii Nakryiko * 3043d5caef5bSAndrii Nakryiko * struct A { 3044d5caef5bSAndrii Nakryiko * int a; 3045d5caef5bSAndrii Nakryiko * struct A* self; 3046d5caef5bSAndrii Nakryiko * struct S* parent; 3047d5caef5bSAndrii Nakryiko * }; 3048d5caef5bSAndrii Nakryiko * struct B { 3049d5caef5bSAndrii Nakryiko * int b; 3050d5caef5bSAndrii Nakryiko * struct B* self; 3051d5caef5bSAndrii Nakryiko * struct S* parent; 3052d5caef5bSAndrii Nakryiko * }; 3053d5caef5bSAndrii Nakryiko * struct S { 3054d5caef5bSAndrii Nakryiko * struct A* a_ptr; 3055d5caef5bSAndrii Nakryiko * struct B* b_ptr; 3056d5caef5bSAndrii Nakryiko * }; 3057d5caef5bSAndrii Nakryiko * 3058d5caef5bSAndrii Nakryiko * Algorithm summary 3059d5caef5bSAndrii Nakryiko * ================= 3060d5caef5bSAndrii Nakryiko * 3061d5caef5bSAndrii Nakryiko * Algorithm completes its work in 6 separate passes: 3062d5caef5bSAndrii Nakryiko * 3063d5caef5bSAndrii Nakryiko * 1. Strings deduplication. 3064d5caef5bSAndrii Nakryiko * 2. Primitive types deduplication (int, enum, fwd). 3065d5caef5bSAndrii Nakryiko * 3. Struct/union types deduplication. 3066d5caef5bSAndrii Nakryiko * 4. Reference types deduplication (pointers, typedefs, arrays, funcs, func 3067d5caef5bSAndrii Nakryiko * protos, and const/volatile/restrict modifiers). 3068d5caef5bSAndrii Nakryiko * 5. Types compaction. 3069d5caef5bSAndrii Nakryiko * 6. Types remapping. 3070d5caef5bSAndrii Nakryiko * 3071d5caef5bSAndrii Nakryiko * Algorithm determines canonical type descriptor, which is a single 3072d5caef5bSAndrii Nakryiko * representative type for each truly unique type. This canonical type is the 3073d5caef5bSAndrii Nakryiko * one that will go into final deduplicated BTF type information. For 3074d5caef5bSAndrii Nakryiko * struct/unions, it is also the type that algorithm will merge additional type 3075d5caef5bSAndrii Nakryiko * information into (while resolving FWDs), as it discovers it from data in 3076d5caef5bSAndrii Nakryiko * other CUs. Each input BTF type eventually gets either mapped to itself, if 3077d5caef5bSAndrii Nakryiko * that type is canonical, or to some other type, if that type is equivalent 3078d5caef5bSAndrii Nakryiko * and was chosen as canonical representative. This mapping is stored in 3079d5caef5bSAndrii Nakryiko * `btf_dedup->map` array. This map is also used to record STRUCT/UNION that 3080d5caef5bSAndrii Nakryiko * FWD type got resolved to. 3081d5caef5bSAndrii Nakryiko * 3082d5caef5bSAndrii Nakryiko * To facilitate fast discovery of canonical types, we also maintain canonical 3083d5caef5bSAndrii Nakryiko * index (`btf_dedup->dedup_table`), which maps type descriptor's signature hash 3084d5caef5bSAndrii Nakryiko * (i.e., hashed kind, name, size, fields, etc) into a list of canonical types 3085d5caef5bSAndrii Nakryiko * that match that signature. With sufficiently good choice of type signature 3086d5caef5bSAndrii Nakryiko * hashing function, we can limit number of canonical types for each unique type 3087d5caef5bSAndrii Nakryiko * signature to a very small number, allowing to find canonical type for any 3088d5caef5bSAndrii Nakryiko * duplicated type very quickly. 3089d5caef5bSAndrii Nakryiko * 3090d5caef5bSAndrii Nakryiko * Struct/union deduplication is the most critical part and algorithm for 3091d5caef5bSAndrii Nakryiko * deduplicating structs/unions is described in greater details in comments for 3092d5caef5bSAndrii Nakryiko * `btf_dedup_is_equiv` function. 3093d5caef5bSAndrii Nakryiko */ 3094957d350aSAndrii Nakryiko 3095957d350aSAndrii Nakryiko DEFAULT_VERSION(btf__dedup_v0_6_0, btf__dedup, LIBBPF_0.6.0) 3096957d350aSAndrii Nakryiko int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts) 3097d5caef5bSAndrii Nakryiko { 3098957d350aSAndrii Nakryiko struct btf_dedup *d; 3099d5caef5bSAndrii Nakryiko int err; 3100d5caef5bSAndrii Nakryiko 3101957d350aSAndrii Nakryiko if (!OPTS_VALID(opts, btf_dedup_opts)) 3102957d350aSAndrii Nakryiko return libbpf_err(-EINVAL); 3103957d350aSAndrii Nakryiko 3104957d350aSAndrii Nakryiko d = btf_dedup_new(btf, opts); 3105d5caef5bSAndrii Nakryiko if (IS_ERR(d)) { 3106d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d)); 3107e9fc3ce9SAndrii Nakryiko return libbpf_err(-EINVAL); 3108d5caef5bSAndrii Nakryiko } 3109d5caef5bSAndrii Nakryiko 31101000298cSMauricio Vásquez if (btf_ensure_modifiable(btf)) { 31111000298cSMauricio Vásquez err = -ENOMEM; 31121000298cSMauricio Vásquez goto done; 31131000298cSMauricio Vásquez } 3114919d2b1dSAndrii Nakryiko 3115f86524efSAndrii Nakryiko err = btf_dedup_prep(d); 3116f86524efSAndrii Nakryiko if (err) { 3117f86524efSAndrii Nakryiko pr_debug("btf_dedup_prep failed:%d\n", err); 3118f86524efSAndrii Nakryiko goto done; 3119f86524efSAndrii Nakryiko } 3120d5caef5bSAndrii Nakryiko err = btf_dedup_strings(d); 3121d5caef5bSAndrii Nakryiko if (err < 0) { 3122d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_strings failed:%d\n", err); 3123d5caef5bSAndrii Nakryiko goto done; 3124d5caef5bSAndrii Nakryiko } 3125d5caef5bSAndrii Nakryiko err = btf_dedup_prim_types(d); 3126d5caef5bSAndrii Nakryiko if (err < 0) { 3127d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_prim_types failed:%d\n", err); 3128d5caef5bSAndrii Nakryiko goto done; 3129d5caef5bSAndrii Nakryiko } 3130d5caef5bSAndrii Nakryiko err = btf_dedup_struct_types(d); 3131d5caef5bSAndrii Nakryiko if (err < 0) { 3132d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_struct_types failed:%d\n", err); 3133d5caef5bSAndrii Nakryiko goto done; 3134d5caef5bSAndrii Nakryiko } 3135d5caef5bSAndrii Nakryiko err = btf_dedup_ref_types(d); 3136d5caef5bSAndrii Nakryiko if (err < 0) { 3137d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_ref_types failed:%d\n", err); 3138d5caef5bSAndrii Nakryiko goto done; 3139d5caef5bSAndrii Nakryiko } 3140d5caef5bSAndrii Nakryiko err = btf_dedup_compact_types(d); 3141d5caef5bSAndrii Nakryiko if (err < 0) { 3142d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_compact_types failed:%d\n", err); 3143d5caef5bSAndrii Nakryiko goto done; 3144d5caef5bSAndrii Nakryiko } 3145d5caef5bSAndrii Nakryiko err = btf_dedup_remap_types(d); 3146d5caef5bSAndrii Nakryiko if (err < 0) { 3147d5caef5bSAndrii Nakryiko pr_debug("btf_dedup_remap_types failed:%d\n", err); 3148d5caef5bSAndrii Nakryiko goto done; 3149d5caef5bSAndrii Nakryiko } 3150d5caef5bSAndrii Nakryiko 3151d5caef5bSAndrii Nakryiko done: 3152d5caef5bSAndrii Nakryiko btf_dedup_free(d); 3153e9fc3ce9SAndrii Nakryiko return libbpf_err(err); 3154d5caef5bSAndrii Nakryiko } 3155d5caef5bSAndrii Nakryiko 3156b69c5c07SVincent Minet COMPAT_VERSION(btf__dedup_deprecated, btf__dedup, LIBBPF_0.0.2) 3157957d350aSAndrii Nakryiko int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *unused_opts) 3158957d350aSAndrii Nakryiko { 3159957d350aSAndrii Nakryiko LIBBPF_OPTS(btf_dedup_opts, opts, .btf_ext = btf_ext); 3160957d350aSAndrii Nakryiko 3161957d350aSAndrii Nakryiko if (unused_opts) { 3162957d350aSAndrii Nakryiko pr_warn("please use new version of btf__dedup() that supports options\n"); 3163957d350aSAndrii Nakryiko return libbpf_err(-ENOTSUP); 3164957d350aSAndrii Nakryiko } 3165957d350aSAndrii Nakryiko 3166957d350aSAndrii Nakryiko return btf__dedup(btf, &opts); 3167957d350aSAndrii Nakryiko } 3168957d350aSAndrii Nakryiko 3169d5caef5bSAndrii Nakryiko #define BTF_UNPROCESSED_ID ((__u32)-1) 3170d5caef5bSAndrii Nakryiko #define BTF_IN_PROGRESS_ID ((__u32)-2) 3171d5caef5bSAndrii Nakryiko 3172d5caef5bSAndrii Nakryiko struct btf_dedup { 3173d5caef5bSAndrii Nakryiko /* .BTF section to be deduped in-place */ 3174d5caef5bSAndrii Nakryiko struct btf *btf; 3175d5caef5bSAndrii Nakryiko /* 3176d5caef5bSAndrii Nakryiko * Optional .BTF.ext section. When provided, any strings referenced 3177d5caef5bSAndrii Nakryiko * from it will be taken into account when deduping strings 3178d5caef5bSAndrii Nakryiko */ 3179d5caef5bSAndrii Nakryiko struct btf_ext *btf_ext; 3180d5caef5bSAndrii Nakryiko /* 3181d5caef5bSAndrii Nakryiko * This is a map from any type's signature hash to a list of possible 3182d5caef5bSAndrii Nakryiko * canonical representative type candidates. Hash collisions are 3183d5caef5bSAndrii Nakryiko * ignored, so even types of various kinds can share same list of 3184d5caef5bSAndrii Nakryiko * candidates, which is fine because we rely on subsequent 3185d5caef5bSAndrii Nakryiko * btf_xxx_equal() checks to authoritatively verify type equality. 3186d5caef5bSAndrii Nakryiko */ 31872fc3fc0bSAndrii Nakryiko struct hashmap *dedup_table; 3188d5caef5bSAndrii Nakryiko /* Canonical types map */ 3189d5caef5bSAndrii Nakryiko __u32 *map; 3190d5caef5bSAndrii Nakryiko /* Hypothetical mapping, used during type graph equivalence checks */ 3191d5caef5bSAndrii Nakryiko __u32 *hypot_map; 3192d5caef5bSAndrii Nakryiko __u32 *hypot_list; 3193d5caef5bSAndrii Nakryiko size_t hypot_cnt; 3194d5caef5bSAndrii Nakryiko size_t hypot_cap; 3195f86524efSAndrii Nakryiko /* Whether hypothetical mapping, if successful, would need to adjust 3196f86524efSAndrii Nakryiko * already canonicalized types (due to a new forward declaration to 3197f86524efSAndrii Nakryiko * concrete type resolution). In such case, during split BTF dedup 3198f86524efSAndrii Nakryiko * candidate type would still be considered as different, because base 3199f86524efSAndrii Nakryiko * BTF is considered to be immutable. 3200f86524efSAndrii Nakryiko */ 3201f86524efSAndrii Nakryiko bool hypot_adjust_canon; 3202d5caef5bSAndrii Nakryiko /* Various option modifying behavior of algorithm */ 3203d5caef5bSAndrii Nakryiko struct btf_dedup_opts opts; 320488a82c2aSAndrii Nakryiko /* temporary strings deduplication state */ 320590d76d3eSAndrii Nakryiko struct strset *strs_set; 3206d5caef5bSAndrii Nakryiko }; 3207d5caef5bSAndrii Nakryiko 32082fc3fc0bSAndrii Nakryiko static long hash_combine(long h, long value) 3209d5caef5bSAndrii Nakryiko { 32102fc3fc0bSAndrii Nakryiko return h * 31 + value; 3211d5caef5bSAndrii Nakryiko } 3212d5caef5bSAndrii Nakryiko 32132fc3fc0bSAndrii Nakryiko #define for_each_dedup_cand(d, node, hash) \ 32142fc3fc0bSAndrii Nakryiko hashmap__for_each_key_entry(d->dedup_table, node, (void *)hash) 3215d5caef5bSAndrii Nakryiko 32162fc3fc0bSAndrii Nakryiko static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id) 3217d5caef5bSAndrii Nakryiko { 32182fc3fc0bSAndrii Nakryiko return hashmap__append(d->dedup_table, 32192fc3fc0bSAndrii Nakryiko (void *)hash, (void *)(long)type_id); 3220d5caef5bSAndrii Nakryiko } 3221d5caef5bSAndrii Nakryiko 3222d5caef5bSAndrii Nakryiko static int btf_dedup_hypot_map_add(struct btf_dedup *d, 3223d5caef5bSAndrii Nakryiko __u32 from_id, __u32 to_id) 3224d5caef5bSAndrii Nakryiko { 3225d5caef5bSAndrii Nakryiko if (d->hypot_cnt == d->hypot_cap) { 3226d5caef5bSAndrii Nakryiko __u32 *new_list; 3227d5caef5bSAndrii Nakryiko 3228fb2426adSMartin KaFai Lau d->hypot_cap += max((size_t)16, d->hypot_cap / 2); 3229029258d7SAndrii Nakryiko new_list = libbpf_reallocarray(d->hypot_list, d->hypot_cap, sizeof(__u32)); 3230d5caef5bSAndrii Nakryiko if (!new_list) 3231d5caef5bSAndrii Nakryiko return -ENOMEM; 3232d5caef5bSAndrii Nakryiko d->hypot_list = new_list; 3233d5caef5bSAndrii Nakryiko } 3234d5caef5bSAndrii Nakryiko d->hypot_list[d->hypot_cnt++] = from_id; 3235d5caef5bSAndrii Nakryiko d->hypot_map[from_id] = to_id; 3236d5caef5bSAndrii Nakryiko return 0; 3237d5caef5bSAndrii Nakryiko } 3238d5caef5bSAndrii Nakryiko 3239d5caef5bSAndrii Nakryiko static void btf_dedup_clear_hypot_map(struct btf_dedup *d) 3240d5caef5bSAndrii Nakryiko { 3241d5caef5bSAndrii Nakryiko int i; 3242d5caef5bSAndrii Nakryiko 3243d5caef5bSAndrii Nakryiko for (i = 0; i < d->hypot_cnt; i++) 3244d5caef5bSAndrii Nakryiko d->hypot_map[d->hypot_list[i]] = BTF_UNPROCESSED_ID; 3245d5caef5bSAndrii Nakryiko d->hypot_cnt = 0; 3246f86524efSAndrii Nakryiko d->hypot_adjust_canon = false; 3247d5caef5bSAndrii Nakryiko } 3248d5caef5bSAndrii Nakryiko 3249d5caef5bSAndrii Nakryiko static void btf_dedup_free(struct btf_dedup *d) 3250d5caef5bSAndrii Nakryiko { 32512fc3fc0bSAndrii Nakryiko hashmap__free(d->dedup_table); 32522fc3fc0bSAndrii Nakryiko d->dedup_table = NULL; 3253d5caef5bSAndrii Nakryiko 3254d5caef5bSAndrii Nakryiko free(d->map); 3255d5caef5bSAndrii Nakryiko d->map = NULL; 3256d5caef5bSAndrii Nakryiko 3257d5caef5bSAndrii Nakryiko free(d->hypot_map); 3258d5caef5bSAndrii Nakryiko d->hypot_map = NULL; 3259d5caef5bSAndrii Nakryiko 3260d5caef5bSAndrii Nakryiko free(d->hypot_list); 3261d5caef5bSAndrii Nakryiko d->hypot_list = NULL; 3262d5caef5bSAndrii Nakryiko 3263d5caef5bSAndrii Nakryiko free(d); 3264d5caef5bSAndrii Nakryiko } 3265d5caef5bSAndrii Nakryiko 32662fc3fc0bSAndrii Nakryiko static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx) 326751edf5f6SAndrii Nakryiko { 32682fc3fc0bSAndrii Nakryiko return (size_t)key; 326951edf5f6SAndrii Nakryiko } 327051edf5f6SAndrii Nakryiko 32712fc3fc0bSAndrii Nakryiko static size_t btf_dedup_collision_hash_fn(const void *key, void *ctx) 32722fc3fc0bSAndrii Nakryiko { 32732fc3fc0bSAndrii Nakryiko return 0; 32742fc3fc0bSAndrii Nakryiko } 32752fc3fc0bSAndrii Nakryiko 32762fc3fc0bSAndrii Nakryiko static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx) 32772fc3fc0bSAndrii Nakryiko { 32782fc3fc0bSAndrii Nakryiko return k1 == k2; 32792fc3fc0bSAndrii Nakryiko } 328051edf5f6SAndrii Nakryiko 3281957d350aSAndrii Nakryiko static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts) 3282d5caef5bSAndrii Nakryiko { 3283d5caef5bSAndrii Nakryiko struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup)); 32842fc3fc0bSAndrii Nakryiko hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn; 3285f86524efSAndrii Nakryiko int i, err = 0, type_cnt; 3286d5caef5bSAndrii Nakryiko 3287d5caef5bSAndrii Nakryiko if (!d) 3288d5caef5bSAndrii Nakryiko return ERR_PTR(-ENOMEM); 3289d5caef5bSAndrii Nakryiko 3290957d350aSAndrii Nakryiko if (OPTS_GET(opts, force_collisions, false)) 32912fc3fc0bSAndrii Nakryiko hash_fn = btf_dedup_collision_hash_fn; 329251edf5f6SAndrii Nakryiko 3293d5caef5bSAndrii Nakryiko d->btf = btf; 3294957d350aSAndrii Nakryiko d->btf_ext = OPTS_GET(opts, btf_ext, NULL); 3295d5caef5bSAndrii Nakryiko 32962fc3fc0bSAndrii Nakryiko d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL); 32972fc3fc0bSAndrii Nakryiko if (IS_ERR(d->dedup_table)) { 32982fc3fc0bSAndrii Nakryiko err = PTR_ERR(d->dedup_table); 32992fc3fc0bSAndrii Nakryiko d->dedup_table = NULL; 3300d5caef5bSAndrii Nakryiko goto done; 3301d5caef5bSAndrii Nakryiko } 3302d5caef5bSAndrii Nakryiko 33036a886de0SHengqi Chen type_cnt = btf__type_cnt(btf); 3304f86524efSAndrii Nakryiko d->map = malloc(sizeof(__u32) * type_cnt); 3305d5caef5bSAndrii Nakryiko if (!d->map) { 3306d5caef5bSAndrii Nakryiko err = -ENOMEM; 3307d5caef5bSAndrii Nakryiko goto done; 3308d5caef5bSAndrii Nakryiko } 3309d5caef5bSAndrii Nakryiko /* special BTF "void" type is made canonical immediately */ 3310d5caef5bSAndrii Nakryiko d->map[0] = 0; 3311f86524efSAndrii Nakryiko for (i = 1; i < type_cnt; i++) { 3312740e69c3SAndrii Nakryiko struct btf_type *t = btf_type_by_id(d->btf, i); 3313189cf5a4SAndrii Nakryiko 3314189cf5a4SAndrii Nakryiko /* VAR and DATASEC are never deduped and are self-canonical */ 3315b03bc685SAndrii Nakryiko if (btf_is_var(t) || btf_is_datasec(t)) 3316189cf5a4SAndrii Nakryiko d->map[i] = i; 3317189cf5a4SAndrii Nakryiko else 3318d5caef5bSAndrii Nakryiko d->map[i] = BTF_UNPROCESSED_ID; 3319189cf5a4SAndrii Nakryiko } 3320d5caef5bSAndrii Nakryiko 3321f86524efSAndrii Nakryiko d->hypot_map = malloc(sizeof(__u32) * type_cnt); 3322d5caef5bSAndrii Nakryiko if (!d->hypot_map) { 3323d5caef5bSAndrii Nakryiko err = -ENOMEM; 3324d5caef5bSAndrii Nakryiko goto done; 3325d5caef5bSAndrii Nakryiko } 3326f86524efSAndrii Nakryiko for (i = 0; i < type_cnt; i++) 3327d5caef5bSAndrii Nakryiko d->hypot_map[i] = BTF_UNPROCESSED_ID; 3328d5caef5bSAndrii Nakryiko 3329d5caef5bSAndrii Nakryiko done: 3330d5caef5bSAndrii Nakryiko if (err) { 3331d5caef5bSAndrii Nakryiko btf_dedup_free(d); 3332d5caef5bSAndrii Nakryiko return ERR_PTR(err); 3333d5caef5bSAndrii Nakryiko } 3334d5caef5bSAndrii Nakryiko 3335d5caef5bSAndrii Nakryiko return d; 3336d5caef5bSAndrii Nakryiko } 3337d5caef5bSAndrii Nakryiko 3338d5caef5bSAndrii Nakryiko /* 3339d5caef5bSAndrii Nakryiko * Iterate over all possible places in .BTF and .BTF.ext that can reference 3340d5caef5bSAndrii Nakryiko * string and pass pointer to it to a provided callback `fn`. 3341d5caef5bSAndrii Nakryiko */ 3342f36e99a4SAndrii Nakryiko static int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx) 3343d5caef5bSAndrii Nakryiko { 3344f36e99a4SAndrii Nakryiko int i, r; 3345d5caef5bSAndrii Nakryiko 3346f86524efSAndrii Nakryiko for (i = 0; i < d->btf->nr_types; i++) { 3347f36e99a4SAndrii Nakryiko struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i); 3348f36e99a4SAndrii Nakryiko 3349f36e99a4SAndrii Nakryiko r = btf_type_visit_str_offs(t, fn, ctx); 3350d5caef5bSAndrii Nakryiko if (r) 3351d5caef5bSAndrii Nakryiko return r; 3352d5caef5bSAndrii Nakryiko } 3353d5caef5bSAndrii Nakryiko 3354d5caef5bSAndrii Nakryiko if (!d->btf_ext) 3355d5caef5bSAndrii Nakryiko return 0; 3356d5caef5bSAndrii Nakryiko 3357f36e99a4SAndrii Nakryiko r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx); 3358d5caef5bSAndrii Nakryiko if (r) 3359d5caef5bSAndrii Nakryiko return r; 3360d5caef5bSAndrii Nakryiko 3361d5caef5bSAndrii Nakryiko return 0; 3362d5caef5bSAndrii Nakryiko } 3363d5caef5bSAndrii Nakryiko 336488a82c2aSAndrii Nakryiko static int strs_dedup_remap_str_off(__u32 *str_off_ptr, void *ctx) 3365d5caef5bSAndrii Nakryiko { 336688a82c2aSAndrii Nakryiko struct btf_dedup *d = ctx; 3367f86524efSAndrii Nakryiko __u32 str_off = *str_off_ptr; 336888a82c2aSAndrii Nakryiko const char *s; 336990d76d3eSAndrii Nakryiko int off, err; 3370d5caef5bSAndrii Nakryiko 3371f86524efSAndrii Nakryiko /* don't touch empty string or string in main BTF */ 3372f86524efSAndrii Nakryiko if (str_off == 0 || str_off < d->btf->start_str_off) 3373d5caef5bSAndrii Nakryiko return 0; 3374d5caef5bSAndrii Nakryiko 3375f86524efSAndrii Nakryiko s = btf__str_by_offset(d->btf, str_off); 3376f86524efSAndrii Nakryiko if (d->btf->base_btf) { 3377f86524efSAndrii Nakryiko err = btf__find_str(d->btf->base_btf, s); 3378f86524efSAndrii Nakryiko if (err >= 0) { 3379f86524efSAndrii Nakryiko *str_off_ptr = err; 3380f86524efSAndrii Nakryiko return 0; 3381f86524efSAndrii Nakryiko } 3382f86524efSAndrii Nakryiko if (err != -ENOENT) 3383f86524efSAndrii Nakryiko return err; 3384f86524efSAndrii Nakryiko } 3385f86524efSAndrii Nakryiko 338690d76d3eSAndrii Nakryiko off = strset__add_str(d->strs_set, s); 338790d76d3eSAndrii Nakryiko if (off < 0) 338890d76d3eSAndrii Nakryiko return off; 338988a82c2aSAndrii Nakryiko 339090d76d3eSAndrii Nakryiko *str_off_ptr = d->btf->start_str_off + off; 3391d5caef5bSAndrii Nakryiko return 0; 3392d5caef5bSAndrii Nakryiko } 3393d5caef5bSAndrii Nakryiko 3394d5caef5bSAndrii Nakryiko /* 3395d5caef5bSAndrii Nakryiko * Dedup string and filter out those that are not referenced from either .BTF 3396d5caef5bSAndrii Nakryiko * or .BTF.ext (if provided) sections. 3397d5caef5bSAndrii Nakryiko * 3398d5caef5bSAndrii Nakryiko * This is done by building index of all strings in BTF's string section, 3399d5caef5bSAndrii Nakryiko * then iterating over all entities that can reference strings (e.g., type 3400d5caef5bSAndrii Nakryiko * names, struct field names, .BTF.ext line info, etc) and marking corresponding 3401d5caef5bSAndrii Nakryiko * strings as used. After that all used strings are deduped and compacted into 3402d5caef5bSAndrii Nakryiko * sequential blob of memory and new offsets are calculated. Then all the string 3403d5caef5bSAndrii Nakryiko * references are iterated again and rewritten using new offsets. 3404d5caef5bSAndrii Nakryiko */ 3405d5caef5bSAndrii Nakryiko static int btf_dedup_strings(struct btf_dedup *d) 3406d5caef5bSAndrii Nakryiko { 340788a82c2aSAndrii Nakryiko int err; 3408d5caef5bSAndrii Nakryiko 3409919d2b1dSAndrii Nakryiko if (d->btf->strs_deduped) 3410919d2b1dSAndrii Nakryiko return 0; 3411919d2b1dSAndrii Nakryiko 341290d76d3eSAndrii Nakryiko d->strs_set = strset__new(BTF_MAX_STR_OFFSET, NULL, 0); 341390d76d3eSAndrii Nakryiko if (IS_ERR(d->strs_set)) { 341490d76d3eSAndrii Nakryiko err = PTR_ERR(d->strs_set); 341588a82c2aSAndrii Nakryiko goto err_out; 3416d5caef5bSAndrii Nakryiko } 3417d5caef5bSAndrii Nakryiko 3418f86524efSAndrii Nakryiko if (!d->btf->base_btf) { 341988a82c2aSAndrii Nakryiko /* insert empty string; we won't be looking it up during strings 342088a82c2aSAndrii Nakryiko * dedup, but it's good to have it for generic BTF string lookups 342188a82c2aSAndrii Nakryiko */ 342290d76d3eSAndrii Nakryiko err = strset__add_str(d->strs_set, ""); 342390d76d3eSAndrii Nakryiko if (err < 0) 342488a82c2aSAndrii Nakryiko goto err_out; 3425f86524efSAndrii Nakryiko } 3426d5caef5bSAndrii Nakryiko 3427d5caef5bSAndrii Nakryiko /* remap string offsets */ 342888a82c2aSAndrii Nakryiko err = btf_for_each_str_off(d, strs_dedup_remap_str_off, d); 3429d5caef5bSAndrii Nakryiko if (err) 343088a82c2aSAndrii Nakryiko goto err_out; 3431d5caef5bSAndrii Nakryiko 343288a82c2aSAndrii Nakryiko /* replace BTF string data and hash with deduped ones */ 343390d76d3eSAndrii Nakryiko strset__free(d->btf->strs_set); 343490d76d3eSAndrii Nakryiko d->btf->hdr->str_len = strset__data_size(d->strs_set); 343590d76d3eSAndrii Nakryiko d->btf->strs_set = d->strs_set; 343690d76d3eSAndrii Nakryiko d->strs_set = NULL; 3437919d2b1dSAndrii Nakryiko d->btf->strs_deduped = true; 343888a82c2aSAndrii Nakryiko return 0; 3439d5caef5bSAndrii Nakryiko 344088a82c2aSAndrii Nakryiko err_out: 344190d76d3eSAndrii Nakryiko strset__free(d->strs_set); 344290d76d3eSAndrii Nakryiko d->strs_set = NULL; 344388a82c2aSAndrii Nakryiko 3444d5caef5bSAndrii Nakryiko return err; 3445d5caef5bSAndrii Nakryiko } 3446d5caef5bSAndrii Nakryiko 34472fc3fc0bSAndrii Nakryiko static long btf_hash_common(struct btf_type *t) 3448d5caef5bSAndrii Nakryiko { 34492fc3fc0bSAndrii Nakryiko long h; 3450d5caef5bSAndrii Nakryiko 3451d5caef5bSAndrii Nakryiko h = hash_combine(0, t->name_off); 3452d5caef5bSAndrii Nakryiko h = hash_combine(h, t->info); 3453d5caef5bSAndrii Nakryiko h = hash_combine(h, t->size); 3454d5caef5bSAndrii Nakryiko return h; 3455d5caef5bSAndrii Nakryiko } 3456d5caef5bSAndrii Nakryiko 3457d5caef5bSAndrii Nakryiko static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2) 3458d5caef5bSAndrii Nakryiko { 3459d5caef5bSAndrii Nakryiko return t1->name_off == t2->name_off && 3460d5caef5bSAndrii Nakryiko t1->info == t2->info && 3461d5caef5bSAndrii Nakryiko t1->size == t2->size; 3462d5caef5bSAndrii Nakryiko } 3463d5caef5bSAndrii Nakryiko 346430025e8bSYonghong Song /* Calculate type signature hash of INT or TAG. */ 3465223f903eSYonghong Song static long btf_hash_int_decl_tag(struct btf_type *t) 3466d5caef5bSAndrii Nakryiko { 3467d5caef5bSAndrii Nakryiko __u32 info = *(__u32 *)(t + 1); 34682fc3fc0bSAndrii Nakryiko long h; 3469d5caef5bSAndrii Nakryiko 3470d5caef5bSAndrii Nakryiko h = btf_hash_common(t); 3471d5caef5bSAndrii Nakryiko h = hash_combine(h, info); 3472d5caef5bSAndrii Nakryiko return h; 3473d5caef5bSAndrii Nakryiko } 3474d5caef5bSAndrii Nakryiko 347530025e8bSYonghong Song /* Check structural equality of two INTs or TAGs. */ 347630025e8bSYonghong Song static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2) 3477d5caef5bSAndrii Nakryiko { 3478d5caef5bSAndrii Nakryiko __u32 info1, info2; 3479d5caef5bSAndrii Nakryiko 3480d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3481d5caef5bSAndrii Nakryiko return false; 3482d5caef5bSAndrii Nakryiko info1 = *(__u32 *)(t1 + 1); 3483d5caef5bSAndrii Nakryiko info2 = *(__u32 *)(t2 + 1); 3484d5caef5bSAndrii Nakryiko return info1 == info2; 3485d5caef5bSAndrii Nakryiko } 3486d5caef5bSAndrii Nakryiko 3487d5caef5bSAndrii Nakryiko /* Calculate type signature hash of ENUM. */ 34882fc3fc0bSAndrii Nakryiko static long btf_hash_enum(struct btf_type *t) 3489d5caef5bSAndrii Nakryiko { 34902fc3fc0bSAndrii Nakryiko long h; 3491d5caef5bSAndrii Nakryiko 34929768095bSAndrii Nakryiko /* don't hash vlen and enum members to support enum fwd resolving */ 34939768095bSAndrii Nakryiko h = hash_combine(0, t->name_off); 34949768095bSAndrii Nakryiko h = hash_combine(h, t->info & ~0xffff); 34959768095bSAndrii Nakryiko h = hash_combine(h, t->size); 3496d5caef5bSAndrii Nakryiko return h; 3497d5caef5bSAndrii Nakryiko } 3498d5caef5bSAndrii Nakryiko 3499d5caef5bSAndrii Nakryiko /* Check structural equality of two ENUMs. */ 3500d5caef5bSAndrii Nakryiko static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) 3501d5caef5bSAndrii Nakryiko { 3502b03bc685SAndrii Nakryiko const struct btf_enum *m1, *m2; 3503d5caef5bSAndrii Nakryiko __u16 vlen; 3504d5caef5bSAndrii Nakryiko int i; 3505d5caef5bSAndrii Nakryiko 3506d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3507d5caef5bSAndrii Nakryiko return false; 3508d5caef5bSAndrii Nakryiko 3509b03bc685SAndrii Nakryiko vlen = btf_vlen(t1); 3510b03bc685SAndrii Nakryiko m1 = btf_enum(t1); 3511b03bc685SAndrii Nakryiko m2 = btf_enum(t2); 3512d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3513d5caef5bSAndrii Nakryiko if (m1->name_off != m2->name_off || m1->val != m2->val) 3514d5caef5bSAndrii Nakryiko return false; 3515d5caef5bSAndrii Nakryiko m1++; 3516d5caef5bSAndrii Nakryiko m2++; 3517d5caef5bSAndrii Nakryiko } 3518d5caef5bSAndrii Nakryiko return true; 3519d5caef5bSAndrii Nakryiko } 3520d5caef5bSAndrii Nakryiko 35219768095bSAndrii Nakryiko static inline bool btf_is_enum_fwd(struct btf_type *t) 35229768095bSAndrii Nakryiko { 3523b03bc685SAndrii Nakryiko return btf_is_enum(t) && btf_vlen(t) == 0; 35249768095bSAndrii Nakryiko } 35259768095bSAndrii Nakryiko 35269768095bSAndrii Nakryiko static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2) 35279768095bSAndrii Nakryiko { 35289768095bSAndrii Nakryiko if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2)) 35299768095bSAndrii Nakryiko return btf_equal_enum(t1, t2); 35309768095bSAndrii Nakryiko /* ignore vlen when comparing */ 35319768095bSAndrii Nakryiko return t1->name_off == t2->name_off && 35329768095bSAndrii Nakryiko (t1->info & ~0xffff) == (t2->info & ~0xffff) && 35339768095bSAndrii Nakryiko t1->size == t2->size; 35349768095bSAndrii Nakryiko } 35359768095bSAndrii Nakryiko 3536d5caef5bSAndrii Nakryiko /* 3537d5caef5bSAndrii Nakryiko * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs, 3538d5caef5bSAndrii Nakryiko * as referenced type IDs equivalence is established separately during type 3539d5caef5bSAndrii Nakryiko * graph equivalence check algorithm. 3540d5caef5bSAndrii Nakryiko */ 35412fc3fc0bSAndrii Nakryiko static long btf_hash_struct(struct btf_type *t) 3542d5caef5bSAndrii Nakryiko { 3543b03bc685SAndrii Nakryiko const struct btf_member *member = btf_members(t); 3544b03bc685SAndrii Nakryiko __u32 vlen = btf_vlen(t); 35452fc3fc0bSAndrii Nakryiko long h = btf_hash_common(t); 3546d5caef5bSAndrii Nakryiko int i; 3547d5caef5bSAndrii Nakryiko 3548d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3549d5caef5bSAndrii Nakryiko h = hash_combine(h, member->name_off); 3550d5caef5bSAndrii Nakryiko h = hash_combine(h, member->offset); 3551d5caef5bSAndrii Nakryiko /* no hashing of referenced type ID, it can be unresolved yet */ 3552d5caef5bSAndrii Nakryiko member++; 3553d5caef5bSAndrii Nakryiko } 3554d5caef5bSAndrii Nakryiko return h; 3555d5caef5bSAndrii Nakryiko } 3556d5caef5bSAndrii Nakryiko 3557d5caef5bSAndrii Nakryiko /* 3558efdd3eb8SAndrii Nakryiko * Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced 3559efdd3eb8SAndrii Nakryiko * type IDs. This check is performed during type graph equivalence check and 3560d5caef5bSAndrii Nakryiko * referenced types equivalence is checked separately. 3561d5caef5bSAndrii Nakryiko */ 356291097fbeSAndrii Nakryiko static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2) 3563d5caef5bSAndrii Nakryiko { 3564b03bc685SAndrii Nakryiko const struct btf_member *m1, *m2; 3565d5caef5bSAndrii Nakryiko __u16 vlen; 3566d5caef5bSAndrii Nakryiko int i; 3567d5caef5bSAndrii Nakryiko 3568d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3569d5caef5bSAndrii Nakryiko return false; 3570d5caef5bSAndrii Nakryiko 3571b03bc685SAndrii Nakryiko vlen = btf_vlen(t1); 3572b03bc685SAndrii Nakryiko m1 = btf_members(t1); 3573b03bc685SAndrii Nakryiko m2 = btf_members(t2); 3574d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3575d5caef5bSAndrii Nakryiko if (m1->name_off != m2->name_off || m1->offset != m2->offset) 3576d5caef5bSAndrii Nakryiko return false; 3577d5caef5bSAndrii Nakryiko m1++; 3578d5caef5bSAndrii Nakryiko m2++; 3579d5caef5bSAndrii Nakryiko } 3580d5caef5bSAndrii Nakryiko return true; 3581d5caef5bSAndrii Nakryiko } 3582d5caef5bSAndrii Nakryiko 3583d5caef5bSAndrii Nakryiko /* 3584d5caef5bSAndrii Nakryiko * Calculate type signature hash of ARRAY, including referenced type IDs, 3585d5caef5bSAndrii Nakryiko * under assumption that they were already resolved to canonical type IDs and 3586d5caef5bSAndrii Nakryiko * are not going to change. 3587d5caef5bSAndrii Nakryiko */ 35882fc3fc0bSAndrii Nakryiko static long btf_hash_array(struct btf_type *t) 3589d5caef5bSAndrii Nakryiko { 3590b03bc685SAndrii Nakryiko const struct btf_array *info = btf_array(t); 35912fc3fc0bSAndrii Nakryiko long h = btf_hash_common(t); 3592d5caef5bSAndrii Nakryiko 3593d5caef5bSAndrii Nakryiko h = hash_combine(h, info->type); 3594d5caef5bSAndrii Nakryiko h = hash_combine(h, info->index_type); 3595d5caef5bSAndrii Nakryiko h = hash_combine(h, info->nelems); 3596d5caef5bSAndrii Nakryiko return h; 3597d5caef5bSAndrii Nakryiko } 3598d5caef5bSAndrii Nakryiko 3599d5caef5bSAndrii Nakryiko /* 3600d5caef5bSAndrii Nakryiko * Check exact equality of two ARRAYs, taking into account referenced 3601d5caef5bSAndrii Nakryiko * type IDs, under assumption that they were already resolved to canonical 3602d5caef5bSAndrii Nakryiko * type IDs and are not going to change. 3603d5caef5bSAndrii Nakryiko * This function is called during reference types deduplication to compare 3604d5caef5bSAndrii Nakryiko * ARRAY to potential canonical representative. 3605d5caef5bSAndrii Nakryiko */ 3606d5caef5bSAndrii Nakryiko static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2) 3607d5caef5bSAndrii Nakryiko { 3608b03bc685SAndrii Nakryiko const struct btf_array *info1, *info2; 3609d5caef5bSAndrii Nakryiko 3610d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3611d5caef5bSAndrii Nakryiko return false; 3612d5caef5bSAndrii Nakryiko 3613b03bc685SAndrii Nakryiko info1 = btf_array(t1); 3614b03bc685SAndrii Nakryiko info2 = btf_array(t2); 3615d5caef5bSAndrii Nakryiko return info1->type == info2->type && 3616d5caef5bSAndrii Nakryiko info1->index_type == info2->index_type && 3617d5caef5bSAndrii Nakryiko info1->nelems == info2->nelems; 3618d5caef5bSAndrii Nakryiko } 3619d5caef5bSAndrii Nakryiko 3620d5caef5bSAndrii Nakryiko /* 3621d5caef5bSAndrii Nakryiko * Check structural compatibility of two ARRAYs, ignoring referenced type 3622d5caef5bSAndrii Nakryiko * IDs. This check is performed during type graph equivalence check and 3623d5caef5bSAndrii Nakryiko * referenced types equivalence is checked separately. 3624d5caef5bSAndrii Nakryiko */ 3625d5caef5bSAndrii Nakryiko static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2) 3626d5caef5bSAndrii Nakryiko { 3627d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3628d5caef5bSAndrii Nakryiko return false; 3629d5caef5bSAndrii Nakryiko 3630b03bc685SAndrii Nakryiko return btf_array(t1)->nelems == btf_array(t2)->nelems; 3631d5caef5bSAndrii Nakryiko } 3632d5caef5bSAndrii Nakryiko 3633d5caef5bSAndrii Nakryiko /* 3634d5caef5bSAndrii Nakryiko * Calculate type signature hash of FUNC_PROTO, including referenced type IDs, 3635d5caef5bSAndrii Nakryiko * under assumption that they were already resolved to canonical type IDs and 3636d5caef5bSAndrii Nakryiko * are not going to change. 3637d5caef5bSAndrii Nakryiko */ 36382fc3fc0bSAndrii Nakryiko static long btf_hash_fnproto(struct btf_type *t) 3639d5caef5bSAndrii Nakryiko { 3640b03bc685SAndrii Nakryiko const struct btf_param *member = btf_params(t); 3641b03bc685SAndrii Nakryiko __u16 vlen = btf_vlen(t); 36422fc3fc0bSAndrii Nakryiko long h = btf_hash_common(t); 3643d5caef5bSAndrii Nakryiko int i; 3644d5caef5bSAndrii Nakryiko 3645d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3646d5caef5bSAndrii Nakryiko h = hash_combine(h, member->name_off); 3647d5caef5bSAndrii Nakryiko h = hash_combine(h, member->type); 3648d5caef5bSAndrii Nakryiko member++; 3649d5caef5bSAndrii Nakryiko } 3650d5caef5bSAndrii Nakryiko return h; 3651d5caef5bSAndrii Nakryiko } 3652d5caef5bSAndrii Nakryiko 3653d5caef5bSAndrii Nakryiko /* 3654d5caef5bSAndrii Nakryiko * Check exact equality of two FUNC_PROTOs, taking into account referenced 3655d5caef5bSAndrii Nakryiko * type IDs, under assumption that they were already resolved to canonical 3656d5caef5bSAndrii Nakryiko * type IDs and are not going to change. 3657d5caef5bSAndrii Nakryiko * This function is called during reference types deduplication to compare 3658d5caef5bSAndrii Nakryiko * FUNC_PROTO to potential canonical representative. 3659d5caef5bSAndrii Nakryiko */ 36602fc3fc0bSAndrii Nakryiko static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2) 3661d5caef5bSAndrii Nakryiko { 3662b03bc685SAndrii Nakryiko const struct btf_param *m1, *m2; 3663d5caef5bSAndrii Nakryiko __u16 vlen; 3664d5caef5bSAndrii Nakryiko int i; 3665d5caef5bSAndrii Nakryiko 3666d5caef5bSAndrii Nakryiko if (!btf_equal_common(t1, t2)) 3667d5caef5bSAndrii Nakryiko return false; 3668d5caef5bSAndrii Nakryiko 3669b03bc685SAndrii Nakryiko vlen = btf_vlen(t1); 3670b03bc685SAndrii Nakryiko m1 = btf_params(t1); 3671b03bc685SAndrii Nakryiko m2 = btf_params(t2); 3672d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3673d5caef5bSAndrii Nakryiko if (m1->name_off != m2->name_off || m1->type != m2->type) 3674d5caef5bSAndrii Nakryiko return false; 3675d5caef5bSAndrii Nakryiko m1++; 3676d5caef5bSAndrii Nakryiko m2++; 3677d5caef5bSAndrii Nakryiko } 3678d5caef5bSAndrii Nakryiko return true; 3679d5caef5bSAndrii Nakryiko } 3680d5caef5bSAndrii Nakryiko 3681d5caef5bSAndrii Nakryiko /* 3682d5caef5bSAndrii Nakryiko * Check structural compatibility of two FUNC_PROTOs, ignoring referenced type 3683d5caef5bSAndrii Nakryiko * IDs. This check is performed during type graph equivalence check and 3684d5caef5bSAndrii Nakryiko * referenced types equivalence is checked separately. 3685d5caef5bSAndrii Nakryiko */ 36862fc3fc0bSAndrii Nakryiko static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2) 3687d5caef5bSAndrii Nakryiko { 3688b03bc685SAndrii Nakryiko const struct btf_param *m1, *m2; 3689d5caef5bSAndrii Nakryiko __u16 vlen; 3690d5caef5bSAndrii Nakryiko int i; 3691d5caef5bSAndrii Nakryiko 3692d5caef5bSAndrii Nakryiko /* skip return type ID */ 3693d5caef5bSAndrii Nakryiko if (t1->name_off != t2->name_off || t1->info != t2->info) 3694d5caef5bSAndrii Nakryiko return false; 3695d5caef5bSAndrii Nakryiko 3696b03bc685SAndrii Nakryiko vlen = btf_vlen(t1); 3697b03bc685SAndrii Nakryiko m1 = btf_params(t1); 3698b03bc685SAndrii Nakryiko m2 = btf_params(t2); 3699d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 3700d5caef5bSAndrii Nakryiko if (m1->name_off != m2->name_off) 3701d5caef5bSAndrii Nakryiko return false; 3702d5caef5bSAndrii Nakryiko m1++; 3703d5caef5bSAndrii Nakryiko m2++; 3704d5caef5bSAndrii Nakryiko } 3705d5caef5bSAndrii Nakryiko return true; 3706d5caef5bSAndrii Nakryiko } 3707d5caef5bSAndrii Nakryiko 3708f86524efSAndrii Nakryiko /* Prepare split BTF for deduplication by calculating hashes of base BTF's 3709f86524efSAndrii Nakryiko * types and initializing the rest of the state (canonical type mapping) for 3710f86524efSAndrii Nakryiko * the fixed base BTF part. 3711f86524efSAndrii Nakryiko */ 3712f86524efSAndrii Nakryiko static int btf_dedup_prep(struct btf_dedup *d) 3713f86524efSAndrii Nakryiko { 3714f86524efSAndrii Nakryiko struct btf_type *t; 3715f86524efSAndrii Nakryiko int type_id; 3716f86524efSAndrii Nakryiko long h; 3717f86524efSAndrii Nakryiko 3718f86524efSAndrii Nakryiko if (!d->btf->base_btf) 3719f86524efSAndrii Nakryiko return 0; 3720f86524efSAndrii Nakryiko 3721f86524efSAndrii Nakryiko for (type_id = 1; type_id < d->btf->start_id; type_id++) { 3722f86524efSAndrii Nakryiko t = btf_type_by_id(d->btf, type_id); 3723f86524efSAndrii Nakryiko 3724f86524efSAndrii Nakryiko /* all base BTF types are self-canonical by definition */ 3725f86524efSAndrii Nakryiko d->map[type_id] = type_id; 3726f86524efSAndrii Nakryiko 3727f86524efSAndrii Nakryiko switch (btf_kind(t)) { 3728f86524efSAndrii Nakryiko case BTF_KIND_VAR: 3729f86524efSAndrii Nakryiko case BTF_KIND_DATASEC: 3730f86524efSAndrii Nakryiko /* VAR and DATASEC are never hash/deduplicated */ 3731f86524efSAndrii Nakryiko continue; 3732f86524efSAndrii Nakryiko case BTF_KIND_CONST: 3733f86524efSAndrii Nakryiko case BTF_KIND_VOLATILE: 3734f86524efSAndrii Nakryiko case BTF_KIND_RESTRICT: 3735f86524efSAndrii Nakryiko case BTF_KIND_PTR: 3736f86524efSAndrii Nakryiko case BTF_KIND_FWD: 3737f86524efSAndrii Nakryiko case BTF_KIND_TYPEDEF: 3738f86524efSAndrii Nakryiko case BTF_KIND_FUNC: 373922541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 37402dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 3741f86524efSAndrii Nakryiko h = btf_hash_common(t); 3742f86524efSAndrii Nakryiko break; 3743f86524efSAndrii Nakryiko case BTF_KIND_INT: 3744223f903eSYonghong Song case BTF_KIND_DECL_TAG: 3745223f903eSYonghong Song h = btf_hash_int_decl_tag(t); 3746f86524efSAndrii Nakryiko break; 3747f86524efSAndrii Nakryiko case BTF_KIND_ENUM: 3748f86524efSAndrii Nakryiko h = btf_hash_enum(t); 3749f86524efSAndrii Nakryiko break; 3750f86524efSAndrii Nakryiko case BTF_KIND_STRUCT: 3751f86524efSAndrii Nakryiko case BTF_KIND_UNION: 3752f86524efSAndrii Nakryiko h = btf_hash_struct(t); 3753f86524efSAndrii Nakryiko break; 3754f86524efSAndrii Nakryiko case BTF_KIND_ARRAY: 3755f86524efSAndrii Nakryiko h = btf_hash_array(t); 3756f86524efSAndrii Nakryiko break; 3757f86524efSAndrii Nakryiko case BTF_KIND_FUNC_PROTO: 3758f86524efSAndrii Nakryiko h = btf_hash_fnproto(t); 3759f86524efSAndrii Nakryiko break; 3760f86524efSAndrii Nakryiko default: 3761f86524efSAndrii Nakryiko pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id); 3762f86524efSAndrii Nakryiko return -EINVAL; 3763f86524efSAndrii Nakryiko } 3764f86524efSAndrii Nakryiko if (btf_dedup_table_add(d, h, type_id)) 3765f86524efSAndrii Nakryiko return -ENOMEM; 3766f86524efSAndrii Nakryiko } 3767f86524efSAndrii Nakryiko 3768f86524efSAndrii Nakryiko return 0; 3769f86524efSAndrii Nakryiko } 3770f86524efSAndrii Nakryiko 3771d5caef5bSAndrii Nakryiko /* 3772d5caef5bSAndrii Nakryiko * Deduplicate primitive types, that can't reference other types, by calculating 3773d5caef5bSAndrii Nakryiko * their type signature hash and comparing them with any possible canonical 3774d5caef5bSAndrii Nakryiko * candidate. If no canonical candidate matches, type itself is marked as 3775d5caef5bSAndrii Nakryiko * canonical and is added into `btf_dedup->dedup_table` as another candidate. 3776d5caef5bSAndrii Nakryiko */ 3777d5caef5bSAndrii Nakryiko static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id) 3778d5caef5bSAndrii Nakryiko { 3779740e69c3SAndrii Nakryiko struct btf_type *t = btf_type_by_id(d->btf, type_id); 37802fc3fc0bSAndrii Nakryiko struct hashmap_entry *hash_entry; 3781d5caef5bSAndrii Nakryiko struct btf_type *cand; 3782d5caef5bSAndrii Nakryiko /* if we don't find equivalent type, then we are canonical */ 3783d5caef5bSAndrii Nakryiko __u32 new_id = type_id; 37842fc3fc0bSAndrii Nakryiko __u32 cand_id; 37852fc3fc0bSAndrii Nakryiko long h; 3786d5caef5bSAndrii Nakryiko 3787b03bc685SAndrii Nakryiko switch (btf_kind(t)) { 3788d5caef5bSAndrii Nakryiko case BTF_KIND_CONST: 3789d5caef5bSAndrii Nakryiko case BTF_KIND_VOLATILE: 3790d5caef5bSAndrii Nakryiko case BTF_KIND_RESTRICT: 3791d5caef5bSAndrii Nakryiko case BTF_KIND_PTR: 3792d5caef5bSAndrii Nakryiko case BTF_KIND_TYPEDEF: 3793d5caef5bSAndrii Nakryiko case BTF_KIND_ARRAY: 3794d5caef5bSAndrii Nakryiko case BTF_KIND_STRUCT: 3795d5caef5bSAndrii Nakryiko case BTF_KIND_UNION: 3796d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC: 3797d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC_PROTO: 3798189cf5a4SAndrii Nakryiko case BTF_KIND_VAR: 3799189cf5a4SAndrii Nakryiko case BTF_KIND_DATASEC: 3800223f903eSYonghong Song case BTF_KIND_DECL_TAG: 38012dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 3802d5caef5bSAndrii Nakryiko return 0; 3803d5caef5bSAndrii Nakryiko 3804d5caef5bSAndrii Nakryiko case BTF_KIND_INT: 3805223f903eSYonghong Song h = btf_hash_int_decl_tag(t); 38062fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 38072fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 3808740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 380930025e8bSYonghong Song if (btf_equal_int_tag(t, cand)) { 38102fc3fc0bSAndrii Nakryiko new_id = cand_id; 3811d5caef5bSAndrii Nakryiko break; 3812d5caef5bSAndrii Nakryiko } 3813d5caef5bSAndrii Nakryiko } 3814d5caef5bSAndrii Nakryiko break; 3815d5caef5bSAndrii Nakryiko 3816d5caef5bSAndrii Nakryiko case BTF_KIND_ENUM: 3817d5caef5bSAndrii Nakryiko h = btf_hash_enum(t); 38182fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 38192fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 3820740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 3821d5caef5bSAndrii Nakryiko if (btf_equal_enum(t, cand)) { 38222fc3fc0bSAndrii Nakryiko new_id = cand_id; 3823d5caef5bSAndrii Nakryiko break; 3824d5caef5bSAndrii Nakryiko } 38259768095bSAndrii Nakryiko if (btf_compat_enum(t, cand)) { 38269768095bSAndrii Nakryiko if (btf_is_enum_fwd(t)) { 38279768095bSAndrii Nakryiko /* resolve fwd to full enum */ 38282fc3fc0bSAndrii Nakryiko new_id = cand_id; 38299768095bSAndrii Nakryiko break; 38309768095bSAndrii Nakryiko } 38319768095bSAndrii Nakryiko /* resolve canonical enum fwd to full enum */ 38322fc3fc0bSAndrii Nakryiko d->map[cand_id] = type_id; 38339768095bSAndrii Nakryiko } 3834d5caef5bSAndrii Nakryiko } 3835d5caef5bSAndrii Nakryiko break; 3836d5caef5bSAndrii Nakryiko 3837d5caef5bSAndrii Nakryiko case BTF_KIND_FWD: 383822541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 3839d5caef5bSAndrii Nakryiko h = btf_hash_common(t); 38402fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 38412fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 3842740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 3843d5caef5bSAndrii Nakryiko if (btf_equal_common(t, cand)) { 38442fc3fc0bSAndrii Nakryiko new_id = cand_id; 3845d5caef5bSAndrii Nakryiko break; 3846d5caef5bSAndrii Nakryiko } 3847d5caef5bSAndrii Nakryiko } 3848d5caef5bSAndrii Nakryiko break; 3849d5caef5bSAndrii Nakryiko 3850d5caef5bSAndrii Nakryiko default: 3851d5caef5bSAndrii Nakryiko return -EINVAL; 3852d5caef5bSAndrii Nakryiko } 3853d5caef5bSAndrii Nakryiko 3854d5caef5bSAndrii Nakryiko d->map[type_id] = new_id; 3855d5caef5bSAndrii Nakryiko if (type_id == new_id && btf_dedup_table_add(d, h, type_id)) 3856d5caef5bSAndrii Nakryiko return -ENOMEM; 3857d5caef5bSAndrii Nakryiko 3858d5caef5bSAndrii Nakryiko return 0; 3859d5caef5bSAndrii Nakryiko } 3860d5caef5bSAndrii Nakryiko 3861d5caef5bSAndrii Nakryiko static int btf_dedup_prim_types(struct btf_dedup *d) 3862d5caef5bSAndrii Nakryiko { 3863d5caef5bSAndrii Nakryiko int i, err; 3864d5caef5bSAndrii Nakryiko 3865f86524efSAndrii Nakryiko for (i = 0; i < d->btf->nr_types; i++) { 3866f86524efSAndrii Nakryiko err = btf_dedup_prim_type(d, d->btf->start_id + i); 3867d5caef5bSAndrii Nakryiko if (err) 3868d5caef5bSAndrii Nakryiko return err; 3869d5caef5bSAndrii Nakryiko } 3870d5caef5bSAndrii Nakryiko return 0; 3871d5caef5bSAndrii Nakryiko } 3872d5caef5bSAndrii Nakryiko 3873d5caef5bSAndrii Nakryiko /* 3874d5caef5bSAndrii Nakryiko * Check whether type is already mapped into canonical one (could be to itself). 3875d5caef5bSAndrii Nakryiko */ 3876d5caef5bSAndrii Nakryiko static inline bool is_type_mapped(struct btf_dedup *d, uint32_t type_id) 3877d5caef5bSAndrii Nakryiko { 38785aab392cSAndrii Nakryiko return d->map[type_id] <= BTF_MAX_NR_TYPES; 3879d5caef5bSAndrii Nakryiko } 3880d5caef5bSAndrii Nakryiko 3881d5caef5bSAndrii Nakryiko /* 3882d5caef5bSAndrii Nakryiko * Resolve type ID into its canonical type ID, if any; otherwise return original 3883d5caef5bSAndrii Nakryiko * type ID. If type is FWD and is resolved into STRUCT/UNION already, follow 3884d5caef5bSAndrii Nakryiko * STRUCT/UNION link and resolve it into canonical type ID as well. 3885d5caef5bSAndrii Nakryiko */ 3886d5caef5bSAndrii Nakryiko static inline __u32 resolve_type_id(struct btf_dedup *d, __u32 type_id) 3887d5caef5bSAndrii Nakryiko { 3888d5caef5bSAndrii Nakryiko while (is_type_mapped(d, type_id) && d->map[type_id] != type_id) 3889d5caef5bSAndrii Nakryiko type_id = d->map[type_id]; 3890d5caef5bSAndrii Nakryiko return type_id; 3891d5caef5bSAndrii Nakryiko } 3892d5caef5bSAndrii Nakryiko 3893d5caef5bSAndrii Nakryiko /* 3894d5caef5bSAndrii Nakryiko * Resolve FWD to underlying STRUCT/UNION, if any; otherwise return original 3895d5caef5bSAndrii Nakryiko * type ID. 3896d5caef5bSAndrii Nakryiko */ 3897d5caef5bSAndrii Nakryiko static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id) 3898d5caef5bSAndrii Nakryiko { 3899d5caef5bSAndrii Nakryiko __u32 orig_type_id = type_id; 3900d5caef5bSAndrii Nakryiko 3901740e69c3SAndrii Nakryiko if (!btf_is_fwd(btf__type_by_id(d->btf, type_id))) 3902d5caef5bSAndrii Nakryiko return type_id; 3903d5caef5bSAndrii Nakryiko 3904d5caef5bSAndrii Nakryiko while (is_type_mapped(d, type_id) && d->map[type_id] != type_id) 3905d5caef5bSAndrii Nakryiko type_id = d->map[type_id]; 3906d5caef5bSAndrii Nakryiko 3907740e69c3SAndrii Nakryiko if (!btf_is_fwd(btf__type_by_id(d->btf, type_id))) 3908d5caef5bSAndrii Nakryiko return type_id; 3909d5caef5bSAndrii Nakryiko 3910d5caef5bSAndrii Nakryiko return orig_type_id; 3911d5caef5bSAndrii Nakryiko } 3912d5caef5bSAndrii Nakryiko 3913d5caef5bSAndrii Nakryiko 3914d5caef5bSAndrii Nakryiko static inline __u16 btf_fwd_kind(struct btf_type *t) 3915d5caef5bSAndrii Nakryiko { 3916b03bc685SAndrii Nakryiko return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT; 3917d5caef5bSAndrii Nakryiko } 3918d5caef5bSAndrii Nakryiko 39196b6e6b1dSAndrii Nakryiko /* Check if given two types are identical ARRAY definitions */ 39206b6e6b1dSAndrii Nakryiko static int btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2) 39216b6e6b1dSAndrii Nakryiko { 39226b6e6b1dSAndrii Nakryiko struct btf_type *t1, *t2; 39236b6e6b1dSAndrii Nakryiko 39246b6e6b1dSAndrii Nakryiko t1 = btf_type_by_id(d->btf, id1); 39256b6e6b1dSAndrii Nakryiko t2 = btf_type_by_id(d->btf, id2); 39266b6e6b1dSAndrii Nakryiko if (!btf_is_array(t1) || !btf_is_array(t2)) 39276b6e6b1dSAndrii Nakryiko return 0; 39286b6e6b1dSAndrii Nakryiko 39296b6e6b1dSAndrii Nakryiko return btf_equal_array(t1, t2); 39306b6e6b1dSAndrii Nakryiko } 39316b6e6b1dSAndrii Nakryiko 3932efdd3eb8SAndrii Nakryiko /* Check if given two types are identical STRUCT/UNION definitions */ 3933efdd3eb8SAndrii Nakryiko static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2) 3934efdd3eb8SAndrii Nakryiko { 3935efdd3eb8SAndrii Nakryiko const struct btf_member *m1, *m2; 3936efdd3eb8SAndrii Nakryiko struct btf_type *t1, *t2; 3937efdd3eb8SAndrii Nakryiko int n, i; 3938efdd3eb8SAndrii Nakryiko 3939efdd3eb8SAndrii Nakryiko t1 = btf_type_by_id(d->btf, id1); 3940efdd3eb8SAndrii Nakryiko t2 = btf_type_by_id(d->btf, id2); 3941efdd3eb8SAndrii Nakryiko 3942efdd3eb8SAndrii Nakryiko if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2)) 3943efdd3eb8SAndrii Nakryiko return false; 3944efdd3eb8SAndrii Nakryiko 3945efdd3eb8SAndrii Nakryiko if (!btf_shallow_equal_struct(t1, t2)) 3946efdd3eb8SAndrii Nakryiko return false; 3947efdd3eb8SAndrii Nakryiko 3948efdd3eb8SAndrii Nakryiko m1 = btf_members(t1); 3949efdd3eb8SAndrii Nakryiko m2 = btf_members(t2); 3950efdd3eb8SAndrii Nakryiko for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) { 3951efdd3eb8SAndrii Nakryiko if (m1->type != m2->type) 3952efdd3eb8SAndrii Nakryiko return false; 3953efdd3eb8SAndrii Nakryiko } 3954efdd3eb8SAndrii Nakryiko return true; 3955efdd3eb8SAndrii Nakryiko } 3956efdd3eb8SAndrii Nakryiko 3957d5caef5bSAndrii Nakryiko /* 3958d5caef5bSAndrii Nakryiko * Check equivalence of BTF type graph formed by candidate struct/union (we'll 3959d5caef5bSAndrii Nakryiko * call it "candidate graph" in this description for brevity) to a type graph 3960d5caef5bSAndrii Nakryiko * formed by (potential) canonical struct/union ("canonical graph" for brevity 3961d5caef5bSAndrii Nakryiko * here, though keep in mind that not all types in canonical graph are 3962d5caef5bSAndrii Nakryiko * necessarily canonical representatives themselves, some of them might be 3963d5caef5bSAndrii Nakryiko * duplicates or its uniqueness might not have been established yet). 3964d5caef5bSAndrii Nakryiko * Returns: 3965d5caef5bSAndrii Nakryiko * - >0, if type graphs are equivalent; 3966d5caef5bSAndrii Nakryiko * - 0, if not equivalent; 3967d5caef5bSAndrii Nakryiko * - <0, on error. 3968d5caef5bSAndrii Nakryiko * 3969d5caef5bSAndrii Nakryiko * Algorithm performs side-by-side DFS traversal of both type graphs and checks 3970d5caef5bSAndrii Nakryiko * equivalence of BTF types at each step. If at any point BTF types in candidate 3971d5caef5bSAndrii Nakryiko * and canonical graphs are not compatible structurally, whole graphs are 3972d5caef5bSAndrii Nakryiko * incompatible. If types are structurally equivalent (i.e., all information 3973d5caef5bSAndrii Nakryiko * except referenced type IDs is exactly the same), a mapping from `canon_id` to 3974d5caef5bSAndrii Nakryiko * a `cand_id` is recored in hypothetical mapping (`btf_dedup->hypot_map`). 3975d5caef5bSAndrii Nakryiko * If a type references other types, then those referenced types are checked 3976d5caef5bSAndrii Nakryiko * for equivalence recursively. 3977d5caef5bSAndrii Nakryiko * 3978d5caef5bSAndrii Nakryiko * During DFS traversal, if we find that for current `canon_id` type we 3979d5caef5bSAndrii Nakryiko * already have some mapping in hypothetical map, we check for two possible 3980d5caef5bSAndrii Nakryiko * situations: 3981d5caef5bSAndrii Nakryiko * - `canon_id` is mapped to exactly the same type as `cand_id`. This will 3982d5caef5bSAndrii Nakryiko * happen when type graphs have cycles. In this case we assume those two 3983d5caef5bSAndrii Nakryiko * types are equivalent. 3984d5caef5bSAndrii Nakryiko * - `canon_id` is mapped to different type. This is contradiction in our 3985d5caef5bSAndrii Nakryiko * hypothetical mapping, because same graph in canonical graph corresponds 3986d5caef5bSAndrii Nakryiko * to two different types in candidate graph, which for equivalent type 3987d5caef5bSAndrii Nakryiko * graphs shouldn't happen. This condition terminates equivalence check 3988d5caef5bSAndrii Nakryiko * with negative result. 3989d5caef5bSAndrii Nakryiko * 3990d5caef5bSAndrii Nakryiko * If type graphs traversal exhausts types to check and find no contradiction, 3991d5caef5bSAndrii Nakryiko * then type graphs are equivalent. 3992d5caef5bSAndrii Nakryiko * 3993d5caef5bSAndrii Nakryiko * When checking types for equivalence, there is one special case: FWD types. 3994d5caef5bSAndrii Nakryiko * If FWD type resolution is allowed and one of the types (either from canonical 3995d5caef5bSAndrii Nakryiko * or candidate graph) is FWD and other is STRUCT/UNION (depending on FWD's kind 3996d5caef5bSAndrii Nakryiko * flag) and their names match, hypothetical mapping is updated to point from 3997d5caef5bSAndrii Nakryiko * FWD to STRUCT/UNION. If graphs will be determined as equivalent successfully, 3998d5caef5bSAndrii Nakryiko * this mapping will be used to record FWD -> STRUCT/UNION mapping permanently. 3999d5caef5bSAndrii Nakryiko * 4000d5caef5bSAndrii Nakryiko * Technically, this could lead to incorrect FWD to STRUCT/UNION resolution, 4001d5caef5bSAndrii Nakryiko * if there are two exactly named (or anonymous) structs/unions that are 4002d5caef5bSAndrii Nakryiko * compatible structurally, one of which has FWD field, while other is concrete 4003d5caef5bSAndrii Nakryiko * STRUCT/UNION, but according to C sources they are different structs/unions 4004d5caef5bSAndrii Nakryiko * that are referencing different types with the same name. This is extremely 4005d5caef5bSAndrii Nakryiko * unlikely to happen, but btf_dedup API allows to disable FWD resolution if 4006d5caef5bSAndrii Nakryiko * this logic is causing problems. 4007d5caef5bSAndrii Nakryiko * 4008d5caef5bSAndrii Nakryiko * Doing FWD resolution means that both candidate and/or canonical graphs can 4009d5caef5bSAndrii Nakryiko * consists of portions of the graph that come from multiple compilation units. 4010d5caef5bSAndrii Nakryiko * This is due to the fact that types within single compilation unit are always 4011d5caef5bSAndrii Nakryiko * deduplicated and FWDs are already resolved, if referenced struct/union 4012d5caef5bSAndrii Nakryiko * definiton is available. So, if we had unresolved FWD and found corresponding 4013d5caef5bSAndrii Nakryiko * STRUCT/UNION, they will be from different compilation units. This 4014d5caef5bSAndrii Nakryiko * consequently means that when we "link" FWD to corresponding STRUCT/UNION, 4015d5caef5bSAndrii Nakryiko * type graph will likely have at least two different BTF types that describe 4016d5caef5bSAndrii Nakryiko * same type (e.g., most probably there will be two different BTF types for the 4017d5caef5bSAndrii Nakryiko * same 'int' primitive type) and could even have "overlapping" parts of type 4018d5caef5bSAndrii Nakryiko * graph that describe same subset of types. 4019d5caef5bSAndrii Nakryiko * 4020d5caef5bSAndrii Nakryiko * This in turn means that our assumption that each type in canonical graph 4021d5caef5bSAndrii Nakryiko * must correspond to exactly one type in candidate graph might not hold 4022d5caef5bSAndrii Nakryiko * anymore and will make it harder to detect contradictions using hypothetical 4023d5caef5bSAndrii Nakryiko * map. To handle this problem, we allow to follow FWD -> STRUCT/UNION 4024d5caef5bSAndrii Nakryiko * resolution only in canonical graph. FWDs in candidate graphs are never 4025d5caef5bSAndrii Nakryiko * resolved. To see why it's OK, let's check all possible situations w.r.t. FWDs 4026d5caef5bSAndrii Nakryiko * that can occur: 4027d5caef5bSAndrii Nakryiko * - Both types in canonical and candidate graphs are FWDs. If they are 4028d5caef5bSAndrii Nakryiko * structurally equivalent, then they can either be both resolved to the 4029d5caef5bSAndrii Nakryiko * same STRUCT/UNION or not resolved at all. In both cases they are 4030d5caef5bSAndrii Nakryiko * equivalent and there is no need to resolve FWD on candidate side. 4031d5caef5bSAndrii Nakryiko * - Both types in canonical and candidate graphs are concrete STRUCT/UNION, 4032d5caef5bSAndrii Nakryiko * so nothing to resolve as well, algorithm will check equivalence anyway. 4033d5caef5bSAndrii Nakryiko * - Type in canonical graph is FWD, while type in candidate is concrete 4034d5caef5bSAndrii Nakryiko * STRUCT/UNION. In this case candidate graph comes from single compilation 4035d5caef5bSAndrii Nakryiko * unit, so there is exactly one BTF type for each unique C type. After 4036d5caef5bSAndrii Nakryiko * resolving FWD into STRUCT/UNION, there might be more than one BTF type 4037d5caef5bSAndrii Nakryiko * in canonical graph mapping to single BTF type in candidate graph, but 4038d5caef5bSAndrii Nakryiko * because hypothetical mapping maps from canonical to candidate types, it's 4039d5caef5bSAndrii Nakryiko * alright, and we still maintain the property of having single `canon_id` 4040d5caef5bSAndrii Nakryiko * mapping to single `cand_id` (there could be two different `canon_id` 4041d5caef5bSAndrii Nakryiko * mapped to the same `cand_id`, but it's not contradictory). 4042d5caef5bSAndrii Nakryiko * - Type in canonical graph is concrete STRUCT/UNION, while type in candidate 4043d5caef5bSAndrii Nakryiko * graph is FWD. In this case we are just going to check compatibility of 4044d5caef5bSAndrii Nakryiko * STRUCT/UNION and corresponding FWD, and if they are compatible, we'll 4045d5caef5bSAndrii Nakryiko * assume that whatever STRUCT/UNION FWD resolves to must be equivalent to 4046d5caef5bSAndrii Nakryiko * a concrete STRUCT/UNION from canonical graph. If the rest of type graphs 4047d5caef5bSAndrii Nakryiko * turn out equivalent, we'll re-resolve FWD to concrete STRUCT/UNION from 4048d5caef5bSAndrii Nakryiko * canonical graph. 4049d5caef5bSAndrii Nakryiko */ 4050d5caef5bSAndrii Nakryiko static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, 4051d5caef5bSAndrii Nakryiko __u32 canon_id) 4052d5caef5bSAndrii Nakryiko { 4053d5caef5bSAndrii Nakryiko struct btf_type *cand_type; 4054d5caef5bSAndrii Nakryiko struct btf_type *canon_type; 4055d5caef5bSAndrii Nakryiko __u32 hypot_type_id; 4056d5caef5bSAndrii Nakryiko __u16 cand_kind; 4057d5caef5bSAndrii Nakryiko __u16 canon_kind; 4058d5caef5bSAndrii Nakryiko int i, eq; 4059d5caef5bSAndrii Nakryiko 4060d5caef5bSAndrii Nakryiko /* if both resolve to the same canonical, they must be equivalent */ 4061d5caef5bSAndrii Nakryiko if (resolve_type_id(d, cand_id) == resolve_type_id(d, canon_id)) 4062d5caef5bSAndrii Nakryiko return 1; 4063d5caef5bSAndrii Nakryiko 4064d5caef5bSAndrii Nakryiko canon_id = resolve_fwd_id(d, canon_id); 4065d5caef5bSAndrii Nakryiko 4066d5caef5bSAndrii Nakryiko hypot_type_id = d->hypot_map[canon_id]; 40676b6e6b1dSAndrii Nakryiko if (hypot_type_id <= BTF_MAX_NR_TYPES) { 4068efdd3eb8SAndrii Nakryiko if (hypot_type_id == cand_id) 4069efdd3eb8SAndrii Nakryiko return 1; 40706b6e6b1dSAndrii Nakryiko /* In some cases compiler will generate different DWARF types 40716b6e6b1dSAndrii Nakryiko * for *identical* array type definitions and use them for 40726b6e6b1dSAndrii Nakryiko * different fields within the *same* struct. This breaks type 40736b6e6b1dSAndrii Nakryiko * equivalence check, which makes an assumption that candidate 40746b6e6b1dSAndrii Nakryiko * types sub-graph has a consistent and deduped-by-compiler 40756b6e6b1dSAndrii Nakryiko * types within a single CU. So work around that by explicitly 40766b6e6b1dSAndrii Nakryiko * allowing identical array types here. 40776b6e6b1dSAndrii Nakryiko */ 4078efdd3eb8SAndrii Nakryiko if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id)) 4079efdd3eb8SAndrii Nakryiko return 1; 4080efdd3eb8SAndrii Nakryiko /* It turns out that similar situation can happen with 4081efdd3eb8SAndrii Nakryiko * struct/union sometimes, sigh... Handle the case where 4082efdd3eb8SAndrii Nakryiko * structs/unions are exactly the same, down to the referenced 4083efdd3eb8SAndrii Nakryiko * type IDs. Anything more complicated (e.g., if referenced 4084efdd3eb8SAndrii Nakryiko * types are different, but equivalent) is *way more* 4085efdd3eb8SAndrii Nakryiko * complicated and requires a many-to-many equivalence mapping. 4086efdd3eb8SAndrii Nakryiko */ 4087efdd3eb8SAndrii Nakryiko if (btf_dedup_identical_structs(d, hypot_type_id, cand_id)) 4088efdd3eb8SAndrii Nakryiko return 1; 4089efdd3eb8SAndrii Nakryiko return 0; 40906b6e6b1dSAndrii Nakryiko } 4091d5caef5bSAndrii Nakryiko 4092d5caef5bSAndrii Nakryiko if (btf_dedup_hypot_map_add(d, canon_id, cand_id)) 4093d5caef5bSAndrii Nakryiko return -ENOMEM; 4094d5caef5bSAndrii Nakryiko 4095740e69c3SAndrii Nakryiko cand_type = btf_type_by_id(d->btf, cand_id); 4096740e69c3SAndrii Nakryiko canon_type = btf_type_by_id(d->btf, canon_id); 4097b03bc685SAndrii Nakryiko cand_kind = btf_kind(cand_type); 4098b03bc685SAndrii Nakryiko canon_kind = btf_kind(canon_type); 4099d5caef5bSAndrii Nakryiko 4100d5caef5bSAndrii Nakryiko if (cand_type->name_off != canon_type->name_off) 4101d5caef5bSAndrii Nakryiko return 0; 4102d5caef5bSAndrii Nakryiko 4103d5caef5bSAndrii Nakryiko /* FWD <--> STRUCT/UNION equivalence check, if enabled */ 4104957d350aSAndrii Nakryiko if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD) 4105d5caef5bSAndrii Nakryiko && cand_kind != canon_kind) { 4106d5caef5bSAndrii Nakryiko __u16 real_kind; 4107d5caef5bSAndrii Nakryiko __u16 fwd_kind; 4108d5caef5bSAndrii Nakryiko 4109d5caef5bSAndrii Nakryiko if (cand_kind == BTF_KIND_FWD) { 4110d5caef5bSAndrii Nakryiko real_kind = canon_kind; 4111d5caef5bSAndrii Nakryiko fwd_kind = btf_fwd_kind(cand_type); 4112d5caef5bSAndrii Nakryiko } else { 4113d5caef5bSAndrii Nakryiko real_kind = cand_kind; 4114d5caef5bSAndrii Nakryiko fwd_kind = btf_fwd_kind(canon_type); 4115f86524efSAndrii Nakryiko /* we'd need to resolve base FWD to STRUCT/UNION */ 4116f86524efSAndrii Nakryiko if (fwd_kind == real_kind && canon_id < d->btf->start_id) 4117f86524efSAndrii Nakryiko d->hypot_adjust_canon = true; 4118d5caef5bSAndrii Nakryiko } 4119d5caef5bSAndrii Nakryiko return fwd_kind == real_kind; 4120d5caef5bSAndrii Nakryiko } 4121d5caef5bSAndrii Nakryiko 41229ec71c1cSAndrii Nakryiko if (cand_kind != canon_kind) 41239ec71c1cSAndrii Nakryiko return 0; 41249ec71c1cSAndrii Nakryiko 4125d5caef5bSAndrii Nakryiko switch (cand_kind) { 4126d5caef5bSAndrii Nakryiko case BTF_KIND_INT: 412730025e8bSYonghong Song return btf_equal_int_tag(cand_type, canon_type); 4128d5caef5bSAndrii Nakryiko 4129d5caef5bSAndrii Nakryiko case BTF_KIND_ENUM: 41309768095bSAndrii Nakryiko return btf_compat_enum(cand_type, canon_type); 4131d5caef5bSAndrii Nakryiko 4132d5caef5bSAndrii Nakryiko case BTF_KIND_FWD: 413322541a9eSIlya Leoshkevich case BTF_KIND_FLOAT: 4134d5caef5bSAndrii Nakryiko return btf_equal_common(cand_type, canon_type); 4135d5caef5bSAndrii Nakryiko 4136d5caef5bSAndrii Nakryiko case BTF_KIND_CONST: 4137d5caef5bSAndrii Nakryiko case BTF_KIND_VOLATILE: 4138d5caef5bSAndrii Nakryiko case BTF_KIND_RESTRICT: 4139d5caef5bSAndrii Nakryiko case BTF_KIND_PTR: 4140d5caef5bSAndrii Nakryiko case BTF_KIND_TYPEDEF: 4141d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC: 414269a055d5SYonghong Song case BTF_KIND_TYPE_TAG: 41439768095bSAndrii Nakryiko if (cand_type->info != canon_type->info) 41449768095bSAndrii Nakryiko return 0; 4145d5caef5bSAndrii Nakryiko return btf_dedup_is_equiv(d, cand_type->type, canon_type->type); 4146d5caef5bSAndrii Nakryiko 4147d5caef5bSAndrii Nakryiko case BTF_KIND_ARRAY: { 4148b03bc685SAndrii Nakryiko const struct btf_array *cand_arr, *canon_arr; 4149d5caef5bSAndrii Nakryiko 4150d5caef5bSAndrii Nakryiko if (!btf_compat_array(cand_type, canon_type)) 4151d5caef5bSAndrii Nakryiko return 0; 4152b03bc685SAndrii Nakryiko cand_arr = btf_array(cand_type); 4153b03bc685SAndrii Nakryiko canon_arr = btf_array(canon_type); 4154f86524efSAndrii Nakryiko eq = btf_dedup_is_equiv(d, cand_arr->index_type, canon_arr->index_type); 4155d5caef5bSAndrii Nakryiko if (eq <= 0) 4156d5caef5bSAndrii Nakryiko return eq; 4157d5caef5bSAndrii Nakryiko return btf_dedup_is_equiv(d, cand_arr->type, canon_arr->type); 4158d5caef5bSAndrii Nakryiko } 4159d5caef5bSAndrii Nakryiko 4160d5caef5bSAndrii Nakryiko case BTF_KIND_STRUCT: 4161d5caef5bSAndrii Nakryiko case BTF_KIND_UNION: { 4162b03bc685SAndrii Nakryiko const struct btf_member *cand_m, *canon_m; 4163d5caef5bSAndrii Nakryiko __u16 vlen; 4164d5caef5bSAndrii Nakryiko 416591097fbeSAndrii Nakryiko if (!btf_shallow_equal_struct(cand_type, canon_type)) 4166d5caef5bSAndrii Nakryiko return 0; 4167b03bc685SAndrii Nakryiko vlen = btf_vlen(cand_type); 4168b03bc685SAndrii Nakryiko cand_m = btf_members(cand_type); 4169b03bc685SAndrii Nakryiko canon_m = btf_members(canon_type); 4170d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 4171d5caef5bSAndrii Nakryiko eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type); 4172d5caef5bSAndrii Nakryiko if (eq <= 0) 4173d5caef5bSAndrii Nakryiko return eq; 4174d5caef5bSAndrii Nakryiko cand_m++; 4175d5caef5bSAndrii Nakryiko canon_m++; 4176d5caef5bSAndrii Nakryiko } 4177d5caef5bSAndrii Nakryiko 4178d5caef5bSAndrii Nakryiko return 1; 4179d5caef5bSAndrii Nakryiko } 4180d5caef5bSAndrii Nakryiko 4181d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC_PROTO: { 4182b03bc685SAndrii Nakryiko const struct btf_param *cand_p, *canon_p; 4183d5caef5bSAndrii Nakryiko __u16 vlen; 4184d5caef5bSAndrii Nakryiko 4185d5caef5bSAndrii Nakryiko if (!btf_compat_fnproto(cand_type, canon_type)) 4186d5caef5bSAndrii Nakryiko return 0; 4187d5caef5bSAndrii Nakryiko eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type); 4188d5caef5bSAndrii Nakryiko if (eq <= 0) 4189d5caef5bSAndrii Nakryiko return eq; 4190b03bc685SAndrii Nakryiko vlen = btf_vlen(cand_type); 4191b03bc685SAndrii Nakryiko cand_p = btf_params(cand_type); 4192b03bc685SAndrii Nakryiko canon_p = btf_params(canon_type); 4193d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 4194d5caef5bSAndrii Nakryiko eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type); 4195d5caef5bSAndrii Nakryiko if (eq <= 0) 4196d5caef5bSAndrii Nakryiko return eq; 4197d5caef5bSAndrii Nakryiko cand_p++; 4198d5caef5bSAndrii Nakryiko canon_p++; 4199d5caef5bSAndrii Nakryiko } 4200d5caef5bSAndrii Nakryiko return 1; 4201d5caef5bSAndrii Nakryiko } 4202d5caef5bSAndrii Nakryiko 4203d5caef5bSAndrii Nakryiko default: 4204d5caef5bSAndrii Nakryiko return -EINVAL; 4205d5caef5bSAndrii Nakryiko } 4206d5caef5bSAndrii Nakryiko return 0; 4207d5caef5bSAndrii Nakryiko } 4208d5caef5bSAndrii Nakryiko 4209d5caef5bSAndrii Nakryiko /* 4210d5caef5bSAndrii Nakryiko * Use hypothetical mapping, produced by successful type graph equivalence 4211d5caef5bSAndrii Nakryiko * check, to augment existing struct/union canonical mapping, where possible. 4212d5caef5bSAndrii Nakryiko * 4213d5caef5bSAndrii Nakryiko * If BTF_KIND_FWD resolution is allowed, this mapping is also used to record 4214d5caef5bSAndrii Nakryiko * FWD -> STRUCT/UNION correspondence as well. FWD resolution is bidirectional: 4215d5caef5bSAndrii Nakryiko * it doesn't matter if FWD type was part of canonical graph or candidate one, 4216d5caef5bSAndrii Nakryiko * we are recording the mapping anyway. As opposed to carefulness required 4217d5caef5bSAndrii Nakryiko * for struct/union correspondence mapping (described below), for FWD resolution 4218d5caef5bSAndrii Nakryiko * it's not important, as by the time that FWD type (reference type) will be 4219d5caef5bSAndrii Nakryiko * deduplicated all structs/unions will be deduped already anyway. 4220d5caef5bSAndrii Nakryiko * 4221d5caef5bSAndrii Nakryiko * Recording STRUCT/UNION mapping is purely a performance optimization and is 4222d5caef5bSAndrii Nakryiko * not required for correctness. It needs to be done carefully to ensure that 4223d5caef5bSAndrii Nakryiko * struct/union from candidate's type graph is not mapped into corresponding 4224d5caef5bSAndrii Nakryiko * struct/union from canonical type graph that itself hasn't been resolved into 4225d5caef5bSAndrii Nakryiko * canonical representative. The only guarantee we have is that canonical 4226d5caef5bSAndrii Nakryiko * struct/union was determined as canonical and that won't change. But any 4227d5caef5bSAndrii Nakryiko * types referenced through that struct/union fields could have been not yet 4228d5caef5bSAndrii Nakryiko * resolved, so in case like that it's too early to establish any kind of 4229d5caef5bSAndrii Nakryiko * correspondence between structs/unions. 4230d5caef5bSAndrii Nakryiko * 4231d5caef5bSAndrii Nakryiko * No canonical correspondence is derived for primitive types (they are already 4232d5caef5bSAndrii Nakryiko * deduplicated completely already anyway) or reference types (they rely on 4233d5caef5bSAndrii Nakryiko * stability of struct/union canonical relationship for equivalence checks). 4234d5caef5bSAndrii Nakryiko */ 4235d5caef5bSAndrii Nakryiko static void btf_dedup_merge_hypot_map(struct btf_dedup *d) 4236d5caef5bSAndrii Nakryiko { 4237f86524efSAndrii Nakryiko __u32 canon_type_id, targ_type_id; 4238d5caef5bSAndrii Nakryiko __u16 t_kind, c_kind; 4239d5caef5bSAndrii Nakryiko __u32 t_id, c_id; 4240d5caef5bSAndrii Nakryiko int i; 4241d5caef5bSAndrii Nakryiko 4242d5caef5bSAndrii Nakryiko for (i = 0; i < d->hypot_cnt; i++) { 4243f86524efSAndrii Nakryiko canon_type_id = d->hypot_list[i]; 4244f86524efSAndrii Nakryiko targ_type_id = d->hypot_map[canon_type_id]; 4245d5caef5bSAndrii Nakryiko t_id = resolve_type_id(d, targ_type_id); 4246f86524efSAndrii Nakryiko c_id = resolve_type_id(d, canon_type_id); 4247740e69c3SAndrii Nakryiko t_kind = btf_kind(btf__type_by_id(d->btf, t_id)); 4248740e69c3SAndrii Nakryiko c_kind = btf_kind(btf__type_by_id(d->btf, c_id)); 4249d5caef5bSAndrii Nakryiko /* 4250d5caef5bSAndrii Nakryiko * Resolve FWD into STRUCT/UNION. 4251d5caef5bSAndrii Nakryiko * It's ok to resolve FWD into STRUCT/UNION that's not yet 4252d5caef5bSAndrii Nakryiko * mapped to canonical representative (as opposed to 4253d5caef5bSAndrii Nakryiko * STRUCT/UNION <--> STRUCT/UNION mapping logic below), because 4254d5caef5bSAndrii Nakryiko * eventually that struct is going to be mapped and all resolved 4255d5caef5bSAndrii Nakryiko * FWDs will automatically resolve to correct canonical 4256d5caef5bSAndrii Nakryiko * representative. This will happen before ref type deduping, 4257d5caef5bSAndrii Nakryiko * which critically depends on stability of these mapping. This 4258d5caef5bSAndrii Nakryiko * stability is not a requirement for STRUCT/UNION equivalence 4259d5caef5bSAndrii Nakryiko * checks, though. 4260d5caef5bSAndrii Nakryiko */ 4261f86524efSAndrii Nakryiko 4262f86524efSAndrii Nakryiko /* if it's the split BTF case, we still need to point base FWD 4263f86524efSAndrii Nakryiko * to STRUCT/UNION in a split BTF, because FWDs from split BTF 4264f86524efSAndrii Nakryiko * will be resolved against base FWD. If we don't point base 4265f86524efSAndrii Nakryiko * canonical FWD to the resolved STRUCT/UNION, then all the 4266f86524efSAndrii Nakryiko * FWDs in split BTF won't be correctly resolved to a proper 4267f86524efSAndrii Nakryiko * STRUCT/UNION. 4268f86524efSAndrii Nakryiko */ 4269d5caef5bSAndrii Nakryiko if (t_kind != BTF_KIND_FWD && c_kind == BTF_KIND_FWD) 4270d5caef5bSAndrii Nakryiko d->map[c_id] = t_id; 4271f86524efSAndrii Nakryiko 4272f86524efSAndrii Nakryiko /* if graph equivalence determined that we'd need to adjust 4273f86524efSAndrii Nakryiko * base canonical types, then we need to only point base FWDs 4274f86524efSAndrii Nakryiko * to STRUCTs/UNIONs and do no more modifications. For all 4275f86524efSAndrii Nakryiko * other purposes the type graphs were not equivalent. 4276f86524efSAndrii Nakryiko */ 4277f86524efSAndrii Nakryiko if (d->hypot_adjust_canon) 4278f86524efSAndrii Nakryiko continue; 4279f86524efSAndrii Nakryiko 4280f86524efSAndrii Nakryiko if (t_kind == BTF_KIND_FWD && c_kind != BTF_KIND_FWD) 4281d5caef5bSAndrii Nakryiko d->map[t_id] = c_id; 4282d5caef5bSAndrii Nakryiko 4283d5caef5bSAndrii Nakryiko if ((t_kind == BTF_KIND_STRUCT || t_kind == BTF_KIND_UNION) && 4284d5caef5bSAndrii Nakryiko c_kind != BTF_KIND_FWD && 4285d5caef5bSAndrii Nakryiko is_type_mapped(d, c_id) && 4286d5caef5bSAndrii Nakryiko !is_type_mapped(d, t_id)) { 4287d5caef5bSAndrii Nakryiko /* 4288d5caef5bSAndrii Nakryiko * as a perf optimization, we can map struct/union 4289d5caef5bSAndrii Nakryiko * that's part of type graph we just verified for 4290d5caef5bSAndrii Nakryiko * equivalence. We can do that for struct/union that has 4291d5caef5bSAndrii Nakryiko * canonical representative only, though. 4292d5caef5bSAndrii Nakryiko */ 4293d5caef5bSAndrii Nakryiko d->map[t_id] = c_id; 4294d5caef5bSAndrii Nakryiko } 4295d5caef5bSAndrii Nakryiko } 4296d5caef5bSAndrii Nakryiko } 4297d5caef5bSAndrii Nakryiko 4298d5caef5bSAndrii Nakryiko /* 4299d5caef5bSAndrii Nakryiko * Deduplicate struct/union types. 4300d5caef5bSAndrii Nakryiko * 4301d5caef5bSAndrii Nakryiko * For each struct/union type its type signature hash is calculated, taking 4302d5caef5bSAndrii Nakryiko * into account type's name, size, number, order and names of fields, but 4303d5caef5bSAndrii Nakryiko * ignoring type ID's referenced from fields, because they might not be deduped 4304d5caef5bSAndrii Nakryiko * completely until after reference types deduplication phase. This type hash 4305d5caef5bSAndrii Nakryiko * is used to iterate over all potential canonical types, sharing same hash. 4306d5caef5bSAndrii Nakryiko * For each canonical candidate we check whether type graphs that they form 4307d5caef5bSAndrii Nakryiko * (through referenced types in fields and so on) are equivalent using algorithm 4308d5caef5bSAndrii Nakryiko * implemented in `btf_dedup_is_equiv`. If such equivalence is found and 4309d5caef5bSAndrii Nakryiko * BTF_KIND_FWD resolution is allowed, then hypothetical mapping 4310d5caef5bSAndrii Nakryiko * (btf_dedup->hypot_map) produced by aforementioned type graph equivalence 4311d5caef5bSAndrii Nakryiko * algorithm is used to record FWD -> STRUCT/UNION mapping. It's also used to 4312d5caef5bSAndrii Nakryiko * potentially map other structs/unions to their canonical representatives, 4313d5caef5bSAndrii Nakryiko * if such relationship hasn't yet been established. This speeds up algorithm 4314d5caef5bSAndrii Nakryiko * by eliminating some of the duplicate work. 4315d5caef5bSAndrii Nakryiko * 4316d5caef5bSAndrii Nakryiko * If no matching canonical representative was found, struct/union is marked 4317d5caef5bSAndrii Nakryiko * as canonical for itself and is added into btf_dedup->dedup_table hash map 4318d5caef5bSAndrii Nakryiko * for further look ups. 4319d5caef5bSAndrii Nakryiko */ 4320d5caef5bSAndrii Nakryiko static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id) 4321d5caef5bSAndrii Nakryiko { 432291097fbeSAndrii Nakryiko struct btf_type *cand_type, *t; 43232fc3fc0bSAndrii Nakryiko struct hashmap_entry *hash_entry; 4324d5caef5bSAndrii Nakryiko /* if we don't find equivalent type, then we are canonical */ 4325d5caef5bSAndrii Nakryiko __u32 new_id = type_id; 4326d5caef5bSAndrii Nakryiko __u16 kind; 43272fc3fc0bSAndrii Nakryiko long h; 4328d5caef5bSAndrii Nakryiko 4329d5caef5bSAndrii Nakryiko /* already deduped or is in process of deduping (loop detected) */ 43305aab392cSAndrii Nakryiko if (d->map[type_id] <= BTF_MAX_NR_TYPES) 4331d5caef5bSAndrii Nakryiko return 0; 4332d5caef5bSAndrii Nakryiko 4333740e69c3SAndrii Nakryiko t = btf_type_by_id(d->btf, type_id); 4334b03bc685SAndrii Nakryiko kind = btf_kind(t); 4335d5caef5bSAndrii Nakryiko 4336d5caef5bSAndrii Nakryiko if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION) 4337d5caef5bSAndrii Nakryiko return 0; 4338d5caef5bSAndrii Nakryiko 4339d5caef5bSAndrii Nakryiko h = btf_hash_struct(t); 43402fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 43412fc3fc0bSAndrii Nakryiko __u32 cand_id = (__u32)(long)hash_entry->value; 4342d5caef5bSAndrii Nakryiko int eq; 4343d5caef5bSAndrii Nakryiko 434491097fbeSAndrii Nakryiko /* 434591097fbeSAndrii Nakryiko * Even though btf_dedup_is_equiv() checks for 434691097fbeSAndrii Nakryiko * btf_shallow_equal_struct() internally when checking two 434791097fbeSAndrii Nakryiko * structs (unions) for equivalence, we need to guard here 434891097fbeSAndrii Nakryiko * from picking matching FWD type as a dedup candidate. 434991097fbeSAndrii Nakryiko * This can happen due to hash collision. In such case just 435091097fbeSAndrii Nakryiko * relying on btf_dedup_is_equiv() would lead to potentially 435191097fbeSAndrii Nakryiko * creating a loop (FWD -> STRUCT and STRUCT -> FWD), because 435291097fbeSAndrii Nakryiko * FWD and compatible STRUCT/UNION are considered equivalent. 435391097fbeSAndrii Nakryiko */ 4354740e69c3SAndrii Nakryiko cand_type = btf_type_by_id(d->btf, cand_id); 435591097fbeSAndrii Nakryiko if (!btf_shallow_equal_struct(t, cand_type)) 435691097fbeSAndrii Nakryiko continue; 435791097fbeSAndrii Nakryiko 4358d5caef5bSAndrii Nakryiko btf_dedup_clear_hypot_map(d); 43592fc3fc0bSAndrii Nakryiko eq = btf_dedup_is_equiv(d, type_id, cand_id); 4360d5caef5bSAndrii Nakryiko if (eq < 0) 4361d5caef5bSAndrii Nakryiko return eq; 4362d5caef5bSAndrii Nakryiko if (!eq) 4363d5caef5bSAndrii Nakryiko continue; 4364d5caef5bSAndrii Nakryiko btf_dedup_merge_hypot_map(d); 4365f86524efSAndrii Nakryiko if (d->hypot_adjust_canon) /* not really equivalent */ 4366f86524efSAndrii Nakryiko continue; 4367f86524efSAndrii Nakryiko new_id = cand_id; 4368d5caef5bSAndrii Nakryiko break; 4369d5caef5bSAndrii Nakryiko } 4370d5caef5bSAndrii Nakryiko 4371d5caef5bSAndrii Nakryiko d->map[type_id] = new_id; 4372d5caef5bSAndrii Nakryiko if (type_id == new_id && btf_dedup_table_add(d, h, type_id)) 4373d5caef5bSAndrii Nakryiko return -ENOMEM; 4374d5caef5bSAndrii Nakryiko 4375d5caef5bSAndrii Nakryiko return 0; 4376d5caef5bSAndrii Nakryiko } 4377d5caef5bSAndrii Nakryiko 4378d5caef5bSAndrii Nakryiko static int btf_dedup_struct_types(struct btf_dedup *d) 4379d5caef5bSAndrii Nakryiko { 4380d5caef5bSAndrii Nakryiko int i, err; 4381d5caef5bSAndrii Nakryiko 4382f86524efSAndrii Nakryiko for (i = 0; i < d->btf->nr_types; i++) { 4383f86524efSAndrii Nakryiko err = btf_dedup_struct_type(d, d->btf->start_id + i); 4384d5caef5bSAndrii Nakryiko if (err) 4385d5caef5bSAndrii Nakryiko return err; 4386d5caef5bSAndrii Nakryiko } 4387d5caef5bSAndrii Nakryiko return 0; 4388d5caef5bSAndrii Nakryiko } 4389d5caef5bSAndrii Nakryiko 4390d5caef5bSAndrii Nakryiko /* 4391d5caef5bSAndrii Nakryiko * Deduplicate reference type. 4392d5caef5bSAndrii Nakryiko * 4393d5caef5bSAndrii Nakryiko * Once all primitive and struct/union types got deduplicated, we can easily 4394d5caef5bSAndrii Nakryiko * deduplicate all other (reference) BTF types. This is done in two steps: 4395d5caef5bSAndrii Nakryiko * 4396d5caef5bSAndrii Nakryiko * 1. Resolve all referenced type IDs into their canonical type IDs. This 4397d5caef5bSAndrii Nakryiko * resolution can be done either immediately for primitive or struct/union types 4398d5caef5bSAndrii Nakryiko * (because they were deduped in previous two phases) or recursively for 4399d5caef5bSAndrii Nakryiko * reference types. Recursion will always terminate at either primitive or 4400d5caef5bSAndrii Nakryiko * struct/union type, at which point we can "unwind" chain of reference types 4401d5caef5bSAndrii Nakryiko * one by one. There is no danger of encountering cycles because in C type 4402d5caef5bSAndrii Nakryiko * system the only way to form type cycle is through struct/union, so any chain 4403d5caef5bSAndrii Nakryiko * of reference types, even those taking part in a type cycle, will inevitably 4404d5caef5bSAndrii Nakryiko * reach struct/union at some point. 4405d5caef5bSAndrii Nakryiko * 4406d5caef5bSAndrii Nakryiko * 2. Once all referenced type IDs are resolved into canonical ones, BTF type 4407d5caef5bSAndrii Nakryiko * becomes "stable", in the sense that no further deduplication will cause 4408d5caef5bSAndrii Nakryiko * any changes to it. With that, it's now possible to calculate type's signature 4409d5caef5bSAndrii Nakryiko * hash (this time taking into account referenced type IDs) and loop over all 4410d5caef5bSAndrii Nakryiko * potential canonical representatives. If no match was found, current type 4411d5caef5bSAndrii Nakryiko * will become canonical representative of itself and will be added into 4412d5caef5bSAndrii Nakryiko * btf_dedup->dedup_table as another possible canonical representative. 4413d5caef5bSAndrii Nakryiko */ 4414d5caef5bSAndrii Nakryiko static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id) 4415d5caef5bSAndrii Nakryiko { 44162fc3fc0bSAndrii Nakryiko struct hashmap_entry *hash_entry; 44172fc3fc0bSAndrii Nakryiko __u32 new_id = type_id, cand_id; 4418d5caef5bSAndrii Nakryiko struct btf_type *t, *cand; 4419d5caef5bSAndrii Nakryiko /* if we don't find equivalent type, then we are representative type */ 44203d8669e6SDan Carpenter int ref_type_id; 44212fc3fc0bSAndrii Nakryiko long h; 4422d5caef5bSAndrii Nakryiko 4423d5caef5bSAndrii Nakryiko if (d->map[type_id] == BTF_IN_PROGRESS_ID) 4424d5caef5bSAndrii Nakryiko return -ELOOP; 44255aab392cSAndrii Nakryiko if (d->map[type_id] <= BTF_MAX_NR_TYPES) 4426d5caef5bSAndrii Nakryiko return resolve_type_id(d, type_id); 4427d5caef5bSAndrii Nakryiko 4428740e69c3SAndrii Nakryiko t = btf_type_by_id(d->btf, type_id); 4429d5caef5bSAndrii Nakryiko d->map[type_id] = BTF_IN_PROGRESS_ID; 4430d5caef5bSAndrii Nakryiko 4431b03bc685SAndrii Nakryiko switch (btf_kind(t)) { 4432d5caef5bSAndrii Nakryiko case BTF_KIND_CONST: 4433d5caef5bSAndrii Nakryiko case BTF_KIND_VOLATILE: 4434d5caef5bSAndrii Nakryiko case BTF_KIND_RESTRICT: 4435d5caef5bSAndrii Nakryiko case BTF_KIND_PTR: 4436d5caef5bSAndrii Nakryiko case BTF_KIND_TYPEDEF: 4437d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC: 44382dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 4439d5caef5bSAndrii Nakryiko ref_type_id = btf_dedup_ref_type(d, t->type); 4440d5caef5bSAndrii Nakryiko if (ref_type_id < 0) 4441d5caef5bSAndrii Nakryiko return ref_type_id; 4442d5caef5bSAndrii Nakryiko t->type = ref_type_id; 4443d5caef5bSAndrii Nakryiko 4444d5caef5bSAndrii Nakryiko h = btf_hash_common(t); 44452fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 44462fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 4447740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 4448d5caef5bSAndrii Nakryiko if (btf_equal_common(t, cand)) { 44492fc3fc0bSAndrii Nakryiko new_id = cand_id; 4450d5caef5bSAndrii Nakryiko break; 4451d5caef5bSAndrii Nakryiko } 4452d5caef5bSAndrii Nakryiko } 4453d5caef5bSAndrii Nakryiko break; 4454d5caef5bSAndrii Nakryiko 4455223f903eSYonghong Song case BTF_KIND_DECL_TAG: 44565b84bd10SYonghong Song ref_type_id = btf_dedup_ref_type(d, t->type); 44575b84bd10SYonghong Song if (ref_type_id < 0) 44585b84bd10SYonghong Song return ref_type_id; 44595b84bd10SYonghong Song t->type = ref_type_id; 44605b84bd10SYonghong Song 4461223f903eSYonghong Song h = btf_hash_int_decl_tag(t); 44625b84bd10SYonghong Song for_each_dedup_cand(d, hash_entry, h) { 44635b84bd10SYonghong Song cand_id = (__u32)(long)hash_entry->value; 44645b84bd10SYonghong Song cand = btf_type_by_id(d->btf, cand_id); 44655b84bd10SYonghong Song if (btf_equal_int_tag(t, cand)) { 44665b84bd10SYonghong Song new_id = cand_id; 44675b84bd10SYonghong Song break; 44685b84bd10SYonghong Song } 44695b84bd10SYonghong Song } 44705b84bd10SYonghong Song break; 44715b84bd10SYonghong Song 4472d5caef5bSAndrii Nakryiko case BTF_KIND_ARRAY: { 4473b03bc685SAndrii Nakryiko struct btf_array *info = btf_array(t); 4474d5caef5bSAndrii Nakryiko 4475d5caef5bSAndrii Nakryiko ref_type_id = btf_dedup_ref_type(d, info->type); 4476d5caef5bSAndrii Nakryiko if (ref_type_id < 0) 4477d5caef5bSAndrii Nakryiko return ref_type_id; 4478d5caef5bSAndrii Nakryiko info->type = ref_type_id; 4479d5caef5bSAndrii Nakryiko 4480d5caef5bSAndrii Nakryiko ref_type_id = btf_dedup_ref_type(d, info->index_type); 4481d5caef5bSAndrii Nakryiko if (ref_type_id < 0) 4482d5caef5bSAndrii Nakryiko return ref_type_id; 4483d5caef5bSAndrii Nakryiko info->index_type = ref_type_id; 4484d5caef5bSAndrii Nakryiko 4485d5caef5bSAndrii Nakryiko h = btf_hash_array(t); 44862fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 44872fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 4488740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 4489d5caef5bSAndrii Nakryiko if (btf_equal_array(t, cand)) { 44902fc3fc0bSAndrii Nakryiko new_id = cand_id; 4491d5caef5bSAndrii Nakryiko break; 4492d5caef5bSAndrii Nakryiko } 4493d5caef5bSAndrii Nakryiko } 4494d5caef5bSAndrii Nakryiko break; 4495d5caef5bSAndrii Nakryiko } 4496d5caef5bSAndrii Nakryiko 4497d5caef5bSAndrii Nakryiko case BTF_KIND_FUNC_PROTO: { 4498d5caef5bSAndrii Nakryiko struct btf_param *param; 4499d5caef5bSAndrii Nakryiko __u16 vlen; 4500d5caef5bSAndrii Nakryiko int i; 4501d5caef5bSAndrii Nakryiko 4502d5caef5bSAndrii Nakryiko ref_type_id = btf_dedup_ref_type(d, t->type); 4503d5caef5bSAndrii Nakryiko if (ref_type_id < 0) 4504d5caef5bSAndrii Nakryiko return ref_type_id; 4505d5caef5bSAndrii Nakryiko t->type = ref_type_id; 4506d5caef5bSAndrii Nakryiko 4507b03bc685SAndrii Nakryiko vlen = btf_vlen(t); 4508b03bc685SAndrii Nakryiko param = btf_params(t); 4509d5caef5bSAndrii Nakryiko for (i = 0; i < vlen; i++) { 4510d5caef5bSAndrii Nakryiko ref_type_id = btf_dedup_ref_type(d, param->type); 4511d5caef5bSAndrii Nakryiko if (ref_type_id < 0) 4512d5caef5bSAndrii Nakryiko return ref_type_id; 4513d5caef5bSAndrii Nakryiko param->type = ref_type_id; 4514d5caef5bSAndrii Nakryiko param++; 4515d5caef5bSAndrii Nakryiko } 4516d5caef5bSAndrii Nakryiko 4517d5caef5bSAndrii Nakryiko h = btf_hash_fnproto(t); 45182fc3fc0bSAndrii Nakryiko for_each_dedup_cand(d, hash_entry, h) { 45192fc3fc0bSAndrii Nakryiko cand_id = (__u32)(long)hash_entry->value; 4520740e69c3SAndrii Nakryiko cand = btf_type_by_id(d->btf, cand_id); 4521d5caef5bSAndrii Nakryiko if (btf_equal_fnproto(t, cand)) { 45222fc3fc0bSAndrii Nakryiko new_id = cand_id; 4523d5caef5bSAndrii Nakryiko break; 4524d5caef5bSAndrii Nakryiko } 4525d5caef5bSAndrii Nakryiko } 4526d5caef5bSAndrii Nakryiko break; 4527d5caef5bSAndrii Nakryiko } 4528d5caef5bSAndrii Nakryiko 4529d5caef5bSAndrii Nakryiko default: 4530d5caef5bSAndrii Nakryiko return -EINVAL; 4531d5caef5bSAndrii Nakryiko } 4532d5caef5bSAndrii Nakryiko 4533d5caef5bSAndrii Nakryiko d->map[type_id] = new_id; 4534d5caef5bSAndrii Nakryiko if (type_id == new_id && btf_dedup_table_add(d, h, type_id)) 4535d5caef5bSAndrii Nakryiko return -ENOMEM; 4536d5caef5bSAndrii Nakryiko 4537d5caef5bSAndrii Nakryiko return new_id; 4538d5caef5bSAndrii Nakryiko } 4539d5caef5bSAndrii Nakryiko 4540d5caef5bSAndrii Nakryiko static int btf_dedup_ref_types(struct btf_dedup *d) 4541d5caef5bSAndrii Nakryiko { 4542d5caef5bSAndrii Nakryiko int i, err; 4543d5caef5bSAndrii Nakryiko 4544f86524efSAndrii Nakryiko for (i = 0; i < d->btf->nr_types; i++) { 4545f86524efSAndrii Nakryiko err = btf_dedup_ref_type(d, d->btf->start_id + i); 4546d5caef5bSAndrii Nakryiko if (err < 0) 4547d5caef5bSAndrii Nakryiko return err; 4548d5caef5bSAndrii Nakryiko } 45492fc3fc0bSAndrii Nakryiko /* we won't need d->dedup_table anymore */ 45502fc3fc0bSAndrii Nakryiko hashmap__free(d->dedup_table); 45512fc3fc0bSAndrii Nakryiko d->dedup_table = NULL; 4552d5caef5bSAndrii Nakryiko return 0; 4553d5caef5bSAndrii Nakryiko } 4554d5caef5bSAndrii Nakryiko 4555d5caef5bSAndrii Nakryiko /* 4556d5caef5bSAndrii Nakryiko * Compact types. 4557d5caef5bSAndrii Nakryiko * 4558d5caef5bSAndrii Nakryiko * After we established for each type its corresponding canonical representative 4559d5caef5bSAndrii Nakryiko * type, we now can eliminate types that are not canonical and leave only 4560d5caef5bSAndrii Nakryiko * canonical ones layed out sequentially in memory by copying them over 4561d5caef5bSAndrii Nakryiko * duplicates. During compaction btf_dedup->hypot_map array is reused to store 4562d5caef5bSAndrii Nakryiko * a map from original type ID to a new compacted type ID, which will be used 4563d5caef5bSAndrii Nakryiko * during next phase to "fix up" type IDs, referenced from struct/union and 4564d5caef5bSAndrii Nakryiko * reference types. 4565d5caef5bSAndrii Nakryiko */ 4566d5caef5bSAndrii Nakryiko static int btf_dedup_compact_types(struct btf_dedup *d) 4567d5caef5bSAndrii Nakryiko { 4568740e69c3SAndrii Nakryiko __u32 *new_offs; 4569f86524efSAndrii Nakryiko __u32 next_type_id = d->btf->start_id; 4570f86524efSAndrii Nakryiko const struct btf_type *t; 4571740e69c3SAndrii Nakryiko void *p; 4572f86524efSAndrii Nakryiko int i, id, len; 4573d5caef5bSAndrii Nakryiko 4574d5caef5bSAndrii Nakryiko /* we are going to reuse hypot_map to store compaction remapping */ 4575d5caef5bSAndrii Nakryiko d->hypot_map[0] = 0; 4576f86524efSAndrii Nakryiko /* base BTF types are not renumbered */ 4577f86524efSAndrii Nakryiko for (id = 1; id < d->btf->start_id; id++) 4578f86524efSAndrii Nakryiko d->hypot_map[id] = id; 4579f86524efSAndrii Nakryiko for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) 4580f86524efSAndrii Nakryiko d->hypot_map[id] = BTF_UNPROCESSED_ID; 4581d5caef5bSAndrii Nakryiko 4582740e69c3SAndrii Nakryiko p = d->btf->types_data; 4583d5caef5bSAndrii Nakryiko 4584f86524efSAndrii Nakryiko for (i = 0, id = d->btf->start_id; i < d->btf->nr_types; i++, id++) { 4585f86524efSAndrii Nakryiko if (d->map[id] != id) 4586d5caef5bSAndrii Nakryiko continue; 4587d5caef5bSAndrii Nakryiko 4588f86524efSAndrii Nakryiko t = btf__type_by_id(d->btf, id); 4589f86524efSAndrii Nakryiko len = btf_type_size(t); 4590d5caef5bSAndrii Nakryiko if (len < 0) 4591d5caef5bSAndrii Nakryiko return len; 4592d5caef5bSAndrii Nakryiko 4593f86524efSAndrii Nakryiko memmove(p, t, len); 4594f86524efSAndrii Nakryiko d->hypot_map[id] = next_type_id; 4595f86524efSAndrii Nakryiko d->btf->type_offs[next_type_id - d->btf->start_id] = p - d->btf->types_data; 4596d5caef5bSAndrii Nakryiko p += len; 4597d5caef5bSAndrii Nakryiko next_type_id++; 4598d5caef5bSAndrii Nakryiko } 4599d5caef5bSAndrii Nakryiko 4600d5caef5bSAndrii Nakryiko /* shrink struct btf's internal types index and update btf_header */ 4601f86524efSAndrii Nakryiko d->btf->nr_types = next_type_id - d->btf->start_id; 4602ba451366SAndrii Nakryiko d->btf->type_offs_cap = d->btf->nr_types; 4603740e69c3SAndrii Nakryiko d->btf->hdr->type_len = p - d->btf->types_data; 4604740e69c3SAndrii Nakryiko new_offs = libbpf_reallocarray(d->btf->type_offs, d->btf->type_offs_cap, 4605740e69c3SAndrii Nakryiko sizeof(*new_offs)); 4606f86524efSAndrii Nakryiko if (d->btf->type_offs_cap && !new_offs) 4607d5caef5bSAndrii Nakryiko return -ENOMEM; 4608740e69c3SAndrii Nakryiko d->btf->type_offs = new_offs; 4609919d2b1dSAndrii Nakryiko d->btf->hdr->str_off = d->btf->hdr->type_len; 4610b8604247SAndrii Nakryiko d->btf->raw_size = d->btf->hdr->hdr_len + d->btf->hdr->type_len + d->btf->hdr->str_len; 4611d5caef5bSAndrii Nakryiko return 0; 4612d5caef5bSAndrii Nakryiko } 4613d5caef5bSAndrii Nakryiko 4614d5caef5bSAndrii Nakryiko /* 4615d5caef5bSAndrii Nakryiko * Figure out final (deduplicated and compacted) type ID for provided original 4616d5caef5bSAndrii Nakryiko * `type_id` by first resolving it into corresponding canonical type ID and 4617d5caef5bSAndrii Nakryiko * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map, 4618d5caef5bSAndrii Nakryiko * which is populated during compaction phase. 4619d5caef5bSAndrii Nakryiko */ 4620f36e99a4SAndrii Nakryiko static int btf_dedup_remap_type_id(__u32 *type_id, void *ctx) 4621d5caef5bSAndrii Nakryiko { 4622f36e99a4SAndrii Nakryiko struct btf_dedup *d = ctx; 4623d5caef5bSAndrii Nakryiko __u32 resolved_type_id, new_type_id; 4624d5caef5bSAndrii Nakryiko 4625f36e99a4SAndrii Nakryiko resolved_type_id = resolve_type_id(d, *type_id); 4626d5caef5bSAndrii Nakryiko new_type_id = d->hypot_map[resolved_type_id]; 46275aab392cSAndrii Nakryiko if (new_type_id > BTF_MAX_NR_TYPES) 4628d5caef5bSAndrii Nakryiko return -EINVAL; 4629f36e99a4SAndrii Nakryiko 4630f36e99a4SAndrii Nakryiko *type_id = new_type_id; 4631f36e99a4SAndrii Nakryiko return 0; 4632d5caef5bSAndrii Nakryiko } 4633d5caef5bSAndrii Nakryiko 4634d5caef5bSAndrii Nakryiko /* 4635d5caef5bSAndrii Nakryiko * Remap referenced type IDs into deduped type IDs. 4636d5caef5bSAndrii Nakryiko * 4637d5caef5bSAndrii Nakryiko * After BTF types are deduplicated and compacted, their final type IDs may 4638d5caef5bSAndrii Nakryiko * differ from original ones. The map from original to a corresponding 4639d5caef5bSAndrii Nakryiko * deduped type ID is stored in btf_dedup->hypot_map and is populated during 4640d5caef5bSAndrii Nakryiko * compaction phase. During remapping phase we are rewriting all type IDs 4641d5caef5bSAndrii Nakryiko * referenced from any BTF type (e.g., struct fields, func proto args, etc) to 4642d5caef5bSAndrii Nakryiko * their final deduped type IDs. 4643d5caef5bSAndrii Nakryiko */ 4644d5caef5bSAndrii Nakryiko static int btf_dedup_remap_types(struct btf_dedup *d) 4645d5caef5bSAndrii Nakryiko { 4646d5caef5bSAndrii Nakryiko int i, r; 4647d5caef5bSAndrii Nakryiko 4648f86524efSAndrii Nakryiko for (i = 0; i < d->btf->nr_types; i++) { 4649f36e99a4SAndrii Nakryiko struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i); 4650f36e99a4SAndrii Nakryiko 4651f36e99a4SAndrii Nakryiko r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d); 4652f36e99a4SAndrii Nakryiko if (r) 4653d5caef5bSAndrii Nakryiko return r; 4654d5caef5bSAndrii Nakryiko } 4655f36e99a4SAndrii Nakryiko 4656f36e99a4SAndrii Nakryiko if (!d->btf_ext) 4657f36e99a4SAndrii Nakryiko return 0; 4658f36e99a4SAndrii Nakryiko 4659f36e99a4SAndrii Nakryiko r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d); 4660f36e99a4SAndrii Nakryiko if (r) 4661f36e99a4SAndrii Nakryiko return r; 4662f36e99a4SAndrii Nakryiko 4663d5caef5bSAndrii Nakryiko return 0; 4664d5caef5bSAndrii Nakryiko } 4665fb2426adSMartin KaFai Lau 4666fb2426adSMartin KaFai Lau /* 4667fb2426adSMartin KaFai Lau * Probe few well-known locations for vmlinux kernel image and try to load BTF 4668fb2426adSMartin KaFai Lau * data out of it to use for target BTF. 4669fb2426adSMartin KaFai Lau */ 4670a710eed3SHengqi Chen struct btf *btf__load_vmlinux_btf(void) 4671fb2426adSMartin KaFai Lau { 4672fb2426adSMartin KaFai Lau struct { 4673fb2426adSMartin KaFai Lau const char *path_fmt; 4674fb2426adSMartin KaFai Lau bool raw_btf; 4675fb2426adSMartin KaFai Lau } locations[] = { 4676fb2426adSMartin KaFai Lau /* try canonical vmlinux BTF through sysfs first */ 4677fb2426adSMartin KaFai Lau { "/sys/kernel/btf/vmlinux", true /* raw BTF */ }, 4678fb2426adSMartin KaFai Lau /* fall back to trying to find vmlinux ELF on disk otherwise */ 4679fb2426adSMartin KaFai Lau { "/boot/vmlinux-%1$s" }, 4680fb2426adSMartin KaFai Lau { "/lib/modules/%1$s/vmlinux-%1$s" }, 4681fb2426adSMartin KaFai Lau { "/lib/modules/%1$s/build/vmlinux" }, 4682fb2426adSMartin KaFai Lau { "/usr/lib/modules/%1$s/kernel/vmlinux" }, 4683fb2426adSMartin KaFai Lau { "/usr/lib/debug/boot/vmlinux-%1$s" }, 4684fb2426adSMartin KaFai Lau { "/usr/lib/debug/boot/vmlinux-%1$s.debug" }, 4685fb2426adSMartin KaFai Lau { "/usr/lib/debug/lib/modules/%1$s/vmlinux" }, 4686fb2426adSMartin KaFai Lau }; 4687fb2426adSMartin KaFai Lau char path[PATH_MAX + 1]; 4688fb2426adSMartin KaFai Lau struct utsname buf; 4689fb2426adSMartin KaFai Lau struct btf *btf; 4690e9fc3ce9SAndrii Nakryiko int i, err; 4691fb2426adSMartin KaFai Lau 4692fb2426adSMartin KaFai Lau uname(&buf); 4693fb2426adSMartin KaFai Lau 4694fb2426adSMartin KaFai Lau for (i = 0; i < ARRAY_SIZE(locations); i++) { 4695fb2426adSMartin KaFai Lau snprintf(path, PATH_MAX, locations[i].path_fmt, buf.release); 4696fb2426adSMartin KaFai Lau 4697fb2426adSMartin KaFai Lau if (access(path, R_OK)) 4698fb2426adSMartin KaFai Lau continue; 4699fb2426adSMartin KaFai Lau 4700fb2426adSMartin KaFai Lau if (locations[i].raw_btf) 470194a1feddSAndrii Nakryiko btf = btf__parse_raw(path); 4702fb2426adSMartin KaFai Lau else 4703fb2426adSMartin KaFai Lau btf = btf__parse_elf(path, NULL); 4704e9fc3ce9SAndrii Nakryiko err = libbpf_get_error(btf); 4705e9fc3ce9SAndrii Nakryiko pr_debug("loading kernel BTF '%s': %d\n", path, err); 4706e9fc3ce9SAndrii Nakryiko if (err) 4707fb2426adSMartin KaFai Lau continue; 4708fb2426adSMartin KaFai Lau 4709fb2426adSMartin KaFai Lau return btf; 4710fb2426adSMartin KaFai Lau } 4711fb2426adSMartin KaFai Lau 4712fb2426adSMartin KaFai Lau pr_warn("failed to find valid kernel BTF\n"); 4713e9fc3ce9SAndrii Nakryiko return libbpf_err_ptr(-ESRCH); 4714fb2426adSMartin KaFai Lau } 4715f36e99a4SAndrii Nakryiko 4716a710eed3SHengqi Chen struct btf *libbpf_find_kernel_btf(void) __attribute__((alias("btf__load_vmlinux_btf"))); 4717a710eed3SHengqi Chen 4718a710eed3SHengqi Chen struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf) 4719a710eed3SHengqi Chen { 4720a710eed3SHengqi Chen char path[80]; 4721a710eed3SHengqi Chen 4722a710eed3SHengqi Chen snprintf(path, sizeof(path), "/sys/kernel/btf/%s", module_name); 4723a710eed3SHengqi Chen return btf__parse_split(path, vmlinux_btf); 4724a710eed3SHengqi Chen } 4725a710eed3SHengqi Chen 4726f36e99a4SAndrii Nakryiko int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx) 4727f36e99a4SAndrii Nakryiko { 4728f36e99a4SAndrii Nakryiko int i, n, err; 4729f36e99a4SAndrii Nakryiko 4730f36e99a4SAndrii Nakryiko switch (btf_kind(t)) { 4731f36e99a4SAndrii Nakryiko case BTF_KIND_INT: 4732f36e99a4SAndrii Nakryiko case BTF_KIND_FLOAT: 4733f36e99a4SAndrii Nakryiko case BTF_KIND_ENUM: 4734f36e99a4SAndrii Nakryiko return 0; 4735f36e99a4SAndrii Nakryiko 4736f36e99a4SAndrii Nakryiko case BTF_KIND_FWD: 4737f36e99a4SAndrii Nakryiko case BTF_KIND_CONST: 4738f36e99a4SAndrii Nakryiko case BTF_KIND_VOLATILE: 4739f36e99a4SAndrii Nakryiko case BTF_KIND_RESTRICT: 4740f36e99a4SAndrii Nakryiko case BTF_KIND_PTR: 4741f36e99a4SAndrii Nakryiko case BTF_KIND_TYPEDEF: 4742f36e99a4SAndrii Nakryiko case BTF_KIND_FUNC: 4743f36e99a4SAndrii Nakryiko case BTF_KIND_VAR: 4744223f903eSYonghong Song case BTF_KIND_DECL_TAG: 47452dc1e488SYonghong Song case BTF_KIND_TYPE_TAG: 4746f36e99a4SAndrii Nakryiko return visit(&t->type, ctx); 4747f36e99a4SAndrii Nakryiko 4748f36e99a4SAndrii Nakryiko case BTF_KIND_ARRAY: { 4749f36e99a4SAndrii Nakryiko struct btf_array *a = btf_array(t); 4750f36e99a4SAndrii Nakryiko 4751f36e99a4SAndrii Nakryiko err = visit(&a->type, ctx); 4752f36e99a4SAndrii Nakryiko err = err ?: visit(&a->index_type, ctx); 4753f36e99a4SAndrii Nakryiko return err; 4754f36e99a4SAndrii Nakryiko } 4755f36e99a4SAndrii Nakryiko 4756f36e99a4SAndrii Nakryiko case BTF_KIND_STRUCT: 4757f36e99a4SAndrii Nakryiko case BTF_KIND_UNION: { 4758f36e99a4SAndrii Nakryiko struct btf_member *m = btf_members(t); 4759f36e99a4SAndrii Nakryiko 4760f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4761f36e99a4SAndrii Nakryiko err = visit(&m->type, ctx); 4762f36e99a4SAndrii Nakryiko if (err) 4763f36e99a4SAndrii Nakryiko return err; 4764f36e99a4SAndrii Nakryiko } 4765f36e99a4SAndrii Nakryiko return 0; 4766f36e99a4SAndrii Nakryiko } 4767f36e99a4SAndrii Nakryiko 4768f36e99a4SAndrii Nakryiko case BTF_KIND_FUNC_PROTO: { 4769f36e99a4SAndrii Nakryiko struct btf_param *m = btf_params(t); 4770f36e99a4SAndrii Nakryiko 4771f36e99a4SAndrii Nakryiko err = visit(&t->type, ctx); 4772f36e99a4SAndrii Nakryiko if (err) 4773f36e99a4SAndrii Nakryiko return err; 4774f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4775f36e99a4SAndrii Nakryiko err = visit(&m->type, ctx); 4776f36e99a4SAndrii Nakryiko if (err) 4777f36e99a4SAndrii Nakryiko return err; 4778f36e99a4SAndrii Nakryiko } 4779f36e99a4SAndrii Nakryiko return 0; 4780f36e99a4SAndrii Nakryiko } 4781f36e99a4SAndrii Nakryiko 4782f36e99a4SAndrii Nakryiko case BTF_KIND_DATASEC: { 4783f36e99a4SAndrii Nakryiko struct btf_var_secinfo *m = btf_var_secinfos(t); 4784f36e99a4SAndrii Nakryiko 4785f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4786f36e99a4SAndrii Nakryiko err = visit(&m->type, ctx); 4787f36e99a4SAndrii Nakryiko if (err) 4788f36e99a4SAndrii Nakryiko return err; 4789f36e99a4SAndrii Nakryiko } 4790f36e99a4SAndrii Nakryiko return 0; 4791f36e99a4SAndrii Nakryiko } 4792f36e99a4SAndrii Nakryiko 4793f36e99a4SAndrii Nakryiko default: 4794f36e99a4SAndrii Nakryiko return -EINVAL; 4795f36e99a4SAndrii Nakryiko } 4796f36e99a4SAndrii Nakryiko } 4797f36e99a4SAndrii Nakryiko 4798f36e99a4SAndrii Nakryiko int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx) 4799f36e99a4SAndrii Nakryiko { 4800f36e99a4SAndrii Nakryiko int i, n, err; 4801f36e99a4SAndrii Nakryiko 4802f36e99a4SAndrii Nakryiko err = visit(&t->name_off, ctx); 4803f36e99a4SAndrii Nakryiko if (err) 4804f36e99a4SAndrii Nakryiko return err; 4805f36e99a4SAndrii Nakryiko 4806f36e99a4SAndrii Nakryiko switch (btf_kind(t)) { 4807f36e99a4SAndrii Nakryiko case BTF_KIND_STRUCT: 4808f36e99a4SAndrii Nakryiko case BTF_KIND_UNION: { 4809f36e99a4SAndrii Nakryiko struct btf_member *m = btf_members(t); 4810f36e99a4SAndrii Nakryiko 4811f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4812f36e99a4SAndrii Nakryiko err = visit(&m->name_off, ctx); 4813f36e99a4SAndrii Nakryiko if (err) 4814f36e99a4SAndrii Nakryiko return err; 4815f36e99a4SAndrii Nakryiko } 4816f36e99a4SAndrii Nakryiko break; 4817f36e99a4SAndrii Nakryiko } 4818f36e99a4SAndrii Nakryiko case BTF_KIND_ENUM: { 4819f36e99a4SAndrii Nakryiko struct btf_enum *m = btf_enum(t); 4820f36e99a4SAndrii Nakryiko 4821f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4822f36e99a4SAndrii Nakryiko err = visit(&m->name_off, ctx); 4823f36e99a4SAndrii Nakryiko if (err) 4824f36e99a4SAndrii Nakryiko return err; 4825f36e99a4SAndrii Nakryiko } 4826f36e99a4SAndrii Nakryiko break; 4827f36e99a4SAndrii Nakryiko } 4828f36e99a4SAndrii Nakryiko case BTF_KIND_FUNC_PROTO: { 4829f36e99a4SAndrii Nakryiko struct btf_param *m = btf_params(t); 4830f36e99a4SAndrii Nakryiko 4831f36e99a4SAndrii Nakryiko for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4832f36e99a4SAndrii Nakryiko err = visit(&m->name_off, ctx); 4833f36e99a4SAndrii Nakryiko if (err) 4834f36e99a4SAndrii Nakryiko return err; 4835f36e99a4SAndrii Nakryiko } 4836f36e99a4SAndrii Nakryiko break; 4837f36e99a4SAndrii Nakryiko } 4838f36e99a4SAndrii Nakryiko default: 4839f36e99a4SAndrii Nakryiko break; 4840f36e99a4SAndrii Nakryiko } 4841f36e99a4SAndrii Nakryiko 4842f36e99a4SAndrii Nakryiko return 0; 4843f36e99a4SAndrii Nakryiko } 4844f36e99a4SAndrii Nakryiko 4845f36e99a4SAndrii Nakryiko int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx) 4846f36e99a4SAndrii Nakryiko { 4847f36e99a4SAndrii Nakryiko const struct btf_ext_info *seg; 4848f36e99a4SAndrii Nakryiko struct btf_ext_info_sec *sec; 4849f36e99a4SAndrii Nakryiko int i, err; 4850f36e99a4SAndrii Nakryiko 4851f36e99a4SAndrii Nakryiko seg = &btf_ext->func_info; 4852f36e99a4SAndrii Nakryiko for_each_btf_ext_sec(seg, sec) { 4853f36e99a4SAndrii Nakryiko struct bpf_func_info_min *rec; 4854f36e99a4SAndrii Nakryiko 4855f36e99a4SAndrii Nakryiko for_each_btf_ext_rec(seg, sec, i, rec) { 4856f36e99a4SAndrii Nakryiko err = visit(&rec->type_id, ctx); 4857f36e99a4SAndrii Nakryiko if (err < 0) 4858f36e99a4SAndrii Nakryiko return err; 4859f36e99a4SAndrii Nakryiko } 4860f36e99a4SAndrii Nakryiko } 4861f36e99a4SAndrii Nakryiko 4862f36e99a4SAndrii Nakryiko seg = &btf_ext->core_relo_info; 4863f36e99a4SAndrii Nakryiko for_each_btf_ext_sec(seg, sec) { 4864f36e99a4SAndrii Nakryiko struct bpf_core_relo *rec; 4865f36e99a4SAndrii Nakryiko 4866f36e99a4SAndrii Nakryiko for_each_btf_ext_rec(seg, sec, i, rec) { 4867f36e99a4SAndrii Nakryiko err = visit(&rec->type_id, ctx); 4868f36e99a4SAndrii Nakryiko if (err < 0) 4869f36e99a4SAndrii Nakryiko return err; 4870f36e99a4SAndrii Nakryiko } 4871f36e99a4SAndrii Nakryiko } 4872f36e99a4SAndrii Nakryiko 4873f36e99a4SAndrii Nakryiko return 0; 4874f36e99a4SAndrii Nakryiko } 4875f36e99a4SAndrii Nakryiko 4876f36e99a4SAndrii Nakryiko int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx) 4877f36e99a4SAndrii Nakryiko { 4878f36e99a4SAndrii Nakryiko const struct btf_ext_info *seg; 4879f36e99a4SAndrii Nakryiko struct btf_ext_info_sec *sec; 4880f36e99a4SAndrii Nakryiko int i, err; 4881f36e99a4SAndrii Nakryiko 4882f36e99a4SAndrii Nakryiko seg = &btf_ext->func_info; 4883f36e99a4SAndrii Nakryiko for_each_btf_ext_sec(seg, sec) { 4884f36e99a4SAndrii Nakryiko err = visit(&sec->sec_name_off, ctx); 4885f36e99a4SAndrii Nakryiko if (err) 4886f36e99a4SAndrii Nakryiko return err; 4887f36e99a4SAndrii Nakryiko } 4888f36e99a4SAndrii Nakryiko 4889f36e99a4SAndrii Nakryiko seg = &btf_ext->line_info; 4890f36e99a4SAndrii Nakryiko for_each_btf_ext_sec(seg, sec) { 4891f36e99a4SAndrii Nakryiko struct bpf_line_info_min *rec; 4892f36e99a4SAndrii Nakryiko 4893f36e99a4SAndrii Nakryiko err = visit(&sec->sec_name_off, ctx); 4894f36e99a4SAndrii Nakryiko if (err) 4895f36e99a4SAndrii Nakryiko return err; 4896f36e99a4SAndrii Nakryiko 4897f36e99a4SAndrii Nakryiko for_each_btf_ext_rec(seg, sec, i, rec) { 4898f36e99a4SAndrii Nakryiko err = visit(&rec->file_name_off, ctx); 4899f36e99a4SAndrii Nakryiko if (err) 4900f36e99a4SAndrii Nakryiko return err; 4901f36e99a4SAndrii Nakryiko err = visit(&rec->line_off, ctx); 4902f36e99a4SAndrii Nakryiko if (err) 4903f36e99a4SAndrii Nakryiko return err; 4904f36e99a4SAndrii Nakryiko } 4905f36e99a4SAndrii Nakryiko } 4906f36e99a4SAndrii Nakryiko 4907f36e99a4SAndrii Nakryiko seg = &btf_ext->core_relo_info; 4908f36e99a4SAndrii Nakryiko for_each_btf_ext_sec(seg, sec) { 4909f36e99a4SAndrii Nakryiko struct bpf_core_relo *rec; 4910f36e99a4SAndrii Nakryiko 4911f36e99a4SAndrii Nakryiko err = visit(&sec->sec_name_off, ctx); 4912f36e99a4SAndrii Nakryiko if (err) 4913f36e99a4SAndrii Nakryiko return err; 4914f36e99a4SAndrii Nakryiko 4915f36e99a4SAndrii Nakryiko for_each_btf_ext_rec(seg, sec, i, rec) { 4916f36e99a4SAndrii Nakryiko err = visit(&rec->access_str_off, ctx); 4917f36e99a4SAndrii Nakryiko if (err) 4918f36e99a4SAndrii Nakryiko return err; 4919f36e99a4SAndrii Nakryiko } 4920f36e99a4SAndrii Nakryiko } 4921f36e99a4SAndrii Nakryiko 4922f36e99a4SAndrii Nakryiko return 0; 4923f36e99a4SAndrii Nakryiko } 4924