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