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