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"
6 #include <sys/syscall.h>
9 static int duration = 0;
11 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
13 #define MODULES_CASE(name, pg_name, tp_name) { \
15 .bpf_obj_file = "test_core_reloc_module.o", \
16 .btf_src_file = NULL, /* find in kernel module BTFs */ \
19 .output = STRUCT_TO_CHAR_PTR(core_reloc_module_output) { \
20 .read_ctx_sz = sizeof(struct bpf_testmod_test_read_ctx),\
21 .read_ctx_exists = true, \
27 .comm = "test_progs", \
28 .comm_len = sizeof("test_progs"), \
30 .output_len = sizeof(struct core_reloc_module_output), \
31 .prog_name = pg_name, \
32 .raw_tp_name = tp_name, \
33 .trigger = __trigger_module_test_read, \
34 .needs_testmod = true, \
37 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
43 #define FLAVORS_CASE_COMMON(name) \
45 .bpf_obj_file = "test_core_reloc_flavors.o", \
46 .btf_src_file = "btf__core_reloc_" #name ".o", \
47 .raw_tp_name = "sys_enter", \
48 .prog_name = "test_core_flavors" \
50 #define FLAVORS_CASE(name) { \
51 FLAVORS_CASE_COMMON(name), \
52 .input = FLAVORS_DATA(core_reloc_##name), \
53 .input_len = sizeof(struct core_reloc_##name), \
54 .output = FLAVORS_DATA(core_reloc_flavors), \
55 .output_len = sizeof(struct core_reloc_flavors), \
58 #define FLAVORS_ERR_CASE(name) { \
59 FLAVORS_CASE_COMMON(name), \
63 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
64 .a = { .a = { .a = 42 } }, \
65 .b = { .b = { .b = 0xc001 } }, \
68 #define NESTING_CASE_COMMON(name) \
70 .bpf_obj_file = "test_core_reloc_nesting.o", \
71 .btf_src_file = "btf__core_reloc_" #name ".o", \
72 .raw_tp_name = "sys_enter", \
73 .prog_name = "test_core_nesting" \
75 #define NESTING_CASE(name) { \
76 NESTING_CASE_COMMON(name), \
77 .input = NESTING_DATA(core_reloc_##name), \
78 .input_len = sizeof(struct core_reloc_##name), \
79 .output = NESTING_DATA(core_reloc_nesting), \
80 .output_len = sizeof(struct core_reloc_nesting) \
83 #define NESTING_ERR_CASE(name) { \
84 NESTING_CASE_COMMON(name), \
88 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
90 .b = { [1] = { [2] = { [3] = 2 } } }, \
91 .c = { [1] = { .c = 3 } }, \
92 .d = { [0] = { [0] = { .d = 4 } } }, \
95 #define ARRAYS_CASE_COMMON(name) \
97 .bpf_obj_file = "test_core_reloc_arrays.o", \
98 .btf_src_file = "btf__core_reloc_" #name ".o", \
99 .raw_tp_name = "sys_enter", \
100 .prog_name = "test_core_arrays" \
102 #define ARRAYS_CASE(name) { \
103 ARRAYS_CASE_COMMON(name), \
104 .input = ARRAYS_DATA(core_reloc_##name), \
105 .input_len = sizeof(struct core_reloc_##name), \
106 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
113 .output_len = sizeof(struct core_reloc_arrays_output) \
116 #define ARRAYS_ERR_CASE(name) { \
117 ARRAYS_CASE_COMMON(name), \
121 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
129 #define PRIMITIVES_CASE_COMMON(name) \
130 .case_name = #name, \
131 .bpf_obj_file = "test_core_reloc_primitives.o", \
132 .btf_src_file = "btf__core_reloc_" #name ".o", \
133 .raw_tp_name = "sys_enter", \
134 .prog_name = "test_core_primitives" \
136 #define PRIMITIVES_CASE(name) { \
137 PRIMITIVES_CASE_COMMON(name), \
138 .input = PRIMITIVES_DATA(core_reloc_##name), \
139 .input_len = sizeof(struct core_reloc_##name), \
140 .output = PRIMITIVES_DATA(core_reloc_primitives), \
141 .output_len = sizeof(struct core_reloc_primitives), \
144 #define PRIMITIVES_ERR_CASE(name) { \
145 PRIMITIVES_CASE_COMMON(name), \
149 #define MODS_CASE(name) { \
150 .case_name = #name, \
151 .bpf_obj_file = "test_core_reloc_mods.o", \
152 .btf_src_file = "btf__core_reloc_" #name ".o", \
153 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
163 .input_len = sizeof(struct core_reloc_##name), \
164 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
165 .a = 1, .b = 2, .c = 3, .d = 4, \
166 .e = 5, .f = 6, .g = 7, .h = 8, \
168 .output_len = sizeof(struct core_reloc_mods_output), \
169 .raw_tp_name = "sys_enter", \
170 .prog_name = "test_core_mods", \
173 #define PTR_AS_ARR_CASE(name) { \
174 .case_name = #name, \
175 .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
176 .btf_src_file = "btf__core_reloc_" #name ".o", \
177 .input = (const char *)&(struct core_reloc_##name []){ \
182 .input_len = 3 * sizeof(struct core_reloc_##name), \
183 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
186 .output_len = sizeof(struct core_reloc_ptr_as_arr), \
187 .raw_tp_name = "sys_enter", \
188 .prog_name = "test_core_ptr_as_arr", \
191 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
202 #define INTS_CASE_COMMON(name) \
203 .case_name = #name, \
204 .bpf_obj_file = "test_core_reloc_ints.o", \
205 .btf_src_file = "btf__core_reloc_" #name ".o", \
206 .raw_tp_name = "sys_enter", \
207 .prog_name = "test_core_ints"
209 #define INTS_CASE(name) { \
210 INTS_CASE_COMMON(name), \
211 .input = INTS_DATA(core_reloc_##name), \
212 .input_len = sizeof(struct core_reloc_##name), \
213 .output = INTS_DATA(core_reloc_ints), \
214 .output_len = sizeof(struct core_reloc_ints), \
217 #define INTS_ERR_CASE(name) { \
218 INTS_CASE_COMMON(name), \
222 #define FIELD_EXISTS_CASE_COMMON(name) \
223 .case_name = #name, \
224 .bpf_obj_file = "test_core_reloc_existence.o", \
225 .btf_src_file = "btf__core_reloc_" #name ".o", \
226 .raw_tp_name = "sys_enter", \
227 .prog_name = "test_core_existence"
229 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
230 .case_name = test_name_prefix#name, \
231 .bpf_obj_file = objfile, \
232 .btf_src_file = "btf__core_reloc_" #name ".o"
234 #define BITFIELDS_CASE(name, ...) { \
235 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
237 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
238 .input_len = sizeof(struct core_reloc_##name), \
239 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
241 .output_len = sizeof(struct core_reloc_bitfields_output), \
242 .raw_tp_name = "sys_enter", \
243 .prog_name = "test_core_bitfields", \
245 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
247 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
248 .input_len = sizeof(struct core_reloc_##name), \
249 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
251 .output_len = sizeof(struct core_reloc_bitfields_output), \
252 .prog_name = "test_core_bitfields_direct", \
256 #define BITFIELDS_ERR_CASE(name) { \
257 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
260 .raw_tp_name = "sys_enter", \
261 .prog_name = "test_core_bitfields", \
263 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
266 .prog_name = "test_core_bitfields_direct", \
269 #define SIZE_CASE_COMMON(name) \
270 .case_name = #name, \
271 .bpf_obj_file = "test_core_reloc_size.o", \
272 .btf_src_file = "btf__core_reloc_" #name ".o", \
273 .raw_tp_name = "sys_enter", \
274 .prog_name = "test_core_size"
276 #define SIZE_OUTPUT_DATA(type) \
277 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
278 .int_sz = sizeof(((type *)0)->int_field), \
279 .struct_sz = sizeof(((type *)0)->struct_field), \
280 .union_sz = sizeof(((type *)0)->union_field), \
281 .arr_sz = sizeof(((type *)0)->arr_field), \
282 .arr_elem_sz = sizeof(((type *)0)->arr_field[0]), \
283 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \
284 .enum_sz = sizeof(((type *)0)->enum_field), \
285 .float_sz = sizeof(((type *)0)->float_field), \
288 #define SIZE_CASE(name) { \
289 SIZE_CASE_COMMON(name), \
291 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
292 .output_len = sizeof(struct core_reloc_size_output), \
295 #define SIZE_ERR_CASE(name) { \
296 SIZE_CASE_COMMON(name), \
300 #define TYPE_BASED_CASE_COMMON(name) \
301 .case_name = #name, \
302 .bpf_obj_file = "test_core_reloc_type_based.o", \
303 .btf_src_file = "btf__core_reloc_" #name ".o", \
304 .raw_tp_name = "sys_enter", \
305 .prog_name = "test_core_type_based"
307 #define TYPE_BASED_CASE(name, ...) { \
308 TYPE_BASED_CASE_COMMON(name), \
309 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \
311 .output_len = sizeof(struct core_reloc_type_based_output), \
314 #define TYPE_BASED_ERR_CASE(name) { \
315 TYPE_BASED_CASE_COMMON(name), \
319 #define TYPE_ID_CASE_COMMON(name) \
320 .case_name = #name, \
321 .bpf_obj_file = "test_core_reloc_type_id.o", \
322 .btf_src_file = "btf__core_reloc_" #name ".o", \
323 .raw_tp_name = "sys_enter", \
324 .prog_name = "test_core_type_id"
326 #define TYPE_ID_CASE(name, setup_fn) { \
327 TYPE_ID_CASE_COMMON(name), \
328 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \
329 .output_len = sizeof(struct core_reloc_type_id_output), \
333 #define TYPE_ID_ERR_CASE(name) { \
334 TYPE_ID_CASE_COMMON(name), \
338 #define ENUMVAL_CASE_COMMON(name) \
339 .case_name = #name, \
340 .bpf_obj_file = "test_core_reloc_enumval.o", \
341 .btf_src_file = "btf__core_reloc_" #name ".o", \
342 .raw_tp_name = "sys_enter", \
343 .prog_name = "test_core_enumval"
345 #define ENUMVAL_CASE(name, ...) { \
346 ENUMVAL_CASE_COMMON(name), \
347 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \
349 .output_len = sizeof(struct core_reloc_enumval_output), \
352 #define ENUMVAL_ERR_CASE(name) { \
353 ENUMVAL_CASE_COMMON(name), \
357 struct core_reloc_test_case;
359 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
360 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
362 struct core_reloc_test_case {
363 const char *case_name;
364 const char *bpf_obj_file;
365 const char *btf_src_file;
372 bool relaxed_core_relocs;
373 const char *prog_name;
374 const char *raw_tp_name;
376 trigger_test_fn trigger;
379 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
383 id = btf__find_by_name_kind(btf, name, kind);
384 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
390 static int setup_type_id_case_local(struct core_reloc_test_case *test)
392 struct core_reloc_type_id_output *exp = (void *)test->output;
393 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
394 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
395 const struct btf_type *t;
399 if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) {
400 btf__free(local_btf);
405 exp->local_anon_struct = -1;
406 exp->local_anon_union = -1;
407 exp->local_anon_enum = -1;
408 exp->local_anon_func_proto_ptr = -1;
409 exp->local_anon_void_ptr = -1;
410 exp->local_anon_arr = -1;
412 for (i = 1; i < btf__type_cnt(local_btf); i++)
414 t = btf__type_by_id(local_btf, i);
415 /* we are interested only in anonymous types */
419 if (btf_is_struct(t) && btf_vlen(t) &&
420 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
421 strcmp(name, "marker_field") == 0) {
422 exp->local_anon_struct = i;
423 } else if (btf_is_union(t) && btf_vlen(t) &&
424 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
425 strcmp(name, "marker_field") == 0) {
426 exp->local_anon_union = i;
427 } else if (btf_is_enum(t) && btf_vlen(t) &&
428 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
429 strcmp(name, "MARKER_ENUM_VAL") == 0) {
430 exp->local_anon_enum = i;
431 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
432 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
433 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
434 strcmp(name, "_Bool") == 0) {
435 /* ptr -> func_proto -> _Bool */
436 exp->local_anon_func_proto_ptr = i;
437 } else if (btf_is_void(t)) {
439 exp->local_anon_void_ptr = i;
441 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
442 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
443 strcmp(name, "_Bool") == 0) {
445 exp->local_anon_arr = i;
449 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
450 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
451 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
452 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
453 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
454 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
455 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
457 btf__free(local_btf);
462 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
463 struct core_reloc_type_id_output *exp = (void *)test->output;
464 struct btf *targ_btf;
467 err = setup_type_id_case_local(test);
471 targ_btf = btf__parse(test->btf_src_file, NULL);
473 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
474 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
475 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
476 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
477 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
478 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
479 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
485 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
487 struct core_reloc_type_id_output *exp = (void *)test->output;
490 err = setup_type_id_case_local(test);
494 exp->targ_struct = 0;
498 exp->targ_struct_typedef = 0;
499 exp->targ_func_proto_typedef = 0;
500 exp->targ_arr_typedef = 0;
505 static int __trigger_module_test_read(const struct core_reloc_test_case *test)
507 struct core_reloc_module_output *exp = (void *)test->output;
509 trigger_module_test_read(exp->len);
514 static struct core_reloc_test_case test_cases[] = {
515 /* validate we can find kernel image and use its BTF for relocs */
517 .case_name = "kernel",
518 .bpf_obj_file = "test_core_reloc_kernel.o",
519 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
522 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
523 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
524 .comm = "test_progs",
525 .comm_len = sizeof("test_progs"),
527 .output_len = sizeof(struct core_reloc_kernel_output),
528 .raw_tp_name = "sys_enter",
529 .prog_name = "test_core_kernel",
532 /* validate we can find kernel module BTF types for relocs/attach */
533 MODULES_CASE("module_probed", "test_core_module_probed", "bpf_testmod_test_read"),
534 MODULES_CASE("module_direct", "test_core_module_direct", NULL),
536 /* validate BPF program can use multiple flavors to match against
537 * single target BTF type
539 FLAVORS_CASE(flavors),
541 FLAVORS_ERR_CASE(flavors__err_wrong_name),
543 /* various struct/enum nesting and resolution scenarios */
544 NESTING_CASE(nesting),
545 NESTING_CASE(nesting___anon_embed),
546 NESTING_CASE(nesting___struct_union_mixup),
547 NESTING_CASE(nesting___extra_nesting),
548 NESTING_CASE(nesting___dup_compat_types),
550 NESTING_ERR_CASE(nesting___err_missing_field),
551 NESTING_ERR_CASE(nesting___err_array_field),
552 NESTING_ERR_CASE(nesting___err_missing_container),
553 NESTING_ERR_CASE(nesting___err_nonstruct_container),
554 NESTING_ERR_CASE(nesting___err_array_container),
555 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
556 NESTING_ERR_CASE(nesting___err_partial_match_dups),
557 NESTING_ERR_CASE(nesting___err_too_deep),
559 /* various array access relocation scenarios */
561 ARRAYS_CASE(arrays___diff_arr_dim),
562 ARRAYS_CASE(arrays___diff_arr_val_sz),
563 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
564 ARRAYS_CASE(arrays___fixed_arr),
566 ARRAYS_ERR_CASE(arrays___err_too_small),
567 ARRAYS_ERR_CASE(arrays___err_too_shallow),
568 ARRAYS_ERR_CASE(arrays___err_non_array),
569 ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
570 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
572 /* enum/ptr/int handling scenarios */
573 PRIMITIVES_CASE(primitives),
574 PRIMITIVES_CASE(primitives___diff_enum_def),
575 PRIMITIVES_CASE(primitives___diff_func_proto),
576 PRIMITIVES_CASE(primitives___diff_ptr_type),
578 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
579 PRIMITIVES_ERR_CASE(primitives___err_non_int),
580 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
582 /* const/volatile/restrict and typedefs scenarios */
584 MODS_CASE(mods___mod_swap),
585 MODS_CASE(mods___typedefs),
587 /* handling "ptr is an array" semantics */
588 PTR_AS_ARR_CASE(ptr_as_arr),
589 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
591 /* int signedness/sizing/bitfield handling */
593 INTS_CASE(ints___bool),
594 INTS_CASE(ints___reverse_sign),
596 /* validate edge cases of capturing relocations */
599 .bpf_obj_file = "test_core_reloc_misc.o",
600 .btf_src_file = "btf__core_reloc_misc.o",
601 .input = (const char *)&(struct core_reloc_misc_extensible[]){
603 { .a = 2 }, /* not read */
606 .input_len = 4 * sizeof(int),
607 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
610 .c = 0, /* BUG in clang, should be 3 */
612 .output_len = sizeof(struct core_reloc_misc_output),
613 .raw_tp_name = "sys_enter",
614 .prog_name = "test_core_misc",
617 /* validate field existence checks */
619 FIELD_EXISTS_CASE_COMMON(existence),
620 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
627 .input_len = sizeof(struct core_reloc_existence),
628 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
640 .output_len = sizeof(struct core_reloc_existence_output),
643 FIELD_EXISTS_CASE_COMMON(existence___minimal),
644 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
647 .input_len = sizeof(struct core_reloc_existence___minimal),
648 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
655 .b_value = 0xff000002u,
656 .c_value = 0xff000003u,
657 .arr_value = 0xff000004u,
658 .s_value = 0xff000005u,
660 .output_len = sizeof(struct core_reloc_existence_output),
663 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
664 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
666 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
667 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
673 .a_value = 0xff000001u,
674 .b_value = 0xff000002u,
675 .c_value = 0xff000003u,
676 .arr_value = 0xff000004u,
677 .s_value = 0xff000005u,
679 .output_len = sizeof(struct core_reloc_existence_output),
682 /* bitfield relocation checks */
683 BITFIELDS_CASE(bitfields, {
692 BITFIELDS_CASE(bitfields___bit_sz_change, {
699 .s32 = -0x3FEDCBA987654321LL,
701 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
702 .ub1 = 0xFEDCBA9876543210LL,
704 .ub7 = -0x7EDCBA987654321LL,
705 .sb4 = -0x6123456789ABCDELL,
708 .s32 = 0x0ADEADBEEFBADB0BLL,
710 BITFIELDS_CASE(bitfields___just_big_enough, {
712 .ub2 = 0x0812345678FEDCBALL,
714 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
716 /* size relocation checks */
718 SIZE_CASE(size___diff_sz),
719 SIZE_ERR_CASE(size___err_ambiguous),
721 /* validate type existence and size relocations */
722 TYPE_BASED_CASE(type_based, {
726 .typedef_named_struct_exists = 1,
727 .typedef_anon_struct_exists = 1,
728 .typedef_struct_ptr_exists = 1,
729 .typedef_int_exists = 1,
730 .typedef_enum_exists = 1,
731 .typedef_void_ptr_exists = 1,
732 .typedef_func_proto_exists = 1,
733 .typedef_arr_exists = 1,
734 .struct_sz = sizeof(struct a_struct),
735 .union_sz = sizeof(union a_union),
736 .enum_sz = sizeof(enum an_enum),
737 .typedef_named_struct_sz = sizeof(named_struct_typedef),
738 .typedef_anon_struct_sz = sizeof(anon_struct_typedef),
739 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
740 .typedef_int_sz = sizeof(int_typedef),
741 .typedef_enum_sz = sizeof(enum_typedef),
742 .typedef_void_ptr_sz = sizeof(void_ptr_typedef),
743 .typedef_func_proto_sz = sizeof(func_proto_typedef),
744 .typedef_arr_sz = sizeof(arr_typedef),
746 TYPE_BASED_CASE(type_based___all_missing, {
749 TYPE_BASED_CASE(type_based___diff_sz, {
753 .typedef_named_struct_exists = 1,
754 .typedef_anon_struct_exists = 1,
755 .typedef_struct_ptr_exists = 1,
756 .typedef_int_exists = 1,
757 .typedef_enum_exists = 1,
758 .typedef_void_ptr_exists = 1,
759 .typedef_func_proto_exists = 1,
760 .typedef_arr_exists = 1,
761 .struct_sz = sizeof(struct a_struct___diff_sz),
762 .union_sz = sizeof(union a_union___diff_sz),
763 .enum_sz = sizeof(enum an_enum___diff_sz),
764 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
765 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
766 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
767 .typedef_int_sz = sizeof(int_typedef___diff_sz),
768 .typedef_enum_sz = sizeof(enum_typedef___diff_sz),
769 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
770 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
771 .typedef_arr_sz = sizeof(arr_typedef___diff_sz),
773 TYPE_BASED_CASE(type_based___incompat, {
775 .enum_sz = sizeof(enum an_enum),
777 TYPE_BASED_CASE(type_based___fn_wrong_args, {
779 .struct_sz = sizeof(struct a_struct),
782 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
783 TYPE_ID_CASE(type_id, setup_type_id_case_success),
784 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
786 /* Enumerator value existence and value relocations */
787 ENUMVAL_CASE(enumval, {
788 .named_val1_exists = true,
789 .named_val2_exists = true,
790 .named_val3_exists = true,
791 .anon_val1_exists = true,
792 .anon_val2_exists = true,
793 .anon_val3_exists = true,
799 ENUMVAL_CASE(enumval___diff, {
800 .named_val1_exists = true,
801 .named_val2_exists = true,
802 .named_val3_exists = true,
803 .anon_val1_exists = true,
804 .anon_val2_exists = true,
805 .anon_val3_exists = true,
811 ENUMVAL_CASE(enumval___val3_missing, {
812 .named_val1_exists = true,
813 .named_val2_exists = true,
814 .named_val3_exists = false,
815 .anon_val1_exists = true,
816 .anon_val2_exists = true,
817 .anon_val3_exists = false,
823 ENUMVAL_ERR_CASE(enumval___err_missing),
830 uint64_t my_pid_tgid;
833 static size_t roundup_page(size_t sz)
835 long page_size = sysconf(_SC_PAGE_SIZE);
836 return (sz + page_size - 1) / page_size * page_size;
839 void test_core_reloc(void)
841 const size_t mmap_sz = roundup_page(sizeof(struct data));
842 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
843 struct core_reloc_test_case *test_case;
844 const char *tp_name, *probe_name;
846 struct bpf_link *link = NULL;
847 struct bpf_map *data_map;
848 struct bpf_program *prog;
849 struct bpf_object *obj;
850 uint64_t my_pid_tgid;
852 void *mmap_data = NULL;
854 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
856 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
857 test_case = &test_cases[i];
858 if (!test__start_subtest(test_case->case_name))
861 if (test_case->needs_testmod && !env.has_testmod) {
866 if (test_case->setup) {
867 err = test_case->setup(test_case);
868 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
872 if (test_case->btf_src_file) {
873 err = access(test_case->btf_src_file, R_OK);
874 if (!ASSERT_OK(err, "btf_src_file"))
878 open_opts.btf_custom_path = test_case->btf_src_file;
879 obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts);
880 if (!ASSERT_OK_PTR(obj, "obj_open"))
883 probe_name = test_case->prog_name;
884 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
885 prog = bpf_object__find_program_by_name(obj, probe_name);
886 if (CHECK(!prog, "find_probe",
887 "prog '%s' not found\n", probe_name))
890 err = bpf_object__load(obj);
892 if (!test_case->fails)
893 ASSERT_OK(err, "obj_load");
897 data_map = bpf_object__find_map_by_name(obj, ".bss");
898 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
901 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
902 MAP_SHARED, bpf_map__fd(data_map), 0);
903 if (CHECK(mmap_data == MAP_FAILED, "mmap",
904 ".bss mmap failed: %d", errno)) {
910 memset(mmap_data, 0, sizeof(*data));
911 if (test_case->input_len)
912 memcpy(data->in, test_case->input, test_case->input_len);
913 data->my_pid_tgid = my_pid_tgid;
915 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
916 if (!ASSERT_OK_PTR(link, "attach_raw_tp"))
919 /* trigger test run */
920 if (test_case->trigger) {
921 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
932 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
935 equal = memcmp(data->out, test_case->output,
936 test_case->output_len) == 0;
937 if (CHECK(!equal, "check_result",
938 "input/output data don't match\n")) {
941 for (j = 0; j < test_case->input_len; j++) {
942 printf("input byte #%d: 0x%02hhx\n",
943 j, test_case->input[j]);
945 for (j = 0; j < test_case->output_len; j++) {
946 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
947 j, test_case->output[j], data->out[j]);
954 CHECK_FAIL(munmap(mmap_data, mmap_sz));
957 bpf_link__destroy(link);
959 bpf_object__close(obj);