libbpf: detect supported kernel BTF features and sanitize BTF
Depending on used versions of libbpf, Clang, and kernel, it's possible to
have valid BPF object files with valid BTF information, that still won't
load successfully due to Clang emitting newer BTF features (e.g.,
BTF_KIND_FUNC, .BTF.ext's line_info/func_info, BTF_KIND_DATASEC, etc), that
are not yet supported by older kernel.
This patch adds detection of BTF features and sanitizes BPF object's BTF
by substituting various supported BTF kinds, which have compatible layout:
- BTF_KIND_FUNC -> BTF_KIND_TYPEDEF
- BTF_KIND_FUNC_PROTO -> BTF_KIND_ENUM
- BTF_KIND_VAR -> BTF_KIND_INT
- BTF_KIND_DATASEC -> BTF_KIND_STRUCT
Replacement is done in such a way as to preserve as much information as
possible (names, sizes, etc) where possible without violating kernel's
validation rules.
v2->v3:
- remove duplicate #defines from libbpf_util.h
v1->v2:
- add internal libbpf_internal.h w/ common stuff
- switch SK storage BTF to use new libbpf__probe_raw_btf()
Reported-by: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-05-11 05:13:15 +08:00
|
|
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal libbpf helpers.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2019 Facebook
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LIBBPF_LIBBPF_INTERNAL_H
|
|
|
|
#define __LIBBPF_LIBBPF_INTERNAL_H
|
|
|
|
|
2020-08-19 09:36:04 +08:00
|
|
|
#include <stdlib.h>
|
2020-08-20 14:14:09 +08:00
|
|
|
#include <limits.h>
|
2020-08-19 09:36:06 +08:00
|
|
|
|
|
|
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
|
|
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
|
|
|
|
|
|
|
/* prevent accidental re-addition of reallocarray() */
|
|
|
|
#pragma GCC poison reallocarray
|
|
|
|
|
2019-05-25 02:58:56 +08:00
|
|
|
#include "libbpf.h"
|
|
|
|
|
libbpf: detect supported kernel BTF features and sanitize BTF
Depending on used versions of libbpf, Clang, and kernel, it's possible to
have valid BPF object files with valid BTF information, that still won't
load successfully due to Clang emitting newer BTF features (e.g.,
BTF_KIND_FUNC, .BTF.ext's line_info/func_info, BTF_KIND_DATASEC, etc), that
are not yet supported by older kernel.
This patch adds detection of BTF features and sanitizes BPF object's BTF
by substituting various supported BTF kinds, which have compatible layout:
- BTF_KIND_FUNC -> BTF_KIND_TYPEDEF
- BTF_KIND_FUNC_PROTO -> BTF_KIND_ENUM
- BTF_KIND_VAR -> BTF_KIND_INT
- BTF_KIND_DATASEC -> BTF_KIND_STRUCT
Replacement is done in such a way as to preserve as much information as
possible (names, sizes, etc) where possible without violating kernel's
validation rules.
v2->v3:
- remove duplicate #defines from libbpf_util.h
v1->v2:
- add internal libbpf_internal.h w/ common stuff
- switch SK storage BTF to use new libbpf__probe_raw_btf()
Reported-by: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-05-11 05:13:15 +08:00
|
|
|
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
|
|
|
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
|
|
|
#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
|
|
|
|
#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
|
|
|
|
((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
|
|
|
|
#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
|
|
|
|
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
|
|
|
|
BTF_INT_ENC(encoding, bits_offset, bits)
|
|
|
|
#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
|
|
|
|
#define BTF_PARAM_ENC(name, type) (name), (type)
|
|
|
|
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
|
|
|
|
2020-08-19 09:36:04 +08:00
|
|
|
#ifndef likely
|
|
|
|
#define likely(x) __builtin_expect(!!(x), 1)
|
|
|
|
#endif
|
|
|
|
#ifndef unlikely
|
|
|
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
|
|
|
#endif
|
2019-06-18 03:26:50 +08:00
|
|
|
#ifndef min
|
|
|
|
# define min(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
#endif
|
|
|
|
#ifndef max
|
|
|
|
# define max(x, y) ((x) < (y) ? (y) : (x))
|
|
|
|
#endif
|
2019-08-08 05:39:50 +08:00
|
|
|
#ifndef offsetofend
|
|
|
|
# define offsetofend(TYPE, FIELD) \
|
|
|
|
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
|
|
|
#endif
|
2019-06-18 03:26:50 +08:00
|
|
|
|
libbpf: handle symbol versioning properly for libbpf.a
bcc uses libbpf repo as a submodule. It brings in libbpf source
code and builds everything together to produce shared libraries.
With latest libbpf, I got the following errors:
/bin/ld: libbcc_bpf.so.0.10.0: version node not found for symbol xsk_umem__create@LIBBPF_0.0.2
/bin/ld: failed to set dynamic section sizes: Bad value
collect2: error: ld returned 1 exit status
make[2]: *** [src/cc/libbcc_bpf.so.0.10.0] Error 1
In xsk.c, we have
asm(".symver xsk_umem__create_v0_0_2, xsk_umem__create@LIBBPF_0.0.2");
asm(".symver xsk_umem__create_v0_0_4, xsk_umem__create@@LIBBPF_0.0.4");
The linker thinks the built is for LIBBPF but cannot find proper version
LIBBPF_0.0.2/4, so emit errors.
I also confirmed that using libbpf.a to produce a shared library also
has issues:
-bash-4.4$ cat t.c
extern void *xsk_umem__create;
void * test() { return xsk_umem__create; }
-bash-4.4$ gcc -c -fPIC t.c
-bash-4.4$ gcc -shared t.o libbpf.a -o t.so
/bin/ld: t.so: version node not found for symbol xsk_umem__create@LIBBPF_0.0.2
/bin/ld: failed to set dynamic section sizes: Bad value
collect2: error: ld returned 1 exit status
-bash-4.4$
Symbol versioning does happens in commonly used libraries, e.g., elfutils
and glibc. For static libraries, for a versioned symbol, the old definitions
will be ignored, and the symbol will be an alias to the latest definition.
For example, glibc sched_setaffinity is versioned.
-bash-4.4$ readelf -s /usr/lib64/libc.so.6 | grep sched_setaffinity
756: 000000000013d3d0 13 FUNC GLOBAL DEFAULT 13 sched_setaffinity@GLIBC_2.3.3
757: 00000000000e2e70 455 FUNC GLOBAL DEFAULT 13 sched_setaffinity@@GLIBC_2.3.4
1800: 0000000000000000 0 FILE LOCAL DEFAULT ABS sched_setaffinity.c
4228: 00000000000e2e70 455 FUNC LOCAL DEFAULT 13 __sched_setaffinity_new
4648: 000000000013d3d0 13 FUNC LOCAL DEFAULT 13 __sched_setaffinity_old
7338: 000000000013d3d0 13 FUNC GLOBAL DEFAULT 13 sched_setaffinity@GLIBC_2
7380: 00000000000e2e70 455 FUNC GLOBAL DEFAULT 13 sched_setaffinity@@GLIBC_
-bash-4.4$
For static library, the definition of sched_setaffinity aliases to the new definition.
-bash-4.4$ readelf -s /usr/lib64/libc.a | grep sched_setaffinity
File: /usr/lib64/libc.a(sched_setaffinity.o)
8: 0000000000000000 455 FUNC GLOBAL DEFAULT 1 __sched_setaffinity_new
12: 0000000000000000 455 FUNC WEAK DEFAULT 1 sched_setaffinity
For both elfutils and glibc, additional macros are used to control different handling
of symbol versioning w.r.t static and shared libraries.
For elfutils, the macro is SYMBOL_VERSIONING
(https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/eu-config.h).
For glibc, the macro is SHARED
(https://sourceware.org/git/?p=glibc.git;a=blob;f=include/shlib-compat.h;hb=refs/heads/master)
This patch used SHARED as the macro name. After this patch, the libbpf.a has
-bash-4.4$ readelf -s libbpf.a | grep xsk_umem__create
372: 0000000000017145 1190 FUNC GLOBAL DEFAULT 1 xsk_umem__create_v0_0_4
405: 0000000000017145 1190 FUNC GLOBAL DEFAULT 1 xsk_umem__create
499: 00000000000175eb 103 FUNC GLOBAL DEFAULT 1 xsk_umem__create_v0_0_2
-bash-4.4$
No versioned symbols for xsk_umem__create.
The libbpf.a can be used to build a shared library succesfully.
-bash-4.4$ cat t.c
extern void *xsk_umem__create;
void * test() { return xsk_umem__create; }
-bash-4.4$ gcc -c -fPIC t.c
-bash-4.4$ gcc -shared t.o libbpf.a -o t.so
-bash-4.4$
Fixes: 10d30e301732 ("libbpf: add flags to umem config")
Cc: Kevin Laatz <kevin.laatz@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-10-01 05:02:03 +08:00
|
|
|
/* Symbol versioning is different between static and shared library.
|
|
|
|
* Properly versioned symbols are needed for shared library, but
|
|
|
|
* only the symbol of the new version is needed for static library.
|
|
|
|
*/
|
|
|
|
#ifdef SHARED
|
|
|
|
# define COMPAT_VERSION(internal_name, api_name, version) \
|
|
|
|
asm(".symver " #internal_name "," #api_name "@" #version);
|
|
|
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
|
|
|
asm(".symver " #internal_name "," #api_name "@@" #version);
|
|
|
|
#else
|
|
|
|
# define COMPAT_VERSION(internal_name, api_name, version)
|
|
|
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
|
|
|
extern typeof(internal_name) api_name \
|
|
|
|
__attribute__((alias(#internal_name)));
|
|
|
|
#endif
|
|
|
|
|
2019-05-16 11:39:27 +08:00
|
|
|
extern void libbpf_print(enum libbpf_print_level level,
|
|
|
|
const char *format, ...)
|
|
|
|
__attribute__((format(printf, 2, 3)));
|
|
|
|
|
|
|
|
#define __pr(level, fmt, ...) \
|
|
|
|
do { \
|
|
|
|
libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \
|
|
|
|
} while (0)
|
|
|
|
|
2019-10-21 13:55:32 +08:00
|
|
|
#define pr_warn(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__)
|
2019-05-16 11:39:27 +08:00
|
|
|
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
|
|
|
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
|
|
|
|
2020-08-20 14:14:09 +08:00
|
|
|
#ifndef __has_builtin
|
|
|
|
#define __has_builtin(x) 0
|
|
|
|
#endif
|
2020-08-19 09:36:04 +08:00
|
|
|
/*
|
|
|
|
* Re-implement glibc's reallocarray() for libbpf internal-only use.
|
|
|
|
* reallocarray(), unfortunately, is not available in all versions of glibc,
|
|
|
|
* so requires extra feature detection and using reallocarray() stub from
|
|
|
|
* <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates
|
|
|
|
* build of libbpf unnecessarily and is just a maintenance burden. Instead,
|
|
|
|
* it's trivial to implement libbpf-specific internal version and use it
|
|
|
|
* throughout libbpf.
|
|
|
|
*/
|
|
|
|
static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)
|
|
|
|
{
|
|
|
|
size_t total;
|
|
|
|
|
2020-08-20 14:14:09 +08:00
|
|
|
#if __has_builtin(__builtin_mul_overflow)
|
2020-08-19 09:36:04 +08:00
|
|
|
if (unlikely(__builtin_mul_overflow(nmemb, size, &total)))
|
|
|
|
return NULL;
|
2020-08-20 14:14:09 +08:00
|
|
|
#else
|
|
|
|
if (size == 0 || nmemb > ULONG_MAX / size)
|
|
|
|
return NULL;
|
|
|
|
total = nmemb * size;
|
|
|
|
#endif
|
2020-08-19 09:36:04 +08:00
|
|
|
return realloc(ptr, total);
|
|
|
|
}
|
|
|
|
|
2020-09-26 09:13:51 +08:00
|
|
|
void *btf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
|
|
|
size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
2020-09-30 07:28:40 +08:00
|
|
|
int btf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
2020-09-26 09:13:51 +08:00
|
|
|
|
libbpf: add bpf_object__open_{file, mem} w/ extensible opts
Add new set of bpf_object__open APIs using new approach to optional
parameters extensibility allowing simpler ABI compatibility approach.
This patch demonstrates an approach to implementing libbpf APIs that
makes it easy to extend existing APIs with extra optional parameters in
such a way, that ABI compatibility is preserved without having to do
symbol versioning and generating lots of boilerplate code to handle it.
To facilitate succinct code for working with options, add OPTS_VALID,
OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero
checks.
Additionally, newly added libbpf APIs are encouraged to follow similar
pattern of having all mandatory parameters as formal function parameters
and always have optional (NULL-able) xxx_opts struct, which should
always have real struct size as a first field and the rest would be
optional parameters added over time, which tune the behavior of existing
API, if specified by user.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-10-05 06:40:35 +08:00
|
|
|
static inline bool libbpf_validate_opts(const char *opts,
|
|
|
|
size_t opts_sz, size_t user_sz,
|
|
|
|
const char *type_name)
|
|
|
|
{
|
|
|
|
if (user_sz < sizeof(size_t)) {
|
2019-10-21 13:55:32 +08:00
|
|
|
pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
libbpf: add bpf_object__open_{file, mem} w/ extensible opts
Add new set of bpf_object__open APIs using new approach to optional
parameters extensibility allowing simpler ABI compatibility approach.
This patch demonstrates an approach to implementing libbpf APIs that
makes it easy to extend existing APIs with extra optional parameters in
such a way, that ABI compatibility is preserved without having to do
symbol versioning and generating lots of boilerplate code to handle it.
To facilitate succinct code for working with options, add OPTS_VALID,
OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero
checks.
Additionally, newly added libbpf APIs are encouraged to follow similar
pattern of having all mandatory parameters as formal function parameters
and always have optional (NULL-able) xxx_opts struct, which should
always have real struct size as a first field and the rest would be
optional parameters added over time, which tune the behavior of existing
API, if specified by user.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-10-05 06:40:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (user_sz > opts_sz) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = opts_sz; i < user_sz; i++) {
|
|
|
|
if (opts[i]) {
|
2019-12-19 20:07:14 +08:00
|
|
|
pr_warn("%s has non-zero extra bytes\n",
|
2019-10-21 13:55:32 +08:00
|
|
|
type_name);
|
libbpf: add bpf_object__open_{file, mem} w/ extensible opts
Add new set of bpf_object__open APIs using new approach to optional
parameters extensibility allowing simpler ABI compatibility approach.
This patch demonstrates an approach to implementing libbpf APIs that
makes it easy to extend existing APIs with extra optional parameters in
such a way, that ABI compatibility is preserved without having to do
symbol versioning and generating lots of boilerplate code to handle it.
To facilitate succinct code for working with options, add OPTS_VALID,
OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero
checks.
Additionally, newly added libbpf APIs are encouraged to follow similar
pattern of having all mandatory parameters as formal function parameters
and always have optional (NULL-able) xxx_opts struct, which should
always have real struct size as a first field and the rest would be
optional parameters added over time, which tune the behavior of existing
API, if specified by user.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-10-05 06:40:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OPTS_VALID(opts, type) \
|
|
|
|
(!(opts) || libbpf_validate_opts((const char *)opts, \
|
|
|
|
offsetofend(struct type, \
|
|
|
|
type##__last_field), \
|
|
|
|
(opts)->sz, #type))
|
|
|
|
#define OPTS_HAS(opts, field) \
|
|
|
|
((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
|
|
|
|
#define OPTS_GET(opts, field, fallback_value) \
|
|
|
|
(OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
|
2020-09-26 04:54:30 +08:00
|
|
|
#define OPTS_SET(opts, field, value) \
|
|
|
|
do { \
|
|
|
|
if (OPTS_HAS(opts, field)) \
|
|
|
|
(opts)->field = value; \
|
|
|
|
} while (0)
|
libbpf: add bpf_object__open_{file, mem} w/ extensible opts
Add new set of bpf_object__open APIs using new approach to optional
parameters extensibility allowing simpler ABI compatibility approach.
This patch demonstrates an approach to implementing libbpf APIs that
makes it easy to extend existing APIs with extra optional parameters in
such a way, that ABI compatibility is preserved without having to do
symbol versioning and generating lots of boilerplate code to handle it.
To facilitate succinct code for working with options, add OPTS_VALID,
OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero
checks.
Additionally, newly added libbpf APIs are encouraged to follow similar
pattern of having all mandatory parameters as formal function parameters
and always have optional (NULL-able) xxx_opts struct, which should
always have real struct size as a first field and the rest would be
optional parameters added over time, which tune the behavior of existing
API, if specified by user.
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-10-05 06:40:35 +08:00
|
|
|
|
2019-12-12 09:35:48 +08:00
|
|
|
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
|
|
|
int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
2019-05-30 02:31:09 +08:00
|
|
|
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
|
|
|
const char *str_sec, size_t str_len);
|
libbpf: detect supported kernel BTF features and sanitize BTF
Depending on used versions of libbpf, Clang, and kernel, it's possible to
have valid BPF object files with valid BTF information, that still won't
load successfully due to Clang emitting newer BTF features (e.g.,
BTF_KIND_FUNC, .BTF.ext's line_info/func_info, BTF_KIND_DATASEC, etc), that
are not yet supported by older kernel.
This patch adds detection of BTF features and sanitizes BPF object's BTF
by substituting various supported BTF kinds, which have compatible layout:
- BTF_KIND_FUNC -> BTF_KIND_TYPEDEF
- BTF_KIND_FUNC_PROTO -> BTF_KIND_ENUM
- BTF_KIND_VAR -> BTF_KIND_INT
- BTF_KIND_DATASEC -> BTF_KIND_STRUCT
Replacement is done in such a way as to preserve as much information as
possible (names, sizes, etc) where possible without violating kernel's
validation rules.
v2->v3:
- remove duplicate #defines from libbpf_util.h
v1->v2:
- add internal libbpf_internal.h w/ common stuff
- switch SK storage BTF to use new libbpf__probe_raw_btf()
Reported-by: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-05-11 05:13:15 +08:00
|
|
|
|
2019-12-14 09:43:27 +08:00
|
|
|
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
|
|
|
__u32 *size);
|
|
|
|
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
|
|
|
__u32 *off);
|
2020-12-04 04:46:23 +08:00
|
|
|
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
2019-12-14 09:43:27 +08:00
|
|
|
|
2019-08-08 05:39:50 +08:00
|
|
|
struct btf_ext_info {
|
|
|
|
/*
|
|
|
|
* info points to the individual info section (e.g. func_info and
|
|
|
|
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
|
|
|
*/
|
|
|
|
void *info;
|
|
|
|
__u32 rec_size;
|
|
|
|
__u32 len;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define for_each_btf_ext_sec(seg, sec) \
|
|
|
|
for (sec = (seg)->info; \
|
|
|
|
(void *)sec < (seg)->info + (seg)->len; \
|
|
|
|
sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
|
|
|
|
(seg)->rec_size * sec->num_info)
|
|
|
|
|
|
|
|
#define for_each_btf_ext_rec(seg, sec, i, rec) \
|
|
|
|
for (i = 0, rec = (void *)&(sec)->data; \
|
|
|
|
i < (sec)->num_info; \
|
|
|
|
i++, rec = (void *)rec + (seg)->rec_size)
|
|
|
|
|
2020-08-19 06:39:14 +08:00
|
|
|
/*
|
|
|
|
* The .BTF.ext ELF section layout defined as
|
|
|
|
* struct btf_ext_header
|
|
|
|
* func_info subsection
|
|
|
|
*
|
|
|
|
* The func_info subsection layout:
|
|
|
|
* record size for struct bpf_func_info in the func_info subsection
|
|
|
|
* struct btf_sec_func_info for section #1
|
|
|
|
* a list of bpf_func_info records for section #1
|
|
|
|
* where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
|
|
|
|
* but may not be identical
|
|
|
|
* struct btf_sec_func_info for section #2
|
|
|
|
* a list of bpf_func_info records for section #2
|
|
|
|
* ......
|
|
|
|
*
|
|
|
|
* Note that the bpf_func_info record size in .BTF.ext may not
|
|
|
|
* be the same as the one defined in include/uapi/linux/bpf.h.
|
|
|
|
* The loader should ensure that record_size meets minimum
|
|
|
|
* requirement and pass the record as is to the kernel. The
|
|
|
|
* kernel will handle the func_info properly based on its contents.
|
|
|
|
*/
|
|
|
|
struct btf_ext_header {
|
|
|
|
__u16 magic;
|
|
|
|
__u8 version;
|
|
|
|
__u8 flags;
|
|
|
|
__u32 hdr_len;
|
|
|
|
|
|
|
|
/* All offsets are in bytes relative to the end of this header */
|
|
|
|
__u32 func_info_off;
|
|
|
|
__u32 func_info_len;
|
|
|
|
__u32 line_info_off;
|
|
|
|
__u32 line_info_len;
|
|
|
|
|
|
|
|
/* optional part of .BTF.ext header */
|
|
|
|
__u32 core_relo_off;
|
|
|
|
__u32 core_relo_len;
|
|
|
|
};
|
|
|
|
|
2019-08-08 05:39:50 +08:00
|
|
|
struct btf_ext {
|
|
|
|
union {
|
|
|
|
struct btf_ext_header *hdr;
|
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
struct btf_ext_info func_info;
|
|
|
|
struct btf_ext_info line_info;
|
2020-08-19 06:39:14 +08:00
|
|
|
struct btf_ext_info core_relo_info;
|
2019-08-08 05:39:50 +08:00
|
|
|
__u32 data_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct btf_ext_info_sec {
|
|
|
|
__u32 sec_name_off;
|
|
|
|
__u32 num_info;
|
|
|
|
/* Followed by num_info * record_size number of bytes */
|
bpf, libbpf: Replace zero-length array with flexible-array
The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to declare
variable-length types such as these ones is a flexible array member[1][2],
introduced in C99:
struct foo {
int stuff;
struct boo array[];
};
By making use of the mechanism above, we will get a compiler warning
in case the flexible array does not occur last in the structure, which
will help us prevent some kind of undefined behavior bugs from being
inadvertently introduced[3] to the codebase from now on.
Also, notice that, dynamic memory allocations won't be affected by
this change:
"Flexible array members have incomplete type, and so the sizeof operator
may not be applied. As a quirk of the original implementation of
zero-length arrays, sizeof evaluates to zero."[1]
sizeof(flexible-array-member) triggers a warning because flexible array
members have incomplete type[1]. There are some instances of code in
which the sizeof operator is being incorrectly/erroneously applied to
zero-length arrays and the result is zero. Such instances may be hiding
some bugs. So, this work (flexible-array member conversions) will also
help to get completely rid of those sorts of issues.
This issue was found with the help of Coccinelle.
[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://github.com/KSPP/linux/issues/21
[3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour")
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20200507185057.GA13981@embeddedor
2020-05-08 02:50:57 +08:00
|
|
|
__u8 data[];
|
2019-08-08 05:39:50 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* The minimum bpf_func_info checked by the loader */
|
|
|
|
struct bpf_func_info_min {
|
|
|
|
__u32 insn_off;
|
|
|
|
__u32 type_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* The minimum bpf_line_info checked by the loader */
|
|
|
|
struct bpf_line_info_min {
|
|
|
|
__u32 insn_off;
|
|
|
|
__u32 file_name_off;
|
|
|
|
__u32 line_off;
|
|
|
|
__u32 line_col;
|
|
|
|
};
|
|
|
|
|
2020-08-19 06:39:14 +08:00
|
|
|
/* bpf_core_relo_kind encodes which aspect of captured field/type/enum value
|
|
|
|
* has to be adjusted by relocations.
|
2019-10-16 02:28:45 +08:00
|
|
|
*/
|
2020-08-19 06:39:14 +08:00
|
|
|
enum bpf_core_relo_kind {
|
2019-10-16 02:28:45 +08:00
|
|
|
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
2020-08-19 06:39:14 +08:00
|
|
|
BPF_FIELD_BYTE_SIZE = 1, /* field size in bytes */
|
2019-10-16 02:28:45 +08:00
|
|
|
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
2020-08-19 06:39:14 +08:00
|
|
|
BPF_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */
|
|
|
|
BPF_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */
|
|
|
|
BPF_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */
|
2020-08-20 03:45:15 +08:00
|
|
|
BPF_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */
|
|
|
|
BPF_TYPE_ID_TARGET = 7, /* type ID in target kernel */
|
|
|
|
BPF_TYPE_EXISTS = 8, /* type existence in target kernel */
|
|
|
|
BPF_TYPE_SIZE = 9, /* type size in bytes */
|
2020-08-20 03:45:18 +08:00
|
|
|
BPF_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */
|
|
|
|
BPF_ENUMVAL_VALUE = 11, /* enum value integer value */
|
2019-10-16 02:28:45 +08:00
|
|
|
};
|
|
|
|
|
2020-08-19 06:39:14 +08:00
|
|
|
/* The minimum bpf_core_relo checked by the loader
|
2019-08-08 05:39:50 +08:00
|
|
|
*
|
2020-08-19 06:39:14 +08:00
|
|
|
* CO-RE relocation captures the following data:
|
2019-08-08 05:39:50 +08:00
|
|
|
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
2019-10-16 02:28:45 +08:00
|
|
|
* its insn->imm field to be relocated with actual field info;
|
2019-08-08 05:39:50 +08:00
|
|
|
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
2020-08-19 06:39:14 +08:00
|
|
|
* type or field;
|
2019-08-08 05:39:50 +08:00
|
|
|
* - access_str_off - offset into corresponding .BTF string section. String
|
2020-08-19 06:39:14 +08:00
|
|
|
* interpretation depends on specific relocation kind:
|
|
|
|
* - for field-based relocations, string encodes an accessed field using
|
|
|
|
* a sequence of field and array indices, separated by colon (:). It's
|
|
|
|
* conceptually very close to LLVM's getelementptr ([0]) instruction's
|
|
|
|
* arguments for identifying offset to a field.
|
|
|
|
* - for type-based relocations, strings is expected to be just "0";
|
|
|
|
* - for enum value-based relocations, string contains an index of enum
|
|
|
|
* value within its enum type;
|
2019-08-08 05:39:50 +08:00
|
|
|
*
|
|
|
|
* Example to provide a better feel.
|
|
|
|
*
|
|
|
|
* struct sample {
|
|
|
|
* int a;
|
|
|
|
* struct {
|
|
|
|
* int b[10];
|
|
|
|
* };
|
|
|
|
* };
|
|
|
|
*
|
|
|
|
* struct sample *s = ...;
|
|
|
|
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
|
|
|
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
|
|
|
* // b is field #0 inside anon struct, accessing elem #5)
|
|
|
|
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
|
|
|
*
|
|
|
|
* type_id for all relocs in this example will capture BTF type id of
|
|
|
|
* `struct sample`.
|
|
|
|
*
|
|
|
|
* Such relocation is emitted when using __builtin_preserve_access_index()
|
|
|
|
* Clang built-in, passing expression that captures field address, e.g.:
|
|
|
|
*
|
|
|
|
* bpf_probe_read(&dst, sizeof(dst),
|
|
|
|
* __builtin_preserve_access_index(&src->a.b.c));
|
|
|
|
*
|
2019-10-16 02:28:45 +08:00
|
|
|
* In this case Clang will emit field relocation recording necessary data to
|
2019-08-08 05:39:50 +08:00
|
|
|
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
|
|
|
*
|
|
|
|
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
|
|
*/
|
2020-08-19 06:39:14 +08:00
|
|
|
struct bpf_core_relo {
|
2019-08-08 05:39:50 +08:00
|
|
|
__u32 insn_off;
|
|
|
|
__u32 type_id;
|
|
|
|
__u32 access_str_off;
|
2020-08-19 06:39:14 +08:00
|
|
|
enum bpf_core_relo_kind kind;
|
2019-08-08 05:39:50 +08:00
|
|
|
};
|
|
|
|
|
libbpf: detect supported kernel BTF features and sanitize BTF
Depending on used versions of libbpf, Clang, and kernel, it's possible to
have valid BPF object files with valid BTF information, that still won't
load successfully due to Clang emitting newer BTF features (e.g.,
BTF_KIND_FUNC, .BTF.ext's line_info/func_info, BTF_KIND_DATASEC, etc), that
are not yet supported by older kernel.
This patch adds detection of BTF features and sanitizes BPF object's BTF
by substituting various supported BTF kinds, which have compatible layout:
- BTF_KIND_FUNC -> BTF_KIND_TYPEDEF
- BTF_KIND_FUNC_PROTO -> BTF_KIND_ENUM
- BTF_KIND_VAR -> BTF_KIND_INT
- BTF_KIND_DATASEC -> BTF_KIND_STRUCT
Replacement is done in such a way as to preserve as much information as
possible (names, sizes, etc) where possible without violating kernel's
validation rules.
v2->v3:
- remove duplicate #defines from libbpf_util.h
v1->v2:
- add internal libbpf_internal.h w/ common stuff
- switch SK storage BTF to use new libbpf__probe_raw_btf()
Reported-by: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-05-11 05:13:15 +08:00
|
|
|
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|