mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-12 21:44:06 +08:00
selftests/bpf: add CO-RE relocs nesting tests
Add a bunch of test validating correct handling of nested structs/unions. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Song Liu <songliubraving@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
002d3afce6
commit
ec6438a988
@ -28,6 +28,29 @@
|
||||
.fails = true, \
|
||||
}
|
||||
|
||||
#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
|
||||
.a = { .a = { .a = 42 } }, \
|
||||
.b = { .b = { .b = 0xc001 } }, \
|
||||
}
|
||||
|
||||
#define NESTING_CASE_COMMON(name) \
|
||||
.case_name = #name, \
|
||||
.bpf_obj_file = "test_core_reloc_nesting.o", \
|
||||
.btf_src_file = "btf__core_reloc_" #name ".o"
|
||||
|
||||
#define NESTING_CASE(name) { \
|
||||
NESTING_CASE_COMMON(name), \
|
||||
.input = NESTING_DATA(core_reloc_##name), \
|
||||
.input_len = sizeof(struct core_reloc_##name), \
|
||||
.output = NESTING_DATA(core_reloc_nesting), \
|
||||
.output_len = sizeof(struct core_reloc_nesting) \
|
||||
}
|
||||
|
||||
#define NESTING_ERR_CASE(name) { \
|
||||
NESTING_CASE_COMMON(name), \
|
||||
.fails = true, \
|
||||
}
|
||||
|
||||
struct core_reloc_test_case {
|
||||
const char *case_name;
|
||||
const char *bpf_obj_file;
|
||||
@ -57,6 +80,22 @@ static struct core_reloc_test_case test_cases[] = {
|
||||
FLAVORS_CASE(flavors),
|
||||
|
||||
FLAVORS_ERR_CASE(flavors__err_wrong_name),
|
||||
|
||||
/* various struct/enum nesting and resolution scenarios */
|
||||
NESTING_CASE(nesting),
|
||||
NESTING_CASE(nesting___anon_embed),
|
||||
NESTING_CASE(nesting___struct_union_mixup),
|
||||
NESTING_CASE(nesting___extra_nesting),
|
||||
NESTING_CASE(nesting___dup_compat_types),
|
||||
|
||||
NESTING_ERR_CASE(nesting___err_missing_field),
|
||||
NESTING_ERR_CASE(nesting___err_array_field),
|
||||
NESTING_ERR_CASE(nesting___err_missing_container),
|
||||
NESTING_ERR_CASE(nesting___err_nonstruct_container),
|
||||
NESTING_ERR_CASE(nesting___err_array_container),
|
||||
NESTING_ERR_CASE(nesting___err_dup_incompat_types),
|
||||
NESTING_ERR_CASE(nesting___err_partial_match_dups),
|
||||
NESTING_ERR_CASE(nesting___err_too_deep),
|
||||
};
|
||||
|
||||
struct data {
|
||||
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___anon_embed x) {}
|
@ -0,0 +1,5 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___dup_compat_types x) {}
|
||||
void f2(struct core_reloc_nesting___dup_compat_types__2 x) {}
|
||||
void f3(struct core_reloc_nesting___dup_compat_types__3 x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_array_container x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_array_field x) {}
|
@ -0,0 +1,4 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___err_dup_incompat_types__1 x) {}
|
||||
void f2(struct core_reloc_nesting___err_dup_incompat_types__2 x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_missing_container x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_missing_field x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_nonstruct_container x) {}
|
@ -0,0 +1,4 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___err_partial_match_dups__a x) {}
|
||||
void f2(struct core_reloc_nesting___err_partial_match_dups__b x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_too_deep x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___extra_nesting x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___struct_union_mixup x) {}
|
@ -13,3 +13,296 @@ struct core_reloc_flavors__err_wrong_name {
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
/*
|
||||
* NESTING
|
||||
*/
|
||||
/* original set up, used to record relocations in BPF program */
|
||||
struct core_reloc_nesting_substruct {
|
||||
int a;
|
||||
};
|
||||
|
||||
union core_reloc_nesting_subunion {
|
||||
int b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting {
|
||||
union {
|
||||
struct core_reloc_nesting_substruct a;
|
||||
} a;
|
||||
struct {
|
||||
union core_reloc_nesting_subunion b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* inlined anonymous struct/union instead of named structs in original */
|
||||
struct core_reloc_nesting___anon_embed {
|
||||
int __just_for_padding;
|
||||
union {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
union {
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* different mix of nested structs/unions than in original */
|
||||
struct core_reloc_nesting___struct_union_mixup {
|
||||
int __a;
|
||||
struct {
|
||||
int __a;
|
||||
union {
|
||||
char __a;
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
int __b;
|
||||
union {
|
||||
int __b;
|
||||
union {
|
||||
char __b;
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */
|
||||
struct core_reloc_nesting___extra_nesting {
|
||||
int __padding;
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
union {
|
||||
int a;
|
||||
} a;
|
||||
};
|
||||
};
|
||||
} a;
|
||||
int __some_more;
|
||||
struct {
|
||||
union {
|
||||
union {
|
||||
union {
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
} b;
|
||||
};
|
||||
} b;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* three flavors of same struct with different structure but same layout for
|
||||
* a.a.a and b.b.b, thus successfully resolved and relocatable */
|
||||
struct core_reloc_nesting___dup_compat_types {
|
||||
char __just_for_padding;
|
||||
/* 3 more bytes of padding */
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
long long __more_padding;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 16 */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___dup_compat_types__2 {
|
||||
int __aligned_padding;
|
||||
struct {
|
||||
int __trickier_noop[0];
|
||||
struct {
|
||||
char __some_more_noops[0];
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
int __more_padding;
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
int __critical_padding;
|
||||
int b; /* offset 16 */
|
||||
} b;
|
||||
int __does_not_matter;
|
||||
};
|
||||
} b;
|
||||
int __more_irrelevant_stuff;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___dup_compat_types__3 {
|
||||
char __correct_padding[4];
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
/* 8 byte padding due to next struct's alignment */
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b;
|
||||
} b __attribute__((aligned(16)));
|
||||
};
|
||||
|
||||
/* b.b.b field is missing */
|
||||
struct core_reloc_nesting___err_missing_field {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int x;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* b.b.b field is an array of integers instead of plain int */
|
||||
struct core_reloc_nesting___err_array_field {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b[1];
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is missing */
|
||||
struct core_reloc_nesting___err_missing_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
int x;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is referenced through pointer instead of being embedded */
|
||||
struct core_reloc_nesting___err_nonstruct_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} *b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is an array of structs instead of plain struct */
|
||||
struct core_reloc_nesting___err_array_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b[1];
|
||||
} b;
|
||||
};
|
||||
|
||||
/* two flavors of same struct with incompatible layout for b.b.b */
|
||||
struct core_reloc_nesting___err_dup_incompat_types__1 {
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 0 */
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 4 */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_dup_incompat_types__2 {
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 0 */
|
||||
} a;
|
||||
} a;
|
||||
int __extra_padding;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 8 (!) */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* two flavors of same struct having one of a.a.a and b.b.b, but not both */
|
||||
struct core_reloc_nesting___err_partial_match_dups__a {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_partial_match_dups__b {
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_too_deep {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
/* 65 levels of nestedness for b.b.b */
|
||||
struct {
|
||||
struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
/* this one is one too much */
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
46
tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
Normal file
46
tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
Normal file
@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_nesting_substruct {
|
||||
int a;
|
||||
};
|
||||
|
||||
union core_reloc_nesting_subunion {
|
||||
int b;
|
||||
};
|
||||
|
||||
/* int a.a.a and b.b.b accesses */
|
||||
struct core_reloc_nesting {
|
||||
union {
|
||||
struct core_reloc_nesting_substruct a;
|
||||
} a;
|
||||
struct {
|
||||
union core_reloc_nesting_subunion b;
|
||||
} b;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_nesting(void *ctx)
|
||||
{
|
||||
struct core_reloc_nesting *in = (void *)&data.in;
|
||||
struct core_reloc_nesting *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a))
|
||||
return 1;
|
||||
if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user