| 1 |
|
| 2 |
|
| 3 | |
| 4 | * Internal libbpf helpers.
|
| 5 | *
|
| 6 | * Copyright (c) 2019 Facebook
|
| 7 |
|
| 8 |
|
| 9 | #ifndef __LIBBPF_LIBBPF_INTERNAL_H
|
| 10 | #define __LIBBPF_LIBBPF_INTERNAL_H
|
| 11 |
|
| 12 | #include <stdlib.h>
|
| 13 | #include <byteswap.h>
|
| 14 | #include <limits.h>
|
| 15 | #include <errno.h>
|
| 16 | #include <linux/err.h>
|
| 17 | #include <fcntl.h>
|
| 18 | #include <unistd.h>
|
| 19 | #include <sys/syscall.h>
|
| 20 | #include <libelf.h>
|
| 21 | #include "relo_core.h"
|
| 22 |
|
| 23 | |
| 24 | * ([0]), and just returns -EINVAL even if file exists and is accessible.
|
| 25 | * See [1] for issues caused by this.
|
| 26 | *
|
| 27 | * So just redefine it to 0 on Android.
|
| 28 | *
|
| 29 | * [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50
|
| 30 | * [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250
|
| 31 |
|
| 32 | #ifdef __ANDROID__
|
| 33 | #undef AT_EACCESS
|
| 34 | #define AT_EACCESS 0
|
| 35 | #endif
|
| 36 |
|
| 37 |
|
| 38 | #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
| 39 |
|
| 40 |
|
| 41 | #pragma GCC poison reallocarray
|
| 42 |
|
| 43 | #include "libbpf.h"
|
| 44 | #include "btf.h"
|
| 45 |
|
| 46 | #ifndef EM_BPF
|
| 47 | #define EM_BPF 247
|
| 48 | #endif
|
| 49 |
|
| 50 | #ifndef R_BPF_64_64
|
| 51 | #define R_BPF_64_64 1
|
| 52 | #endif
|
| 53 | #ifndef R_BPF_64_ABS64
|
| 54 | #define R_BPF_64_ABS64 2
|
| 55 | #endif
|
| 56 | #ifndef R_BPF_64_ABS32
|
| 57 | #define R_BPF_64_ABS32 3
|
| 58 | #endif
|
| 59 | #ifndef R_BPF_64_32
|
| 60 | #define R_BPF_64_32 10
|
| 61 | #endif
|
| 62 |
|
| 63 | #ifndef SHT_LLVM_ADDRSIG
|
| 64 | #define SHT_LLVM_ADDRSIG 0x6FFF4C03
|
| 65 | #endif
|
| 66 |
|
| 67 |
|
| 68 | #ifndef ELF_C_READ_MMAP
|
| 69 | #define ELF_C_READ_MMAP ELF_C_READ
|
| 70 | #endif
|
| 71 |
|
| 72 |
|
| 73 | #ifndef ELF64_ST_VISIBILITY
|
| 74 | #define ELF64_ST_VISIBILITY(o) ((o) & 0x03)
|
| 75 | #endif
|
| 76 |
|
| 77 | #define JUMPTABLES_SEC ".jumptables"
|
| 78 |
|
| 79 | #define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
| 80 | ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
| 81 | #define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
|
| 82 | #define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
|
| 83 | ((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
|
| 84 | #define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
|
| 85 | BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
|
| 86 | BTF_INT_ENC(encoding, bits_offset, bits)
|
| 87 | #define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
|
| 88 | #define BTF_PARAM_ENC(name, type) (name), (type)
|
| 89 | #define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
| 90 | #define BTF_TYPE_FLOAT_ENC(name, sz) \
|
| 91 | BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)
|
| 92 | #define BTF_TYPE_DECL_TAG_ENC(value, type, component_idx) \
|
| 93 | BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx)
|
| 94 | #define BTF_TYPE_TYPE_TAG_ENC(value, type) \
|
| 95 | BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type)
|
| 96 |
|
| 97 | #ifndef likely
|
| 98 | #define likely(x) __builtin_expect(!!(x), 1)
|
| 99 | #endif
|
| 100 | #ifndef unlikely
|
| 101 | #define unlikely(x) __builtin_expect(!!(x), 0)
|
| 102 | #endif
|
| 103 | #ifndef min
|
| 104 | # define min(x, y) ((x) < (y) ? (x) : (y))
|
| 105 | #endif
|
| 106 | #ifndef max
|
| 107 | # define max(x, y) ((x) < (y) ? (y) : (x))
|
| 108 | #endif
|
| 109 | #ifndef offsetofend
|
| 110 | # define offsetofend(TYPE, FIELD) \
|
| 111 | (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
| 112 | #endif
|
| 113 | #ifndef __alias
|
| 114 | #define __alias(symbol) __attribute__((alias(#symbol)))
|
| 115 | #endif
|
| 116 |
|
| 117 | |
| 118 | * a string literal known at compilation time or char * pointer known only at
|
| 119 | * runtime.
|
| 120 |
|
| 121 | #define str_has_pfx(str, pfx) \
|
| 122 | (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
|
| 123 |
|
| 124 |
|
| 125 | static inline bool str_has_sfx(const char *str, const char *sfx)
|
| 126 | {
|
| 127 | size_t str_len = strlen(str);
|
| 128 | size_t sfx_len = strlen(sfx);
|
| 129 |
|
| 130 | if (sfx_len > str_len)
|
| 131 | return false;
|
| 132 | return strcmp(str + str_len - sfx_len, sfx) == 0;
|
| 133 | }
|
| 134 |
|
| 135 | |
| 136 | * Properly versioned symbols are needed for shared library, but
|
| 137 | * only the symbol of the new version is needed for static library.
|
| 138 | * Starting with GNU C 10, use symver attribute instead of .symver assembler
|
| 139 | * directive, which works better with GCC LTO builds.
|
| 140 |
|
| 141 | #if defined(SHARED) && defined(__GNUC__) && __GNUC__ >= 10
|
| 142 |
|
| 143 | #define DEFAULT_VERSION(internal_name, api_name, version) \
|
| 144 | __attribute__((symver(#api_name "@@" #version)))
|
| 145 | #define COMPAT_VERSION(internal_name, api_name, version) \
|
| 146 | __attribute__((symver(#api_name "@" #version)))
|
| 147 |
|
| 148 | #elif defined(SHARED)
|
| 149 |
|
| 150 | #define COMPAT_VERSION(internal_name, api_name, version) \
|
| 151 | asm(".symver " #internal_name "," #api_name "@" #version);
|
| 152 | #define DEFAULT_VERSION(internal_name, api_name, version) \
|
| 153 | asm(".symver " #internal_name "," #api_name "@@" #version);
|
| 154 |
|
| 155 | #else
|
| 156 |
|
| 157 | #define COMPAT_VERSION(internal_name, api_name, version)
|
| 158 | #define DEFAULT_VERSION(internal_name, api_name, version) \
|
| 159 | extern typeof(internal_name) api_name \
|
| 160 | __attribute__((alias(#internal_name)));
|
| 161 |
|
| 162 | #endif
|
| 163 |
|
| 164 | extern void libbpf_print(enum libbpf_print_level level,
|
| 165 | const char *format, ...)
|
| 166 | __attribute__((format(printf, 2, 3)));
|
| 167 |
|
| 168 | #define __pr(level, fmt, ...) \
|
| 169 | do { \
|
| 170 | libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \
|
| 171 | } while (0)
|
| 172 |
|
| 173 | #define pr_warn(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__)
|
| 174 | #define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
| 175 | #define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
| 176 |
|
| 177 | |
| 178 | * @brief **libbpf_errstr()** returns string corresponding to numeric errno
|
| 179 | * @param err negative numeric errno
|
| 180 | * @return pointer to string representation of the errno, that is invalidated
|
| 181 | * upon the next call.
|
| 182 |
|
| 183 | const char *libbpf_errstr(int err);
|
| 184 |
|
| 185 | #define errstr(err) libbpf_errstr(err)
|
| 186 |
|
| 187 | #ifndef __has_builtin
|
| 188 | #define __has_builtin(x) 0
|
| 189 | #endif
|
| 190 |
|
| 191 | struct bpf_link {
|
| 192 | int (*detach)(struct bpf_link *link);
|
| 193 | void (*dealloc)(struct bpf_link *link);
|
| 194 | char *pin_path;
|
| 195 | int fd;
|
| 196 | bool disconnected;
|
| 197 | };
|
| 198 |
|
| 199 | |
| 200 | * Re-implement glibc's reallocarray() for libbpf internal-only use.
|
| 201 | * reallocarray(), unfortunately, is not available in all versions of glibc,
|
| 202 | * so requires extra feature detection and using reallocarray() stub from
|
| 203 | * <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates
|
| 204 | * build of libbpf unnecessarily and is just a maintenance burden. Instead,
|
| 205 | * it's trivial to implement libbpf-specific internal version and use it
|
| 206 | * throughout libbpf.
|
| 207 |
|
| 208 | static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)
|
| 209 | {
|
| 210 | size_t total;
|
| 211 |
|
| 212 | #if __has_builtin(__builtin_mul_overflow)
|
| 213 | if (unlikely(__builtin_mul_overflow(nmemb, size, &total)))
|
| 214 | return NULL;
|
| 215 | #else
|
| 216 | if (size == 0 || nmemb > ULONG_MAX / size)
|
| 217 | return NULL;
|
| 218 | total = nmemb * size;
|
| 219 | #endif
|
| 220 | return realloc(ptr, total);
|
| 221 | }
|
| 222 |
|
| 223 | |
| 224 | * is zero-terminated string no matter what (unless sz == 0, in which case
|
| 225 | * it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs
|
| 226 | * in what is returned. Given this is internal helper, it's trivial to extend
|
| 227 | * this, when necessary. Use this instead of strncpy inside libbpf source code.
|
| 228 |
|
| 229 | static inline void libbpf_strlcpy(char *dst, const char *src, size_t sz)
|
| 230 | {
|
| 231 | size_t i;
|
| 232 |
|
| 233 | if (sz == 0)
|
| 234 | return;
|
| 235 |
|
| 236 | sz--;
|
| 237 | for (i = 0; i < sz && src[i]; i++)
|
| 238 | dst[i] = src[i];
|
| 239 | dst[i] = '\0';
|
| 240 | }
|
| 241 |
|
| 242 | __u32 get_kernel_version(void);
|
| 243 |
|
| 244 | struct btf;
|
| 245 | struct btf_type;
|
| 246 |
|
| 247 | struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id);
|
| 248 | const char *btf_kind_str(const struct btf_type *t);
|
| 249 | const struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);
|
| 250 | const struct btf_header *btf_header(const struct btf *btf);
|
| 251 | void btf_set_base_btf(struct btf *btf, const struct btf *base_btf);
|
| 252 | int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map);
|
| 253 | bool btf_type_is_traceable_func(const struct btf *btf, const struct btf_type *t);
|
| 254 |
|
| 255 | static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t)
|
| 256 | {
|
| 257 | return (enum btf_func_linkage)(int)btf_vlen(t);
|
| 258 | }
|
| 259 |
|
| 260 | static inline __u32 btf_type_info(int kind, int vlen, int kflag)
|
| 261 | {
|
| 262 | return (kflag << 31) | (kind << 24) | vlen;
|
| 263 | }
|
| 264 |
|
| 265 | enum map_def_parts {
|
| 266 | MAP_DEF_MAP_TYPE = 0x001,
|
| 267 | MAP_DEF_KEY_TYPE = 0x002,
|
| 268 | MAP_DEF_KEY_SIZE = 0x004,
|
| 269 | MAP_DEF_VALUE_TYPE = 0x008,
|
| 270 | MAP_DEF_VALUE_SIZE = 0x010,
|
| 271 | MAP_DEF_MAX_ENTRIES = 0x020,
|
| 272 | MAP_DEF_MAP_FLAGS = 0x040,
|
| 273 | MAP_DEF_NUMA_NODE = 0x080,
|
| 274 | MAP_DEF_PINNING = 0x100,
|
| 275 | MAP_DEF_INNER_MAP = 0x200,
|
| 276 | MAP_DEF_MAP_EXTRA = 0x400,
|
| 277 |
|
| 278 | MAP_DEF_ALL = 0x7ff,
|
| 279 | };
|
| 280 |
|
| 281 | struct btf_map_def {
|
| 282 | enum map_def_parts parts;
|
| 283 | __u32 map_type;
|
| 284 | __u32 key_type_id;
|
| 285 | __u32 key_size;
|
| 286 | __u32 value_type_id;
|
| 287 | __u32 value_size;
|
| 288 | __u32 max_entries;
|
| 289 | __u32 map_flags;
|
| 290 | __u32 numa_node;
|
| 291 | __u32 pinning;
|
| 292 | __u64 map_extra;
|
| 293 | };
|
| 294 |
|
| 295 | int parse_btf_map_def(const char *map_name, struct btf *btf,
|
| 296 | const struct btf_type *def_t, bool strict,
|
| 297 | struct btf_map_def *map_def, struct btf_map_def *inner_def);
|
| 298 |
|
| 299 | void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
| 300 | size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
| 301 | int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
| 302 |
|
| 303 | static inline bool libbpf_is_mem_zeroed(const char *p, ssize_t len)
|
| 304 | {
|
| 305 | while (len > 0) {
|
| 306 | if (*p)
|
| 307 | return false;
|
| 308 | p++;
|
| 309 | len--;
|
| 310 | }
|
| 311 | return true;
|
| 312 | }
|
| 313 |
|
| 314 | static inline bool libbpf_validate_opts(const char *opts,
|
| 315 | size_t opts_sz, size_t user_sz,
|
| 316 | const char *type_name)
|
| 317 | {
|
| 318 | if (user_sz < sizeof(size_t)) {
|
| 319 | pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
| 320 | return false;
|
| 321 | }
|
| 322 | if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {
|
| 323 | pr_warn("%s has non-zero extra bytes\n", type_name);
|
| 324 | return false;
|
| 325 | }
|
| 326 | return true;
|
| 327 | }
|
| 328 |
|
| 329 | #define OPTS_VALID(opts, type) \
|
| 330 | (!(opts) || libbpf_validate_opts((const char *)opts, \
|
| 331 | offsetofend(struct type, \
|
| 332 | type##__last_field), \
|
| 333 | (opts)->sz, #type))
|
| 334 | #define OPTS_HAS(opts, field) \
|
| 335 | ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
|
| 336 | #define OPTS_GET(opts, field, fallback_value) \
|
| 337 | (OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
|
| 338 | #define OPTS_SET(opts, field, value) \
|
| 339 | do { \
|
| 340 | if (OPTS_HAS(opts, field)) \
|
| 341 | (opts)->field = value; \
|
| 342 | } while (0)
|
| 343 |
|
| 344 | #define OPTS_ZEROED(opts, last_nonzero_field) \
|
| 345 | ({ \
|
| 346 | ssize_t __off = offsetofend(typeof(*(opts)), last_nonzero_field); \
|
| 347 | !(opts) || libbpf_is_mem_zeroed((const void *)opts + __off, \
|
| 348 | (opts)->sz - __off); \
|
| 349 | })
|
| 350 |
|
| 351 | enum kern_feature_id {
|
| 352 |
|
| 353 | FEAT_PROG_NAME,
|
| 354 |
|
| 355 | FEAT_GLOBAL_DATA,
|
| 356 |
|
| 357 | FEAT_BTF,
|
| 358 |
|
| 359 | FEAT_BTF_FUNC,
|
| 360 |
|
| 361 | FEAT_BTF_DATASEC,
|
| 362 |
|
| 363 | FEAT_BTF_GLOBAL_FUNC,
|
| 364 |
|
| 365 | FEAT_ARRAY_MMAP,
|
| 366 |
|
| 367 | FEAT_EXP_ATTACH_TYPE,
|
| 368 |
|
| 369 | FEAT_PROBE_READ_KERN,
|
| 370 |
|
| 371 | FEAT_PROG_BIND_MAP,
|
| 372 |
|
| 373 | FEAT_MODULE_BTF,
|
| 374 |
|
| 375 | FEAT_BTF_FLOAT,
|
| 376 |
|
| 377 | FEAT_PERF_LINK,
|
| 378 |
|
| 379 | FEAT_BTF_DECL_TAG,
|
| 380 |
|
| 381 | FEAT_BTF_TYPE_TAG,
|
| 382 |
|
| 383 | FEAT_MEMCG_ACCOUNT,
|
| 384 |
|
| 385 | FEAT_BPF_COOKIE,
|
| 386 |
|
| 387 | FEAT_BTF_ENUM64,
|
| 388 |
|
| 389 | FEAT_SYSCALL_WRAPPER,
|
| 390 |
|
| 391 | FEAT_UPROBE_MULTI_LINK,
|
| 392 |
|
| 393 | FEAT_ARG_CTX_TAG,
|
| 394 |
|
| 395 | FEAT_BTF_QMARK_DATASEC,
|
| 396 |
|
| 397 | FEAT_LDIMM64_FULL_RANGE_OFF,
|
| 398 |
|
| 399 | FEAT_UPROBE_SYSCALL,
|
| 400 |
|
| 401 | FEAT_BTF_LAYOUT,
|
| 402 |
|
| 403 | FEAT_BPF_SYSCALL_COMMON_ATTRS,
|
| 404 |
|
| 405 | FEAT_PERCPU_DATA,
|
| 406 | __FEAT_CNT,
|
| 407 | };
|
| 408 |
|
| 409 | enum kern_feature_result {
|
| 410 | FEAT_UNKNOWN = 0,
|
| 411 | FEAT_SUPPORTED = 1,
|
| 412 | FEAT_MISSING = 2,
|
| 413 | };
|
| 414 |
|
| 415 | struct kern_feature_cache {
|
| 416 | enum kern_feature_result res[__FEAT_CNT];
|
| 417 | int token_fd;
|
| 418 | };
|
| 419 |
|
| 420 | bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
|
| 421 | bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
|
| 422 | void bpf_object_set_feat_cache(struct bpf_object *obj, struct kern_feature_cache *cache);
|
| 423 |
|
| 424 | int probe_kern_syscall_wrapper(int token_fd);
|
| 425 | int probe_memcg_account(int token_fd);
|
| 426 | int bump_rlimit_memlock(void);
|
| 427 |
|
| 428 | int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
| 429 | int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
| 430 | int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
| 431 | const char *str_sec, size_t str_len,
|
| 432 | int token_fd);
|
| 433 | int libbpf__load_raw_btf_hdr(const struct btf_header *hdr,
|
| 434 | const char *raw_types, const char *str_sec,
|
| 435 | const char *layout_sec, int token_fd);
|
| 436 | struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf);
|
| 437 | int btf_load_into_kernel(struct btf *btf,
|
| 438 | char *log_buf, size_t log_sz, __u32 log_level,
|
| 439 | int token_fd);
|
| 440 | struct btf *btf_load_from_kernel(__u32 id, struct btf *base_btf, int token_fd);
|
| 441 |
|
| 442 | struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
| 443 | void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
|
| 444 | const char **prefix, int *kind);
|
| 445 |
|
| 446 | struct btf_ext_info {
|
| 447 | |
| 448 | * info points to the individual info section (e.g. func_info and
|
| 449 | * line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
| 450 |
|
| 451 | void *info;
|
| 452 | __u32 rec_size;
|
| 453 | __u32 len;
|
| 454 | |
| 455 | * section and corresponding ELF section. This is used to join
|
| 456 | * information like CO-RE relocation records with corresponding BPF
|
| 457 | * programs defined in ELF sections
|
| 458 |
|
| 459 | __u32 *sec_idxs;
|
| 460 | int sec_cnt;
|
| 461 | };
|
| 462 |
|
| 463 | #define for_each_btf_ext_sec(seg, sec) \
|
| 464 | for (sec = (seg)->info; \
|
| 465 | (void *)sec < (seg)->info + (seg)->len; \
|
| 466 | sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
|
| 467 | (seg)->rec_size * sec->num_info)
|
| 468 |
|
| 469 | #define for_each_btf_ext_rec(seg, sec, i, rec) \
|
| 470 | for (i = 0, rec = (void *)&(sec)->data; \
|
| 471 | i < (sec)->num_info; \
|
| 472 | i++, rec = (void *)rec + (seg)->rec_size)
|
| 473 |
|
| 474 | |
| 475 | * The .BTF.ext ELF section layout defined as
|
| 476 | * struct btf_ext_header
|
| 477 | * func_info subsection
|
| 478 | *
|
| 479 | * The func_info subsection layout:
|
| 480 | * record size for struct bpf_func_info in the func_info subsection
|
| 481 | * struct btf_ext_info_sec for section #1
|
| 482 | * a list of bpf_func_info records for section #1
|
| 483 | * where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
|
| 484 | * but may not be identical
|
| 485 | * struct btf_ext_info_sec for section #2
|
| 486 | * a list of bpf_func_info records for section #2
|
| 487 | * ......
|
| 488 | *
|
| 489 | * Note that the bpf_func_info record size in .BTF.ext may not
|
| 490 | * be the same as the one defined in include/uapi/linux/bpf.h.
|
| 491 | * The loader should ensure that record_size meets minimum
|
| 492 | * requirement and pass the record as is to the kernel. The
|
| 493 | * kernel will handle the func_info properly based on its contents.
|
| 494 |
|
| 495 | struct btf_ext_header {
|
| 496 | __u16 magic;
|
| 497 | __u8 version;
|
| 498 | __u8 flags;
|
| 499 | __u32 hdr_len;
|
| 500 |
|
| 501 |
|
| 502 | __u32 func_info_off;
|
| 503 | __u32 func_info_len;
|
| 504 | __u32 line_info_off;
|
| 505 | __u32 line_info_len;
|
| 506 |
|
| 507 |
|
| 508 | __u32 core_relo_off;
|
| 509 | __u32 core_relo_len;
|
| 510 | };
|
| 511 |
|
| 512 | struct btf_ext {
|
| 513 | union {
|
| 514 | struct btf_ext_header *hdr;
|
| 515 | void *data;
|
| 516 | };
|
| 517 | void *data_swapped;
|
| 518 | bool swapped_endian;
|
| 519 | struct btf_ext_info func_info;
|
| 520 | struct btf_ext_info line_info;
|
| 521 | struct btf_ext_info core_relo_info;
|
| 522 | __u32 data_size;
|
| 523 | };
|
| 524 |
|
| 525 | struct btf_ext_info_sec {
|
| 526 | __u32 sec_name_off;
|
| 527 | __u32 num_info;
|
| 528 |
|
| 529 | __u8 data[];
|
| 530 | };
|
| 531 |
|
| 532 |
|
| 533 | struct bpf_func_info_min {
|
| 534 | __u32 insn_off;
|
| 535 | __u32 type_id;
|
| 536 | };
|
| 537 |
|
| 538 |
|
| 539 | struct bpf_line_info_min {
|
| 540 | __u32 insn_off;
|
| 541 | __u32 file_name_off;
|
| 542 | __u32 line_off;
|
| 543 | __u32 line_col;
|
| 544 | };
|
| 545 |
|
| 546 |
|
| 547 |
|
| 548 | typedef void (*info_rec_bswap_fn)(void *);
|
| 549 |
|
| 550 | static inline void bpf_func_info_bswap(struct bpf_func_info *i)
|
| 551 | {
|
| 552 | i->insn_off = bswap_32(i->insn_off);
|
| 553 | i->type_id = bswap_32(i->type_id);
|
| 554 | }
|
| 555 |
|
| 556 | static inline void bpf_line_info_bswap(struct bpf_line_info *i)
|
| 557 | {
|
| 558 | i->insn_off = bswap_32(i->insn_off);
|
| 559 | i->file_name_off = bswap_32(i->file_name_off);
|
| 560 | i->line_off = bswap_32(i->line_off);
|
| 561 | i->line_col = bswap_32(i->line_col);
|
| 562 | }
|
| 563 |
|
| 564 | static inline void bpf_core_relo_bswap(struct bpf_core_relo *i)
|
| 565 | {
|
| 566 | i->insn_off = bswap_32(i->insn_off);
|
| 567 | i->type_id = bswap_32(i->type_id);
|
| 568 | i->access_str_off = bswap_32(i->access_str_off);
|
| 569 | i->kind = bswap_32(i->kind);
|
| 570 | }
|
| 571 |
|
| 572 | enum btf_field_iter_kind {
|
| 573 | BTF_FIELD_ITER_IDS,
|
| 574 | BTF_FIELD_ITER_STRS,
|
| 575 | };
|
| 576 |
|
| 577 | struct btf_field_desc {
|
| 578 |
|
| 579 | int t_off_cnt, t_offs[2];
|
| 580 |
|
| 581 | int m_sz;
|
| 582 |
|
| 583 | int m_off_cnt, m_offs[1];
|
| 584 | };
|
| 585 |
|
| 586 | struct btf_field_iter {
|
| 587 | struct btf_field_desc desc;
|
| 588 | void *p;
|
| 589 | int m_idx;
|
| 590 | int off_idx;
|
| 591 | int vlen;
|
| 592 | };
|
| 593 |
|
| 594 | int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, enum btf_field_iter_kind iter_kind);
|
| 595 | __u32 *btf_field_iter_next(struct btf_field_iter *it);
|
| 596 |
|
| 597 | typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);
|
| 598 | typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);
|
| 599 | int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
|
| 600 | int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
|
| 601 |
|
| 602 |
|
| 603 | static inline int libbpf_err(int ret)
|
| 604 | {
|
| 605 | if (ret < 0)
|
| 606 | errno = -ret;
|
| 607 | return ret;
|
| 608 | }
|
| 609 |
|
| 610 | |
| 611 | * strict mode settings
|
| 612 |
|
| 613 | static inline int libbpf_err_errno(int ret)
|
| 614 | {
|
| 615 |
|
| 616 | return ret < 0 ? -errno : ret;
|
| 617 | }
|
| 618 |
|
| 619 |
|
| 620 | static inline void *libbpf_err_ptr(int err)
|
| 621 | {
|
| 622 |
|
| 623 | errno = -err;
|
| 624 | return NULL;
|
| 625 | }
|
| 626 |
|
| 627 |
|
| 628 | static inline void *libbpf_ptr(void *ret)
|
| 629 | {
|
| 630 |
|
| 631 | if (IS_ERR(ret))
|
| 632 | errno = -PTR_ERR(ret);
|
| 633 |
|
| 634 | return IS_ERR(ret) ? NULL : ret;
|
| 635 | }
|
| 636 |
|
| 637 | static inline bool str_is_empty(const char *s)
|
| 638 | {
|
| 639 | return !s || !s[0];
|
| 640 | }
|
| 641 |
|
| 642 | static inline bool is_ldimm64_insn(struct bpf_insn *insn)
|
| 643 | {
|
| 644 | return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
| 645 | }
|
| 646 |
|
| 647 | static inline void bpf_insn_bswap(struct bpf_insn *insn)
|
| 648 | {
|
| 649 | __u8 tmp_reg = insn->dst_reg;
|
| 650 |
|
| 651 | insn->dst_reg = insn->src_reg;
|
| 652 | insn->src_reg = tmp_reg;
|
| 653 | insn->off = bswap_16(insn->off);
|
| 654 | insn->imm = bswap_32(insn->imm);
|
| 655 | }
|
| 656 |
|
| 657 | |
| 658 | * Original FD is not closed or altered in any other way.
|
| 659 | * Preserves original FD value, if it's invalid (negative).
|
| 660 |
|
| 661 | static inline int dup_good_fd(int fd)
|
| 662 | {
|
| 663 | if (fd < 0)
|
| 664 | return fd;
|
| 665 | return fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
| 666 | }
|
| 667 |
|
| 668 | |
| 669 | * Takes ownership of the fd passed in, and closes it if calling
|
| 670 | * fcntl(fd, F_DUPFD_CLOEXEC, 3).
|
| 671 |
|
| 672 | static inline int ensure_good_fd(int fd)
|
| 673 | {
|
| 674 | int old_fd = fd, saved_errno;
|
| 675 |
|
| 676 | if (fd < 0)
|
| 677 | return fd;
|
| 678 | if (fd < 3) {
|
| 679 | fd = dup_good_fd(fd);
|
| 680 | saved_errno = errno;
|
| 681 | close(old_fd);
|
| 682 | errno = saved_errno;
|
| 683 | if (fd < 0) {
|
| 684 | pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
| 685 | errno = saved_errno;
|
| 686 | }
|
| 687 | }
|
| 688 | return fd;
|
| 689 | }
|
| 690 |
|
| 691 | static inline int sys_dup3(int oldfd, int newfd, int flags)
|
| 692 | {
|
| 693 | return syscall(__NR_dup3, oldfd, newfd, flags);
|
| 694 | }
|
| 695 |
|
| 696 | |
| 697 | * implementation, so avoid complications and just go straight to Linux
|
| 698 | * syscall.
|
| 699 |
|
| 700 | static inline int sys_memfd_create(const char *name, unsigned flags)
|
| 701 | {
|
| 702 | return syscall(__NR_memfd_create, name, flags);
|
| 703 | }
|
| 704 |
|
| 705 | |
| 706 | * Regardless of success, *tmp_fd* is closed.
|
| 707 | * Whatever *fixed_fd* pointed to is closed silently.
|
| 708 |
|
| 709 | static inline int reuse_fd(int fixed_fd, int tmp_fd)
|
| 710 | {
|
| 711 | int err;
|
| 712 |
|
| 713 | err = sys_dup3(tmp_fd, fixed_fd, O_CLOEXEC);
|
| 714 | err = err < 0 ? -errno : 0;
|
| 715 | close(tmp_fd);
|
| 716 | return err;
|
| 717 | }
|
| 718 |
|
| 719 |
|
| 720 | int bpf_core_add_cands(struct bpf_core_cand *local_cand,
|
| 721 | size_t local_essent_len,
|
| 722 | const struct btf *targ_btf,
|
| 723 | const char *targ_btf_name,
|
| 724 | int targ_start_id,
|
| 725 | struct bpf_core_cand_list *cands);
|
| 726 | void bpf_core_free_cands(struct bpf_core_cand_list *cands);
|
| 727 |
|
| 728 | struct usdt_manager *usdt_manager_new(struct bpf_object *obj);
|
| 729 | void usdt_manager_free(struct usdt_manager *man);
|
| 730 | struct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man,
|
| 731 | const struct bpf_program *prog,
|
| 732 | pid_t pid, const char *path,
|
| 733 | const char *usdt_provider, const char *usdt_name,
|
| 734 | __u64 usdt_cookie);
|
| 735 |
|
| 736 | static inline bool is_pow_of_2(size_t x)
|
| 737 | {
|
| 738 | return x && (x & (x - 1)) == 0;
|
| 739 | }
|
| 740 |
|
| 741 | static inline __u32 ror32(__u32 v, int bits)
|
| 742 | {
|
| 743 | return (v >> bits) | (v << (32 - bits));
|
| 744 | }
|
| 745 |
|
| 746 | #define PROG_LOAD_ATTEMPTS 5
|
| 747 | int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts);
|
| 748 |
|
| 749 | bool glob_match(const char *str, const char *pat);
|
| 750 |
|
| 751 | long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
|
| 752 | long elf_find_func_offset_from_file(const char *binary_path, const char *name);
|
| 753 |
|
| 754 | struct elf_fd {
|
| 755 | Elf *elf;
|
| 756 | int fd;
|
| 757 | };
|
| 758 |
|
| 759 | int elf_open(const char *binary_path, struct elf_fd *elf_fd);
|
| 760 | void elf_close(struct elf_fd *elf_fd);
|
| 761 |
|
| 762 | int elf_resolve_syms_offsets(const char *binary_path, int cnt,
|
| 763 | const char **syms, unsigned long **poffsets,
|
| 764 | int st_type);
|
| 765 | int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
|
| 766 | unsigned long **poffsets, size_t *pcnt);
|
| 767 |
|
| 768 | int probe_fd(int fd);
|
| 769 |
|
| 770 | #define SHA256_DIGEST_LENGTH 32
|
| 771 |
|
| 772 | void libbpf_sha256(const void *data, size_t len, __u8 out[SHA256_DIGEST_LENGTH]);
|
| 773 | int probe_sys_bpf_ext(void);
|
| 774 | #endif
|