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>
7 #include <sys/syscall.h>
10 static int duration = 0;
12 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
14 #define MODULES_CASE(name, pg_name, tp_name) { \
16 .bpf_obj_file = "test_core_reloc_module.o", \
17 .btf_src_file = NULL, /* find in kernel module BTFs */ \
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, \
28 .comm = "test_progs", \
29 .comm_len = sizeof("test_progs"), \
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, \
38 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
44 #define FLAVORS_CASE_COMMON(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" \
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), \
59 #define FLAVORS_ERR_CASE(name) { \
60 FLAVORS_CASE_COMMON(name), \
64 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
65 .a = { .a = { .a = 42 } }, \
66 .b = { .b = { .b = 0xc001 } }, \
69 #define NESTING_CASE_COMMON(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" \
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) \
84 #define NESTING_ERR_CASE(name) { \
85 NESTING_CASE_COMMON(name), \
87 .run_btfgen_fails = true, \
90 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
92 .b = { [1] = { [2] = { [3] = 2 } } }, \
93 .c = { [1] = { .c = 3 } }, \
94 .d = { [0] = { [0] = { .d = 4 } } }, \
97 #define ARRAYS_CASE_COMMON(name) \
99 .bpf_obj_file = "test_core_reloc_arrays.o", \
100 .btf_src_file = "btf__core_reloc_" #name ".o", \
101 .raw_tp_name = "sys_enter", \
102 .prog_name = "test_core_arrays" \
104 #define ARRAYS_CASE(name) { \
105 ARRAYS_CASE_COMMON(name), \
106 .input = ARRAYS_DATA(core_reloc_##name), \
107 .input_len = sizeof(struct core_reloc_##name), \
108 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
115 .output_len = sizeof(struct core_reloc_arrays_output) \
118 #define ARRAYS_ERR_CASE(name) { \
119 ARRAYS_CASE_COMMON(name), \
123 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
131 #define PRIMITIVES_CASE_COMMON(name) \
132 .case_name = #name, \
133 .bpf_obj_file = "test_core_reloc_primitives.o", \
134 .btf_src_file = "btf__core_reloc_" #name ".o", \
135 .raw_tp_name = "sys_enter", \
136 .prog_name = "test_core_primitives" \
138 #define PRIMITIVES_CASE(name) { \
139 PRIMITIVES_CASE_COMMON(name), \
140 .input = PRIMITIVES_DATA(core_reloc_##name), \
141 .input_len = sizeof(struct core_reloc_##name), \
142 .output = PRIMITIVES_DATA(core_reloc_primitives), \
143 .output_len = sizeof(struct core_reloc_primitives), \
146 #define PRIMITIVES_ERR_CASE(name) { \
147 PRIMITIVES_CASE_COMMON(name), \
151 #define MODS_CASE(name) { \
152 .case_name = #name, \
153 .bpf_obj_file = "test_core_reloc_mods.o", \
154 .btf_src_file = "btf__core_reloc_" #name ".o", \
155 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
165 .input_len = sizeof(struct core_reloc_##name), \
166 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
167 .a = 1, .b = 2, .c = 3, .d = 4, \
168 .e = 5, .f = 6, .g = 7, .h = 8, \
170 .output_len = sizeof(struct core_reloc_mods_output), \
171 .raw_tp_name = "sys_enter", \
172 .prog_name = "test_core_mods", \
175 #define PTR_AS_ARR_CASE(name) { \
176 .case_name = #name, \
177 .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
178 .btf_src_file = "btf__core_reloc_" #name ".o", \
179 .input = (const char *)&(struct core_reloc_##name []){ \
184 .input_len = 3 * sizeof(struct core_reloc_##name), \
185 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
188 .output_len = sizeof(struct core_reloc_ptr_as_arr), \
189 .raw_tp_name = "sys_enter", \
190 .prog_name = "test_core_ptr_as_arr", \
193 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
204 #define INTS_CASE_COMMON(name) \
205 .case_name = #name, \
206 .bpf_obj_file = "test_core_reloc_ints.o", \
207 .btf_src_file = "btf__core_reloc_" #name ".o", \
208 .raw_tp_name = "sys_enter", \
209 .prog_name = "test_core_ints"
211 #define INTS_CASE(name) { \
212 INTS_CASE_COMMON(name), \
213 .input = INTS_DATA(core_reloc_##name), \
214 .input_len = sizeof(struct core_reloc_##name), \
215 .output = INTS_DATA(core_reloc_ints), \
216 .output_len = sizeof(struct core_reloc_ints), \
219 #define INTS_ERR_CASE(name) { \
220 INTS_CASE_COMMON(name), \
224 #define FIELD_EXISTS_CASE_COMMON(name) \
225 .case_name = #name, \
226 .bpf_obj_file = "test_core_reloc_existence.o", \
227 .btf_src_file = "btf__core_reloc_" #name ".o", \
228 .raw_tp_name = "sys_enter", \
229 .prog_name = "test_core_existence"
231 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
232 .case_name = test_name_prefix#name, \
233 .bpf_obj_file = objfile, \
234 .btf_src_file = "btf__core_reloc_" #name ".o"
236 #define BITFIELDS_CASE(name, ...) { \
237 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
239 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
240 .input_len = sizeof(struct core_reloc_##name), \
241 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
243 .output_len = sizeof(struct core_reloc_bitfields_output), \
244 .raw_tp_name = "sys_enter", \
245 .prog_name = "test_core_bitfields", \
247 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
249 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
250 .input_len = sizeof(struct core_reloc_##name), \
251 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
253 .output_len = sizeof(struct core_reloc_bitfields_output), \
254 .prog_name = "test_core_bitfields_direct", \
258 #define BITFIELDS_ERR_CASE(name) { \
259 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
262 .run_btfgen_fails = true, \
263 .raw_tp_name = "sys_enter", \
264 .prog_name = "test_core_bitfields", \
266 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
269 .run_btfgen_fails = true, \
270 .prog_name = "test_core_bitfields_direct", \
273 #define SIZE_CASE_COMMON(name) \
274 .case_name = #name, \
275 .bpf_obj_file = "test_core_reloc_size.o", \
276 .btf_src_file = "btf__core_reloc_" #name ".o", \
277 .raw_tp_name = "sys_enter", \
278 .prog_name = "test_core_size"
280 #define SIZE_OUTPUT_DATA(type) \
281 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
282 .int_sz = sizeof(((type *)0)->int_field), \
283 .int_off = offsetof(type, int_field), \
284 .struct_sz = sizeof(((type *)0)->struct_field), \
285 .struct_off = offsetof(type, struct_field), \
286 .union_sz = sizeof(((type *)0)->union_field), \
287 .union_off = offsetof(type, union_field), \
288 .arr_sz = sizeof(((type *)0)->arr_field), \
289 .arr_off = offsetof(type, arr_field), \
290 .arr_elem_sz = sizeof(((type *)0)->arr_field[1]), \
291 .arr_elem_off = offsetof(type, arr_field[1]), \
292 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \
293 .ptr_off = offsetof(type, ptr_field), \
294 .enum_sz = sizeof(((type *)0)->enum_field), \
295 .enum_off = offsetof(type, enum_field), \
296 .float_sz = sizeof(((type *)0)->float_field), \
297 .float_off = offsetof(type, float_field), \
300 #define SIZE_CASE(name) { \
301 SIZE_CASE_COMMON(name), \
303 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
304 .output_len = sizeof(struct core_reloc_size_output), \
307 #define SIZE_ERR_CASE(name) { \
308 SIZE_CASE_COMMON(name), \
310 .run_btfgen_fails = true, \
313 #define TYPE_BASED_CASE_COMMON(name) \
314 .case_name = #name, \
315 .bpf_obj_file = "test_core_reloc_type_based.o", \
316 .btf_src_file = "btf__core_reloc_" #name ".o", \
317 .raw_tp_name = "sys_enter", \
318 .prog_name = "test_core_type_based"
320 #define TYPE_BASED_CASE(name, ...) { \
321 TYPE_BASED_CASE_COMMON(name), \
322 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \
324 .output_len = sizeof(struct core_reloc_type_based_output), \
327 #define TYPE_BASED_ERR_CASE(name) { \
328 TYPE_BASED_CASE_COMMON(name), \
332 #define TYPE_ID_CASE_COMMON(name) \
333 .case_name = #name, \
334 .bpf_obj_file = "test_core_reloc_type_id.o", \
335 .btf_src_file = "btf__core_reloc_" #name ".o", \
336 .raw_tp_name = "sys_enter", \
337 .prog_name = "test_core_type_id"
339 #define TYPE_ID_CASE(name, setup_fn) { \
340 TYPE_ID_CASE_COMMON(name), \
341 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \
342 .output_len = sizeof(struct core_reloc_type_id_output), \
346 #define TYPE_ID_ERR_CASE(name) { \
347 TYPE_ID_CASE_COMMON(name), \
351 #define ENUMVAL_CASE_COMMON(name) \
352 .case_name = #name, \
353 .bpf_obj_file = "test_core_reloc_enumval.o", \
354 .btf_src_file = "btf__core_reloc_" #name ".o", \
355 .raw_tp_name = "sys_enter", \
356 .prog_name = "test_core_enumval"
358 #define ENUMVAL_CASE(name, ...) { \
359 ENUMVAL_CASE_COMMON(name), \
360 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \
362 .output_len = sizeof(struct core_reloc_enumval_output), \
365 #define ENUMVAL_ERR_CASE(name) { \
366 ENUMVAL_CASE_COMMON(name), \
370 #define ENUM64VAL_CASE_COMMON(name) \
371 .case_name = #name, \
372 .bpf_obj_file = "test_core_reloc_enum64val.o", \
373 .btf_src_file = "btf__core_reloc_" #name ".o", \
374 .raw_tp_name = "sys_enter", \
375 .prog_name = "test_core_enum64val"
377 #define ENUM64VAL_CASE(name, ...) { \
378 ENUM64VAL_CASE_COMMON(name), \
379 .output = STRUCT_TO_CHAR_PTR(core_reloc_enum64val_output) \
381 .output_len = sizeof(struct core_reloc_enum64val_output), \
384 #define ENUM64VAL_ERR_CASE(name) { \
385 ENUM64VAL_CASE_COMMON(name), \
389 struct core_reloc_test_case;
391 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
392 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
394 struct core_reloc_test_case {
395 const char *case_name;
396 const char *bpf_obj_file;
397 const char *btf_src_file;
403 bool run_btfgen_fails;
405 bool relaxed_core_relocs;
406 const char *prog_name;
407 const char *raw_tp_name;
409 trigger_test_fn trigger;
412 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
416 id = btf__find_by_name_kind(btf, name, kind);
417 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
423 static int setup_type_id_case_local(struct core_reloc_test_case *test)
425 struct core_reloc_type_id_output *exp = (void *)test->output;
426 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
427 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
428 const struct btf_type *t;
432 if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) {
433 btf__free(local_btf);
438 exp->local_anon_struct = -1;
439 exp->local_anon_union = -1;
440 exp->local_anon_enum = -1;
441 exp->local_anon_func_proto_ptr = -1;
442 exp->local_anon_void_ptr = -1;
443 exp->local_anon_arr = -1;
445 for (i = 1; i < btf__type_cnt(local_btf); i++)
447 t = btf__type_by_id(local_btf, i);
448 /* we are interested only in anonymous types */
452 if (btf_is_struct(t) && btf_vlen(t) &&
453 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
454 strcmp(name, "marker_field") == 0) {
455 exp->local_anon_struct = i;
456 } else if (btf_is_union(t) && btf_vlen(t) &&
457 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
458 strcmp(name, "marker_field") == 0) {
459 exp->local_anon_union = i;
460 } else if (btf_is_enum(t) && btf_vlen(t) &&
461 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
462 strcmp(name, "MARKER_ENUM_VAL") == 0) {
463 exp->local_anon_enum = i;
464 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
465 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
466 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
467 strcmp(name, "_Bool") == 0) {
468 /* ptr -> func_proto -> _Bool */
469 exp->local_anon_func_proto_ptr = i;
470 } else if (btf_is_void(t)) {
472 exp->local_anon_void_ptr = i;
474 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
475 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
476 strcmp(name, "_Bool") == 0) {
478 exp->local_anon_arr = i;
482 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
483 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
484 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
485 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
486 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
487 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
488 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
490 btf__free(local_btf);
495 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
496 struct core_reloc_type_id_output *exp = (void *)test->output;
497 struct btf *targ_btf;
500 err = setup_type_id_case_local(test);
504 targ_btf = btf__parse(test->btf_src_file, NULL);
506 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
507 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
508 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
509 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
510 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
511 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
512 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
518 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
520 struct core_reloc_type_id_output *exp = (void *)test->output;
523 err = setup_type_id_case_local(test);
527 exp->targ_struct = 0;
531 exp->targ_struct_typedef = 0;
532 exp->targ_func_proto_typedef = 0;
533 exp->targ_arr_typedef = 0;
538 static int __trigger_module_test_read(const struct core_reloc_test_case *test)
540 struct core_reloc_module_output *exp = (void *)test->output;
542 trigger_module_test_read(exp->len);
546 static const struct core_reloc_test_case test_cases[] = {
547 /* validate we can find kernel image and use its BTF for relocs */
549 .case_name = "kernel",
550 .bpf_obj_file = "test_core_reloc_kernel.o",
551 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
554 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
555 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
556 .comm = "test_progs",
557 .comm_len = sizeof("test_progs"),
559 .output_len = sizeof(struct core_reloc_kernel_output),
560 .raw_tp_name = "sys_enter",
561 .prog_name = "test_core_kernel",
564 /* validate we can find kernel module BTF types for relocs/attach */
565 MODULES_CASE("module_probed", "test_core_module_probed", "bpf_testmod_test_read"),
566 MODULES_CASE("module_direct", "test_core_module_direct", NULL),
568 /* validate BPF program can use multiple flavors to match against
569 * single target BTF type
571 FLAVORS_CASE(flavors),
573 FLAVORS_ERR_CASE(flavors__err_wrong_name),
575 /* various struct/enum nesting and resolution scenarios */
576 NESTING_CASE(nesting),
577 NESTING_CASE(nesting___anon_embed),
578 NESTING_CASE(nesting___struct_union_mixup),
579 NESTING_CASE(nesting___extra_nesting),
580 NESTING_CASE(nesting___dup_compat_types),
582 NESTING_ERR_CASE(nesting___err_missing_field),
583 NESTING_ERR_CASE(nesting___err_array_field),
584 NESTING_ERR_CASE(nesting___err_missing_container),
585 NESTING_ERR_CASE(nesting___err_nonstruct_container),
586 NESTING_ERR_CASE(nesting___err_array_container),
587 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
588 NESTING_ERR_CASE(nesting___err_partial_match_dups),
589 NESTING_ERR_CASE(nesting___err_too_deep),
591 /* various array access relocation scenarios */
593 ARRAYS_CASE(arrays___diff_arr_dim),
594 ARRAYS_CASE(arrays___diff_arr_val_sz),
595 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
596 ARRAYS_CASE(arrays___fixed_arr),
598 ARRAYS_ERR_CASE(arrays___err_too_small),
599 ARRAYS_ERR_CASE(arrays___err_too_shallow),
600 ARRAYS_ERR_CASE(arrays___err_non_array),
601 ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
602 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
604 /* enum/ptr/int handling scenarios */
605 PRIMITIVES_CASE(primitives),
606 PRIMITIVES_CASE(primitives___diff_enum_def),
607 PRIMITIVES_CASE(primitives___diff_func_proto),
608 PRIMITIVES_CASE(primitives___diff_ptr_type),
610 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
611 PRIMITIVES_ERR_CASE(primitives___err_non_int),
612 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
614 /* const/volatile/restrict and typedefs scenarios */
616 MODS_CASE(mods___mod_swap),
617 MODS_CASE(mods___typedefs),
619 /* handling "ptr is an array" semantics */
620 PTR_AS_ARR_CASE(ptr_as_arr),
621 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
623 /* int signedness/sizing/bitfield handling */
625 INTS_CASE(ints___bool),
626 INTS_CASE(ints___reverse_sign),
628 /* validate edge cases of capturing relocations */
631 .bpf_obj_file = "test_core_reloc_misc.o",
632 .btf_src_file = "btf__core_reloc_misc.o",
633 .input = (const char *)&(struct core_reloc_misc_extensible[]){
635 { .a = 2 }, /* not read */
638 .input_len = 4 * sizeof(int),
639 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
642 .c = 0, /* BUG in clang, should be 3 */
644 .output_len = sizeof(struct core_reloc_misc_output),
645 .raw_tp_name = "sys_enter",
646 .prog_name = "test_core_misc",
649 /* validate field existence checks */
651 FIELD_EXISTS_CASE_COMMON(existence),
652 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
659 .input_len = sizeof(struct core_reloc_existence),
660 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
672 .output_len = sizeof(struct core_reloc_existence_output),
675 FIELD_EXISTS_CASE_COMMON(existence___minimal),
676 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
679 .input_len = sizeof(struct core_reloc_existence___minimal),
680 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
687 .b_value = 0xff000002u,
688 .c_value = 0xff000003u,
689 .arr_value = 0xff000004u,
690 .s_value = 0xff000005u,
692 .output_len = sizeof(struct core_reloc_existence_output),
695 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
696 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
698 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
699 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
705 .a_value = 0xff000001u,
706 .b_value = 0xff000002u,
707 .c_value = 0xff000003u,
708 .arr_value = 0xff000004u,
709 .s_value = 0xff000005u,
711 .output_len = sizeof(struct core_reloc_existence_output),
714 /* bitfield relocation checks */
715 BITFIELDS_CASE(bitfields, {
724 BITFIELDS_CASE(bitfields___bit_sz_change, {
731 .s32 = -0x3FEDCBA987654321LL,
733 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
734 .ub1 = 0xFEDCBA9876543210LL,
736 .ub7 = -0x7EDCBA987654321LL,
737 .sb4 = -0x6123456789ABCDELL,
740 .s32 = 0x0ADEADBEEFBADB0BLL,
742 BITFIELDS_CASE(bitfields___just_big_enough, {
744 .ub2 = 0x0812345678FEDCBALL,
746 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
748 /* field size and offset relocation checks */
750 SIZE_CASE(size___diff_sz),
751 SIZE_CASE(size___diff_offs),
752 SIZE_ERR_CASE(size___err_ambiguous),
754 /* validate type existence, match, and size relocations */
755 TYPE_BASED_CASE(type_based, {
759 .typedef_named_struct_exists = 1,
760 .typedef_anon_struct_exists = 1,
761 .typedef_struct_ptr_exists = 1,
762 .typedef_int_exists = 1,
763 .typedef_enum_exists = 1,
764 .typedef_void_ptr_exists = 1,
765 .typedef_func_proto_exists = 1,
766 .typedef_arr_exists = 1,
771 .typedef_named_struct_matches = 1,
772 .typedef_anon_struct_matches = 1,
773 .typedef_struct_ptr_matches = 1,
774 .typedef_int_matches = 1,
775 .typedef_enum_matches = 1,
776 .typedef_void_ptr_matches = 1,
777 .typedef_func_proto_matches = 1,
778 .typedef_arr_matches = 1,
780 .struct_sz = sizeof(struct a_struct),
781 .union_sz = sizeof(union a_union),
782 .enum_sz = sizeof(enum an_enum),
783 .typedef_named_struct_sz = sizeof(named_struct_typedef),
784 .typedef_anon_struct_sz = sizeof(anon_struct_typedef),
785 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
786 .typedef_int_sz = sizeof(int_typedef),
787 .typedef_enum_sz = sizeof(enum_typedef),
788 .typedef_void_ptr_sz = sizeof(void_ptr_typedef),
789 .typedef_func_proto_sz = sizeof(func_proto_typedef),
790 .typedef_arr_sz = sizeof(arr_typedef),
792 TYPE_BASED_CASE(type_based___all_missing, {
795 TYPE_BASED_CASE(type_based___diff_sz, {
799 .typedef_named_struct_exists = 1,
800 .typedef_anon_struct_exists = 1,
801 .typedef_struct_ptr_exists = 1,
802 .typedef_int_exists = 1,
803 .typedef_enum_exists = 1,
804 .typedef_void_ptr_exists = 1,
805 .typedef_func_proto_exists = 1,
806 .typedef_arr_exists = 1,
811 .typedef_named_struct_matches = 0,
812 .typedef_anon_struct_matches = 0,
813 .typedef_struct_ptr_matches = 1,
814 .typedef_int_matches = 0,
815 .typedef_enum_matches = 0,
816 .typedef_void_ptr_matches = 1,
817 .typedef_func_proto_matches = 0,
818 .typedef_arr_matches = 0,
820 .struct_sz = sizeof(struct a_struct___diff_sz),
821 .union_sz = sizeof(union a_union___diff_sz),
822 .enum_sz = sizeof(enum an_enum___diff_sz),
823 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
824 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
825 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
826 .typedef_int_sz = sizeof(int_typedef___diff_sz),
827 .typedef_enum_sz = sizeof(enum_typedef___diff_sz),
828 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
829 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
830 .typedef_arr_sz = sizeof(arr_typedef___diff_sz),
832 TYPE_BASED_CASE(type_based___incompat, {
835 .enum_sz = sizeof(enum an_enum),
837 TYPE_BASED_CASE(type_based___fn_wrong_args, {
840 .struct_sz = sizeof(struct a_struct),
843 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
844 TYPE_ID_CASE(type_id, setup_type_id_case_success),
845 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
847 /* Enumerator value existence and value relocations */
848 ENUMVAL_CASE(enumval, {
849 .named_val1_exists = true,
850 .named_val2_exists = true,
851 .named_val3_exists = true,
852 .anon_val1_exists = true,
853 .anon_val2_exists = true,
854 .anon_val3_exists = true,
860 ENUMVAL_CASE(enumval___diff, {
861 .named_val1_exists = true,
862 .named_val2_exists = true,
863 .named_val3_exists = true,
864 .anon_val1_exists = true,
865 .anon_val2_exists = true,
866 .anon_val3_exists = true,
872 ENUMVAL_CASE(enumval___val3_missing, {
873 .named_val1_exists = true,
874 .named_val2_exists = true,
875 .named_val3_exists = false,
876 .anon_val1_exists = true,
877 .anon_val2_exists = true,
878 .anon_val3_exists = false,
884 ENUMVAL_ERR_CASE(enumval___err_missing),
886 /* 64bit enumerator value existence and value relocations */
887 ENUM64VAL_CASE(enum64val, {
888 .unsigned_val1_exists = true,
889 .unsigned_val2_exists = true,
890 .unsigned_val3_exists = true,
891 .signed_val1_exists = true,
892 .signed_val2_exists = true,
893 .signed_val3_exists = true,
894 .unsigned_val1 = 0x1ffffffffULL,
895 .unsigned_val2 = 0x2,
896 .signed_val1 = 0x1ffffffffLL,
899 ENUM64VAL_CASE(enum64val___diff, {
900 .unsigned_val1_exists = true,
901 .unsigned_val2_exists = true,
902 .unsigned_val3_exists = true,
903 .signed_val1_exists = true,
904 .signed_val2_exists = true,
905 .signed_val3_exists = true,
906 .unsigned_val1 = 0x101ffffffffULL,
907 .unsigned_val2 = 0x202ffffffffULL,
911 ENUM64VAL_CASE(enum64val___val3_missing, {
912 .unsigned_val1_exists = true,
913 .unsigned_val2_exists = true,
914 .unsigned_val3_exists = false,
915 .signed_val1_exists = true,
916 .signed_val2_exists = true,
917 .signed_val3_exists = false,
918 .unsigned_val1 = 0x111ffffffffULL,
919 .unsigned_val2 = 0x222,
920 .signed_val1 = 0x111ffffffffLL,
923 ENUM64VAL_ERR_CASE(enum64val___err_missing),
930 uint64_t my_pid_tgid;
933 static size_t roundup_page(size_t sz)
935 long page_size = sysconf(_SC_PAGE_SIZE);
936 return (sz + page_size - 1) / page_size * page_size;
939 static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objpath)
944 n = snprintf(command, sizeof(command),
945 "./bpftool gen min_core_btf %s %s %s",
946 src_btf, dst_btf, objpath);
947 if (n < 0 || n >= sizeof(command))
950 return system(command);
953 static void run_core_reloc_tests(bool use_btfgen)
955 const size_t mmap_sz = roundup_page(sizeof(struct data));
956 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
957 struct core_reloc_test_case *test_case, test_case_copy;
958 const char *tp_name, *probe_name;
959 int err, i, equal, fd;
960 struct bpf_link *link = NULL;
961 struct bpf_map *data_map;
962 struct bpf_program *prog;
963 struct bpf_object *obj;
964 uint64_t my_pid_tgid;
966 void *mmap_data = NULL;
968 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
970 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
971 char btf_file[] = "/tmp/core_reloc.btf.XXXXXX";
973 test_case_copy = test_cases[i];
974 test_case = &test_case_copy;
976 if (!test__start_subtest(test_case->case_name))
979 if (test_case->needs_testmod && !env.has_testmod) {
984 /* generate a "minimal" BTF file and use it as source */
987 if (!test_case->btf_src_file || test_case->run_btfgen_fails) {
992 fd = mkstemp(btf_file);
993 if (!ASSERT_GE(fd, 0, "btf_tmp"))
995 close(fd); /* we only need the path */
996 err = run_btfgen(test_case->btf_src_file, btf_file,
997 test_case->bpf_obj_file);
998 if (!ASSERT_OK(err, "run_btfgen"))
1001 test_case->btf_src_file = btf_file;
1004 if (test_case->setup) {
1005 err = test_case->setup(test_case);
1006 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
1010 if (test_case->btf_src_file) {
1011 err = access(test_case->btf_src_file, R_OK);
1012 if (!ASSERT_OK(err, "btf_src_file"))
1016 open_opts.btf_custom_path = test_case->btf_src_file;
1017 obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts);
1018 if (!ASSERT_OK_PTR(obj, "obj_open"))
1021 probe_name = test_case->prog_name;
1022 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
1023 prog = bpf_object__find_program_by_name(obj, probe_name);
1024 if (CHECK(!prog, "find_probe",
1025 "prog '%s' not found\n", probe_name))
1028 err = bpf_object__load(obj);
1030 if (!test_case->fails)
1031 ASSERT_OK(err, "obj_load");
1035 data_map = bpf_object__find_map_by_name(obj, ".bss");
1036 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
1039 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
1040 MAP_SHARED, bpf_map__fd(data_map), 0);
1041 if (CHECK(mmap_data == MAP_FAILED, "mmap",
1042 ".bss mmap failed: %d", errno)) {
1048 memset(mmap_data, 0, sizeof(*data));
1049 if (test_case->input_len)
1050 memcpy(data->in, test_case->input, test_case->input_len);
1051 data->my_pid_tgid = my_pid_tgid;
1053 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
1054 if (!ASSERT_OK_PTR(link, "attach_raw_tp"))
1057 /* trigger test run */
1058 if (test_case->trigger) {
1059 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
1070 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
1073 equal = memcmp(data->out, test_case->output,
1074 test_case->output_len) == 0;
1075 if (CHECK(!equal, "check_result",
1076 "input/output data don't match\n")) {
1079 for (j = 0; j < test_case->input_len; j++) {
1080 printf("input byte #%d: 0x%02hhx\n",
1081 j, test_case->input[j]);
1083 for (j = 0; j < test_case->output_len; j++) {
1084 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
1085 j, test_case->output[j], data->out[j]);
1092 CHECK_FAIL(munmap(mmap_data, mmap_sz));
1096 remove(test_case->btf_src_file);
1097 bpf_link__destroy(link);
1099 bpf_object__close(obj);
1103 void test_core_reloc(void)
1105 run_core_reloc_tests(false);
1108 void test_core_reloc_btfgen(void)
1110 run_core_reloc_tests(true);