Commit ec6438a9 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

selftests/bpf: add CO-RE relocs nesting tests

Add a bunch of test validating correct handling of nested
structs/unions.
Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Acked-by: default avatarSong Liu <songliubraving@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 002d3afc
...@@ -28,6 +28,29 @@ ...@@ -28,6 +28,29 @@
.fails = true, \ .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 { struct core_reloc_test_case {
const char *case_name; const char *case_name;
const char *bpf_obj_file; const char *bpf_obj_file;
...@@ -57,6 +80,22 @@ static struct core_reloc_test_case test_cases[] = { ...@@ -57,6 +80,22 @@ static struct core_reloc_test_case test_cases[] = {
FLAVORS_CASE(flavors), FLAVORS_CASE(flavors),
FLAVORS_ERR_CASE(flavors__err_wrong_name), 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 { struct data {
......
#include "core_reloc_types.h"
void f(struct core_reloc_nesting x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___anon_embed x) {}
#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) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_array_container x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_array_field x) {}
#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) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_missing_container x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_missing_field x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_nonstruct_container x) {}
#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) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___err_too_deep x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_nesting___extra_nesting x) {}
#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 { ...@@ -13,3 +13,296 @@ struct core_reloc_flavors__err_wrong_name {
int b; int b;
int c; 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;
};
// 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment