162306a36Sopenharmony_ci/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Internal libbpf helpers. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2019 Facebook 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef __LIBBPF_LIBBPF_INTERNAL_H 1062306a36Sopenharmony_ci#define __LIBBPF_LIBBPF_INTERNAL_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <limits.h> 1462306a36Sopenharmony_ci#include <errno.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <fcntl.h> 1762306a36Sopenharmony_ci#include <unistd.h> 1862306a36Sopenharmony_ci#include <libelf.h> 1962306a36Sopenharmony_ci#include "relo_core.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Android's libc doesn't support AT_EACCESS in faccessat() implementation 2262306a36Sopenharmony_ci * ([0]), and just returns -EINVAL even if file exists and is accessible. 2362306a36Sopenharmony_ci * See [1] for issues caused by this. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * So just redefine it to 0 on Android. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50 2862306a36Sopenharmony_ci * [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#ifdef __ANDROID__ 3162306a36Sopenharmony_ci#undef AT_EACCESS 3262306a36Sopenharmony_ci#define AT_EACCESS 0 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* make sure libbpf doesn't use kernel-only integer typedefs */ 3662306a36Sopenharmony_ci#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* prevent accidental re-addition of reallocarray() */ 3962306a36Sopenharmony_ci#pragma GCC poison reallocarray 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "libbpf.h" 4262306a36Sopenharmony_ci#include "btf.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifndef EM_BPF 4562306a36Sopenharmony_ci#define EM_BPF 247 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifndef R_BPF_64_64 4962306a36Sopenharmony_ci#define R_BPF_64_64 1 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci#ifndef R_BPF_64_ABS64 5262306a36Sopenharmony_ci#define R_BPF_64_ABS64 2 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci#ifndef R_BPF_64_ABS32 5562306a36Sopenharmony_ci#define R_BPF_64_ABS32 3 5662306a36Sopenharmony_ci#endif 5762306a36Sopenharmony_ci#ifndef R_BPF_64_32 5862306a36Sopenharmony_ci#define R_BPF_64_32 10 5962306a36Sopenharmony_ci#endif 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#ifndef SHT_LLVM_ADDRSIG 6262306a36Sopenharmony_ci#define SHT_LLVM_ADDRSIG 0x6FFF4C03 6362306a36Sopenharmony_ci#endif 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* if libelf is old and doesn't support mmap(), fall back to read() */ 6662306a36Sopenharmony_ci#ifndef ELF_C_READ_MMAP 6762306a36Sopenharmony_ci#define ELF_C_READ_MMAP ELF_C_READ 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Older libelf all end up in this expression, for both 32 and 64 bit */ 7162306a36Sopenharmony_ci#ifndef ELF64_ST_VISIBILITY 7262306a36Sopenharmony_ci#define ELF64_ST_VISIBILITY(o) ((o) & 0x03) 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define BTF_INFO_ENC(kind, kind_flag, vlen) \ 7662306a36Sopenharmony_ci ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) 7762306a36Sopenharmony_ci#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type) 7862306a36Sopenharmony_ci#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \ 7962306a36Sopenharmony_ci ((encoding) << 24 | (bits_offset) << 16 | (nr_bits)) 8062306a36Sopenharmony_ci#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \ 8162306a36Sopenharmony_ci BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ 8262306a36Sopenharmony_ci BTF_INT_ENC(encoding, bits_offset, bits) 8362306a36Sopenharmony_ci#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset) 8462306a36Sopenharmony_ci#define BTF_PARAM_ENC(name, type) (name), (type) 8562306a36Sopenharmony_ci#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size) 8662306a36Sopenharmony_ci#define BTF_TYPE_FLOAT_ENC(name, sz) \ 8762306a36Sopenharmony_ci BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz) 8862306a36Sopenharmony_ci#define BTF_TYPE_DECL_TAG_ENC(value, type, component_idx) \ 8962306a36Sopenharmony_ci BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx) 9062306a36Sopenharmony_ci#define BTF_TYPE_TYPE_TAG_ENC(value, type) \ 9162306a36Sopenharmony_ci BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#ifndef likely 9462306a36Sopenharmony_ci#define likely(x) __builtin_expect(!!(x), 1) 9562306a36Sopenharmony_ci#endif 9662306a36Sopenharmony_ci#ifndef unlikely 9762306a36Sopenharmony_ci#define unlikely(x) __builtin_expect(!!(x), 0) 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci#ifndef min 10062306a36Sopenharmony_ci# define min(x, y) ((x) < (y) ? (x) : (y)) 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci#ifndef max 10362306a36Sopenharmony_ci# define max(x, y) ((x) < (y) ? (y) : (x)) 10462306a36Sopenharmony_ci#endif 10562306a36Sopenharmony_ci#ifndef offsetofend 10662306a36Sopenharmony_ci# define offsetofend(TYPE, FIELD) \ 10762306a36Sopenharmony_ci (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD)) 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci#ifndef __alias 11062306a36Sopenharmony_ci#define __alias(symbol) __attribute__((alias(#symbol))) 11162306a36Sopenharmony_ci#endif 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* Check whether a string `str` has prefix `pfx`, regardless if `pfx` is 11462306a36Sopenharmony_ci * a string literal known at compilation time or char * pointer known only at 11562306a36Sopenharmony_ci * runtime. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci#define str_has_pfx(str, pfx) \ 11862306a36Sopenharmony_ci (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* suffix check */ 12162306a36Sopenharmony_cistatic inline bool str_has_sfx(const char *str, const char *sfx) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci size_t str_len = strlen(str); 12462306a36Sopenharmony_ci size_t sfx_len = strlen(sfx); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (sfx_len > str_len) 12762306a36Sopenharmony_ci return false; 12862306a36Sopenharmony_ci return strcmp(str + str_len - sfx_len, sfx) == 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* Symbol versioning is different between static and shared library. 13262306a36Sopenharmony_ci * Properly versioned symbols are needed for shared library, but 13362306a36Sopenharmony_ci * only the symbol of the new version is needed for static library. 13462306a36Sopenharmony_ci * Starting with GNU C 10, use symver attribute instead of .symver assembler 13562306a36Sopenharmony_ci * directive, which works better with GCC LTO builds. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci#if defined(SHARED) && defined(__GNUC__) && __GNUC__ >= 10 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define DEFAULT_VERSION(internal_name, api_name, version) \ 14062306a36Sopenharmony_ci __attribute__((symver(#api_name "@@" #version))) 14162306a36Sopenharmony_ci#define COMPAT_VERSION(internal_name, api_name, version) \ 14262306a36Sopenharmony_ci __attribute__((symver(#api_name "@" #version))) 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#elif defined(SHARED) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define COMPAT_VERSION(internal_name, api_name, version) \ 14762306a36Sopenharmony_ci asm(".symver " #internal_name "," #api_name "@" #version); 14862306a36Sopenharmony_ci#define DEFAULT_VERSION(internal_name, api_name, version) \ 14962306a36Sopenharmony_ci asm(".symver " #internal_name "," #api_name "@@" #version); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#else /* !SHARED */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define COMPAT_VERSION(internal_name, api_name, version) 15462306a36Sopenharmony_ci#define DEFAULT_VERSION(internal_name, api_name, version) \ 15562306a36Sopenharmony_ci extern typeof(internal_name) api_name \ 15662306a36Sopenharmony_ci __attribute__((alias(#internal_name))); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciextern void libbpf_print(enum libbpf_print_level level, 16162306a36Sopenharmony_ci const char *format, ...) 16262306a36Sopenharmony_ci __attribute__((format(printf, 2, 3))); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define __pr(level, fmt, ...) \ 16562306a36Sopenharmony_cido { \ 16662306a36Sopenharmony_ci libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \ 16762306a36Sopenharmony_ci} while (0) 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#define pr_warn(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__) 17062306a36Sopenharmony_ci#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__) 17162306a36Sopenharmony_ci#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#ifndef __has_builtin 17462306a36Sopenharmony_ci#define __has_builtin(x) 0 17562306a36Sopenharmony_ci#endif 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct bpf_link { 17862306a36Sopenharmony_ci int (*detach)(struct bpf_link *link); 17962306a36Sopenharmony_ci void (*dealloc)(struct bpf_link *link); 18062306a36Sopenharmony_ci char *pin_path; /* NULL, if not pinned */ 18162306a36Sopenharmony_ci int fd; /* hook FD, -1 if not applicable */ 18262306a36Sopenharmony_ci bool disconnected; 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* 18662306a36Sopenharmony_ci * Re-implement glibc's reallocarray() for libbpf internal-only use. 18762306a36Sopenharmony_ci * reallocarray(), unfortunately, is not available in all versions of glibc, 18862306a36Sopenharmony_ci * so requires extra feature detection and using reallocarray() stub from 18962306a36Sopenharmony_ci * <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates 19062306a36Sopenharmony_ci * build of libbpf unnecessarily and is just a maintenance burden. Instead, 19162306a36Sopenharmony_ci * it's trivial to implement libbpf-specific internal version and use it 19262306a36Sopenharmony_ci * throughout libbpf. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistatic inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci size_t total; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#if __has_builtin(__builtin_mul_overflow) 19962306a36Sopenharmony_ci if (unlikely(__builtin_mul_overflow(nmemb, size, &total))) 20062306a36Sopenharmony_ci return NULL; 20162306a36Sopenharmony_ci#else 20262306a36Sopenharmony_ci if (size == 0 || nmemb > ULONG_MAX / size) 20362306a36Sopenharmony_ci return NULL; 20462306a36Sopenharmony_ci total = nmemb * size; 20562306a36Sopenharmony_ci#endif 20662306a36Sopenharmony_ci return realloc(ptr, total); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* Copy up to sz - 1 bytes from zero-terminated src string and ensure that dst 21062306a36Sopenharmony_ci * is zero-terminated string no matter what (unless sz == 0, in which case 21162306a36Sopenharmony_ci * it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs 21262306a36Sopenharmony_ci * in what is returned. Given this is internal helper, it's trivial to extend 21362306a36Sopenharmony_ci * this, when necessary. Use this instead of strncpy inside libbpf source code. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_cistatic inline void libbpf_strlcpy(char *dst, const char *src, size_t sz) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci size_t i; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (sz == 0) 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci sz--; 22362306a36Sopenharmony_ci for (i = 0; i < sz && src[i]; i++) 22462306a36Sopenharmony_ci dst[i] = src[i]; 22562306a36Sopenharmony_ci dst[i] = '\0'; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci__u32 get_kernel_version(void); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct btf; 23162306a36Sopenharmony_cistruct btf_type; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistruct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id); 23462306a36Sopenharmony_ciconst char *btf_kind_str(const struct btf_type *t); 23562306a36Sopenharmony_ciconst struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return (enum btf_func_linkage)(int)btf_vlen(t); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic inline __u32 btf_type_info(int kind, int vlen, int kflag) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return (kflag << 31) | (kind << 24) | vlen; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cienum map_def_parts { 24862306a36Sopenharmony_ci MAP_DEF_MAP_TYPE = 0x001, 24962306a36Sopenharmony_ci MAP_DEF_KEY_TYPE = 0x002, 25062306a36Sopenharmony_ci MAP_DEF_KEY_SIZE = 0x004, 25162306a36Sopenharmony_ci MAP_DEF_VALUE_TYPE = 0x008, 25262306a36Sopenharmony_ci MAP_DEF_VALUE_SIZE = 0x010, 25362306a36Sopenharmony_ci MAP_DEF_MAX_ENTRIES = 0x020, 25462306a36Sopenharmony_ci MAP_DEF_MAP_FLAGS = 0x040, 25562306a36Sopenharmony_ci MAP_DEF_NUMA_NODE = 0x080, 25662306a36Sopenharmony_ci MAP_DEF_PINNING = 0x100, 25762306a36Sopenharmony_ci MAP_DEF_INNER_MAP = 0x200, 25862306a36Sopenharmony_ci MAP_DEF_MAP_EXTRA = 0x400, 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci MAP_DEF_ALL = 0x7ff, /* combination of all above */ 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistruct btf_map_def { 26462306a36Sopenharmony_ci enum map_def_parts parts; 26562306a36Sopenharmony_ci __u32 map_type; 26662306a36Sopenharmony_ci __u32 key_type_id; 26762306a36Sopenharmony_ci __u32 key_size; 26862306a36Sopenharmony_ci __u32 value_type_id; 26962306a36Sopenharmony_ci __u32 value_size; 27062306a36Sopenharmony_ci __u32 max_entries; 27162306a36Sopenharmony_ci __u32 map_flags; 27262306a36Sopenharmony_ci __u32 numa_node; 27362306a36Sopenharmony_ci __u32 pinning; 27462306a36Sopenharmony_ci __u64 map_extra; 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciint parse_btf_map_def(const char *map_name, struct btf *btf, 27862306a36Sopenharmony_ci const struct btf_type *def_t, bool strict, 27962306a36Sopenharmony_ci struct btf_map_def *map_def, struct btf_map_def *inner_def); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_civoid *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz, 28262306a36Sopenharmony_ci size_t cur_cnt, size_t max_cnt, size_t add_cnt); 28362306a36Sopenharmony_ciint libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic inline bool libbpf_is_mem_zeroed(const char *p, ssize_t len) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci while (len > 0) { 28862306a36Sopenharmony_ci if (*p) 28962306a36Sopenharmony_ci return false; 29062306a36Sopenharmony_ci p++; 29162306a36Sopenharmony_ci len--; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci return true; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic inline bool libbpf_validate_opts(const char *opts, 29762306a36Sopenharmony_ci size_t opts_sz, size_t user_sz, 29862306a36Sopenharmony_ci const char *type_name) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci if (user_sz < sizeof(size_t)) { 30162306a36Sopenharmony_ci pr_warn("%s size (%zu) is too small\n", type_name, user_sz); 30262306a36Sopenharmony_ci return false; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) { 30562306a36Sopenharmony_ci pr_warn("%s has non-zero extra bytes\n", type_name); 30662306a36Sopenharmony_ci return false; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci return true; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci#define OPTS_VALID(opts, type) \ 31262306a36Sopenharmony_ci (!(opts) || libbpf_validate_opts((const char *)opts, \ 31362306a36Sopenharmony_ci offsetofend(struct type, \ 31462306a36Sopenharmony_ci type##__last_field), \ 31562306a36Sopenharmony_ci (opts)->sz, #type)) 31662306a36Sopenharmony_ci#define OPTS_HAS(opts, field) \ 31762306a36Sopenharmony_ci ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field)) 31862306a36Sopenharmony_ci#define OPTS_GET(opts, field, fallback_value) \ 31962306a36Sopenharmony_ci (OPTS_HAS(opts, field) ? (opts)->field : fallback_value) 32062306a36Sopenharmony_ci#define OPTS_SET(opts, field, value) \ 32162306a36Sopenharmony_ci do { \ 32262306a36Sopenharmony_ci if (OPTS_HAS(opts, field)) \ 32362306a36Sopenharmony_ci (opts)->field = value; \ 32462306a36Sopenharmony_ci } while (0) 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#define OPTS_ZEROED(opts, last_nonzero_field) \ 32762306a36Sopenharmony_ci({ \ 32862306a36Sopenharmony_ci ssize_t __off = offsetofend(typeof(*(opts)), last_nonzero_field); \ 32962306a36Sopenharmony_ci !(opts) || libbpf_is_mem_zeroed((const void *)opts + __off, \ 33062306a36Sopenharmony_ci (opts)->sz - __off); \ 33162306a36Sopenharmony_ci}) 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cienum kern_feature_id { 33462306a36Sopenharmony_ci /* v4.14: kernel support for program & map names. */ 33562306a36Sopenharmony_ci FEAT_PROG_NAME, 33662306a36Sopenharmony_ci /* v5.2: kernel support for global data sections. */ 33762306a36Sopenharmony_ci FEAT_GLOBAL_DATA, 33862306a36Sopenharmony_ci /* BTF support */ 33962306a36Sopenharmony_ci FEAT_BTF, 34062306a36Sopenharmony_ci /* BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support */ 34162306a36Sopenharmony_ci FEAT_BTF_FUNC, 34262306a36Sopenharmony_ci /* BTF_KIND_VAR and BTF_KIND_DATASEC support */ 34362306a36Sopenharmony_ci FEAT_BTF_DATASEC, 34462306a36Sopenharmony_ci /* BTF_FUNC_GLOBAL is supported */ 34562306a36Sopenharmony_ci FEAT_BTF_GLOBAL_FUNC, 34662306a36Sopenharmony_ci /* BPF_F_MMAPABLE is supported for arrays */ 34762306a36Sopenharmony_ci FEAT_ARRAY_MMAP, 34862306a36Sopenharmony_ci /* kernel support for expected_attach_type in BPF_PROG_LOAD */ 34962306a36Sopenharmony_ci FEAT_EXP_ATTACH_TYPE, 35062306a36Sopenharmony_ci /* bpf_probe_read_{kernel,user}[_str] helpers */ 35162306a36Sopenharmony_ci FEAT_PROBE_READ_KERN, 35262306a36Sopenharmony_ci /* BPF_PROG_BIND_MAP is supported */ 35362306a36Sopenharmony_ci FEAT_PROG_BIND_MAP, 35462306a36Sopenharmony_ci /* Kernel support for module BTFs */ 35562306a36Sopenharmony_ci FEAT_MODULE_BTF, 35662306a36Sopenharmony_ci /* BTF_KIND_FLOAT support */ 35762306a36Sopenharmony_ci FEAT_BTF_FLOAT, 35862306a36Sopenharmony_ci /* BPF perf link support */ 35962306a36Sopenharmony_ci FEAT_PERF_LINK, 36062306a36Sopenharmony_ci /* BTF_KIND_DECL_TAG support */ 36162306a36Sopenharmony_ci FEAT_BTF_DECL_TAG, 36262306a36Sopenharmony_ci /* BTF_KIND_TYPE_TAG support */ 36362306a36Sopenharmony_ci FEAT_BTF_TYPE_TAG, 36462306a36Sopenharmony_ci /* memcg-based accounting for BPF maps and progs */ 36562306a36Sopenharmony_ci FEAT_MEMCG_ACCOUNT, 36662306a36Sopenharmony_ci /* BPF cookie (bpf_get_attach_cookie() BPF helper) support */ 36762306a36Sopenharmony_ci FEAT_BPF_COOKIE, 36862306a36Sopenharmony_ci /* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */ 36962306a36Sopenharmony_ci FEAT_BTF_ENUM64, 37062306a36Sopenharmony_ci /* Kernel uses syscall wrapper (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) */ 37162306a36Sopenharmony_ci FEAT_SYSCALL_WRAPPER, 37262306a36Sopenharmony_ci /* BPF multi-uprobe link support */ 37362306a36Sopenharmony_ci FEAT_UPROBE_MULTI_LINK, 37462306a36Sopenharmony_ci __FEAT_CNT, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciint probe_memcg_account(void); 37862306a36Sopenharmony_cibool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id); 37962306a36Sopenharmony_ciint bump_rlimit_memlock(void); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciint parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz); 38262306a36Sopenharmony_ciint parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz); 38362306a36Sopenharmony_ciint libbpf__load_raw_btf(const char *raw_types, size_t types_len, 38462306a36Sopenharmony_ci const char *str_sec, size_t str_len); 38562306a36Sopenharmony_ciint btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistruct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf); 38862306a36Sopenharmony_civoid btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type, 38962306a36Sopenharmony_ci const char **prefix, int *kind); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistruct btf_ext_info { 39262306a36Sopenharmony_ci /* 39362306a36Sopenharmony_ci * info points to the individual info section (e.g. func_info and 39462306a36Sopenharmony_ci * line_info) from the .BTF.ext. It does not include the __u32 rec_size. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ci void *info; 39762306a36Sopenharmony_ci __u32 rec_size; 39862306a36Sopenharmony_ci __u32 len; 39962306a36Sopenharmony_ci /* optional (maintained internally by libbpf) mapping between .BTF.ext 40062306a36Sopenharmony_ci * section and corresponding ELF section. This is used to join 40162306a36Sopenharmony_ci * information like CO-RE relocation records with corresponding BPF 40262306a36Sopenharmony_ci * programs defined in ELF sections 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci __u32 *sec_idxs; 40562306a36Sopenharmony_ci int sec_cnt; 40662306a36Sopenharmony_ci}; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#define for_each_btf_ext_sec(seg, sec) \ 40962306a36Sopenharmony_ci for (sec = (seg)->info; \ 41062306a36Sopenharmony_ci (void *)sec < (seg)->info + (seg)->len; \ 41162306a36Sopenharmony_ci sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \ 41262306a36Sopenharmony_ci (seg)->rec_size * sec->num_info) 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci#define for_each_btf_ext_rec(seg, sec, i, rec) \ 41562306a36Sopenharmony_ci for (i = 0, rec = (void *)&(sec)->data; \ 41662306a36Sopenharmony_ci i < (sec)->num_info; \ 41762306a36Sopenharmony_ci i++, rec = (void *)rec + (seg)->rec_size) 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* 42062306a36Sopenharmony_ci * The .BTF.ext ELF section layout defined as 42162306a36Sopenharmony_ci * struct btf_ext_header 42262306a36Sopenharmony_ci * func_info subsection 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * The func_info subsection layout: 42562306a36Sopenharmony_ci * record size for struct bpf_func_info in the func_info subsection 42662306a36Sopenharmony_ci * struct btf_sec_func_info for section #1 42762306a36Sopenharmony_ci * a list of bpf_func_info records for section #1 42862306a36Sopenharmony_ci * where struct bpf_func_info mimics one in include/uapi/linux/bpf.h 42962306a36Sopenharmony_ci * but may not be identical 43062306a36Sopenharmony_ci * struct btf_sec_func_info for section #2 43162306a36Sopenharmony_ci * a list of bpf_func_info records for section #2 43262306a36Sopenharmony_ci * ...... 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Note that the bpf_func_info record size in .BTF.ext may not 43562306a36Sopenharmony_ci * be the same as the one defined in include/uapi/linux/bpf.h. 43662306a36Sopenharmony_ci * The loader should ensure that record_size meets minimum 43762306a36Sopenharmony_ci * requirement and pass the record as is to the kernel. The 43862306a36Sopenharmony_ci * kernel will handle the func_info properly based on its contents. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_cistruct btf_ext_header { 44162306a36Sopenharmony_ci __u16 magic; 44262306a36Sopenharmony_ci __u8 version; 44362306a36Sopenharmony_ci __u8 flags; 44462306a36Sopenharmony_ci __u32 hdr_len; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* All offsets are in bytes relative to the end of this header */ 44762306a36Sopenharmony_ci __u32 func_info_off; 44862306a36Sopenharmony_ci __u32 func_info_len; 44962306a36Sopenharmony_ci __u32 line_info_off; 45062306a36Sopenharmony_ci __u32 line_info_len; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* optional part of .BTF.ext header */ 45362306a36Sopenharmony_ci __u32 core_relo_off; 45462306a36Sopenharmony_ci __u32 core_relo_len; 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistruct btf_ext { 45862306a36Sopenharmony_ci union { 45962306a36Sopenharmony_ci struct btf_ext_header *hdr; 46062306a36Sopenharmony_ci void *data; 46162306a36Sopenharmony_ci }; 46262306a36Sopenharmony_ci struct btf_ext_info func_info; 46362306a36Sopenharmony_ci struct btf_ext_info line_info; 46462306a36Sopenharmony_ci struct btf_ext_info core_relo_info; 46562306a36Sopenharmony_ci __u32 data_size; 46662306a36Sopenharmony_ci}; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistruct btf_ext_info_sec { 46962306a36Sopenharmony_ci __u32 sec_name_off; 47062306a36Sopenharmony_ci __u32 num_info; 47162306a36Sopenharmony_ci /* Followed by num_info * record_size number of bytes */ 47262306a36Sopenharmony_ci __u8 data[]; 47362306a36Sopenharmony_ci}; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* The minimum bpf_func_info checked by the loader */ 47662306a36Sopenharmony_cistruct bpf_func_info_min { 47762306a36Sopenharmony_ci __u32 insn_off; 47862306a36Sopenharmony_ci __u32 type_id; 47962306a36Sopenharmony_ci}; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci/* The minimum bpf_line_info checked by the loader */ 48262306a36Sopenharmony_cistruct bpf_line_info_min { 48362306a36Sopenharmony_ci __u32 insn_off; 48462306a36Sopenharmony_ci __u32 file_name_off; 48562306a36Sopenharmony_ci __u32 line_off; 48662306a36Sopenharmony_ci __u32 line_col; 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_citypedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx); 49162306a36Sopenharmony_citypedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx); 49262306a36Sopenharmony_ciint btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx); 49362306a36Sopenharmony_ciint btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx); 49462306a36Sopenharmony_ciint btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx); 49562306a36Sopenharmony_ciint btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx); 49662306a36Sopenharmony_ci__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name, 49762306a36Sopenharmony_ci __u32 kind); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_citypedef int (*kallsyms_cb_t)(unsigned long long sym_addr, char sym_type, 50062306a36Sopenharmony_ci const char *sym_name, void *ctx); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciint libbpf_kallsyms_parse(kallsyms_cb_t cb, void *arg); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* handle direct returned errors */ 50562306a36Sopenharmony_cistatic inline int libbpf_err(int ret) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci if (ret < 0) 50862306a36Sopenharmony_ci errno = -ret; 50962306a36Sopenharmony_ci return ret; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* handle errno-based (e.g., syscall or libc) errors according to libbpf's 51362306a36Sopenharmony_ci * strict mode settings 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_cistatic inline int libbpf_err_errno(int ret) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci /* errno is already assumed to be set on error */ 51862306a36Sopenharmony_ci return ret < 0 ? -errno : ret; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* handle error for pointer-returning APIs, err is assumed to be < 0 always */ 52262306a36Sopenharmony_cistatic inline void *libbpf_err_ptr(int err) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci /* set errno on error, this doesn't break anything */ 52562306a36Sopenharmony_ci errno = -err; 52662306a36Sopenharmony_ci return NULL; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/* handle pointer-returning APIs' error handling */ 53062306a36Sopenharmony_cistatic inline void *libbpf_ptr(void *ret) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci /* set errno on error, this doesn't break anything */ 53362306a36Sopenharmony_ci if (IS_ERR(ret)) 53462306a36Sopenharmony_ci errno = -PTR_ERR(ret); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return IS_ERR(ret) ? NULL : ret; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic inline bool str_is_empty(const char *s) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci return !s || !s[0]; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic inline bool is_ldimm64_insn(struct bpf_insn *insn) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci return insn->code == (BPF_LD | BPF_IMM | BPF_DW); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2 55062306a36Sopenharmony_ci * Takes ownership of the fd passed in, and closes it if calling 55162306a36Sopenharmony_ci * fcntl(fd, F_DUPFD_CLOEXEC, 3). 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_cistatic inline int ensure_good_fd(int fd) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci int old_fd = fd, saved_errno; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (fd < 0) 55862306a36Sopenharmony_ci return fd; 55962306a36Sopenharmony_ci if (fd < 3) { 56062306a36Sopenharmony_ci fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); 56162306a36Sopenharmony_ci saved_errno = errno; 56262306a36Sopenharmony_ci close(old_fd); 56362306a36Sopenharmony_ci errno = saved_errno; 56462306a36Sopenharmony_ci if (fd < 0) { 56562306a36Sopenharmony_ci pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno); 56662306a36Sopenharmony_ci errno = saved_errno; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci return fd; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/* The following two functions are exposed to bpftool */ 57362306a36Sopenharmony_ciint bpf_core_add_cands(struct bpf_core_cand *local_cand, 57462306a36Sopenharmony_ci size_t local_essent_len, 57562306a36Sopenharmony_ci const struct btf *targ_btf, 57662306a36Sopenharmony_ci const char *targ_btf_name, 57762306a36Sopenharmony_ci int targ_start_id, 57862306a36Sopenharmony_ci struct bpf_core_cand_list *cands); 57962306a36Sopenharmony_civoid bpf_core_free_cands(struct bpf_core_cand_list *cands); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistruct usdt_manager *usdt_manager_new(struct bpf_object *obj); 58262306a36Sopenharmony_civoid usdt_manager_free(struct usdt_manager *man); 58362306a36Sopenharmony_cistruct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man, 58462306a36Sopenharmony_ci const struct bpf_program *prog, 58562306a36Sopenharmony_ci pid_t pid, const char *path, 58662306a36Sopenharmony_ci const char *usdt_provider, const char *usdt_name, 58762306a36Sopenharmony_ci __u64 usdt_cookie); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic inline bool is_pow_of_2(size_t x) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci return x && (x & (x - 1)) == 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci#define PROG_LOAD_ATTEMPTS 5 59562306a36Sopenharmony_ciint sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cibool glob_match(const char *str, const char *pat); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cilong elf_find_func_offset(Elf *elf, const char *binary_path, const char *name); 60062306a36Sopenharmony_cilong elf_find_func_offset_from_file(const char *binary_path, const char *name); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistruct elf_fd { 60362306a36Sopenharmony_ci Elf *elf; 60462306a36Sopenharmony_ci int fd; 60562306a36Sopenharmony_ci}; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ciint elf_open(const char *binary_path, struct elf_fd *elf_fd); 60862306a36Sopenharmony_civoid elf_close(struct elf_fd *elf_fd); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciint elf_resolve_syms_offsets(const char *binary_path, int cnt, 61162306a36Sopenharmony_ci const char **syms, unsigned long **poffsets); 61262306a36Sopenharmony_ciint elf_resolve_pattern_offsets(const char *binary_path, const char *pattern, 61362306a36Sopenharmony_ci unsigned long **poffsets, size_t *pcnt); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci#endif /* __LIBBPF_LIBBPF_INTERNAL_H */ 616