1*8a138aedSMartin KaFai Lau /* SPDX-License-Identifier: GPL-2.0 */ 2*8a138aedSMartin KaFai Lau /* Copyright (c) 2018 Facebook */ 3*8a138aedSMartin KaFai Lau 4*8a138aedSMartin KaFai Lau #include <stdlib.h> 5*8a138aedSMartin KaFai Lau #include <stdint.h> 6*8a138aedSMartin KaFai Lau #include <string.h> 7*8a138aedSMartin KaFai Lau #include <unistd.h> 8*8a138aedSMartin KaFai Lau #include <errno.h> 9*8a138aedSMartin KaFai Lau #include <linux/err.h> 10*8a138aedSMartin KaFai Lau #include <linux/btf.h> 11*8a138aedSMartin KaFai Lau #include "btf.h" 12*8a138aedSMartin KaFai Lau #include "bpf.h" 13*8a138aedSMartin KaFai Lau 14*8a138aedSMartin KaFai Lau #define elog(fmt, ...) { if (err_log) err_log(fmt, ##__VA_ARGS__); } 15*8a138aedSMartin KaFai Lau #define max(a, b) ((a) > (b) ? (a) : (b)) 16*8a138aedSMartin KaFai Lau #define min(a, b) ((a) < (b) ? (a) : (b)) 17*8a138aedSMartin KaFai Lau 18*8a138aedSMartin KaFai Lau #define BTF_MAX_NR_TYPES 65535 19*8a138aedSMartin KaFai Lau 20*8a138aedSMartin KaFai Lau static struct btf_type btf_void; 21*8a138aedSMartin KaFai Lau 22*8a138aedSMartin KaFai Lau struct btf { 23*8a138aedSMartin KaFai Lau union { 24*8a138aedSMartin KaFai Lau struct btf_header *hdr; 25*8a138aedSMartin KaFai Lau void *data; 26*8a138aedSMartin KaFai Lau }; 27*8a138aedSMartin KaFai Lau struct btf_type **types; 28*8a138aedSMartin KaFai Lau const char *strings; 29*8a138aedSMartin KaFai Lau void *nohdr_data; 30*8a138aedSMartin KaFai Lau uint32_t nr_types; 31*8a138aedSMartin KaFai Lau uint32_t types_size; 32*8a138aedSMartin KaFai Lau uint32_t data_size; 33*8a138aedSMartin KaFai Lau int fd; 34*8a138aedSMartin KaFai Lau }; 35*8a138aedSMartin KaFai Lau 36*8a138aedSMartin KaFai Lau static const char *btf_name_by_offset(const struct btf *btf, uint32_t offset) 37*8a138aedSMartin KaFai Lau { 38*8a138aedSMartin KaFai Lau if (!BTF_STR_TBL_ELF_ID(offset) && 39*8a138aedSMartin KaFai Lau BTF_STR_OFFSET(offset) < btf->hdr->str_len) 40*8a138aedSMartin KaFai Lau return &btf->strings[BTF_STR_OFFSET(offset)]; 41*8a138aedSMartin KaFai Lau else 42*8a138aedSMartin KaFai Lau return NULL; 43*8a138aedSMartin KaFai Lau } 44*8a138aedSMartin KaFai Lau 45*8a138aedSMartin KaFai Lau static int btf_add_type(struct btf *btf, struct btf_type *t) 46*8a138aedSMartin KaFai Lau { 47*8a138aedSMartin KaFai Lau if (btf->types_size - btf->nr_types < 2) { 48*8a138aedSMartin KaFai Lau struct btf_type **new_types; 49*8a138aedSMartin KaFai Lau u32 expand_by, new_size; 50*8a138aedSMartin KaFai Lau 51*8a138aedSMartin KaFai Lau if (btf->types_size == BTF_MAX_NR_TYPES) 52*8a138aedSMartin KaFai Lau return -E2BIG; 53*8a138aedSMartin KaFai Lau 54*8a138aedSMartin KaFai Lau expand_by = max(btf->types_size >> 2, 16); 55*8a138aedSMartin KaFai Lau new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by); 56*8a138aedSMartin KaFai Lau 57*8a138aedSMartin KaFai Lau new_types = realloc(btf->types, sizeof(*new_types) * new_size); 58*8a138aedSMartin KaFai Lau if (!new_types) 59*8a138aedSMartin KaFai Lau return -ENOMEM; 60*8a138aedSMartin KaFai Lau 61*8a138aedSMartin KaFai Lau if (btf->nr_types == 0) 62*8a138aedSMartin KaFai Lau new_types[0] = &btf_void; 63*8a138aedSMartin KaFai Lau 64*8a138aedSMartin KaFai Lau btf->types = new_types; 65*8a138aedSMartin KaFai Lau btf->types_size = new_size; 66*8a138aedSMartin KaFai Lau } 67*8a138aedSMartin KaFai Lau 68*8a138aedSMartin KaFai Lau btf->types[++(btf->nr_types)] = t; 69*8a138aedSMartin KaFai Lau 70*8a138aedSMartin KaFai Lau return 0; 71*8a138aedSMartin KaFai Lau } 72*8a138aedSMartin KaFai Lau 73*8a138aedSMartin KaFai Lau static int btf_parse_hdr(struct btf *btf, btf_print_fn_t err_log) 74*8a138aedSMartin KaFai Lau { 75*8a138aedSMartin KaFai Lau const struct btf_header *hdr = btf->hdr; 76*8a138aedSMartin KaFai Lau u32 meta_left; 77*8a138aedSMartin KaFai Lau 78*8a138aedSMartin KaFai Lau if (btf->data_size < sizeof(struct btf_header)) { 79*8a138aedSMartin KaFai Lau elog("BTF header not found\n"); 80*8a138aedSMartin KaFai Lau return -EINVAL; 81*8a138aedSMartin KaFai Lau } 82*8a138aedSMartin KaFai Lau 83*8a138aedSMartin KaFai Lau if (hdr->magic != BTF_MAGIC) { 84*8a138aedSMartin KaFai Lau elog("Invalid BTF magic:%x\n", hdr->magic); 85*8a138aedSMartin KaFai Lau return -EINVAL; 86*8a138aedSMartin KaFai Lau } 87*8a138aedSMartin KaFai Lau 88*8a138aedSMartin KaFai Lau if (hdr->version != BTF_VERSION) { 89*8a138aedSMartin KaFai Lau elog("Unsupported BTF version:%u\n", hdr->version); 90*8a138aedSMartin KaFai Lau return -ENOTSUP; 91*8a138aedSMartin KaFai Lau } 92*8a138aedSMartin KaFai Lau 93*8a138aedSMartin KaFai Lau if (hdr->flags) { 94*8a138aedSMartin KaFai Lau elog("Unsupported BTF flags:%x\n", hdr->flags); 95*8a138aedSMartin KaFai Lau return -ENOTSUP; 96*8a138aedSMartin KaFai Lau } 97*8a138aedSMartin KaFai Lau 98*8a138aedSMartin KaFai Lau meta_left = btf->data_size - sizeof(*hdr); 99*8a138aedSMartin KaFai Lau if (!meta_left) { 100*8a138aedSMartin KaFai Lau elog("BTF has no data\n"); 101*8a138aedSMartin KaFai Lau return -EINVAL; 102*8a138aedSMartin KaFai Lau } 103*8a138aedSMartin KaFai Lau 104*8a138aedSMartin KaFai Lau if (meta_left < hdr->type_off) { 105*8a138aedSMartin KaFai Lau elog("Invalid BTF type section offset:%u\n", hdr->type_off); 106*8a138aedSMartin KaFai Lau return -EINVAL; 107*8a138aedSMartin KaFai Lau } 108*8a138aedSMartin KaFai Lau 109*8a138aedSMartin KaFai Lau if (meta_left < hdr->str_off) { 110*8a138aedSMartin KaFai Lau elog("Invalid BTF string section offset:%u\n", hdr->str_off); 111*8a138aedSMartin KaFai Lau return -EINVAL; 112*8a138aedSMartin KaFai Lau } 113*8a138aedSMartin KaFai Lau 114*8a138aedSMartin KaFai Lau if (hdr->type_off >= hdr->str_off) { 115*8a138aedSMartin KaFai Lau elog("BTF type section offset >= string section offset. No type?\n"); 116*8a138aedSMartin KaFai Lau return -EINVAL; 117*8a138aedSMartin KaFai Lau } 118*8a138aedSMartin KaFai Lau 119*8a138aedSMartin KaFai Lau if (hdr->type_off & 0x02) { 120*8a138aedSMartin KaFai Lau elog("BTF type section is not aligned to 4 bytes\n"); 121*8a138aedSMartin KaFai Lau return -EINVAL; 122*8a138aedSMartin KaFai Lau } 123*8a138aedSMartin KaFai Lau 124*8a138aedSMartin KaFai Lau btf->nohdr_data = btf->hdr + 1; 125*8a138aedSMartin KaFai Lau 126*8a138aedSMartin KaFai Lau return 0; 127*8a138aedSMartin KaFai Lau } 128*8a138aedSMartin KaFai Lau 129*8a138aedSMartin KaFai Lau static int btf_parse_str_sec(struct btf *btf, btf_print_fn_t err_log) 130*8a138aedSMartin KaFai Lau { 131*8a138aedSMartin KaFai Lau const struct btf_header *hdr = btf->hdr; 132*8a138aedSMartin KaFai Lau const char *start = btf->nohdr_data + hdr->str_off; 133*8a138aedSMartin KaFai Lau const char *end = start + btf->hdr->str_len; 134*8a138aedSMartin KaFai Lau 135*8a138aedSMartin KaFai Lau if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET || 136*8a138aedSMartin KaFai Lau start[0] || end[-1]) { 137*8a138aedSMartin KaFai Lau elog("Invalid BTF string section\n"); 138*8a138aedSMartin KaFai Lau return -EINVAL; 139*8a138aedSMartin KaFai Lau } 140*8a138aedSMartin KaFai Lau 141*8a138aedSMartin KaFai Lau btf->strings = start; 142*8a138aedSMartin KaFai Lau 143*8a138aedSMartin KaFai Lau return 0; 144*8a138aedSMartin KaFai Lau } 145*8a138aedSMartin KaFai Lau 146*8a138aedSMartin KaFai Lau static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log) 147*8a138aedSMartin KaFai Lau { 148*8a138aedSMartin KaFai Lau struct btf_header *hdr = btf->hdr; 149*8a138aedSMartin KaFai Lau void *nohdr_data = btf->nohdr_data; 150*8a138aedSMartin KaFai Lau void *next_type = nohdr_data + hdr->type_off; 151*8a138aedSMartin KaFai Lau void *end_type = nohdr_data + hdr->str_off; 152*8a138aedSMartin KaFai Lau 153*8a138aedSMartin KaFai Lau while (next_type < end_type) { 154*8a138aedSMartin KaFai Lau struct btf_type *t = next_type; 155*8a138aedSMartin KaFai Lau uint16_t vlen = BTF_INFO_VLEN(t->info); 156*8a138aedSMartin KaFai Lau int err; 157*8a138aedSMartin KaFai Lau 158*8a138aedSMartin KaFai Lau next_type += sizeof(*t); 159*8a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 160*8a138aedSMartin KaFai Lau case BTF_KIND_INT: 161*8a138aedSMartin KaFai Lau next_type += sizeof(int); 162*8a138aedSMartin KaFai Lau break; 163*8a138aedSMartin KaFai Lau case BTF_KIND_ARRAY: 164*8a138aedSMartin KaFai Lau next_type += sizeof(struct btf_array); 165*8a138aedSMartin KaFai Lau break; 166*8a138aedSMartin KaFai Lau case BTF_KIND_STRUCT: 167*8a138aedSMartin KaFai Lau case BTF_KIND_UNION: 168*8a138aedSMartin KaFai Lau next_type += vlen * sizeof(struct btf_member); 169*8a138aedSMartin KaFai Lau break; 170*8a138aedSMartin KaFai Lau case BTF_KIND_ENUM: 171*8a138aedSMartin KaFai Lau next_type += vlen * sizeof(struct btf_enum); 172*8a138aedSMartin KaFai Lau break; 173*8a138aedSMartin KaFai Lau case BTF_KIND_TYPEDEF: 174*8a138aedSMartin KaFai Lau case BTF_KIND_PTR: 175*8a138aedSMartin KaFai Lau case BTF_KIND_FWD: 176*8a138aedSMartin KaFai Lau case BTF_KIND_VOLATILE: 177*8a138aedSMartin KaFai Lau case BTF_KIND_CONST: 178*8a138aedSMartin KaFai Lau case BTF_KIND_RESTRICT: 179*8a138aedSMartin KaFai Lau break; 180*8a138aedSMartin KaFai Lau default: 181*8a138aedSMartin KaFai Lau elog("Unsupported BTF_KIND:%u\n", 182*8a138aedSMartin KaFai Lau BTF_INFO_KIND(t->info)); 183*8a138aedSMartin KaFai Lau return -EINVAL; 184*8a138aedSMartin KaFai Lau } 185*8a138aedSMartin KaFai Lau 186*8a138aedSMartin KaFai Lau err = btf_add_type(btf, t); 187*8a138aedSMartin KaFai Lau if (err) 188*8a138aedSMartin KaFai Lau return err; 189*8a138aedSMartin KaFai Lau } 190*8a138aedSMartin KaFai Lau 191*8a138aedSMartin KaFai Lau return 0; 192*8a138aedSMartin KaFai Lau } 193*8a138aedSMartin KaFai Lau 194*8a138aedSMartin KaFai Lau static const struct btf_type *btf_type_by_id(const struct btf *btf, 195*8a138aedSMartin KaFai Lau uint32_t type_id) 196*8a138aedSMartin KaFai Lau { 197*8a138aedSMartin KaFai Lau if (type_id > btf->nr_types) 198*8a138aedSMartin KaFai Lau return NULL; 199*8a138aedSMartin KaFai Lau 200*8a138aedSMartin KaFai Lau return btf->types[type_id]; 201*8a138aedSMartin KaFai Lau } 202*8a138aedSMartin KaFai Lau 203*8a138aedSMartin KaFai Lau static bool btf_type_is_void(const struct btf_type *t) 204*8a138aedSMartin KaFai Lau { 205*8a138aedSMartin KaFai Lau return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD; 206*8a138aedSMartin KaFai Lau } 207*8a138aedSMartin KaFai Lau 208*8a138aedSMartin KaFai Lau static bool btf_type_is_void_or_null(const struct btf_type *t) 209*8a138aedSMartin KaFai Lau { 210*8a138aedSMartin KaFai Lau return !t || btf_type_is_void(t); 211*8a138aedSMartin KaFai Lau } 212*8a138aedSMartin KaFai Lau 213*8a138aedSMartin KaFai Lau static int64_t btf_type_size(const struct btf_type *t) 214*8a138aedSMartin KaFai Lau { 215*8a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 216*8a138aedSMartin KaFai Lau case BTF_KIND_INT: 217*8a138aedSMartin KaFai Lau case BTF_KIND_STRUCT: 218*8a138aedSMartin KaFai Lau case BTF_KIND_UNION: 219*8a138aedSMartin KaFai Lau case BTF_KIND_ENUM: 220*8a138aedSMartin KaFai Lau return t->size; 221*8a138aedSMartin KaFai Lau case BTF_KIND_PTR: 222*8a138aedSMartin KaFai Lau return sizeof(void *); 223*8a138aedSMartin KaFai Lau default: 224*8a138aedSMartin KaFai Lau return -EINVAL; 225*8a138aedSMartin KaFai Lau } 226*8a138aedSMartin KaFai Lau } 227*8a138aedSMartin KaFai Lau 228*8a138aedSMartin KaFai Lau #define MAX_RESOLVE_DEPTH 32 229*8a138aedSMartin KaFai Lau 230*8a138aedSMartin KaFai Lau int64_t btf__resolve_size(const struct btf *btf, uint32_t type_id) 231*8a138aedSMartin KaFai Lau { 232*8a138aedSMartin KaFai Lau const struct btf_array *array; 233*8a138aedSMartin KaFai Lau const struct btf_type *t; 234*8a138aedSMartin KaFai Lau uint32_t nelems = 1; 235*8a138aedSMartin KaFai Lau int64_t size = -1; 236*8a138aedSMartin KaFai Lau int i; 237*8a138aedSMartin KaFai Lau 238*8a138aedSMartin KaFai Lau t = btf_type_by_id(btf, type_id); 239*8a138aedSMartin KaFai Lau for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); 240*8a138aedSMartin KaFai Lau i++) { 241*8a138aedSMartin KaFai Lau size = btf_type_size(t); 242*8a138aedSMartin KaFai Lau if (size >= 0) 243*8a138aedSMartin KaFai Lau break; 244*8a138aedSMartin KaFai Lau 245*8a138aedSMartin KaFai Lau switch (BTF_INFO_KIND(t->info)) { 246*8a138aedSMartin KaFai Lau case BTF_KIND_TYPEDEF: 247*8a138aedSMartin KaFai Lau case BTF_KIND_VOLATILE: 248*8a138aedSMartin KaFai Lau case BTF_KIND_CONST: 249*8a138aedSMartin KaFai Lau case BTF_KIND_RESTRICT: 250*8a138aedSMartin KaFai Lau type_id = t->type; 251*8a138aedSMartin KaFai Lau break; 252*8a138aedSMartin KaFai Lau case BTF_KIND_ARRAY: 253*8a138aedSMartin KaFai Lau array = (const struct btf_array *)(t + 1); 254*8a138aedSMartin KaFai Lau if (nelems && array->nelems > UINT32_MAX / nelems) 255*8a138aedSMartin KaFai Lau return -E2BIG; 256*8a138aedSMartin KaFai Lau nelems *= array->nelems; 257*8a138aedSMartin KaFai Lau type_id = array->type; 258*8a138aedSMartin KaFai Lau break; 259*8a138aedSMartin KaFai Lau default: 260*8a138aedSMartin KaFai Lau return -EINVAL; 261*8a138aedSMartin KaFai Lau } 262*8a138aedSMartin KaFai Lau 263*8a138aedSMartin KaFai Lau t = btf_type_by_id(btf, type_id); 264*8a138aedSMartin KaFai Lau } 265*8a138aedSMartin KaFai Lau 266*8a138aedSMartin KaFai Lau if (size < 0) 267*8a138aedSMartin KaFai Lau return -EINVAL; 268*8a138aedSMartin KaFai Lau 269*8a138aedSMartin KaFai Lau if (nelems && size > UINT32_MAX / nelems) 270*8a138aedSMartin KaFai Lau return -E2BIG; 271*8a138aedSMartin KaFai Lau 272*8a138aedSMartin KaFai Lau return nelems * size; 273*8a138aedSMartin KaFai Lau } 274*8a138aedSMartin KaFai Lau 275*8a138aedSMartin KaFai Lau int32_t btf__find_by_name(const struct btf *btf, const char *type_name) 276*8a138aedSMartin KaFai Lau { 277*8a138aedSMartin KaFai Lau uint32_t i; 278*8a138aedSMartin KaFai Lau 279*8a138aedSMartin KaFai Lau if (!strcmp(type_name, "void")) 280*8a138aedSMartin KaFai Lau return 0; 281*8a138aedSMartin KaFai Lau 282*8a138aedSMartin KaFai Lau for (i = 1; i <= btf->nr_types; i++) { 283*8a138aedSMartin KaFai Lau const struct btf_type *t = btf->types[i]; 284*8a138aedSMartin KaFai Lau const char *name = btf_name_by_offset(btf, t->name); 285*8a138aedSMartin KaFai Lau 286*8a138aedSMartin KaFai Lau if (name && !strcmp(type_name, name)) 287*8a138aedSMartin KaFai Lau return i; 288*8a138aedSMartin KaFai Lau } 289*8a138aedSMartin KaFai Lau 290*8a138aedSMartin KaFai Lau return -ENOENT; 291*8a138aedSMartin KaFai Lau } 292*8a138aedSMartin KaFai Lau 293*8a138aedSMartin KaFai Lau void btf__free(struct btf *btf) 294*8a138aedSMartin KaFai Lau { 295*8a138aedSMartin KaFai Lau if (!btf) 296*8a138aedSMartin KaFai Lau return; 297*8a138aedSMartin KaFai Lau 298*8a138aedSMartin KaFai Lau if (btf->fd != -1) 299*8a138aedSMartin KaFai Lau close(btf->fd); 300*8a138aedSMartin KaFai Lau 301*8a138aedSMartin KaFai Lau free(btf->data); 302*8a138aedSMartin KaFai Lau free(btf->types); 303*8a138aedSMartin KaFai Lau free(btf); 304*8a138aedSMartin KaFai Lau } 305*8a138aedSMartin KaFai Lau 306*8a138aedSMartin KaFai Lau struct btf *btf__new(uint8_t *data, uint32_t size, 307*8a138aedSMartin KaFai Lau btf_print_fn_t err_log) 308*8a138aedSMartin KaFai Lau { 309*8a138aedSMartin KaFai Lau uint32_t log_buf_size = 0; 310*8a138aedSMartin KaFai Lau char *log_buf = NULL; 311*8a138aedSMartin KaFai Lau struct btf *btf; 312*8a138aedSMartin KaFai Lau int err; 313*8a138aedSMartin KaFai Lau 314*8a138aedSMartin KaFai Lau btf = calloc(1, sizeof(struct btf)); 315*8a138aedSMartin KaFai Lau if (!btf) 316*8a138aedSMartin KaFai Lau return ERR_PTR(-ENOMEM); 317*8a138aedSMartin KaFai Lau 318*8a138aedSMartin KaFai Lau btf->fd = -1; 319*8a138aedSMartin KaFai Lau 320*8a138aedSMartin KaFai Lau if (err_log) { 321*8a138aedSMartin KaFai Lau log_buf = malloc(BPF_LOG_BUF_SIZE); 322*8a138aedSMartin KaFai Lau if (!log_buf) { 323*8a138aedSMartin KaFai Lau err = -ENOMEM; 324*8a138aedSMartin KaFai Lau goto done; 325*8a138aedSMartin KaFai Lau } 326*8a138aedSMartin KaFai Lau *log_buf = 0; 327*8a138aedSMartin KaFai Lau log_buf_size = BPF_LOG_BUF_SIZE; 328*8a138aedSMartin KaFai Lau } 329*8a138aedSMartin KaFai Lau 330*8a138aedSMartin KaFai Lau btf->data = malloc(size); 331*8a138aedSMartin KaFai Lau if (!btf->data) { 332*8a138aedSMartin KaFai Lau err = -ENOMEM; 333*8a138aedSMartin KaFai Lau goto done; 334*8a138aedSMartin KaFai Lau } 335*8a138aedSMartin KaFai Lau 336*8a138aedSMartin KaFai Lau memcpy(btf->data, data, size); 337*8a138aedSMartin KaFai Lau btf->data_size = size; 338*8a138aedSMartin KaFai Lau 339*8a138aedSMartin KaFai Lau btf->fd = bpf_load_btf(btf->data, btf->data_size, 340*8a138aedSMartin KaFai Lau log_buf, log_buf_size, false); 341*8a138aedSMartin KaFai Lau 342*8a138aedSMartin KaFai Lau if (btf->fd == -1) { 343*8a138aedSMartin KaFai Lau err = -errno; 344*8a138aedSMartin KaFai Lau elog("Error loading BTF: %s(%d)\n", strerror(errno), errno); 345*8a138aedSMartin KaFai Lau if (log_buf && *log_buf) 346*8a138aedSMartin KaFai Lau elog("%s\n", log_buf); 347*8a138aedSMartin KaFai Lau goto done; 348*8a138aedSMartin KaFai Lau } 349*8a138aedSMartin KaFai Lau 350*8a138aedSMartin KaFai Lau err = btf_parse_hdr(btf, err_log); 351*8a138aedSMartin KaFai Lau if (err) 352*8a138aedSMartin KaFai Lau goto done; 353*8a138aedSMartin KaFai Lau 354*8a138aedSMartin KaFai Lau err = btf_parse_str_sec(btf, err_log); 355*8a138aedSMartin KaFai Lau if (err) 356*8a138aedSMartin KaFai Lau goto done; 357*8a138aedSMartin KaFai Lau 358*8a138aedSMartin KaFai Lau err = btf_parse_type_sec(btf, err_log); 359*8a138aedSMartin KaFai Lau 360*8a138aedSMartin KaFai Lau done: 361*8a138aedSMartin KaFai Lau free(log_buf); 362*8a138aedSMartin KaFai Lau 363*8a138aedSMartin KaFai Lau if (err) { 364*8a138aedSMartin KaFai Lau btf__free(btf); 365*8a138aedSMartin KaFai Lau return ERR_PTR(err); 366*8a138aedSMartin KaFai Lau } 367*8a138aedSMartin KaFai Lau 368*8a138aedSMartin KaFai Lau return btf; 369*8a138aedSMartin KaFai Lau } 370*8a138aedSMartin KaFai Lau 371*8a138aedSMartin KaFai Lau int btf__fd(const struct btf *btf) 372*8a138aedSMartin KaFai Lau { 373*8a138aedSMartin KaFai Lau return btf->fd; 374*8a138aedSMartin KaFai Lau } 375