cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core_reloc.c (30338B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <test_progs.h>
      3#include "progs/core_reloc_types.h"
      4#include "bpf_testmod/bpf_testmod.h"
      5#include <linux/limits.h>
      6#include <sys/mman.h>
      7#include <sys/syscall.h>
      8#include <bpf/btf.h>
      9
     10static int duration = 0;
     11
     12#define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
     13
     14#define MODULES_CASE(name, pg_name, tp_name) {				\
     15	.case_name = name,						\
     16	.bpf_obj_file = "test_core_reloc_module.o",			\
     17	.btf_src_file = NULL, /* find in kernel module BTFs */		\
     18	.input = "",							\
     19	.input_len = 0,							\
     20	.output = STRUCT_TO_CHAR_PTR(core_reloc_module_output) {	\
     21		.read_ctx_sz = sizeof(struct bpf_testmod_test_read_ctx),\
     22		.read_ctx_exists = true,				\
     23		.buf_exists = true,					\
     24		.len_exists = true,					\
     25		.off_exists = true,					\
     26		.len = 123,						\
     27		.off = 0,						\
     28		.comm = "test_progs",					\
     29		.comm_len = sizeof("test_progs"),			\
     30	},								\
     31	.output_len = sizeof(struct core_reloc_module_output),		\
     32	.prog_name = pg_name,						\
     33	.raw_tp_name = tp_name,						\
     34	.trigger = __trigger_module_test_read,				\
     35	.needs_testmod = true,						\
     36}
     37
     38#define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
     39	.a = 42,							\
     40	.b = 0xc001,							\
     41	.c = 0xbeef,							\
     42}
     43
     44#define FLAVORS_CASE_COMMON(name)					\
     45	.case_name = #name,						\
     46	.bpf_obj_file = "test_core_reloc_flavors.o",			\
     47	.btf_src_file = "btf__core_reloc_" #name ".o",			\
     48	.raw_tp_name = "sys_enter",					\
     49	.prog_name = "test_core_flavors"				\
     50
     51#define FLAVORS_CASE(name) {						\
     52	FLAVORS_CASE_COMMON(name),					\
     53	.input = FLAVORS_DATA(core_reloc_##name),			\
     54	.input_len = sizeof(struct core_reloc_##name),			\
     55	.output = FLAVORS_DATA(core_reloc_flavors),			\
     56	.output_len = sizeof(struct core_reloc_flavors),		\
     57}
     58
     59#define FLAVORS_ERR_CASE(name) {					\
     60	FLAVORS_CASE_COMMON(name),					\
     61	.fails = true,							\
     62}
     63
     64#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
     65	.a = { .a = { .a = 42 } },					\
     66	.b = { .b = { .b = 0xc001 } },					\
     67}
     68
     69#define NESTING_CASE_COMMON(name)					\
     70	.case_name = #name,						\
     71	.bpf_obj_file = "test_core_reloc_nesting.o",			\
     72	.btf_src_file = "btf__core_reloc_" #name ".o",			\
     73	.raw_tp_name = "sys_enter",					\
     74	.prog_name = "test_core_nesting"				\
     75
     76#define NESTING_CASE(name) {						\
     77	NESTING_CASE_COMMON(name),					\
     78	.input = NESTING_DATA(core_reloc_##name),			\
     79	.input_len = sizeof(struct core_reloc_##name),			\
     80	.output = NESTING_DATA(core_reloc_nesting),			\
     81	.output_len = sizeof(struct core_reloc_nesting)			\
     82}
     83
     84#define NESTING_ERR_CASE(name) {					\
     85	NESTING_CASE_COMMON(name),					\
     86	.fails = true,							\
     87}
     88
     89#define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
     90	.a = { [2] = 1 },						\
     91	.b = { [1] = { [2] = { [3] = 2 } } },				\
     92	.c = { [1] = { .c =  3 } },					\
     93	.d = { [0] = { [0] = { .d = 4 } } },				\
     94}
     95
     96#define ARRAYS_CASE_COMMON(name)					\
     97	.case_name = #name,						\
     98	.bpf_obj_file = "test_core_reloc_arrays.o",			\
     99	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    100	.raw_tp_name = "sys_enter",					\
    101	.prog_name = "test_core_arrays"					\
    102
    103#define ARRAYS_CASE(name) {						\
    104	ARRAYS_CASE_COMMON(name),					\
    105	.input = ARRAYS_DATA(core_reloc_##name),			\
    106	.input_len = sizeof(struct core_reloc_##name),			\
    107	.output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) {	\
    108		.a2   = 1,						\
    109		.b123 = 2,						\
    110		.c1c  = 3,						\
    111		.d00d = 4,						\
    112		.f10c = 0,						\
    113	},								\
    114	.output_len = sizeof(struct core_reloc_arrays_output)		\
    115}
    116
    117#define ARRAYS_ERR_CASE(name) {						\
    118	ARRAYS_CASE_COMMON(name),					\
    119	.fails = true,							\
    120}
    121
    122#define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
    123	.a = 1,								\
    124	.b = 2,								\
    125	.c = 3,								\
    126	.d = (void *)4,							\
    127	.f = (void *)5,							\
    128}
    129
    130#define PRIMITIVES_CASE_COMMON(name)					\
    131	.case_name = #name,						\
    132	.bpf_obj_file = "test_core_reloc_primitives.o",			\
    133	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    134	.raw_tp_name = "sys_enter",					\
    135	.prog_name = "test_core_primitives"				\
    136
    137#define PRIMITIVES_CASE(name) {						\
    138	PRIMITIVES_CASE_COMMON(name),					\
    139	.input = PRIMITIVES_DATA(core_reloc_##name),			\
    140	.input_len = sizeof(struct core_reloc_##name),			\
    141	.output = PRIMITIVES_DATA(core_reloc_primitives),		\
    142	.output_len = sizeof(struct core_reloc_primitives),		\
    143}
    144
    145#define PRIMITIVES_ERR_CASE(name) {					\
    146	PRIMITIVES_CASE_COMMON(name),					\
    147	.fails = true,							\
    148}
    149
    150#define MODS_CASE(name) {						\
    151	.case_name = #name,						\
    152	.bpf_obj_file = "test_core_reloc_mods.o",			\
    153	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    154	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) {		\
    155		.a = 1,							\
    156		.b = 2,							\
    157		.c = (void *)3,						\
    158		.d = (void *)4,						\
    159		.e = { [2] = 5 },					\
    160		.f = { [1] = 6 },					\
    161		.g = { .x = 7 },					\
    162		.h = { .y = 8 },					\
    163	},								\
    164	.input_len = sizeof(struct core_reloc_##name),			\
    165	.output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) {		\
    166		.a = 1, .b = 2, .c = 3, .d = 4,				\
    167		.e = 5, .f = 6, .g = 7, .h = 8,				\
    168	},								\
    169	.output_len = sizeof(struct core_reloc_mods_output),		\
    170	.raw_tp_name = "sys_enter",					\
    171	.prog_name = "test_core_mods",					\
    172}
    173
    174#define PTR_AS_ARR_CASE(name) {						\
    175	.case_name = #name,						\
    176	.bpf_obj_file = "test_core_reloc_ptr_as_arr.o",			\
    177	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    178	.input = (const char *)&(struct core_reloc_##name []){		\
    179		{ .a = 1 },						\
    180		{ .a = 2 },						\
    181		{ .a = 3 },						\
    182	},								\
    183	.input_len = 3 * sizeof(struct core_reloc_##name),		\
    184	.output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) {		\
    185		.a = 3,							\
    186	},								\
    187	.output_len = sizeof(struct core_reloc_ptr_as_arr),		\
    188	.raw_tp_name = "sys_enter",					\
    189	.prog_name = "test_core_ptr_as_arr",				\
    190}
    191
    192#define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
    193	.u8_field = 1,							\
    194	.s8_field = 2,							\
    195	.u16_field = 3,							\
    196	.s16_field = 4,							\
    197	.u32_field = 5,							\
    198	.s32_field = 6,							\
    199	.u64_field = 7,							\
    200	.s64_field = 8,							\
    201}
    202
    203#define INTS_CASE_COMMON(name)						\
    204	.case_name = #name,						\
    205	.bpf_obj_file = "test_core_reloc_ints.o",			\
    206	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    207	.raw_tp_name = "sys_enter",					\
    208	.prog_name = "test_core_ints"
    209
    210#define INTS_CASE(name) {						\
    211	INTS_CASE_COMMON(name),						\
    212	.input = INTS_DATA(core_reloc_##name),				\
    213	.input_len = sizeof(struct core_reloc_##name),			\
    214	.output = INTS_DATA(core_reloc_ints),				\
    215	.output_len = sizeof(struct core_reloc_ints),			\
    216}
    217
    218#define INTS_ERR_CASE(name) {						\
    219	INTS_CASE_COMMON(name),						\
    220	.fails = true,							\
    221}
    222
    223#define FIELD_EXISTS_CASE_COMMON(name)					\
    224	.case_name = #name,						\
    225	.bpf_obj_file = "test_core_reloc_existence.o",			\
    226	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    227	.raw_tp_name = "sys_enter",					\
    228	.prog_name = "test_core_existence"
    229
    230#define BITFIELDS_CASE_COMMON(objfile, test_name_prefix,  name)		\
    231	.case_name = test_name_prefix#name,				\
    232	.bpf_obj_file = objfile,					\
    233	.btf_src_file = "btf__core_reloc_" #name ".o"
    234
    235#define BITFIELDS_CASE(name, ...) {					\
    236	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o",	\
    237			      "probed:", name),				\
    238	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__,	\
    239	.input_len = sizeof(struct core_reloc_##name),			\
    240	.output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output)	\
    241		__VA_ARGS__,						\
    242	.output_len = sizeof(struct core_reloc_bitfields_output),	\
    243	.raw_tp_name = "sys_enter",					\
    244	.prog_name = "test_core_bitfields",				\
    245}, {									\
    246	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o",	\
    247			      "direct:", name),				\
    248	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__,	\
    249	.input_len = sizeof(struct core_reloc_##name),			\
    250	.output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output)	\
    251		__VA_ARGS__,						\
    252	.output_len = sizeof(struct core_reloc_bitfields_output),	\
    253	.prog_name = "test_core_bitfields_direct",			\
    254}
    255
    256
    257#define BITFIELDS_ERR_CASE(name) {					\
    258	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o",	\
    259			      "probed:", name),				\
    260	.fails = true,							\
    261	.raw_tp_name = "sys_enter",					\
    262	.prog_name = "test_core_bitfields",				\
    263}, {									\
    264	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o",	\
    265			      "direct:", name),				\
    266	.fails = true,							\
    267	.prog_name = "test_core_bitfields_direct",			\
    268}
    269
    270#define SIZE_CASE_COMMON(name)						\
    271	.case_name = #name,						\
    272	.bpf_obj_file = "test_core_reloc_size.o",			\
    273	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    274	.raw_tp_name = "sys_enter",					\
    275	.prog_name = "test_core_size"
    276
    277#define SIZE_OUTPUT_DATA(type)						\
    278	STRUCT_TO_CHAR_PTR(core_reloc_size_output) {			\
    279		.int_sz = sizeof(((type *)0)->int_field),		\
    280		.int_off = offsetof(type, int_field),			\
    281		.struct_sz = sizeof(((type *)0)->struct_field),		\
    282		.struct_off = offsetof(type, struct_field),		\
    283		.union_sz = sizeof(((type *)0)->union_field),		\
    284		.union_off = offsetof(type, union_field),		\
    285		.arr_sz = sizeof(((type *)0)->arr_field),		\
    286		.arr_off = offsetof(type, arr_field),			\
    287		.arr_elem_sz = sizeof(((type *)0)->arr_field[1]),	\
    288		.arr_elem_off = offsetof(type, arr_field[1]),		\
    289		.ptr_sz = 8, /* always 8-byte pointer for BPF */	\
    290		.ptr_off = offsetof(type, ptr_field),			\
    291		.enum_sz = sizeof(((type *)0)->enum_field),		\
    292		.enum_off = offsetof(type, enum_field),			\
    293		.float_sz = sizeof(((type *)0)->float_field),		\
    294		.float_off = offsetof(type, float_field),		\
    295	}
    296
    297#define SIZE_CASE(name) {						\
    298	SIZE_CASE_COMMON(name),						\
    299	.input_len = 0,							\
    300	.output = SIZE_OUTPUT_DATA(struct core_reloc_##name),		\
    301	.output_len = sizeof(struct core_reloc_size_output),		\
    302}
    303
    304#define SIZE_ERR_CASE(name) {						\
    305	SIZE_CASE_COMMON(name),						\
    306	.fails = true,							\
    307}
    308
    309#define TYPE_BASED_CASE_COMMON(name)					\
    310	.case_name = #name,						\
    311	.bpf_obj_file = "test_core_reloc_type_based.o",			\
    312	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    313	.raw_tp_name = "sys_enter",					\
    314	.prog_name = "test_core_type_based"
    315
    316#define TYPE_BASED_CASE(name, ...) {					\
    317	TYPE_BASED_CASE_COMMON(name),					\
    318	.output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output)	\
    319			__VA_ARGS__,					\
    320	.output_len = sizeof(struct core_reloc_type_based_output),	\
    321}
    322
    323#define TYPE_BASED_ERR_CASE(name) {					\
    324	TYPE_BASED_CASE_COMMON(name),					\
    325	.fails = true,							\
    326}
    327
    328#define TYPE_ID_CASE_COMMON(name)					\
    329	.case_name = #name,						\
    330	.bpf_obj_file = "test_core_reloc_type_id.o",			\
    331	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    332	.raw_tp_name = "sys_enter",					\
    333	.prog_name = "test_core_type_id"
    334
    335#define TYPE_ID_CASE(name, setup_fn) {					\
    336	TYPE_ID_CASE_COMMON(name),					\
    337	.output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {},	\
    338	.output_len = sizeof(struct core_reloc_type_id_output),		\
    339	.setup = setup_fn,						\
    340}
    341
    342#define TYPE_ID_ERR_CASE(name) {					\
    343	TYPE_ID_CASE_COMMON(name),					\
    344	.fails = true,							\
    345}
    346
    347#define ENUMVAL_CASE_COMMON(name)					\
    348	.case_name = #name,						\
    349	.bpf_obj_file = "test_core_reloc_enumval.o",			\
    350	.btf_src_file = "btf__core_reloc_" #name ".o",			\
    351	.raw_tp_name = "sys_enter",					\
    352	.prog_name = "test_core_enumval"
    353
    354#define ENUMVAL_CASE(name, ...) {					\
    355	ENUMVAL_CASE_COMMON(name),					\
    356	.output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output)		\
    357			__VA_ARGS__,					\
    358	.output_len = sizeof(struct core_reloc_enumval_output),		\
    359}
    360
    361#define ENUMVAL_ERR_CASE(name) {					\
    362	ENUMVAL_CASE_COMMON(name),					\
    363	.fails = true,							\
    364}
    365
    366struct core_reloc_test_case;
    367
    368typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
    369typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
    370
    371struct core_reloc_test_case {
    372	const char *case_name;
    373	const char *bpf_obj_file;
    374	const char *btf_src_file;
    375	const char *input;
    376	int input_len;
    377	const char *output;
    378	int output_len;
    379	bool fails;
    380	bool needs_testmod;
    381	bool relaxed_core_relocs;
    382	const char *prog_name;
    383	const char *raw_tp_name;
    384	setup_test_fn setup;
    385	trigger_test_fn trigger;
    386};
    387
    388static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
    389{
    390	int id;
    391
    392	id = btf__find_by_name_kind(btf, name, kind);
    393	if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
    394		return -1;
    395
    396	return id;
    397}
    398
    399static int setup_type_id_case_local(struct core_reloc_test_case *test)
    400{
    401	struct core_reloc_type_id_output *exp = (void *)test->output;
    402	struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
    403	struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
    404	const struct btf_type *t;
    405	const char *name;
    406	int i;
    407
    408	if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) {
    409		btf__free(local_btf);
    410		btf__free(targ_btf);
    411		return -EINVAL;
    412	}
    413
    414	exp->local_anon_struct = -1;
    415	exp->local_anon_union = -1;
    416	exp->local_anon_enum = -1;
    417	exp->local_anon_func_proto_ptr = -1;
    418	exp->local_anon_void_ptr = -1;
    419	exp->local_anon_arr = -1;
    420
    421	for (i = 1; i < btf__type_cnt(local_btf); i++)
    422	{
    423		t = btf__type_by_id(local_btf, i);
    424		/* we are interested only in anonymous types */
    425		if (t->name_off)
    426			continue;
    427
    428		if (btf_is_struct(t) && btf_vlen(t) &&
    429		    (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
    430		    strcmp(name, "marker_field") == 0) {
    431			exp->local_anon_struct = i;
    432		} else if (btf_is_union(t) && btf_vlen(t) &&
    433			 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
    434			 strcmp(name, "marker_field") == 0) {
    435			exp->local_anon_union = i;
    436		} else if (btf_is_enum(t) && btf_vlen(t) &&
    437			 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
    438			 strcmp(name, "MARKER_ENUM_VAL") == 0) {
    439			exp->local_anon_enum = i;
    440		} else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
    441			if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
    442			    btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
    443			    strcmp(name, "_Bool") == 0) {
    444				/* ptr -> func_proto -> _Bool */
    445				exp->local_anon_func_proto_ptr = i;
    446			} else if (btf_is_void(t)) {
    447				/* ptr -> void */
    448				exp->local_anon_void_ptr = i;
    449			}
    450		} else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
    451			   btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
    452			   strcmp(name, "_Bool") == 0) {
    453			/* _Bool[] */
    454			exp->local_anon_arr = i;
    455		}
    456	}
    457
    458	exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
    459	exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
    460	exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
    461	exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
    462	exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
    463	exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
    464	exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
    465
    466	btf__free(local_btf);
    467	btf__free(targ_btf);
    468	return 0;
    469}
    470
    471static int setup_type_id_case_success(struct core_reloc_test_case *test) {
    472	struct core_reloc_type_id_output *exp = (void *)test->output;
    473	struct btf *targ_btf;
    474	int err;
    475
    476	err = setup_type_id_case_local(test);
    477	if (err)
    478		return err;
    479
    480	targ_btf = btf__parse(test->btf_src_file, NULL);
    481
    482	exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
    483	exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
    484	exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
    485	exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
    486	exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
    487	exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
    488	exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
    489
    490	btf__free(targ_btf);
    491	return 0;
    492}
    493
    494static int setup_type_id_case_failure(struct core_reloc_test_case *test)
    495{
    496	struct core_reloc_type_id_output *exp = (void *)test->output;
    497	int err;
    498
    499	err = setup_type_id_case_local(test);
    500	if (err)
    501		return err;
    502
    503	exp->targ_struct = 0;
    504	exp->targ_union = 0;
    505	exp->targ_enum = 0;
    506	exp->targ_int = 0;
    507	exp->targ_struct_typedef = 0;
    508	exp->targ_func_proto_typedef = 0;
    509	exp->targ_arr_typedef = 0;
    510
    511	return 0;
    512}
    513
    514static int __trigger_module_test_read(const struct core_reloc_test_case *test)
    515{
    516	struct core_reloc_module_output *exp = (void *)test->output;
    517
    518	trigger_module_test_read(exp->len);
    519	return 0;
    520}
    521
    522
    523static const struct core_reloc_test_case test_cases[] = {
    524	/* validate we can find kernel image and use its BTF for relocs */
    525	{
    526		.case_name = "kernel",
    527		.bpf_obj_file = "test_core_reloc_kernel.o",
    528		.btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
    529		.input = "",
    530		.input_len = 0,
    531		.output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
    532			.valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
    533			.comm = "test_progs",
    534			.comm_len = sizeof("test_progs"),
    535		},
    536		.output_len = sizeof(struct core_reloc_kernel_output),
    537		.raw_tp_name = "sys_enter",
    538		.prog_name = "test_core_kernel",
    539	},
    540
    541	/* validate we can find kernel module BTF types for relocs/attach */
    542	MODULES_CASE("module_probed", "test_core_module_probed", "bpf_testmod_test_read"),
    543	MODULES_CASE("module_direct", "test_core_module_direct", NULL),
    544
    545	/* validate BPF program can use multiple flavors to match against
    546	 * single target BTF type
    547	 */
    548	FLAVORS_CASE(flavors),
    549
    550	FLAVORS_ERR_CASE(flavors__err_wrong_name),
    551
    552	/* various struct/enum nesting and resolution scenarios */
    553	NESTING_CASE(nesting),
    554	NESTING_CASE(nesting___anon_embed),
    555	NESTING_CASE(nesting___struct_union_mixup),
    556	NESTING_CASE(nesting___extra_nesting),
    557	NESTING_CASE(nesting___dup_compat_types),
    558
    559	NESTING_ERR_CASE(nesting___err_missing_field),
    560	NESTING_ERR_CASE(nesting___err_array_field),
    561	NESTING_ERR_CASE(nesting___err_missing_container),
    562	NESTING_ERR_CASE(nesting___err_nonstruct_container),
    563	NESTING_ERR_CASE(nesting___err_array_container),
    564	NESTING_ERR_CASE(nesting___err_dup_incompat_types),
    565	NESTING_ERR_CASE(nesting___err_partial_match_dups),
    566	NESTING_ERR_CASE(nesting___err_too_deep),
    567
    568	/* various array access relocation scenarios */
    569	ARRAYS_CASE(arrays),
    570	ARRAYS_CASE(arrays___diff_arr_dim),
    571	ARRAYS_CASE(arrays___diff_arr_val_sz),
    572	ARRAYS_CASE(arrays___equiv_zero_sz_arr),
    573	ARRAYS_CASE(arrays___fixed_arr),
    574
    575	ARRAYS_ERR_CASE(arrays___err_too_small),
    576	ARRAYS_ERR_CASE(arrays___err_too_shallow),
    577	ARRAYS_ERR_CASE(arrays___err_non_array),
    578	ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
    579	ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
    580
    581	/* enum/ptr/int handling scenarios */
    582	PRIMITIVES_CASE(primitives),
    583	PRIMITIVES_CASE(primitives___diff_enum_def),
    584	PRIMITIVES_CASE(primitives___diff_func_proto),
    585	PRIMITIVES_CASE(primitives___diff_ptr_type),
    586
    587	PRIMITIVES_ERR_CASE(primitives___err_non_enum),
    588	PRIMITIVES_ERR_CASE(primitives___err_non_int),
    589	PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
    590
    591	/* const/volatile/restrict and typedefs scenarios */
    592	MODS_CASE(mods),
    593	MODS_CASE(mods___mod_swap),
    594	MODS_CASE(mods___typedefs),
    595
    596	/* handling "ptr is an array" semantics */
    597	PTR_AS_ARR_CASE(ptr_as_arr),
    598	PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
    599
    600	/* int signedness/sizing/bitfield handling */
    601	INTS_CASE(ints),
    602	INTS_CASE(ints___bool),
    603	INTS_CASE(ints___reverse_sign),
    604
    605	/* validate edge cases of capturing relocations */
    606	{
    607		.case_name = "misc",
    608		.bpf_obj_file = "test_core_reloc_misc.o",
    609		.btf_src_file = "btf__core_reloc_misc.o",
    610		.input = (const char *)&(struct core_reloc_misc_extensible[]){
    611			{ .a = 1 },
    612			{ .a = 2 }, /* not read */
    613			{ .a = 3 },
    614		},
    615		.input_len = 4 * sizeof(int),
    616		.output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
    617			.a = 1,
    618			.b = 1,
    619			.c = 0, /* BUG in clang, should be 3 */
    620		},
    621		.output_len = sizeof(struct core_reloc_misc_output),
    622		.raw_tp_name = "sys_enter",
    623		.prog_name = "test_core_misc",
    624	},
    625
    626	/* validate field existence checks */
    627	{
    628		FIELD_EXISTS_CASE_COMMON(existence),
    629		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
    630			.a = 1,
    631			.b = 2,
    632			.c = 3,
    633			.arr = { 4 },
    634			.s = { .x = 5 },
    635		},
    636		.input_len = sizeof(struct core_reloc_existence),
    637		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
    638			.a_exists = 1,
    639			.b_exists = 1,
    640			.c_exists = 1,
    641			.arr_exists = 1,
    642			.s_exists = 1,
    643			.a_value = 1,
    644			.b_value = 2,
    645			.c_value = 3,
    646			.arr_value = 4,
    647			.s_value = 5,
    648		},
    649		.output_len = sizeof(struct core_reloc_existence_output),
    650	},
    651	{
    652		FIELD_EXISTS_CASE_COMMON(existence___minimal),
    653		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
    654			.a = 42,
    655		},
    656		.input_len = sizeof(struct core_reloc_existence___minimal),
    657		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
    658			.a_exists = 1,
    659			.b_exists = 0,
    660			.c_exists = 0,
    661			.arr_exists = 0,
    662			.s_exists = 0,
    663			.a_value = 42,
    664			.b_value = 0xff000002u,
    665			.c_value = 0xff000003u,
    666			.arr_value = 0xff000004u,
    667			.s_value = 0xff000005u,
    668		},
    669		.output_len = sizeof(struct core_reloc_existence_output),
    670	},
    671	{
    672		FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
    673		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
    674		},
    675		.input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
    676		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
    677			.a_exists = 0,
    678			.b_exists = 0,
    679			.c_exists = 0,
    680			.arr_exists = 0,
    681			.s_exists = 0,
    682			.a_value = 0xff000001u,
    683			.b_value = 0xff000002u,
    684			.c_value = 0xff000003u,
    685			.arr_value = 0xff000004u,
    686			.s_value = 0xff000005u,
    687		},
    688		.output_len = sizeof(struct core_reloc_existence_output),
    689	},
    690
    691	/* bitfield relocation checks */
    692	BITFIELDS_CASE(bitfields, {
    693		.ub1 = 1,
    694		.ub2 = 2,
    695		.ub7 = 96,
    696		.sb4 = -7,
    697		.sb20 = -0x76543,
    698		.u32 = 0x80000000,
    699		.s32 = -0x76543210,
    700	}),
    701	BITFIELDS_CASE(bitfields___bit_sz_change, {
    702		.ub1 = 6,
    703		.ub2 = 0xABCDE,
    704		.ub7 = 1,
    705		.sb4 = -1,
    706		.sb20 = -0x17654321,
    707		.u32 = 0xBEEF,
    708		.s32 = -0x3FEDCBA987654321LL,
    709	}),
    710	BITFIELDS_CASE(bitfields___bitfield_vs_int, {
    711		.ub1 = 0xFEDCBA9876543210LL,
    712		.ub2 = 0xA6,
    713		.ub7 = -0x7EDCBA987654321LL,
    714		.sb4 = -0x6123456789ABCDELL,
    715		.sb20 = 0xD00DLL,
    716		.u32 = -0x76543,
    717		.s32 = 0x0ADEADBEEFBADB0BLL,
    718	}),
    719	BITFIELDS_CASE(bitfields___just_big_enough, {
    720		.ub1 = 0xFLL,
    721		.ub2 = 0x0812345678FEDCBALL,
    722	}),
    723	BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
    724
    725	/* field size and offset relocation checks */
    726	SIZE_CASE(size),
    727	SIZE_CASE(size___diff_sz),
    728	SIZE_CASE(size___diff_offs),
    729	SIZE_ERR_CASE(size___err_ambiguous),
    730
    731	/* validate type existence and size relocations */
    732	TYPE_BASED_CASE(type_based, {
    733		.struct_exists = 1,
    734		.union_exists = 1,
    735		.enum_exists = 1,
    736		.typedef_named_struct_exists = 1,
    737		.typedef_anon_struct_exists = 1,
    738		.typedef_struct_ptr_exists = 1,
    739		.typedef_int_exists = 1,
    740		.typedef_enum_exists = 1,
    741		.typedef_void_ptr_exists = 1,
    742		.typedef_func_proto_exists = 1,
    743		.typedef_arr_exists = 1,
    744		.struct_sz = sizeof(struct a_struct),
    745		.union_sz = sizeof(union a_union),
    746		.enum_sz = sizeof(enum an_enum),
    747		.typedef_named_struct_sz = sizeof(named_struct_typedef),
    748		.typedef_anon_struct_sz = sizeof(anon_struct_typedef),
    749		.typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
    750		.typedef_int_sz = sizeof(int_typedef),
    751		.typedef_enum_sz = sizeof(enum_typedef),
    752		.typedef_void_ptr_sz = sizeof(void_ptr_typedef),
    753		.typedef_func_proto_sz = sizeof(func_proto_typedef),
    754		.typedef_arr_sz = sizeof(arr_typedef),
    755	}),
    756	TYPE_BASED_CASE(type_based___all_missing, {
    757		/* all zeros */
    758	}),
    759	TYPE_BASED_CASE(type_based___diff_sz, {
    760		.struct_exists = 1,
    761		.union_exists = 1,
    762		.enum_exists = 1,
    763		.typedef_named_struct_exists = 1,
    764		.typedef_anon_struct_exists = 1,
    765		.typedef_struct_ptr_exists = 1,
    766		.typedef_int_exists = 1,
    767		.typedef_enum_exists = 1,
    768		.typedef_void_ptr_exists = 1,
    769		.typedef_func_proto_exists = 1,
    770		.typedef_arr_exists = 1,
    771		.struct_sz = sizeof(struct a_struct___diff_sz),
    772		.union_sz = sizeof(union a_union___diff_sz),
    773		.enum_sz = sizeof(enum an_enum___diff_sz),
    774		.typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
    775		.typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
    776		.typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
    777		.typedef_int_sz = sizeof(int_typedef___diff_sz),
    778		.typedef_enum_sz = sizeof(enum_typedef___diff_sz),
    779		.typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
    780		.typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
    781		.typedef_arr_sz = sizeof(arr_typedef___diff_sz),
    782	}),
    783	TYPE_BASED_CASE(type_based___incompat, {
    784		.enum_exists = 1,
    785		.enum_sz = sizeof(enum an_enum),
    786	}),
    787	TYPE_BASED_CASE(type_based___fn_wrong_args, {
    788		.struct_exists = 1,
    789		.struct_sz = sizeof(struct a_struct),
    790	}),
    791
    792	/* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
    793	TYPE_ID_CASE(type_id, setup_type_id_case_success),
    794	TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
    795
    796	/* Enumerator value existence and value relocations */
    797	ENUMVAL_CASE(enumval, {
    798		.named_val1_exists = true,
    799		.named_val2_exists = true,
    800		.named_val3_exists = true,
    801		.anon_val1_exists = true,
    802		.anon_val2_exists = true,
    803		.anon_val3_exists = true,
    804		.named_val1 = 1,
    805		.named_val2 = 2,
    806		.anon_val1 = 0x10,
    807		.anon_val2 = 0x20,
    808	}),
    809	ENUMVAL_CASE(enumval___diff, {
    810		.named_val1_exists = true,
    811		.named_val2_exists = true,
    812		.named_val3_exists = true,
    813		.anon_val1_exists = true,
    814		.anon_val2_exists = true,
    815		.anon_val3_exists = true,
    816		.named_val1 = 101,
    817		.named_val2 = 202,
    818		.anon_val1 = 0x11,
    819		.anon_val2 = 0x22,
    820	}),
    821	ENUMVAL_CASE(enumval___val3_missing, {
    822		.named_val1_exists = true,
    823		.named_val2_exists = true,
    824		.named_val3_exists = false,
    825		.anon_val1_exists = true,
    826		.anon_val2_exists = true,
    827		.anon_val3_exists = false,
    828		.named_val1 = 111,
    829		.named_val2 = 222,
    830		.anon_val1 = 0x111,
    831		.anon_val2 = 0x222,
    832	}),
    833	ENUMVAL_ERR_CASE(enumval___err_missing),
    834};
    835
    836struct data {
    837	char in[256];
    838	char out[256];
    839	bool skip;
    840	uint64_t my_pid_tgid;
    841};
    842
    843static size_t roundup_page(size_t sz)
    844{
    845	long page_size = sysconf(_SC_PAGE_SIZE);
    846	return (sz + page_size - 1) / page_size * page_size;
    847}
    848
    849static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objpath)
    850{
    851	char command[4096];
    852	int n;
    853
    854	n = snprintf(command, sizeof(command),
    855		     "./bpftool gen min_core_btf %s %s %s",
    856		     src_btf, dst_btf, objpath);
    857	if (n < 0 || n >= sizeof(command))
    858		return -1;
    859
    860	return system(command);
    861}
    862
    863static void run_core_reloc_tests(bool use_btfgen)
    864{
    865	const size_t mmap_sz = roundup_page(sizeof(struct data));
    866	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
    867	struct core_reloc_test_case *test_case, test_case_copy;
    868	const char *tp_name, *probe_name;
    869	int err, i, equal, fd;
    870	struct bpf_link *link = NULL;
    871	struct bpf_map *data_map;
    872	struct bpf_program *prog;
    873	struct bpf_object *obj;
    874	uint64_t my_pid_tgid;
    875	struct data *data;
    876	void *mmap_data = NULL;
    877
    878	my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
    879
    880	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
    881		char btf_file[] = "/tmp/core_reloc.btf.XXXXXX";
    882
    883		test_case_copy = test_cases[i];
    884		test_case = &test_case_copy;
    885
    886		if (!test__start_subtest(test_case->case_name))
    887			continue;
    888
    889		if (test_case->needs_testmod && !env.has_testmod) {
    890			test__skip();
    891			continue;
    892		}
    893
    894		/* generate a "minimal" BTF file and use it as source */
    895		if (use_btfgen) {
    896
    897			if (!test_case->btf_src_file || test_case->fails) {
    898				test__skip();
    899				continue;
    900			}
    901
    902			fd = mkstemp(btf_file);
    903			if (!ASSERT_GE(fd, 0, "btf_tmp"))
    904				continue;
    905			close(fd); /* we only need the path */
    906			err = run_btfgen(test_case->btf_src_file, btf_file,
    907					 test_case->bpf_obj_file);
    908			if (!ASSERT_OK(err, "run_btfgen"))
    909				continue;
    910
    911			test_case->btf_src_file = btf_file;
    912		}
    913
    914		if (test_case->setup) {
    915			err = test_case->setup(test_case);
    916			if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
    917				continue;
    918		}
    919
    920		if (test_case->btf_src_file) {
    921			err = access(test_case->btf_src_file, R_OK);
    922			if (!ASSERT_OK(err, "btf_src_file"))
    923				continue;
    924		}
    925
    926		open_opts.btf_custom_path = test_case->btf_src_file;
    927		obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts);
    928		if (!ASSERT_OK_PTR(obj, "obj_open"))
    929			goto cleanup;
    930
    931		probe_name = test_case->prog_name;
    932		tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
    933		prog = bpf_object__find_program_by_name(obj, probe_name);
    934		if (CHECK(!prog, "find_probe",
    935			  "prog '%s' not found\n", probe_name))
    936			goto cleanup;
    937
    938		err = bpf_object__load(obj);
    939		if (err) {
    940			if (!test_case->fails)
    941				ASSERT_OK(err, "obj_load");
    942			goto cleanup;
    943		}
    944
    945		data_map = bpf_object__find_map_by_name(obj, ".bss");
    946		if (CHECK(!data_map, "find_data_map", "data map not found\n"))
    947			goto cleanup;
    948
    949		mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
    950				 MAP_SHARED, bpf_map__fd(data_map), 0);
    951		if (CHECK(mmap_data == MAP_FAILED, "mmap",
    952			  ".bss mmap failed: %d", errno)) {
    953			mmap_data = NULL;
    954			goto cleanup;
    955		}
    956		data = mmap_data;
    957
    958		memset(mmap_data, 0, sizeof(*data));
    959		if (test_case->input_len)
    960			memcpy(data->in, test_case->input, test_case->input_len);
    961		data->my_pid_tgid = my_pid_tgid;
    962
    963		link = bpf_program__attach_raw_tracepoint(prog, tp_name);
    964		if (!ASSERT_OK_PTR(link, "attach_raw_tp"))
    965			goto cleanup;
    966
    967		/* trigger test run */
    968		if (test_case->trigger) {
    969			if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
    970				goto cleanup;
    971		} else {
    972			usleep(1);
    973		}
    974
    975		if (data->skip) {
    976			test__skip();
    977			goto cleanup;
    978		}
    979
    980		if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
    981			goto cleanup;
    982
    983		equal = memcmp(data->out, test_case->output,
    984			       test_case->output_len) == 0;
    985		if (CHECK(!equal, "check_result",
    986			  "input/output data don't match\n")) {
    987			int j;
    988
    989			for (j = 0; j < test_case->input_len; j++) {
    990				printf("input byte #%d: 0x%02hhx\n",
    991				       j, test_case->input[j]);
    992			}
    993			for (j = 0; j < test_case->output_len; j++) {
    994				printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
    995				       j, test_case->output[j], data->out[j]);
    996			}
    997			goto cleanup;
    998		}
    999
   1000cleanup:
   1001		if (mmap_data) {
   1002			CHECK_FAIL(munmap(mmap_data, mmap_sz));
   1003			mmap_data = NULL;
   1004		}
   1005		if (use_btfgen)
   1006			remove(test_case->btf_src_file);
   1007		bpf_link__destroy(link);
   1008		link = NULL;
   1009		bpf_object__close(obj);
   1010	}
   1011}
   1012
   1013void test_core_reloc(void)
   1014{
   1015	run_core_reloc_tests(false);
   1016}
   1017
   1018void test_core_reloc_btfgen(void)
   1019{
   1020	run_core_reloc_tests(true);
   1021}