Merge branch 'bpf-btf-type-fixes'
Yonghong Song says:
====================
Commit 69b693f0ae
("bpf: btf: Introduce BPF Type Format (BTF)")
introduced BTF, a debug info format for BTF.
The original design has a couple of issues though.
First, the bitfield size is only encoded in int type.
If the struct member bitfield type is enum, pahole ([1])
or llvm is forced to replace enum with int type. As a result, the original
type information gets lost.
Second, the original BTF design does not envision the possibility of
BTF=>header_file conversion ([2]), hence does not encode "struct" or
"union" info for a forward type. Such information is necessary to
convert BTF to a header file.
This patch set fixed the issue by introducing kind_flag, using one bit
in type->info. When kind_flag, the struct/union btf_member->offset
will encode both bitfield_size and bit_offset, covering both
int and enum base types. The kind_flag is also used to indicate whether
the forward type is a union (when set) or a struct.
Patch #1 refactors function btf_int_bits_seq_show() so Patch #2
can reuse part of the function.
Patch #2 implemented kind_flag support for struct/union/fwd types.
Patch #3 added kind_flag support for cgroup local storage map pretty print.
Patch #4 syncs kernel uapi btf.h to tools directory.
Patch #5 added unit tests for kind_flag.
Patch #6 added tests for kernel bpffs based pretty print with kind_flag.
Patch #7 refactors function btf_dumper_int_bits() so Patch #8
can reuse part of the function.
Patch #8 added bpftool support of pretty print with kind_flag set.
[1] https://git.kernel.org/pub/scm/devel/pahole/pahole.git/commit/?id=b18354f64cc215368c3bc0df4a7e5341c55c378c
[2] https://lwn.net/SubscriberLink/773198/fe3074838f5c3f26/
Change logs:
v2 -> v3:
. Relocated comments about bitfield_size/bit_offset interpretation
of the "offset" field right before the "offset" struct member.
. Added missing byte alignment checking for non-bitfield enum
member of a struct with kind_flag set.
. Added two test cases in unit tests for struct type, kind_flag set,
non-bitfield int/enum member, not-byte aligned bit offsets.
. Added comments to help understand there is no overflow for
total_bits_offset in bpftool function btf_dumper_int_bits().
. Added explanation of typedef type dumping fix in Patch #8 commit
message.
v1 -> v2:
. If kind_flag is set for a structure, ensure an int member,
whether it is a bitfield or not, is a regular int type.
. Added support so cgroup local storage map pretty print
works with kind_flag.
====================
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
Коммит
37c7b1caea
|
@ -7,6 +7,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
struct btf;
|
||||
struct btf_member;
|
||||
struct btf_type;
|
||||
union bpf_attr;
|
||||
|
||||
|
@ -46,7 +47,9 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
|
|||
struct seq_file *m);
|
||||
int btf_get_fd_by_id(u32 id);
|
||||
u32 btf_id(const struct btf *btf);
|
||||
bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size);
|
||||
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
||||
const struct btf_member *m,
|
||||
u32 expected_offset, u32 expected_size);
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
|
||||
|
|
|
@ -34,7 +34,9 @@ struct btf_type {
|
|||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-31: unused
|
||||
* bits 28-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||
|
@ -52,6 +54,7 @@ struct btf_type {
|
|||
|
||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||
|
||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||
#define BTF_KIND_INT 1 /* Integer */
|
||||
|
@ -110,9 +113,22 @@ struct btf_array {
|
|||
struct btf_member {
|
||||
__u32 name_off;
|
||||
__u32 type;
|
||||
__u32 offset; /* offset in bits */
|
||||
/* If the type info kind_flag is set, the btf_member offset
|
||||
* contains both member bitfield size and bit offset. The
|
||||
* bitfield size is set for bitfield members. If the type
|
||||
* info kind_flag is not set, the offset contains only bit
|
||||
* offset.
|
||||
*/
|
||||
__u32 offset;
|
||||
};
|
||||
|
||||
/* If the struct/union type info kind_flag is set, the
|
||||
* following two macros are used to access bitfield_size
|
||||
* and bit_offset from btf_member.offset.
|
||||
*/
|
||||
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
|
||||
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
|
||||
|
||||
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
||||
* The exact number of btf_param is stored in the vlen (of the
|
||||
* info in "struct btf_type").
|
||||
|
|
352
kernel/bpf/btf.c
352
kernel/bpf/btf.c
|
@ -164,7 +164,7 @@
|
|||
#define BITS_ROUNDUP_BYTES(bits) \
|
||||
(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
|
||||
|
||||
#define BTF_INFO_MASK 0x0f00ffff
|
||||
#define BTF_INFO_MASK 0x8f00ffff
|
||||
#define BTF_INT_MASK 0x0fffffff
|
||||
#define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
|
||||
#define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)
|
||||
|
@ -274,6 +274,10 @@ struct btf_kind_operations {
|
|||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type);
|
||||
int (*check_kflag_member)(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type);
|
||||
void (*log_details)(struct btf_verifier_env *env,
|
||||
const struct btf_type *t);
|
||||
void (*seq_show)(const struct btf *btf, const struct btf_type *t,
|
||||
|
@ -419,6 +423,25 @@ static u16 btf_type_vlen(const struct btf_type *t)
|
|||
return BTF_INFO_VLEN(t->info);
|
||||
}
|
||||
|
||||
static bool btf_type_kflag(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KFLAG(t->info);
|
||||
}
|
||||
|
||||
static u32 btf_member_bit_offset(const struct btf_type *struct_type,
|
||||
const struct btf_member *member)
|
||||
{
|
||||
return btf_type_kflag(struct_type) ? BTF_MEMBER_BIT_OFFSET(member->offset)
|
||||
: member->offset;
|
||||
}
|
||||
|
||||
static u32 btf_member_bitfield_size(const struct btf_type *struct_type,
|
||||
const struct btf_member *member)
|
||||
{
|
||||
return btf_type_kflag(struct_type) ? BTF_MEMBER_BITFIELD_SIZE(member->offset)
|
||||
: 0;
|
||||
}
|
||||
|
||||
static u32 btf_type_int(const struct btf_type *t)
|
||||
{
|
||||
return *(u32 *)(t + 1);
|
||||
|
@ -523,22 +546,41 @@ static bool btf_type_int_is_regular(const struct btf_type *t)
|
|||
}
|
||||
|
||||
/*
|
||||
* Check that given type is a regular int and has the expected size.
|
||||
* Check that given struct member is a regular int with expected
|
||||
* offset and size.
|
||||
*/
|
||||
bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size)
|
||||
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
||||
const struct btf_member *m,
|
||||
u32 expected_offset, u32 expected_size)
|
||||
{
|
||||
u8 nr_bits, nr_bytes;
|
||||
u32 int_data;
|
||||
const struct btf_type *t;
|
||||
u32 id, int_data;
|
||||
u8 nr_bits;
|
||||
|
||||
if (!btf_type_is_int(t))
|
||||
id = m->type;
|
||||
t = btf_type_id_size(btf, &id, NULL);
|
||||
if (!t || !btf_type_is_int(t))
|
||||
return false;
|
||||
|
||||
int_data = btf_type_int(t);
|
||||
nr_bits = BTF_INT_BITS(int_data);
|
||||
nr_bytes = BITS_ROUNDUP_BYTES(nr_bits);
|
||||
if (BITS_PER_BYTE_MASKED(nr_bits) ||
|
||||
BTF_INT_OFFSET(int_data) ||
|
||||
nr_bytes != expected_size)
|
||||
if (btf_type_kflag(s)) {
|
||||
u32 bitfield_size = BTF_MEMBER_BITFIELD_SIZE(m->offset);
|
||||
u32 bit_offset = BTF_MEMBER_BIT_OFFSET(m->offset);
|
||||
|
||||
/* if kflag set, int should be a regular int and
|
||||
* bit offset should be at byte boundary.
|
||||
*/
|
||||
return !bitfield_size &&
|
||||
BITS_ROUNDUP_BYTES(bit_offset) == expected_offset &&
|
||||
BITS_ROUNDUP_BYTES(nr_bits) == expected_size;
|
||||
}
|
||||
|
||||
if (BTF_INT_OFFSET(int_data) ||
|
||||
BITS_PER_BYTE_MASKED(m->offset) ||
|
||||
BITS_ROUNDUP_BYTES(m->offset) != expected_offset ||
|
||||
BITS_PER_BYTE_MASKED(nr_bits) ||
|
||||
BITS_ROUNDUP_BYTES(nr_bits) != expected_size)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -627,9 +669,17 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
|
|||
if (env->phase != CHECK_META)
|
||||
btf_verifier_log_type(env, struct_type, NULL);
|
||||
|
||||
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
|
||||
__btf_name_by_offset(btf, member->name_off),
|
||||
member->type, member->offset);
|
||||
if (btf_type_kflag(struct_type))
|
||||
__btf_verifier_log(log,
|
||||
"\t%s type_id=%u bitfield_size=%u bits_offset=%u",
|
||||
__btf_name_by_offset(btf, member->name_off),
|
||||
member->type,
|
||||
BTF_MEMBER_BITFIELD_SIZE(member->offset),
|
||||
BTF_MEMBER_BIT_OFFSET(member->offset));
|
||||
else
|
||||
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
|
||||
__btf_name_by_offset(btf, member->name_off),
|
||||
member->type, member->offset);
|
||||
|
||||
if (fmt && *fmt) {
|
||||
__btf_verifier_log(log, " ");
|
||||
|
@ -945,6 +995,38 @@ static int btf_df_check_member(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int btf_df_check_kflag_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type)
|
||||
{
|
||||
btf_verifier_log_basic(env, struct_type,
|
||||
"Unsupported check_kflag_member");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Used for ptr, array and struct/union type members.
|
||||
* int, enum and modifier types have their specific callback functions.
|
||||
*/
|
||||
static int btf_generic_check_kflag_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type)
|
||||
{
|
||||
if (BTF_MEMBER_BITFIELD_SIZE(member->offset)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member bitfield_size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* bitfield size is 0, so member->offset represents bit offset only.
|
||||
* It is safe to call non kflag check_member variants.
|
||||
*/
|
||||
return btf_type_ops(member_type)->check_member(env, struct_type,
|
||||
member,
|
||||
member_type);
|
||||
}
|
||||
|
||||
static int btf_df_resolve(struct btf_verifier_env *env,
|
||||
const struct resolve_vertex *v)
|
||||
{
|
||||
|
@ -997,6 +1079,62 @@ static int btf_int_check_member(struct btf_verifier_env *env,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int btf_int_check_kflag_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type)
|
||||
{
|
||||
u32 struct_bits_off, nr_bits, nr_int_data_bits, bytes_offset;
|
||||
u32 int_data = btf_type_int(member_type);
|
||||
u32 struct_size = struct_type->size;
|
||||
u32 nr_copy_bits;
|
||||
|
||||
/* a regular int type is required for the kflag int member */
|
||||
if (!btf_type_int_is_regular(member_type)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member base type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check sanity of bitfield size */
|
||||
nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
|
||||
struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
|
||||
nr_int_data_bits = BTF_INT_BITS(int_data);
|
||||
if (!nr_bits) {
|
||||
/* Not a bitfield member, member offset must be at byte
|
||||
* boundary.
|
||||
*/
|
||||
if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member offset");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nr_bits = nr_int_data_bits;
|
||||
} else if (nr_bits > nr_int_data_bits) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member bitfield_size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
|
||||
nr_copy_bits = nr_bits + BITS_PER_BYTE_MASKED(struct_bits_off);
|
||||
if (nr_copy_bits > BITS_PER_U64) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"nr_copy_bits exceeds 64");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (struct_size < bytes_offset ||
|
||||
struct_size - bytes_offset < BITS_ROUNDUP_BYTES(nr_copy_bits)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Member exceeds struct_size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 btf_int_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
|
@ -1016,6 +1154,11 @@ static s32 btf_int_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int_data = btf_type_int(t);
|
||||
if (int_data & ~BTF_INT_MASK) {
|
||||
btf_verifier_log_basic(env, t, "Invalid int_data:%x",
|
||||
|
@ -1068,26 +1211,16 @@ static void btf_int_log(struct btf_verifier_env *env,
|
|||
btf_int_encoding_str(BTF_INT_ENCODING(int_data)));
|
||||
}
|
||||
|
||||
static void btf_int_bits_seq_show(const struct btf *btf,
|
||||
const struct btf_type *t,
|
||||
void *data, u8 bits_offset,
|
||||
struct seq_file *m)
|
||||
static void btf_bitfield_seq_show(void *data, u8 bits_offset,
|
||||
u8 nr_bits, struct seq_file *m)
|
||||
{
|
||||
u16 left_shift_bits, right_shift_bits;
|
||||
u32 int_data = btf_type_int(t);
|
||||
u8 nr_bits = BTF_INT_BITS(int_data);
|
||||
u8 total_bits_offset;
|
||||
u8 nr_copy_bytes;
|
||||
u8 nr_copy_bits;
|
||||
u64 print_num;
|
||||
|
||||
/*
|
||||
* bits_offset is at most 7.
|
||||
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
||||
*/
|
||||
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
|
||||
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
||||
bits_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
|
||||
data += BITS_ROUNDDOWN_BYTES(bits_offset);
|
||||
bits_offset = BITS_PER_BYTE_MASKED(bits_offset);
|
||||
nr_copy_bits = nr_bits + bits_offset;
|
||||
nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
|
||||
|
||||
|
@ -1107,6 +1240,24 @@ static void btf_int_bits_seq_show(const struct btf *btf,
|
|||
seq_printf(m, "0x%llx", print_num);
|
||||
}
|
||||
|
||||
|
||||
static void btf_int_bits_seq_show(const struct btf *btf,
|
||||
const struct btf_type *t,
|
||||
void *data, u8 bits_offset,
|
||||
struct seq_file *m)
|
||||
{
|
||||
u32 int_data = btf_type_int(t);
|
||||
u8 nr_bits = BTF_INT_BITS(int_data);
|
||||
u8 total_bits_offset;
|
||||
|
||||
/*
|
||||
* bits_offset is at most 7.
|
||||
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
||||
*/
|
||||
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
|
||||
btf_bitfield_seq_show(data, total_bits_offset, nr_bits, m);
|
||||
}
|
||||
|
||||
static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,
|
||||
u32 type_id, void *data, u8 bits_offset,
|
||||
struct seq_file *m)
|
||||
|
@ -1156,6 +1307,7 @@ static const struct btf_kind_operations int_ops = {
|
|||
.check_meta = btf_int_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_int_check_member,
|
||||
.check_kflag_member = btf_int_check_kflag_member,
|
||||
.log_details = btf_int_log,
|
||||
.seq_show = btf_int_seq_show,
|
||||
};
|
||||
|
@ -1185,6 +1337,31 @@ static int btf_modifier_check_member(struct btf_verifier_env *env,
|
|||
resolved_type);
|
||||
}
|
||||
|
||||
static int btf_modifier_check_kflag_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type)
|
||||
{
|
||||
const struct btf_type *resolved_type;
|
||||
u32 resolved_type_id = member->type;
|
||||
struct btf_member resolved_member;
|
||||
struct btf *btf = env->btf;
|
||||
|
||||
resolved_type = btf_type_id_size(btf, &resolved_type_id, NULL);
|
||||
if (!resolved_type) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
resolved_member = *member;
|
||||
resolved_member.type = resolved_type_id;
|
||||
|
||||
return btf_type_ops(resolved_type)->check_kflag_member(env, struct_type,
|
||||
&resolved_member,
|
||||
resolved_type);
|
||||
}
|
||||
|
||||
static int btf_ptr_check_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
|
@ -1220,6 +1397,11 @@ static int btf_ref_type_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!BTF_TYPE_ID_VALID(t->type)) {
|
||||
btf_verifier_log_type(env, t, "Invalid type_id");
|
||||
return -EINVAL;
|
||||
|
@ -1373,6 +1555,7 @@ static struct btf_kind_operations modifier_ops = {
|
|||
.check_meta = btf_ref_type_check_meta,
|
||||
.resolve = btf_modifier_resolve,
|
||||
.check_member = btf_modifier_check_member,
|
||||
.check_kflag_member = btf_modifier_check_kflag_member,
|
||||
.log_details = btf_ref_type_log,
|
||||
.seq_show = btf_modifier_seq_show,
|
||||
};
|
||||
|
@ -1381,6 +1564,7 @@ static struct btf_kind_operations ptr_ops = {
|
|||
.check_meta = btf_ref_type_check_meta,
|
||||
.resolve = btf_ptr_resolve,
|
||||
.check_member = btf_ptr_check_member,
|
||||
.check_kflag_member = btf_generic_check_kflag_member,
|
||||
.log_details = btf_ref_type_log,
|
||||
.seq_show = btf_ptr_seq_show,
|
||||
};
|
||||
|
@ -1415,6 +1599,7 @@ static struct btf_kind_operations fwd_ops = {
|
|||
.check_meta = btf_fwd_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_ref_type_log,
|
||||
.seq_show = btf_df_seq_show,
|
||||
};
|
||||
|
@ -1473,6 +1658,11 @@ static s32 btf_array_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->size) {
|
||||
btf_verifier_log_type(env, t, "size != 0");
|
||||
return -EINVAL;
|
||||
|
@ -1596,6 +1786,7 @@ static struct btf_kind_operations array_ops = {
|
|||
.check_meta = btf_array_check_meta,
|
||||
.resolve = btf_array_resolve,
|
||||
.check_member = btf_array_check_member,
|
||||
.check_kflag_member = btf_generic_check_kflag_member,
|
||||
.log_details = btf_array_log,
|
||||
.seq_show = btf_array_seq_show,
|
||||
};
|
||||
|
@ -1634,6 +1825,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
|
|||
u32 meta_needed, last_offset;
|
||||
struct btf *btf = env->btf;
|
||||
u32 struct_size = t->size;
|
||||
u32 offset;
|
||||
u16 i;
|
||||
|
||||
meta_needed = btf_type_vlen(t) * sizeof(*member);
|
||||
|
@ -1675,7 +1867,8 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_union && member->offset) {
|
||||
offset = btf_member_bit_offset(t, member);
|
||||
if (is_union && offset) {
|
||||
btf_verifier_log_member(env, t, member,
|
||||
"Invalid member bits_offset");
|
||||
return -EINVAL;
|
||||
|
@ -1685,20 +1878,20 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
|
|||
* ">" instead of ">=" because the last member could be
|
||||
* "char a[0];"
|
||||
*/
|
||||
if (last_offset > member->offset) {
|
||||
if (last_offset > offset) {
|
||||
btf_verifier_log_member(env, t, member,
|
||||
"Invalid member bits_offset");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) {
|
||||
if (BITS_ROUNDUP_BYTES(offset) > struct_size) {
|
||||
btf_verifier_log_member(env, t, member,
|
||||
"Member bits_offset exceeds its struct size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_member(env, t, member, NULL);
|
||||
last_offset = member->offset;
|
||||
last_offset = offset;
|
||||
}
|
||||
|
||||
return meta_needed;
|
||||
|
@ -1728,9 +1921,14 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
|
|||
|
||||
last_member_type = btf_type_by_id(env->btf,
|
||||
last_member_type_id);
|
||||
err = btf_type_ops(last_member_type)->check_member(env, v->t,
|
||||
last_member,
|
||||
last_member_type);
|
||||
if (btf_type_kflag(v->t))
|
||||
err = btf_type_ops(last_member_type)->check_kflag_member(env, v->t,
|
||||
last_member,
|
||||
last_member_type);
|
||||
else
|
||||
err = btf_type_ops(last_member_type)->check_member(env, v->t,
|
||||
last_member,
|
||||
last_member_type);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -1752,9 +1950,14 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
|
|||
return env_stack_push(env, member_type, member_type_id);
|
||||
}
|
||||
|
||||
err = btf_type_ops(member_type)->check_member(env, v->t,
|
||||
member,
|
||||
member_type);
|
||||
if (btf_type_kflag(v->t))
|
||||
err = btf_type_ops(member_type)->check_kflag_member(env, v->t,
|
||||
member,
|
||||
member_type);
|
||||
else
|
||||
err = btf_type_ops(member_type)->check_member(env, v->t,
|
||||
member,
|
||||
member_type);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -1782,17 +1985,26 @@ static void btf_struct_seq_show(const struct btf *btf, const struct btf_type *t,
|
|||
for_each_member(i, t, member) {
|
||||
const struct btf_type *member_type = btf_type_by_id(btf,
|
||||
member->type);
|
||||
u32 member_offset = member->offset;
|
||||
u32 bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
|
||||
u8 bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
|
||||
const struct btf_kind_operations *ops;
|
||||
u32 member_offset, bitfield_size;
|
||||
u32 bytes_offset;
|
||||
u8 bits8_offset;
|
||||
|
||||
if (i)
|
||||
seq_puts(m, seq);
|
||||
|
||||
ops = btf_type_ops(member_type);
|
||||
ops->seq_show(btf, member_type, member->type,
|
||||
data + bytes_offset, bits8_offset, m);
|
||||
member_offset = btf_member_bit_offset(t, member);
|
||||
bitfield_size = btf_member_bitfield_size(t, member);
|
||||
if (bitfield_size) {
|
||||
btf_bitfield_seq_show(data, member_offset,
|
||||
bitfield_size, m);
|
||||
} else {
|
||||
bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
|
||||
bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
|
||||
ops = btf_type_ops(member_type);
|
||||
ops->seq_show(btf, member_type, member->type,
|
||||
data + bytes_offset, bits8_offset, m);
|
||||
}
|
||||
}
|
||||
seq_puts(m, "}");
|
||||
}
|
||||
|
@ -1801,6 +2013,7 @@ static struct btf_kind_operations struct_ops = {
|
|||
.check_meta = btf_struct_check_meta,
|
||||
.resolve = btf_struct_resolve,
|
||||
.check_member = btf_struct_check_member,
|
||||
.check_kflag_member = btf_generic_check_kflag_member,
|
||||
.log_details = btf_struct_log,
|
||||
.seq_show = btf_struct_seq_show,
|
||||
};
|
||||
|
@ -1830,6 +2043,41 @@ static int btf_enum_check_member(struct btf_verifier_env *env,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int btf_enum_check_kflag_member(struct btf_verifier_env *env,
|
||||
const struct btf_type *struct_type,
|
||||
const struct btf_member *member,
|
||||
const struct btf_type *member_type)
|
||||
{
|
||||
u32 struct_bits_off, nr_bits, bytes_end, struct_size;
|
||||
u32 int_bitsize = sizeof(int) * BITS_PER_BYTE;
|
||||
|
||||
struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
|
||||
nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
|
||||
if (!nr_bits) {
|
||||
if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Member is not byte aligned");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nr_bits = int_bitsize;
|
||||
} else if (nr_bits > int_bitsize) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Invalid member bitfield_size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct_size = struct_type->size;
|
||||
bytes_end = BITS_ROUNDUP_BYTES(struct_bits_off + nr_bits);
|
||||
if (struct_size < bytes_end) {
|
||||
btf_verifier_log_member(env, struct_type, member,
|
||||
"Member exceeds struct_size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
|
@ -1849,6 +2097,11 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->size != sizeof(int)) {
|
||||
btf_verifier_log_type(env, t, "Expected size:%zu",
|
||||
sizeof(int));
|
||||
|
@ -1917,6 +2170,7 @@ static struct btf_kind_operations enum_ops = {
|
|||
.check_meta = btf_enum_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_enum_check_member,
|
||||
.check_kflag_member = btf_enum_check_kflag_member,
|
||||
.log_details = btf_enum_log,
|
||||
.seq_show = btf_enum_seq_show,
|
||||
};
|
||||
|
@ -1939,6 +2193,11 @@ static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
return meta_needed;
|
||||
|
@ -1998,6 +2257,7 @@ static struct btf_kind_operations func_proto_ops = {
|
|||
* Hence, there is no btf_func_check_member().
|
||||
*/
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_func_proto_log,
|
||||
.seq_show = btf_df_seq_show,
|
||||
};
|
||||
|
@ -2017,6 +2277,11 @@ static s32 btf_func_check_meta(struct btf_verifier_env *env,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
return 0;
|
||||
|
@ -2026,6 +2291,7 @@ static struct btf_kind_operations func_ops = {
|
|||
.check_meta = btf_func_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_df_check_member,
|
||||
.check_kflag_member = btf_df_check_kflag_member,
|
||||
.log_details = btf_ref_type_log,
|
||||
.seq_show = btf_df_seq_show,
|
||||
};
|
||||
|
|
|
@ -315,9 +315,8 @@ static int cgroup_storage_check_btf(const struct bpf_map *map,
|
|||
const struct btf_type *key_type,
|
||||
const struct btf_type *value_type)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
struct btf_member *m;
|
||||
u32 id, size;
|
||||
u32 offset, size;
|
||||
|
||||
/* Key is expected to be of struct bpf_cgroup_storage_key type,
|
||||
* which is:
|
||||
|
@ -338,25 +337,17 @@ static int cgroup_storage_check_btf(const struct bpf_map *map,
|
|||
* The first field must be a 64 bit integer at 0 offset.
|
||||
*/
|
||||
m = (struct btf_member *)(key_type + 1);
|
||||
if (m->offset)
|
||||
return -EINVAL;
|
||||
id = m->type;
|
||||
t = btf_type_id_size(btf, &id, NULL);
|
||||
size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, cgroup_inode_id);
|
||||
if (!t || !btf_type_is_reg_int(t, size))
|
||||
if (!btf_member_is_reg_int(btf, key_type, m, 0, size))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The second field must be a 32 bit integer at 64 bit offset.
|
||||
*/
|
||||
m++;
|
||||
if (m->offset != offsetof(struct bpf_cgroup_storage_key, attach_type) *
|
||||
BITS_PER_BYTE)
|
||||
return -EINVAL;
|
||||
id = m->type;
|
||||
t = btf_type_id_size(btf, &id, NULL);
|
||||
offset = offsetof(struct bpf_cgroup_storage_key, attach_type);
|
||||
size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, attach_type);
|
||||
if (!t || !btf_type_is_reg_int(t, size))
|
||||
if (!btf_member_is_reg_int(btf, key_type, m, offset, size))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -73,20 +73,17 @@ static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
|
||||
static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
|
||||
const void *data, json_writer_t *jw,
|
||||
bool is_plain_text)
|
||||
{
|
||||
int left_shift_bits, right_shift_bits;
|
||||
int nr_bits = BTF_INT_BITS(int_type);
|
||||
int total_bits_offset;
|
||||
int bytes_to_copy;
|
||||
int bits_to_copy;
|
||||
__u64 print_num;
|
||||
|
||||
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
|
||||
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
||||
bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
|
||||
data += BITS_ROUNDDOWN_BYTES(bit_offset);
|
||||
bit_offset = BITS_PER_BYTE_MASKED(bit_offset);
|
||||
bits_to_copy = bit_offset + nr_bits;
|
||||
bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
|
||||
|
||||
|
@ -109,6 +106,22 @@ static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
|
|||
jsonw_printf(jw, "%llu", print_num);
|
||||
}
|
||||
|
||||
|
||||
static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
|
||||
const void *data, json_writer_t *jw,
|
||||
bool is_plain_text)
|
||||
{
|
||||
int nr_bits = BTF_INT_BITS(int_type);
|
||||
int total_bits_offset;
|
||||
|
||||
/* bits_offset is at most 7.
|
||||
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
||||
*/
|
||||
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
|
||||
btf_dumper_bitfield(nr_bits, total_bits_offset, data, jw,
|
||||
is_plain_text);
|
||||
}
|
||||
|
||||
static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
|
||||
const void *data, json_writer_t *jw,
|
||||
bool is_plain_text)
|
||||
|
@ -180,6 +193,7 @@ static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
|
|||
const struct btf_type *t;
|
||||
struct btf_member *m;
|
||||
const void *data_off;
|
||||
int kind_flag;
|
||||
int ret = 0;
|
||||
int i, vlen;
|
||||
|
||||
|
@ -187,18 +201,32 @@ static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
|
|||
if (!t)
|
||||
return -EINVAL;
|
||||
|
||||
kind_flag = BTF_INFO_KFLAG(t->info);
|
||||
vlen = BTF_INFO_VLEN(t->info);
|
||||
jsonw_start_object(d->jw);
|
||||
m = (struct btf_member *)(t + 1);
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset);
|
||||
__u32 bit_offset = m[i].offset;
|
||||
__u32 bitfield_size = 0;
|
||||
|
||||
if (kind_flag) {
|
||||
bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
|
||||
bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
|
||||
}
|
||||
|
||||
jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
|
||||
ret = btf_dumper_do_type(d, m[i].type,
|
||||
BITS_PER_BYTE_MASKED(m[i].offset),
|
||||
data_off);
|
||||
if (ret)
|
||||
break;
|
||||
if (bitfield_size) {
|
||||
btf_dumper_bitfield(bitfield_size, bit_offset,
|
||||
data, d->jw, d->is_plain_text);
|
||||
} else {
|
||||
data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
|
||||
ret = btf_dumper_do_type(d, m[i].type,
|
||||
BITS_PER_BYTE_MASKED(bit_offset),
|
||||
data_off);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jsonw_end_object(d->jw);
|
||||
|
@ -285,6 +313,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
|
|||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
|
@ -308,10 +337,11 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
|
|||
BTF_PRINT_TYPE(t->type);
|
||||
BTF_PRINT_ARG("* ");
|
||||
break;
|
||||
case BTF_KIND_UNKN:
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
return -1;
|
||||
BTF_PRINT_ARG("%s %s ",
|
||||
BTF_INFO_KFLAG(t->info) ? "union" : "struct",
|
||||
btf__name_by_offset(btf, t->name_off));
|
||||
break;
|
||||
case BTF_KIND_VOLATILE:
|
||||
BTF_PRINT_ARG("volatile ");
|
||||
BTF_PRINT_TYPE(t->type);
|
||||
|
@ -335,6 +365,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
|
|||
if (pos == -1)
|
||||
return -1;
|
||||
break;
|
||||
case BTF_KIND_UNKN:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,9 @@ struct btf_type {
|
|||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-31: unused
|
||||
* bits 28-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||
|
@ -52,6 +54,7 @@ struct btf_type {
|
|||
|
||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||
|
||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||
#define BTF_KIND_INT 1 /* Integer */
|
||||
|
@ -110,9 +113,22 @@ struct btf_array {
|
|||
struct btf_member {
|
||||
__u32 name_off;
|
||||
__u32 type;
|
||||
__u32 offset; /* offset in bits */
|
||||
/* If the type info kind_flag is set, the btf_member offset
|
||||
* contains both member bitfield size and bit offset. The
|
||||
* bitfield size is set for bitfield members. If the type
|
||||
* info kind_flag is not set, the offset contains only bit
|
||||
* offset.
|
||||
*/
|
||||
__u32 offset;
|
||||
};
|
||||
|
||||
/* If the struct/union type info kind_flag is set, the
|
||||
* following two macros are used to access bitfield_size
|
||||
* and bit_offset from btf_member.offset.
|
||||
*/
|
||||
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
|
||||
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
|
||||
|
||||
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
||||
* The exact number of btf_param is stored in the vlen (of the
|
||||
* info in "struct btf_type").
|
||||
|
|
|
@ -65,8 +65,8 @@ static int __base_pr(const char *format, ...)
|
|||
return err;
|
||||
}
|
||||
|
||||
#define BTF_INFO_ENC(kind, root, vlen) \
|
||||
((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
||||
#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)
|
||||
|
@ -86,6 +86,8 @@ static int __base_pr(const char *format, ...)
|
|||
#define BTF_MEMBER_ENC(name, type, bits_offset) \
|
||||
(name), (type), (bits_offset)
|
||||
#define BTF_ENUM_ENC(name, val) (name), (val)
|
||||
#define BTF_MEMBER_OFFSET(bitfield_size, bits_offset) \
|
||||
((bitfield_size) << 24 | (bits_offset))
|
||||
|
||||
#define BTF_TYPEDEF_ENC(name, type) \
|
||||
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), type)
|
||||
|
@ -2215,6 +2217,496 @@ static struct btf_raw_test raw_tests[] = {
|
|||
.err_str = "Invalid type_id",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid int kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_INT, 1, 0), 4), /* [2] */
|
||||
BTF_INT_ENC(0, 0, 32),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "int_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid ptr kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 1, 0), 1), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "ptr_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid array kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ARRAY, 1, 0), 0), /* [2] */
|
||||
BTF_ARRAY_ENC(1, 1, 1),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "array_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid enum kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 1, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "enum_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid fwd kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(NAME_TBD,
|
||||
BTF_INFO_ENC(BTF_KIND_FWD, 1, 0), 0), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "fwd_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid typedef kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(NAME_TBD,
|
||||
BTF_INFO_ENC(BTF_KIND_TYPEDEF, 1, 0), 1), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "typedef_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid volatile kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 1, 0), 1), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "volatile_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid const kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 1, 0), 1), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "const_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid restrict kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_RESTRICT, 1, 0), 1), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "restrict_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid func kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 0), 0), /* [2] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 1, 0), 2), /* [3] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "func_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid func_proto kind_flag",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 1, 0), 0), /* [2] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC(""),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "func_proto_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid btf_info kind_flag",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid struct, kind_flag, bitfield_size = 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 8), /* [2] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(0, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(0, 32)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid struct, kind_flag, int member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [2] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 4)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid union, kind_flag, int member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [2] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "union_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid struct, kind_flag, enum member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4),/* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 4)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B\0C"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid union, kind_flag, enum member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B\0C"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "union_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid struct, kind_flag, typedef member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4),/* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 5, BTF_MEMBER_OFFSET(4, 4)),
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 1), /* [4] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 2), /* [5] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B\0C\0D\0E"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "valid union, kind_flag, typedef member, bitfield_size != 0",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 4, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 5, BTF_MEMBER_OFFSET(4, 0)),
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 1), /* [4] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 2), /* [5] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B\0C\0D\0E"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "union_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid struct, kind_flag, bitfield_size greater than struct size",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [2] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 20)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid struct, kind_flag, bitfield base_type int not regular",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 20, 4), /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(20, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(20, 20)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member base type",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid struct, kind_flag, base_type int not regular",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 12, 4), /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(8, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(8, 8)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member base type",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid union, kind_flag, bitfield_size greater than struct size",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 2), /* [2] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(8, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 0)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "union_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Member exceeds struct_size",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid struct, kind_flag, int member, bitfield_size = 0, wrong byte alignment",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 12), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 36)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member offset",
|
||||
},
|
||||
|
||||
{
|
||||
.descr = "invalid struct, kind_flag, enum member, bitfield_size = 0, wrong byte alignment",
|
||||
.raw_types = {
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 12), /* [3] */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 36)),
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0A\0B\0C"),
|
||||
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||
.map_name = "struct_type_check_btf",
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.key_type_id = 1,
|
||||
.value_type_id = 1,
|
||||
.max_entries = 4,
|
||||
.btf_load_err = true,
|
||||
.err_str = "Invalid member offset",
|
||||
},
|
||||
|
||||
}; /* struct btf_raw_test raw_tests[] */
|
||||
|
||||
static const char *get_next_str(const char *start, const char *end)
|
||||
|
@ -3036,7 +3528,8 @@ struct pprint_mapv {
|
|||
} aenum;
|
||||
};
|
||||
|
||||
static struct btf_raw_test pprint_test_template = {
|
||||
static struct btf_raw_test pprint_test_template[] = {
|
||||
{
|
||||
.raw_types = {
|
||||
/* unsighed char */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
|
||||
|
@ -3086,13 +3579,140 @@ static struct btf_raw_test pprint_test_template = {
|
|||
BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
.str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum",
|
||||
.str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
.value_type_id = 16, /* struct pprint_mapv */
|
||||
.max_entries = 128 * 1024,
|
||||
},
|
||||
|
||||
{
|
||||
/* this type will have the same type as the
|
||||
* first .raw_types definition, but struct type will
|
||||
* be encoded with kind_flag set.
|
||||
*/
|
||||
.raw_types = {
|
||||
/* unsighed char */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
|
||||
/* unsigned short */ /* [2] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
|
||||
/* unsigned int */ /* [3] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
|
||||
/* int */ /* [4] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* unsigned long long */ /* [5] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [6] */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [7] */
|
||||
/* uint8_t[8] */ /* [8] */
|
||||
BTF_TYPE_ARRAY_ENC(9, 1, 8),
|
||||
/* typedef unsigned char uint8_t */ /* [9] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 1),
|
||||
/* typedef unsigned short uint16_t */ /* [10] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 2),
|
||||
/* typedef unsigned int uint32_t */ /* [11] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 3),
|
||||
/* typedef int int32_t */ /* [12] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 4),
|
||||
/* typedef unsigned long long uint64_t *//* [13] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 5),
|
||||
/* union (anon) */ /* [14] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
|
||||
/* enum (anon) */ /* [15] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_ENUM_ENC(NAME_TBD, 1),
|
||||
BTF_ENUM_ENC(NAME_TBD, 2),
|
||||
BTF_ENUM_ENC(NAME_TBD, 3),
|
||||
/* struct pprint_mapv */ /* [16] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 96)), /* unused_bits2a */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* bits28 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 126)), /* unused_bits2b */
|
||||
BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
.value_type_id = 16, /* struct pprint_mapv */
|
||||
.max_entries = 128 * 1024,
|
||||
},
|
||||
|
||||
{
|
||||
/* this type will have the same layout as the
|
||||
* first .raw_types definition. The struct type will
|
||||
* be encoded with kind_flag set, bitfield members
|
||||
* are added typedef/const/volatile, and bitfield members
|
||||
* will have both int and enum types.
|
||||
*/
|
||||
.raw_types = {
|
||||
/* unsighed char */ /* [1] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
|
||||
/* unsigned short */ /* [2] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
|
||||
/* unsigned int */ /* [3] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
|
||||
/* int */ /* [4] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* unsigned long long */ /* [5] */
|
||||
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [6] */
|
||||
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [7] */
|
||||
/* uint8_t[8] */ /* [8] */
|
||||
BTF_TYPE_ARRAY_ENC(9, 1, 8),
|
||||
/* typedef unsigned char uint8_t */ /* [9] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 1),
|
||||
/* typedef unsigned short uint16_t */ /* [10] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 2),
|
||||
/* typedef unsigned int uint32_t */ /* [11] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 3),
|
||||
/* typedef int int32_t */ /* [12] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 4),
|
||||
/* typedef unsigned long long uint64_t *//* [13] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 5),
|
||||
/* union (anon) */ /* [14] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
|
||||
/* enum (anon) */ /* [15] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
|
||||
BTF_ENUM_ENC(NAME_TBD, 0),
|
||||
BTF_ENUM_ENC(NAME_TBD, 1),
|
||||
BTF_ENUM_ENC(NAME_TBD, 2),
|
||||
BTF_ENUM_ENC(NAME_TBD, 3),
|
||||
/* struct pprint_mapv */ /* [16] */
|
||||
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32),
|
||||
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 96)), /* unused_bits2a */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* bits28 */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 19, BTF_MEMBER_OFFSET(2, 126)),/* unused_bits2b */
|
||||
BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */
|
||||
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
|
||||
/* typedef unsigned int ___int */ /* [17] */
|
||||
BTF_TYPEDEF_ENC(NAME_TBD, 18),
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6), /* [18] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15), /* [19] */
|
||||
BTF_END_RAW,
|
||||
},
|
||||
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0___int"),
|
||||
.key_size = sizeof(unsigned int),
|
||||
.value_size = sizeof(struct pprint_mapv),
|
||||
.key_type_id = 3, /* unsigned int */
|
||||
.value_type_id = 16, /* struct pprint_mapv */
|
||||
.max_entries = 128 * 1024,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static struct btf_pprint_test_meta {
|
||||
|
@ -3195,9 +3815,9 @@ static int check_line(const char *expected_line, int nexpected_line,
|
|||
}
|
||||
|
||||
|
||||
static int do_test_pprint(void)
|
||||
static int do_test_pprint(int test_num)
|
||||
{
|
||||
const struct btf_raw_test *test = &pprint_test_template;
|
||||
const struct btf_raw_test *test = &pprint_test_template[test_num];
|
||||
struct bpf_create_map_attr create_attr = {};
|
||||
bool ordered_map, lossless_map, percpu_map;
|
||||
int err, ret, num_cpus, rounded_value_size;
|
||||
|
@ -3213,7 +3833,7 @@ static int do_test_pprint(void)
|
|||
uint8_t *raw_btf;
|
||||
ssize_t nread;
|
||||
|
||||
fprintf(stderr, "%s......", test->descr);
|
||||
fprintf(stderr, "%s(#%d)......", test->descr, test_num);
|
||||
raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
|
||||
test->str_sec, test->str_sec_size,
|
||||
&raw_btf_size, NULL);
|
||||
|
@ -3406,15 +4026,27 @@ static int test_pprint(void)
|
|||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
/* test various maps with the first test template */
|
||||
for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
|
||||
pprint_test_template.descr = pprint_tests_meta[i].descr;
|
||||
pprint_test_template.map_type = pprint_tests_meta[i].map_type;
|
||||
pprint_test_template.map_name = pprint_tests_meta[i].map_name;
|
||||
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
|
||||
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
|
||||
pprint_test_template.percpu_map = pprint_tests_meta[i].percpu_map;
|
||||
pprint_test_template[0].descr = pprint_tests_meta[i].descr;
|
||||
pprint_test_template[0].map_type = pprint_tests_meta[i].map_type;
|
||||
pprint_test_template[0].map_name = pprint_tests_meta[i].map_name;
|
||||
pprint_test_template[0].ordered_map = pprint_tests_meta[i].ordered_map;
|
||||
pprint_test_template[0].lossless_map = pprint_tests_meta[i].lossless_map;
|
||||
pprint_test_template[0].percpu_map = pprint_tests_meta[i].percpu_map;
|
||||
|
||||
err |= count_result(do_test_pprint());
|
||||
err |= count_result(do_test_pprint(0));
|
||||
}
|
||||
|
||||
/* test rest test templates with the first map */
|
||||
for (i = 1; i < ARRAY_SIZE(pprint_test_template); i++) {
|
||||
pprint_test_template[i].descr = pprint_tests_meta[0].descr;
|
||||
pprint_test_template[i].map_type = pprint_tests_meta[0].map_type;
|
||||
pprint_test_template[i].map_name = pprint_tests_meta[0].map_name;
|
||||
pprint_test_template[i].ordered_map = pprint_tests_meta[0].ordered_map;
|
||||
pprint_test_template[i].lossless_map = pprint_tests_meta[0].lossless_map;
|
||||
pprint_test_template[i].percpu_map = pprint_tests_meta[0].percpu_map;
|
||||
err |= count_result(do_test_pprint(i));
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
Загрузка…
Ссылка в новой задаче