1*1bc38b8fSAlexei Starovoitov // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 28a138aedSMartin KaFai Lau /* Copyright (c) 2018 Facebook */ 38a138aedSMartin KaFai Lau 48a138aedSMartin KaFai Lau #include <stdlib.h> 58a138aedSMartin KaFai Lau #include <string.h> 68a138aedSMartin KaFai Lau #include <unistd.h> 78a138aedSMartin KaFai Lau #include <errno.h> 88a138aedSMartin KaFai Lau #include <linux/err.h> 98a138aedSMartin KaFai Lau #include <linux/btf.h> 108a138aedSMartin KaFai Lau #include "btf.h" 118a138aedSMartin KaFai Lau #include "bpf.h" 128a138aedSMartin KaFai Lau 138a138aedSMartin KaFai Lau #define elog(fmt, ...) { if (err_log) err_log(fmt, ##__VA_ARGS__); } 148a138aedSMartin KaFai Lau #define max(a, b) ((a) > (b) ? (a) : (b)) 158a138aedSMartin KaFai Lau #define min(a, b) ((a) < (b) ? (a) : (b)) 168a138aedSMartin KaFai Lau 178a138aedSMartin KaFai Lau #define BTF_MAX_NR_TYPES 65535 188a138aedSMartin KaFai Lau 1992b57121SOkash Khawaja #define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \ 2092b57121SOkash Khawaja ((k) == BTF_KIND_VOLATILE) || \ 2192b57121SOkash Khawaja ((k) == BTF_KIND_CONST) || \ 2292b57121SOkash Khawaja ((k) == BTF_KIND_RESTRICT)) 2392b57121SOkash Khawaja 248a138aedSMartin KaFai Lau static struct btf_type btf_void; 258a138aedSMartin KaFai Lau 268a138aedSMartin KaFai Lau struct btf { 278a138aedSMartin KaFai Lau union { 288a138aedSMartin KaFai Lau struct btf_header *hdr; 298a138aedSMartin KaFai Lau void *data; 308a138aedSMartin KaFai Lau }; 318a138aedSMartin KaFai Lau struct btf_type **types; 328a138aedSMartin KaFai Lau const char *strings; 338a138aedSMartin KaFai Lau void *nohdr_data; 345b891af7SMartin KaFai Lau __u32 nr_types; 355b891af7SMartin KaFai Lau __u32 types_size; 365b891af7SMartin KaFai Lau __u32 data_size; 378a138aedSMartin KaFai Lau int fd; 388a138aedSMartin KaFai Lau }; 398a138aedSMartin KaFai Lau 408a138aedSMartin KaFai Lau static int btf_add_type(struct btf *btf, struct btf_type *t) 418a138aedSMartin KaFai Lau { 428a138aedSMartin KaFai Lau if (btf->types_size - btf->nr_types < 2) { 438a138aedSMartin KaFai Lau struct btf_type **new_types; 445b891af7SMartin KaFai Lau __u32 expand_by, new_size; 458a138aedSMartin KaFai Lau 468a138aedSMartin KaFai Lau if (btf->types_size == BTF_MAX_NR_TYPES) 478a138aedSMartin KaFai Lau return -E2BIG; 488a138aedSMartin KaFai Lau 498a138aedSMartin KaFai Lau expand_by = max(btf->types_size >> 2, 16); 508a138aedSMartin KaFai Lau new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by); 518a138aedSMartin KaFai Lau 528a138aedSMartin KaFai Lau new_types = realloc(btf->types, sizeof(*new_types) * new_size); 538a138aedSMartin KaFai Lau if (!new_types) 548a138aedSMartin KaFai Lau return -ENOMEM; 558a138aedSMartin KaFai Lau 568a138aedSMartin KaFai Lau if (btf->nr_types == 0) 578a138aedSMartin KaFai Lau new_types[0] = &btf_void; 588a138aedSMartin KaFai Lau 598a138aedSMartin KaFai Lau btf->types = new_types; 608a138aedSMartin KaFai Lau btf->types_size = new_size; 618a138aedSMartin KaFai Lau } 628a138aedSMartin KaFai Lau 638a138aedSMartin KaFai Lau btf->types[++(btf->nr_types)] = t; 648a138aedSMartin KaFai Lau 658a138aedSMartin KaFai Lau return 0; 668a138aedSMartin KaFai Lau } 678a138aedSMartin KaFai Lau 688a138aedSMartin KaFai Lau static int btf_parse_hdr(struct btf *btf, btf_print_fn_t err_log) 698a138aedSMartin KaFai Lau { 708a138aedSMartin KaFai Lau const struct btf_header *hdr = btf->hdr; 715b891af7SMartin KaFai Lau __u32 meta_left; 728a138aedSMartin KaFai Lau 738a138aedSMartin KaFai Lau if (btf->data_size < sizeof(struct btf_header)) { 748a138aedSMartin KaFai Lau elog("BTF header not found\n"); 758a138aedSMartin KaFai Lau return -EINVAL; 768a138aedSMartin KaFai Lau } 778a138aedSMartin KaFai Lau 788a138aedSMartin KaFai Lau if (hdr->magic != BTF_MAGIC) { 798a138aedSMartin KaFai Lau elog("Invalid BTF magic:%x\n", hdr->magic); 808a138aedSMartin KaFai Lau return -EINVAL; 818a138aedSMartin KaFai Lau } 828a138aedSMartin KaFai Lau 838a138aedSMartin KaFai Lau if (hdr->version != BTF_VERSION) { 848a138aedSMartin KaFai Lau elog("Unsupported BTF version:%u\n", hdr->version); 858a138aedSMartin KaFai Lau return -ENOTSUP; 868a138aedSMartin KaFai Lau } 878a138aedSMartin KaFai Lau 888a138aedSMartin KaFai Lau if (hdr->flags) { 898a138aedSMartin KaFai Lau elog("Unsupported BTF flags:%x\n", hdr->flags); 908a138aedSMartin KaFai Lau return -ENOTSUP; 918a138aedSMartin KaFai Lau } 928a138aedSMartin KaFai Lau 938a138aedSMartin KaFai Lau meta_left = btf->data_size - sizeof(*hdr); 948a138aedSMartin KaFai Lau if (!meta_left) { 958a138aedSMartin KaFai Lau elog("BTF has no data\n"); 968a138aedSMartin KaFai Lau return -EINVAL; 978a138aedSMartin KaFai Lau } 988a138aedSMartin KaFai Lau 998a138aedSMartin KaFai Lau if (meta_left < hdr->type_off) { 1008a138aedSMartin KaFai Lau elog("Invalid BTF type section offset:%u\n", hdr->type_off); 1018a138aedSMartin KaFai Lau return -EINVAL; 1028a138aedSMartin KaFai Lau } 1038a138aedSMartin KaFai Lau 1048a138aedSMartin KaFai Lau if (meta_left < hdr->str_off) { 1058a138aedSMartin KaFai Lau elog("Invalid BTF string section offset:%u\n", hdr->str_off); 1068a138aedSMartin KaFai Lau return -EINVAL; 1078a138aedSMartin KaFai Lau } 1088a138aedSMartin KaFai Lau 1098a138aedSMartin KaFai Lau if (hdr->type_off >= hdr->str_off) { 1108a138aedSMartin KaFai Lau elog("BTF type section offset >= string section offset. No type?\n"); 1118a138aedSMartin KaFai Lau return -EINVAL; 1128a138aedSMartin KaFai Lau } 1138a138aedSMartin KaFai Lau 1148a138aedSMartin KaFai Lau if (hdr->type_off & 0x02) { 1158a138aedSMartin KaFai Lau elog("BTF type section is not aligned to 4 bytes\n"); 1168a138aedSMartin KaFai Lau return -EINVAL; 1178a138aedSMartin KaFai Lau } 1188a138aedSMartin KaFai Lau 1198a138aedSMartin KaFai Lau btf->nohdr_data = btf->hdr + 1; 1208a138aedSMartin KaFai Lau 1218a138aedSMartin KaFai Lau return 0; 1228a138aedSMartin KaFai Lau } 1238a138aedSMartin KaFai Lau 1248a138aedSMartin KaFai Lau static int btf_parse_str_sec(struct btf *btf, btf_print_fn_t err_log) 1258a138aedSMartin KaFai Lau { 1268a138aedSMartin KaFai Lau const struct btf_header *hdr = btf->hdr; 1278a138aedSMartin KaFai Lau const char *start = btf->nohdr_data + hdr->str_off; 1288a138aedSMartin KaFai Lau const char *end = start + btf->hdr->str_len; 1298a138aedSMartin KaFai Lau 1308a138aedSMartin KaFai Lau if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET || 1318a138aedSMartin KaFai Lau start[0] || end[-1]) { 1328a138aedSMartin KaFai Lau elog("Invalid BTF string section\n"); 1338a138aedSMartin KaFai Lau return -EINVAL; 1348a138aedSMartin KaFai Lau } 1358a138aedSMartin KaFai Lau 1368a138aedSMartin KaFai Lau btf->strings = start; 1378a138aedSMartin KaFai Lau 1388a138aedSMartin KaFai Lau return 0; 1398a138aedSMartin KaFai Lau } 1408a138aedSMartin KaFai Lau 1418a138aedSMartin KaFai Lau static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log) 1428a138aedSMartin KaFai Lau { 1438a138aedSMartin KaFai Lau struct btf_header *hdr = btf->hdr; 1448a138aedSMartin KaFai Lau void *nohdr_data = btf->nohdr_data; 1458a138aedSMartin KaFai Lau void *next_type = nohdr_data + hdr->type_off; 1468a138aedSMartin KaFai Lau void *end_type = nohdr_data + hdr->str_off; 1478a138aedSMartin KaFai Lau 1488a138aedSMartin KaFai Lau while (next_type < end_type) { 1498a138aedSMartin KaFai Lau struct btf_type *t = next_type; 1505b891af7SMartin KaFai Lau __u16 vlen = BTF_INFO_VLEN(t->info); 1518a138aedSMartin KaFai Lau int err; 1528a138aedSMartin KaFai Lau 1538a138aedSMartin KaFai Lau next_type += sizeof(*t); 1548a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 1558a138aedSMartin KaFai Lau case BTF_KIND_INT: 1568a138aedSMartin KaFai Lau next_type += sizeof(int); 1578a138aedSMartin KaFai Lau break; 1588a138aedSMartin KaFai Lau case BTF_KIND_ARRAY: 1598a138aedSMartin KaFai Lau next_type += sizeof(struct btf_array); 1608a138aedSMartin KaFai Lau break; 1618a138aedSMartin KaFai Lau case BTF_KIND_STRUCT: 1628a138aedSMartin KaFai Lau case BTF_KIND_UNION: 1638a138aedSMartin KaFai Lau next_type += vlen * sizeof(struct btf_member); 1648a138aedSMartin KaFai Lau break; 1658a138aedSMartin KaFai Lau case BTF_KIND_ENUM: 1668a138aedSMartin KaFai Lau next_type += vlen * sizeof(struct btf_enum); 1678a138aedSMartin KaFai Lau break; 1688a138aedSMartin KaFai Lau case BTF_KIND_TYPEDEF: 1698a138aedSMartin KaFai Lau case BTF_KIND_PTR: 1708a138aedSMartin KaFai Lau case BTF_KIND_FWD: 1718a138aedSMartin KaFai Lau case BTF_KIND_VOLATILE: 1728a138aedSMartin KaFai Lau case BTF_KIND_CONST: 1738a138aedSMartin KaFai Lau case BTF_KIND_RESTRICT: 1748a138aedSMartin KaFai Lau break; 1758a138aedSMartin KaFai Lau default: 1768a138aedSMartin KaFai Lau elog("Unsupported BTF_KIND:%u\n", 1778a138aedSMartin KaFai Lau BTF_INFO_KIND(t->info)); 1788a138aedSMartin KaFai Lau return -EINVAL; 1798a138aedSMartin KaFai Lau } 1808a138aedSMartin KaFai Lau 1818a138aedSMartin KaFai Lau err = btf_add_type(btf, t); 1828a138aedSMartin KaFai Lau if (err) 1838a138aedSMartin KaFai Lau return err; 1848a138aedSMartin KaFai Lau } 1858a138aedSMartin KaFai Lau 1868a138aedSMartin KaFai Lau return 0; 1878a138aedSMartin KaFai Lau } 1888a138aedSMartin KaFai Lau 18938d5d3b3SMartin KaFai Lau const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id) 1908a138aedSMartin KaFai Lau { 1918a138aedSMartin KaFai Lau if (type_id > btf->nr_types) 1928a138aedSMartin KaFai Lau return NULL; 1938a138aedSMartin KaFai Lau 1948a138aedSMartin KaFai Lau return btf->types[type_id]; 1958a138aedSMartin KaFai Lau } 1968a138aedSMartin KaFai Lau 1978a138aedSMartin KaFai Lau static bool btf_type_is_void(const struct btf_type *t) 1988a138aedSMartin KaFai Lau { 1998a138aedSMartin KaFai Lau return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD; 2008a138aedSMartin KaFai Lau } 2018a138aedSMartin KaFai Lau 2028a138aedSMartin KaFai Lau static bool btf_type_is_void_or_null(const struct btf_type *t) 2038a138aedSMartin KaFai Lau { 2048a138aedSMartin KaFai Lau return !t || btf_type_is_void(t); 2058a138aedSMartin KaFai Lau } 2068a138aedSMartin KaFai Lau 2075b891af7SMartin KaFai Lau static __s64 btf_type_size(const struct btf_type *t) 2088a138aedSMartin KaFai Lau { 2098a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 2108a138aedSMartin KaFai Lau case BTF_KIND_INT: 2118a138aedSMartin KaFai Lau case BTF_KIND_STRUCT: 2128a138aedSMartin KaFai Lau case BTF_KIND_UNION: 2138a138aedSMartin KaFai Lau case BTF_KIND_ENUM: 2148a138aedSMartin KaFai Lau return t->size; 2158a138aedSMartin KaFai Lau case BTF_KIND_PTR: 2168a138aedSMartin KaFai Lau return sizeof(void *); 2178a138aedSMartin KaFai Lau default: 2188a138aedSMartin KaFai Lau return -EINVAL; 2198a138aedSMartin KaFai Lau } 2208a138aedSMartin KaFai Lau } 2218a138aedSMartin KaFai Lau 2228a138aedSMartin KaFai Lau #define MAX_RESOLVE_DEPTH 32 2238a138aedSMartin KaFai Lau 2245b891af7SMartin KaFai Lau __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) 2258a138aedSMartin KaFai Lau { 2268a138aedSMartin KaFai Lau const struct btf_array *array; 2278a138aedSMartin KaFai Lau const struct btf_type *t; 2285b891af7SMartin KaFai Lau __u32 nelems = 1; 2295b891af7SMartin KaFai Lau __s64 size = -1; 2308a138aedSMartin KaFai Lau int i; 2318a138aedSMartin KaFai Lau 23292b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 2338a138aedSMartin KaFai Lau for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); 2348a138aedSMartin KaFai Lau i++) { 2358a138aedSMartin KaFai Lau size = btf_type_size(t); 2368a138aedSMartin KaFai Lau if (size >= 0) 2378a138aedSMartin KaFai Lau break; 2388a138aedSMartin KaFai Lau 2398a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 2408a138aedSMartin KaFai Lau case BTF_KIND_TYPEDEF: 2418a138aedSMartin KaFai Lau case BTF_KIND_VOLATILE: 2428a138aedSMartin KaFai Lau case BTF_KIND_CONST: 2438a138aedSMartin KaFai Lau case BTF_KIND_RESTRICT: 2448a138aedSMartin KaFai Lau type_id = t->type; 2458a138aedSMartin KaFai Lau break; 2468a138aedSMartin KaFai Lau case BTF_KIND_ARRAY: 2478a138aedSMartin KaFai Lau array = (const struct btf_array *)(t + 1); 2488a138aedSMartin KaFai Lau if (nelems && array->nelems > UINT32_MAX / nelems) 2498a138aedSMartin KaFai Lau return -E2BIG; 2508a138aedSMartin KaFai Lau nelems *= array->nelems; 2518a138aedSMartin KaFai Lau type_id = array->type; 2528a138aedSMartin KaFai Lau break; 2538a138aedSMartin KaFai Lau default: 2548a138aedSMartin KaFai Lau return -EINVAL; 2558a138aedSMartin KaFai Lau } 2568a138aedSMartin KaFai Lau 25792b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 2588a138aedSMartin KaFai Lau } 2598a138aedSMartin KaFai Lau 2608a138aedSMartin KaFai Lau if (size < 0) 2618a138aedSMartin KaFai Lau return -EINVAL; 2628a138aedSMartin KaFai Lau 2638a138aedSMartin KaFai Lau if (nelems && size > UINT32_MAX / nelems) 2648a138aedSMartin KaFai Lau return -E2BIG; 2658a138aedSMartin KaFai Lau 2668a138aedSMartin KaFai Lau return nelems * size; 2678a138aedSMartin KaFai Lau } 2688a138aedSMartin KaFai Lau 26992b57121SOkash Khawaja int btf__resolve_type(const struct btf *btf, __u32 type_id) 27092b57121SOkash Khawaja { 27192b57121SOkash Khawaja const struct btf_type *t; 27292b57121SOkash Khawaja int depth = 0; 27392b57121SOkash Khawaja 27492b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 27592b57121SOkash Khawaja while (depth < MAX_RESOLVE_DEPTH && 27692b57121SOkash Khawaja !btf_type_is_void_or_null(t) && 27792b57121SOkash Khawaja IS_MODIFIER(BTF_INFO_KIND(t->info))) { 27892b57121SOkash Khawaja type_id = t->type; 27992b57121SOkash Khawaja t = btf__type_by_id(btf, type_id); 28092b57121SOkash Khawaja depth++; 28192b57121SOkash Khawaja } 28292b57121SOkash Khawaja 28392b57121SOkash Khawaja if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t)) 28492b57121SOkash Khawaja return -EINVAL; 28592b57121SOkash Khawaja 28692b57121SOkash Khawaja return type_id; 28792b57121SOkash Khawaja } 28892b57121SOkash Khawaja 2895b891af7SMartin KaFai Lau __s32 btf__find_by_name(const struct btf *btf, const char *type_name) 2908a138aedSMartin KaFai Lau { 2915b891af7SMartin KaFai Lau __u32 i; 2928a138aedSMartin KaFai Lau 2938a138aedSMartin KaFai Lau if (!strcmp(type_name, "void")) 2948a138aedSMartin KaFai Lau return 0; 2958a138aedSMartin KaFai Lau 2968a138aedSMartin KaFai Lau for (i = 1; i <= btf->nr_types; i++) { 2978a138aedSMartin KaFai Lau const struct btf_type *t = btf->types[i]; 29892b57121SOkash Khawaja const char *name = btf__name_by_offset(btf, t->name_off); 2998a138aedSMartin KaFai Lau 3008a138aedSMartin KaFai Lau if (name && !strcmp(type_name, name)) 3018a138aedSMartin KaFai Lau return i; 3028a138aedSMartin KaFai Lau } 3038a138aedSMartin KaFai Lau 3048a138aedSMartin KaFai Lau return -ENOENT; 3058a138aedSMartin KaFai Lau } 3068a138aedSMartin KaFai Lau 3078a138aedSMartin KaFai Lau void btf__free(struct btf *btf) 3088a138aedSMartin KaFai Lau { 3098a138aedSMartin KaFai Lau if (!btf) 3108a138aedSMartin KaFai Lau return; 3118a138aedSMartin KaFai Lau 3128a138aedSMartin KaFai Lau if (btf->fd != -1) 3138a138aedSMartin KaFai Lau close(btf->fd); 3148a138aedSMartin KaFai Lau 3158a138aedSMartin KaFai Lau free(btf->data); 3168a138aedSMartin KaFai Lau free(btf->types); 3178a138aedSMartin KaFai Lau free(btf); 3188a138aedSMartin KaFai Lau } 3198a138aedSMartin KaFai Lau 3205b891af7SMartin KaFai Lau struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log) 3218a138aedSMartin KaFai Lau { 3225b891af7SMartin KaFai Lau __u32 log_buf_size = 0; 3238a138aedSMartin KaFai Lau char *log_buf = NULL; 3248a138aedSMartin KaFai Lau struct btf *btf; 3258a138aedSMartin KaFai Lau int err; 3268a138aedSMartin KaFai Lau 3278a138aedSMartin KaFai Lau btf = calloc(1, sizeof(struct btf)); 3288a138aedSMartin KaFai Lau if (!btf) 3298a138aedSMartin KaFai Lau return ERR_PTR(-ENOMEM); 3308a138aedSMartin KaFai Lau 3318a138aedSMartin KaFai Lau btf->fd = -1; 3328a138aedSMartin KaFai Lau 3338a138aedSMartin KaFai Lau if (err_log) { 3348a138aedSMartin KaFai Lau log_buf = malloc(BPF_LOG_BUF_SIZE); 3358a138aedSMartin KaFai Lau if (!log_buf) { 3368a138aedSMartin KaFai Lau err = -ENOMEM; 3378a138aedSMartin KaFai Lau goto done; 3388a138aedSMartin KaFai Lau } 3398a138aedSMartin KaFai Lau *log_buf = 0; 3408a138aedSMartin KaFai Lau log_buf_size = BPF_LOG_BUF_SIZE; 3418a138aedSMartin KaFai Lau } 3428a138aedSMartin KaFai Lau 3438a138aedSMartin KaFai Lau btf->data = malloc(size); 3448a138aedSMartin KaFai Lau if (!btf->data) { 3458a138aedSMartin KaFai Lau err = -ENOMEM; 3468a138aedSMartin KaFai Lau goto done; 3478a138aedSMartin KaFai Lau } 3488a138aedSMartin KaFai Lau 3498a138aedSMartin KaFai Lau memcpy(btf->data, data, size); 3508a138aedSMartin KaFai Lau btf->data_size = size; 3518a138aedSMartin KaFai Lau 3528a138aedSMartin KaFai Lau btf->fd = bpf_load_btf(btf->data, btf->data_size, 3538a138aedSMartin KaFai Lau log_buf, log_buf_size, false); 3548a138aedSMartin KaFai Lau 3558a138aedSMartin KaFai Lau if (btf->fd == -1) { 3568a138aedSMartin KaFai Lau err = -errno; 3578a138aedSMartin KaFai Lau elog("Error loading BTF: %s(%d)\n", strerror(errno), errno); 3588a138aedSMartin KaFai Lau if (log_buf && *log_buf) 3598a138aedSMartin KaFai Lau elog("%s\n", log_buf); 3608a138aedSMartin KaFai Lau goto done; 3618a138aedSMartin KaFai Lau } 3628a138aedSMartin KaFai Lau 3638a138aedSMartin KaFai Lau err = btf_parse_hdr(btf, err_log); 3648a138aedSMartin KaFai Lau if (err) 3658a138aedSMartin KaFai Lau goto done; 3668a138aedSMartin KaFai Lau 3678a138aedSMartin KaFai Lau err = btf_parse_str_sec(btf, err_log); 3688a138aedSMartin KaFai Lau if (err) 3698a138aedSMartin KaFai Lau goto done; 3708a138aedSMartin KaFai Lau 3718a138aedSMartin KaFai Lau err = btf_parse_type_sec(btf, err_log); 3728a138aedSMartin KaFai Lau 3738a138aedSMartin KaFai Lau done: 3748a138aedSMartin KaFai Lau free(log_buf); 3758a138aedSMartin KaFai Lau 3768a138aedSMartin KaFai Lau if (err) { 3778a138aedSMartin KaFai Lau btf__free(btf); 3788a138aedSMartin KaFai Lau return ERR_PTR(err); 3798a138aedSMartin KaFai Lau } 3808a138aedSMartin KaFai Lau 3818a138aedSMartin KaFai Lau return btf; 3828a138aedSMartin KaFai Lau } 3838a138aedSMartin KaFai Lau 3848a138aedSMartin KaFai Lau int btf__fd(const struct btf *btf) 3858a138aedSMartin KaFai Lau { 3868a138aedSMartin KaFai Lau return btf->fd; 3878a138aedSMartin KaFai Lau } 38892b57121SOkash Khawaja 38992b57121SOkash Khawaja const char *btf__name_by_offset(const struct btf *btf, __u32 offset) 39092b57121SOkash Khawaja { 39192b57121SOkash Khawaja if (offset < btf->hdr->str_len) 39292b57121SOkash Khawaja return &btf->strings[offset]; 39392b57121SOkash Khawaja else 39492b57121SOkash Khawaja return NULL; 39592b57121SOkash Khawaja } 396