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 
10 static 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 
366 struct core_reloc_test_case;
367 
368 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
369 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
370 
371 struct 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 
388 static 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 
399 static 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 
471 static 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 
494 static 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 
514 static 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 
523 static 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 
836 struct data {
837 	char in[256];
838 	char out[256];
839 	bool skip;
840 	uint64_t my_pid_tgid;
841 };
842 
843 static 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 
849 static 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 
863 static 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 
1000 cleanup:
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 
1013 void test_core_reloc(void)
1014 {
1015 	run_core_reloc_tests(false);
1016 }
1017 
1018 void test_core_reloc_btfgen(void)
1019 {
1020 	run_core_reloc_tests(true);
1021 }
1022