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