691 lines · c
1/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */2 3/*4 * Internal libbpf helpers.5 *6 * Copyright (c) 2019 Facebook7 */8 9#ifndef __LIBBPF_LIBBPF_INTERNAL_H10#define __LIBBPF_LIBBPF_INTERNAL_H11 12#include <stdlib.h>13#include <limits.h>14#include <errno.h>15#include <linux/err.h>16#include <fcntl.h>17#include <unistd.h>18#include <sys/syscall.h>19#include <libelf.h>20#include "relo_core.h"21 22/* Android's libc doesn't support AT_EACCESS in faccessat() implementation23 * ([0]), and just returns -EINVAL even if file exists and is accessible.24 * See [1] for issues caused by this.25 *26 * So just redefine it to 0 on Android.27 *28 * [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#5029 * [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-191132425030 */31#ifdef __ANDROID__32#undef AT_EACCESS33#define AT_EACCESS 034#endif35 36/* make sure libbpf doesn't use kernel-only integer typedefs */37#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s6438 39/* prevent accidental re-addition of reallocarray() */40#pragma GCC poison reallocarray41 42#include "libbpf.h"43#include "btf.h"44 45#ifndef EM_BPF46#define EM_BPF 24747#endif48 49#ifndef R_BPF_64_6450#define R_BPF_64_64 151#endif52#ifndef R_BPF_64_ABS6453#define R_BPF_64_ABS64 254#endif55#ifndef R_BPF_64_ABS3256#define R_BPF_64_ABS32 357#endif58#ifndef R_BPF_64_3259#define R_BPF_64_32 1060#endif61 62#ifndef SHT_LLVM_ADDRSIG63#define SHT_LLVM_ADDRSIG 0x6FFF4C0364#endif65 66/* if libelf is old and doesn't support mmap(), fall back to read() */67#ifndef ELF_C_READ_MMAP68#define ELF_C_READ_MMAP ELF_C_READ69#endif70 71/* Older libelf all end up in this expression, for both 32 and 64 bit */72#ifndef ELF64_ST_VISIBILITY73#define ELF64_ST_VISIBILITY(o) ((o) & 0x03)74#endif75 76#define BTF_INFO_ENC(kind, kind_flag, vlen) \77 ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))78#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)79#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \80 ((encoding) << 24 | (bits_offset) << 16 | (nr_bits))81#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \82 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \83 BTF_INT_ENC(encoding, bits_offset, bits)84#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)85#define BTF_PARAM_ENC(name, type) (name), (type)86#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)87#define BTF_TYPE_FLOAT_ENC(name, sz) \88 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)89#define BTF_TYPE_DECL_TAG_ENC(value, type, component_idx) \90 BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx)91#define BTF_TYPE_TYPE_TAG_ENC(value, type) \92 BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type)93 94#ifndef likely95#define likely(x) __builtin_expect(!!(x), 1)96#endif97#ifndef unlikely98#define unlikely(x) __builtin_expect(!!(x), 0)99#endif100#ifndef min101# define min(x, y) ((x) < (y) ? (x) : (y))102#endif103#ifndef max104# define max(x, y) ((x) < (y) ? (y) : (x))105#endif106#ifndef offsetofend107# define offsetofend(TYPE, FIELD) \108 (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))109#endif110#ifndef __alias111#define __alias(symbol) __attribute__((alias(#symbol)))112#endif113 114/* Check whether a string `str` has prefix `pfx`, regardless if `pfx` is115 * a string literal known at compilation time or char * pointer known only at116 * runtime.117 */118#define str_has_pfx(str, pfx) \119 (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)120 121/* suffix check */122static inline bool str_has_sfx(const char *str, const char *sfx)123{124 size_t str_len = strlen(str);125 size_t sfx_len = strlen(sfx);126 127 if (sfx_len > str_len)128 return false;129 return strcmp(str + str_len - sfx_len, sfx) == 0;130}131 132/* Symbol versioning is different between static and shared library.133 * Properly versioned symbols are needed for shared library, but134 * only the symbol of the new version is needed for static library.135 * Starting with GNU C 10, use symver attribute instead of .symver assembler136 * directive, which works better with GCC LTO builds.137 */138#if defined(SHARED) && defined(__GNUC__) && __GNUC__ >= 10139 140#define DEFAULT_VERSION(internal_name, api_name, version) \141 __attribute__((symver(#api_name "@@" #version)))142#define COMPAT_VERSION(internal_name, api_name, version) \143 __attribute__((symver(#api_name "@" #version)))144 145#elif defined(SHARED)146 147#define COMPAT_VERSION(internal_name, api_name, version) \148 asm(".symver " #internal_name "," #api_name "@" #version);149#define DEFAULT_VERSION(internal_name, api_name, version) \150 asm(".symver " #internal_name "," #api_name "@@" #version);151 152#else /* !SHARED */153 154#define COMPAT_VERSION(internal_name, api_name, version)155#define DEFAULT_VERSION(internal_name, api_name, version) \156 extern typeof(internal_name) api_name \157 __attribute__((alias(#internal_name)));158 159#endif160 161extern void libbpf_print(enum libbpf_print_level level,162 const char *format, ...)163 __attribute__((format(printf, 2, 3)));164 165#define __pr(level, fmt, ...) \166do { \167 libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \168} while (0)169 170#define pr_warn(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__)171#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)172#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)173 174#ifndef __has_builtin175#define __has_builtin(x) 0176#endif177 178struct bpf_link {179 int (*detach)(struct bpf_link *link);180 void (*dealloc)(struct bpf_link *link);181 char *pin_path; /* NULL, if not pinned */182 int fd; /* hook FD, -1 if not applicable */183 bool disconnected;184};185 186/*187 * Re-implement glibc's reallocarray() for libbpf internal-only use.188 * reallocarray(), unfortunately, is not available in all versions of glibc,189 * so requires extra feature detection and using reallocarray() stub from190 * <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates191 * build of libbpf unnecessarily and is just a maintenance burden. Instead,192 * it's trivial to implement libbpf-specific internal version and use it193 * throughout libbpf.194 */195static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)196{197 size_t total;198 199#if __has_builtin(__builtin_mul_overflow)200 if (unlikely(__builtin_mul_overflow(nmemb, size, &total)))201 return NULL;202#else203 if (size == 0 || nmemb > ULONG_MAX / size)204 return NULL;205 total = nmemb * size;206#endif207 return realloc(ptr, total);208}209 210/* Copy up to sz - 1 bytes from zero-terminated src string and ensure that dst211 * is zero-terminated string no matter what (unless sz == 0, in which case212 * it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs213 * in what is returned. Given this is internal helper, it's trivial to extend214 * this, when necessary. Use this instead of strncpy inside libbpf source code.215 */216static inline void libbpf_strlcpy(char *dst, const char *src, size_t sz)217{218 size_t i;219 220 if (sz == 0)221 return;222 223 sz--;224 for (i = 0; i < sz && src[i]; i++)225 dst[i] = src[i];226 dst[i] = '\0';227}228 229__u32 get_kernel_version(void);230 231struct btf;232struct btf_type;233 234struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id);235const char *btf_kind_str(const struct btf_type *t);236const struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);237const struct btf_header *btf_header(const struct btf *btf);238void btf_set_base_btf(struct btf *btf, const struct btf *base_btf);239int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map);240 241static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t)242{243 return (enum btf_func_linkage)(int)btf_vlen(t);244}245 246static inline __u32 btf_type_info(int kind, int vlen, int kflag)247{248 return (kflag << 31) | (kind << 24) | vlen;249}250 251enum map_def_parts {252 MAP_DEF_MAP_TYPE = 0x001,253 MAP_DEF_KEY_TYPE = 0x002,254 MAP_DEF_KEY_SIZE = 0x004,255 MAP_DEF_VALUE_TYPE = 0x008,256 MAP_DEF_VALUE_SIZE = 0x010,257 MAP_DEF_MAX_ENTRIES = 0x020,258 MAP_DEF_MAP_FLAGS = 0x040,259 MAP_DEF_NUMA_NODE = 0x080,260 MAP_DEF_PINNING = 0x100,261 MAP_DEF_INNER_MAP = 0x200,262 MAP_DEF_MAP_EXTRA = 0x400,263 264 MAP_DEF_ALL = 0x7ff, /* combination of all above */265};266 267struct btf_map_def {268 enum map_def_parts parts;269 __u32 map_type;270 __u32 key_type_id;271 __u32 key_size;272 __u32 value_type_id;273 __u32 value_size;274 __u32 max_entries;275 __u32 map_flags;276 __u32 numa_node;277 __u32 pinning;278 __u64 map_extra;279};280 281int parse_btf_map_def(const char *map_name, struct btf *btf,282 const struct btf_type *def_t, bool strict,283 struct btf_map_def *map_def, struct btf_map_def *inner_def);284 285void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,286 size_t cur_cnt, size_t max_cnt, size_t add_cnt);287int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);288 289static inline bool libbpf_is_mem_zeroed(const char *p, ssize_t len)290{291 while (len > 0) {292 if (*p)293 return false;294 p++;295 len--;296 }297 return true;298}299 300static inline bool libbpf_validate_opts(const char *opts,301 size_t opts_sz, size_t user_sz,302 const char *type_name)303{304 if (user_sz < sizeof(size_t)) {305 pr_warn("%s size (%zu) is too small\n", type_name, user_sz);306 return false;307 }308 if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {309 pr_warn("%s has non-zero extra bytes\n", type_name);310 return false;311 }312 return true;313}314 315#define OPTS_VALID(opts, type) \316 (!(opts) || libbpf_validate_opts((const char *)opts, \317 offsetofend(struct type, \318 type##__last_field), \319 (opts)->sz, #type))320#define OPTS_HAS(opts, field) \321 ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))322#define OPTS_GET(opts, field, fallback_value) \323 (OPTS_HAS(opts, field) ? (opts)->field : fallback_value)324#define OPTS_SET(opts, field, value) \325 do { \326 if (OPTS_HAS(opts, field)) \327 (opts)->field = value; \328 } while (0)329 330#define OPTS_ZEROED(opts, last_nonzero_field) \331({ \332 ssize_t __off = offsetofend(typeof(*(opts)), last_nonzero_field); \333 !(opts) || libbpf_is_mem_zeroed((const void *)opts + __off, \334 (opts)->sz - __off); \335})336 337enum kern_feature_id {338 /* v4.14: kernel support for program & map names. */339 FEAT_PROG_NAME,340 /* v5.2: kernel support for global data sections. */341 FEAT_GLOBAL_DATA,342 /* BTF support */343 FEAT_BTF,344 /* BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support */345 FEAT_BTF_FUNC,346 /* BTF_KIND_VAR and BTF_KIND_DATASEC support */347 FEAT_BTF_DATASEC,348 /* BTF_FUNC_GLOBAL is supported */349 FEAT_BTF_GLOBAL_FUNC,350 /* BPF_F_MMAPABLE is supported for arrays */351 FEAT_ARRAY_MMAP,352 /* kernel support for expected_attach_type in BPF_PROG_LOAD */353 FEAT_EXP_ATTACH_TYPE,354 /* bpf_probe_read_{kernel,user}[_str] helpers */355 FEAT_PROBE_READ_KERN,356 /* BPF_PROG_BIND_MAP is supported */357 FEAT_PROG_BIND_MAP,358 /* Kernel support for module BTFs */359 FEAT_MODULE_BTF,360 /* BTF_KIND_FLOAT support */361 FEAT_BTF_FLOAT,362 /* BPF perf link support */363 FEAT_PERF_LINK,364 /* BTF_KIND_DECL_TAG support */365 FEAT_BTF_DECL_TAG,366 /* BTF_KIND_TYPE_TAG support */367 FEAT_BTF_TYPE_TAG,368 /* memcg-based accounting for BPF maps and progs */369 FEAT_MEMCG_ACCOUNT,370 /* BPF cookie (bpf_get_attach_cookie() BPF helper) support */371 FEAT_BPF_COOKIE,372 /* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */373 FEAT_BTF_ENUM64,374 /* Kernel uses syscall wrapper (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) */375 FEAT_SYSCALL_WRAPPER,376 /* BPF multi-uprobe link support */377 FEAT_UPROBE_MULTI_LINK,378 /* Kernel supports arg:ctx tag (__arg_ctx) for global subprogs natively */379 FEAT_ARG_CTX_TAG,380 /* Kernel supports '?' at the front of datasec names */381 FEAT_BTF_QMARK_DATASEC,382 __FEAT_CNT,383};384 385enum kern_feature_result {386 FEAT_UNKNOWN = 0,387 FEAT_SUPPORTED = 1,388 FEAT_MISSING = 2,389};390 391struct kern_feature_cache {392 enum kern_feature_result res[__FEAT_CNT];393 int token_fd;394};395 396bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);397bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);398 399int probe_kern_syscall_wrapper(int token_fd);400int probe_memcg_account(int token_fd);401int bump_rlimit_memlock(void);402 403int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);404int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);405int libbpf__load_raw_btf(const char *raw_types, size_t types_len,406 const char *str_sec, size_t str_len,407 int token_fd);408int btf_load_into_kernel(struct btf *btf,409 char *log_buf, size_t log_sz, __u32 log_level,410 int token_fd);411 412struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);413void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,414 const char **prefix, int *kind);415 416struct btf_ext_info {417 /*418 * info points to the individual info section (e.g. func_info and419 * line_info) from the .BTF.ext. It does not include the __u32 rec_size.420 */421 void *info;422 __u32 rec_size;423 __u32 len;424 /* optional (maintained internally by libbpf) mapping between .BTF.ext425 * section and corresponding ELF section. This is used to join426 * information like CO-RE relocation records with corresponding BPF427 * programs defined in ELF sections428 */429 __u32 *sec_idxs;430 int sec_cnt;431};432 433#define for_each_btf_ext_sec(seg, sec) \434 for (sec = (seg)->info; \435 (void *)sec < (seg)->info + (seg)->len; \436 sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \437 (seg)->rec_size * sec->num_info)438 439#define for_each_btf_ext_rec(seg, sec, i, rec) \440 for (i = 0, rec = (void *)&(sec)->data; \441 i < (sec)->num_info; \442 i++, rec = (void *)rec + (seg)->rec_size)443 444/*445 * The .BTF.ext ELF section layout defined as446 * struct btf_ext_header447 * func_info subsection448 *449 * The func_info subsection layout:450 * record size for struct bpf_func_info in the func_info subsection451 * struct btf_sec_func_info for section #1452 * a list of bpf_func_info records for section #1453 * where struct bpf_func_info mimics one in include/uapi/linux/bpf.h454 * but may not be identical455 * struct btf_sec_func_info for section #2456 * a list of bpf_func_info records for section #2457 * ......458 *459 * Note that the bpf_func_info record size in .BTF.ext may not460 * be the same as the one defined in include/uapi/linux/bpf.h.461 * The loader should ensure that record_size meets minimum462 * requirement and pass the record as is to the kernel. The463 * kernel will handle the func_info properly based on its contents.464 */465struct btf_ext_header {466 __u16 magic;467 __u8 version;468 __u8 flags;469 __u32 hdr_len;470 471 /* All offsets are in bytes relative to the end of this header */472 __u32 func_info_off;473 __u32 func_info_len;474 __u32 line_info_off;475 __u32 line_info_len;476 477 /* optional part of .BTF.ext header */478 __u32 core_relo_off;479 __u32 core_relo_len;480};481 482struct btf_ext {483 union {484 struct btf_ext_header *hdr;485 void *data;486 };487 struct btf_ext_info func_info;488 struct btf_ext_info line_info;489 struct btf_ext_info core_relo_info;490 __u32 data_size;491};492 493struct btf_ext_info_sec {494 __u32 sec_name_off;495 __u32 num_info;496 /* Followed by num_info * record_size number of bytes */497 __u8 data[];498};499 500/* The minimum bpf_func_info checked by the loader */501struct bpf_func_info_min {502 __u32 insn_off;503 __u32 type_id;504};505 506/* The minimum bpf_line_info checked by the loader */507struct bpf_line_info_min {508 __u32 insn_off;509 __u32 file_name_off;510 __u32 line_off;511 __u32 line_col;512};513 514enum btf_field_iter_kind {515 BTF_FIELD_ITER_IDS,516 BTF_FIELD_ITER_STRS,517};518 519struct btf_field_desc {520 /* once-per-type offsets */521 int t_off_cnt, t_offs[2];522 /* member struct size, or zero, if no members */523 int m_sz;524 /* repeated per-member offsets */525 int m_off_cnt, m_offs[1];526};527 528struct btf_field_iter {529 struct btf_field_desc desc;530 void *p;531 int m_idx;532 int off_idx;533 int vlen;534};535 536int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, enum btf_field_iter_kind iter_kind);537__u32 *btf_field_iter_next(struct btf_field_iter *it);538 539typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);540typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);541int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);542int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);543__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,544 __u32 kind);545 546/* handle direct returned errors */547static inline int libbpf_err(int ret)548{549 if (ret < 0)550 errno = -ret;551 return ret;552}553 554/* handle errno-based (e.g., syscall or libc) errors according to libbpf's555 * strict mode settings556 */557static inline int libbpf_err_errno(int ret)558{559 /* errno is already assumed to be set on error */560 return ret < 0 ? -errno : ret;561}562 563/* handle error for pointer-returning APIs, err is assumed to be < 0 always */564static inline void *libbpf_err_ptr(int err)565{566 /* set errno on error, this doesn't break anything */567 errno = -err;568 return NULL;569}570 571/* handle pointer-returning APIs' error handling */572static inline void *libbpf_ptr(void *ret)573{574 /* set errno on error, this doesn't break anything */575 if (IS_ERR(ret))576 errno = -PTR_ERR(ret);577 578 return IS_ERR(ret) ? NULL : ret;579}580 581static inline bool str_is_empty(const char *s)582{583 return !s || !s[0];584}585 586static inline bool is_ldimm64_insn(struct bpf_insn *insn)587{588 return insn->code == (BPF_LD | BPF_IMM | BPF_DW);589}590 591/* Unconditionally dup FD, ensuring it doesn't use [0, 2] range.592 * Original FD is not closed or altered in any other way.593 * Preserves original FD value, if it's invalid (negative).594 */595static inline int dup_good_fd(int fd)596{597 if (fd < 0)598 return fd;599 return fcntl(fd, F_DUPFD_CLOEXEC, 3);600}601 602/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2603 * Takes ownership of the fd passed in, and closes it if calling604 * fcntl(fd, F_DUPFD_CLOEXEC, 3).605 */606static inline int ensure_good_fd(int fd)607{608 int old_fd = fd, saved_errno;609 610 if (fd < 0)611 return fd;612 if (fd < 3) {613 fd = dup_good_fd(fd);614 saved_errno = errno;615 close(old_fd);616 errno = saved_errno;617 if (fd < 0) {618 pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);619 errno = saved_errno;620 }621 }622 return fd;623}624 625static inline int sys_dup3(int oldfd, int newfd, int flags)626{627 return syscall(__NR_dup3, oldfd, newfd, flags);628}629 630/* Point *fixed_fd* to the same file that *tmp_fd* points to.631 * Regardless of success, *tmp_fd* is closed.632 * Whatever *fixed_fd* pointed to is closed silently.633 */634static inline int reuse_fd(int fixed_fd, int tmp_fd)635{636 int err;637 638 err = sys_dup3(tmp_fd, fixed_fd, O_CLOEXEC);639 err = err < 0 ? -errno : 0;640 close(tmp_fd); /* clean up temporary FD */641 return err;642}643 644/* The following two functions are exposed to bpftool */645int bpf_core_add_cands(struct bpf_core_cand *local_cand,646 size_t local_essent_len,647 const struct btf *targ_btf,648 const char *targ_btf_name,649 int targ_start_id,650 struct bpf_core_cand_list *cands);651void bpf_core_free_cands(struct bpf_core_cand_list *cands);652 653struct usdt_manager *usdt_manager_new(struct bpf_object *obj);654void usdt_manager_free(struct usdt_manager *man);655struct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man,656 const struct bpf_program *prog,657 pid_t pid, const char *path,658 const char *usdt_provider, const char *usdt_name,659 __u64 usdt_cookie);660 661static inline bool is_pow_of_2(size_t x)662{663 return x && (x & (x - 1)) == 0;664}665 666#define PROG_LOAD_ATTEMPTS 5667int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts);668 669bool glob_match(const char *str, const char *pat);670 671long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);672long elf_find_func_offset_from_file(const char *binary_path, const char *name);673 674struct elf_fd {675 Elf *elf;676 int fd;677};678 679int elf_open(const char *binary_path, struct elf_fd *elf_fd);680void elf_close(struct elf_fd *elf_fd);681 682int elf_resolve_syms_offsets(const char *binary_path, int cnt,683 const char **syms, unsigned long **poffsets,684 int st_type);685int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,686 unsigned long **poffsets, size_t *pcnt);687 688int probe_fd(int fd);689 690#endif /* __LIBBPF_LIBBPF_INTERNAL_H */691