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