1 // SPDX-License-Identifier: GPL-2.0
3 #include <test_progs.h>
4 #include "progs/core_reloc_types.h"
5 #include "bpf_testmod/bpf_testmod.h"
6 #include <linux/limits.h>
8 #include <sys/syscall.h>
11 static int duration = 0;
13 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
15 #define MODULES_CASE(name, pg_name, tp_name) { \
17 .bpf_obj_file = "test_core_reloc_module.bpf.o", \
18 .btf_src_file = NULL, /* find in kernel module BTFs */ \
21 .output = STRUCT_TO_CHAR_PTR(core_reloc_module_output) { \
22 .read_ctx_sz = sizeof(struct bpf_testmod_test_read_ctx),\
23 .read_ctx_exists = true, \
29 .comm = "test_progs", \
30 .comm_len = sizeof("test_progs"), \
32 .output_len = sizeof(struct core_reloc_module_output), \
33 .prog_name = pg_name, \
34 .raw_tp_name = tp_name, \
35 .trigger = __trigger_module_test_read, \
36 .needs_testmod = true, \
39 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
45 #define FLAVORS_CASE_COMMON(name) \
47 .bpf_obj_file = "test_core_reloc_flavors.bpf.o", \
48 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
49 .raw_tp_name = "sys_enter", \
50 .prog_name = "test_core_flavors" \
52 #define FLAVORS_CASE(name) { \
53 FLAVORS_CASE_COMMON(name), \
54 .input = FLAVORS_DATA(core_reloc_##name), \
55 .input_len = sizeof(struct core_reloc_##name), \
56 .output = FLAVORS_DATA(core_reloc_flavors), \
57 .output_len = sizeof(struct core_reloc_flavors), \
60 #define FLAVORS_ERR_CASE(name) { \
61 FLAVORS_CASE_COMMON(name), \
65 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
66 .a = { .a = { .a = 42 } }, \
67 .b = { .b = { .b = 0xc001 } }, \
70 #define NESTING_CASE_COMMON(name) \
72 .bpf_obj_file = "test_core_reloc_nesting.bpf.o", \
73 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
74 .raw_tp_name = "sys_enter", \
75 .prog_name = "test_core_nesting" \
77 #define NESTING_CASE(name) { \
78 NESTING_CASE_COMMON(name), \
79 .input = NESTING_DATA(core_reloc_##name), \
80 .input_len = sizeof(struct core_reloc_##name), \
81 .output = NESTING_DATA(core_reloc_nesting), \
82 .output_len = sizeof(struct core_reloc_nesting) \
85 #define NESTING_ERR_CASE(name) { \
86 NESTING_CASE_COMMON(name), \
88 .run_btfgen_fails = true, \
91 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
93 .b = { [1] = { [2] = { [3] = 2 } } }, \
94 .c = { [1] = { .c = 3 } }, \
95 .d = { [0] = { [0] = { .d = 4 } } }, \
98 #define ARRAYS_CASE_COMMON(name) \
100 .bpf_obj_file = "test_core_reloc_arrays.bpf.o", \
101 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
102 .raw_tp_name = "sys_enter", \
103 .prog_name = "test_core_arrays" \
105 #define ARRAYS_CASE(name) { \
106 ARRAYS_CASE_COMMON(name), \
107 .input = ARRAYS_DATA(core_reloc_##name), \
108 .input_len = sizeof(struct core_reloc_##name), \
109 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
116 .output_len = sizeof(struct core_reloc_arrays_output) \
119 #define ARRAYS_ERR_CASE(name) { \
120 ARRAYS_CASE_COMMON(name), \
124 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
132 #define PRIMITIVES_CASE_COMMON(name) \
133 .case_name = #name, \
134 .bpf_obj_file = "test_core_reloc_primitives.bpf.o", \
135 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
136 .raw_tp_name = "sys_enter", \
137 .prog_name = "test_core_primitives" \
139 #define PRIMITIVES_CASE(name) { \
140 PRIMITIVES_CASE_COMMON(name), \
141 .input = PRIMITIVES_DATA(core_reloc_##name), \
142 .input_len = sizeof(struct core_reloc_##name), \
143 .output = PRIMITIVES_DATA(core_reloc_primitives), \
144 .output_len = sizeof(struct core_reloc_primitives), \
147 #define PRIMITIVES_ERR_CASE(name) { \
148 PRIMITIVES_CASE_COMMON(name), \
152 #define MODS_CASE(name) { \
153 .case_name = #name, \
154 .bpf_obj_file = "test_core_reloc_mods.bpf.o", \
155 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
156 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
166 .input_len = sizeof(struct core_reloc_##name), \
167 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
168 .a = 1, .b = 2, .c = 3, .d = 4, \
169 .e = 5, .f = 6, .g = 7, .h = 8, \
171 .output_len = sizeof(struct core_reloc_mods_output), \
172 .raw_tp_name = "sys_enter", \
173 .prog_name = "test_core_mods", \
176 #define PTR_AS_ARR_CASE(name) { \
177 .case_name = #name, \
178 .bpf_obj_file = "test_core_reloc_ptr_as_arr.bpf.o", \
179 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
180 .input = (const char *)&(struct core_reloc_##name []){ \
185 .input_len = 3 * sizeof(struct core_reloc_##name), \
186 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
189 .output_len = sizeof(struct core_reloc_ptr_as_arr), \
190 .raw_tp_name = "sys_enter", \
191 .prog_name = "test_core_ptr_as_arr", \
194 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
205 #define INTS_CASE_COMMON(name) \
206 .case_name = #name, \
207 .bpf_obj_file = "test_core_reloc_ints.bpf.o", \
208 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
209 .raw_tp_name = "sys_enter", \
210 .prog_name = "test_core_ints"
212 #define INTS_CASE(name) { \
213 INTS_CASE_COMMON(name), \
214 .input = INTS_DATA(core_reloc_##name), \
215 .input_len = sizeof(struct core_reloc_##name), \
216 .output = INTS_DATA(core_reloc_ints), \
217 .output_len = sizeof(struct core_reloc_ints), \
220 #define INTS_ERR_CASE(name) { \
221 INTS_CASE_COMMON(name), \
225 #define FIELD_EXISTS_CASE_COMMON(name) \
226 .case_name = #name, \
227 .bpf_obj_file = "test_core_reloc_existence.bpf.o", \
228 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
229 .raw_tp_name = "sys_enter", \
230 .prog_name = "test_core_existence"
232 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
233 .case_name = test_name_prefix#name, \
234 .bpf_obj_file = objfile, \
235 .btf_src_file = "btf__core_reloc_" #name ".bpf.o"
237 #define BITFIELDS_CASE(name, ...) { \
238 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \
240 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
241 .input_len = sizeof(struct core_reloc_##name), \
242 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
244 .output_len = sizeof(struct core_reloc_bitfields_output), \
245 .raw_tp_name = "sys_enter", \
246 .prog_name = "test_core_bitfields", \
248 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \
250 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
251 .input_len = sizeof(struct core_reloc_##name), \
252 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
254 .output_len = sizeof(struct core_reloc_bitfields_output), \
255 .prog_name = "test_core_bitfields_direct", \
259 #define BITFIELDS_ERR_CASE(name) { \
260 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \
263 .run_btfgen_fails = true, \
264 .raw_tp_name = "sys_enter", \
265 .prog_name = "test_core_bitfields", \
267 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \
270 .run_btfgen_fails = true, \
271 .prog_name = "test_core_bitfields_direct", \
274 #define SIZE_CASE_COMMON(name) \
275 .case_name = #name, \
276 .bpf_obj_file = "test_core_reloc_size.bpf.o", \
277 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
278 .raw_tp_name = "sys_enter", \
279 .prog_name = "test_core_size"
281 #define SIZE_OUTPUT_DATA(type) \
282 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
283 .int_sz = sizeof(((type *)0)->int_field), \
284 .int_off = offsetof(type, int_field), \
285 .struct_sz = sizeof(((type *)0)->struct_field), \
286 .struct_off = offsetof(type, struct_field), \
287 .union_sz = sizeof(((type *)0)->union_field), \
288 .union_off = offsetof(type, union_field), \
289 .arr_sz = sizeof(((type *)0)->arr_field), \
290 .arr_off = offsetof(type, arr_field), \
291 .arr_elem_sz = sizeof(((type *)0)->arr_field[1]), \
292 .arr_elem_off = offsetof(type, arr_field[1]), \
293 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \
294 .ptr_off = offsetof(type, ptr_field), \
295 .enum_sz = sizeof(((type *)0)->enum_field), \
296 .enum_off = offsetof(type, enum_field), \
297 .float_sz = sizeof(((type *)0)->float_field), \
298 .float_off = offsetof(type, float_field), \
301 #define SIZE_CASE(name) { \
302 SIZE_CASE_COMMON(name), \
304 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
305 .output_len = sizeof(struct core_reloc_size_output), \
308 #define SIZE_ERR_CASE(name) { \
309 SIZE_CASE_COMMON(name), \
311 .run_btfgen_fails = true, \
314 #define TYPE_BASED_CASE_COMMON(name) \
315 .case_name = #name, \
316 .bpf_obj_file = "test_core_reloc_type_based.bpf.o", \
317 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
318 .raw_tp_name = "sys_enter", \
319 .prog_name = "test_core_type_based"
321 #define TYPE_BASED_CASE(name, ...) { \
322 TYPE_BASED_CASE_COMMON(name), \
323 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \
325 .output_len = sizeof(struct core_reloc_type_based_output), \
328 #define TYPE_BASED_ERR_CASE(name) { \
329 TYPE_BASED_CASE_COMMON(name), \
333 #define TYPE_ID_CASE_COMMON(name) \
334 .case_name = #name, \
335 .bpf_obj_file = "test_core_reloc_type_id.bpf.o", \
336 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
337 .raw_tp_name = "sys_enter", \
338 .prog_name = "test_core_type_id"
340 #define TYPE_ID_CASE(name, setup_fn) { \
341 TYPE_ID_CASE_COMMON(name), \
342 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \
343 .output_len = sizeof(struct core_reloc_type_id_output), \
347 #define TYPE_ID_ERR_CASE(name) { \
348 TYPE_ID_CASE_COMMON(name), \
352 #define ENUMVAL_CASE_COMMON(name) \
353 .case_name = #name, \
354 .bpf_obj_file = "test_core_reloc_enumval.bpf.o", \
355 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
356 .raw_tp_name = "sys_enter", \
357 .prog_name = "test_core_enumval"
359 #define ENUMVAL_CASE(name, ...) { \
360 ENUMVAL_CASE_COMMON(name), \
361 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \
363 .output_len = sizeof(struct core_reloc_enumval_output), \
366 #define ENUMVAL_ERR_CASE(name) { \
367 ENUMVAL_CASE_COMMON(name), \
371 #define ENUM64VAL_CASE_COMMON(name) \
372 .case_name = #name, \
373 .bpf_obj_file = "test_core_reloc_enum64val.bpf.o", \
374 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \
375 .raw_tp_name = "sys_enter", \
376 .prog_name = "test_core_enum64val"
378 #define ENUM64VAL_CASE(name, ...) { \
379 ENUM64VAL_CASE_COMMON(name), \
380 .output = STRUCT_TO_CHAR_PTR(core_reloc_enum64val_output) \
382 .output_len = sizeof(struct core_reloc_enum64val_output), \
385 #define ENUM64VAL_ERR_CASE(name) { \
386 ENUM64VAL_CASE_COMMON(name), \
390 struct core_reloc_test_case;
392 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
393 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
395 struct core_reloc_test_case {
396 const char *case_name;
397 const char *bpf_obj_file;
398 const char *btf_src_file;
404 bool run_btfgen_fails;
406 bool relaxed_core_relocs;
407 const char *prog_name;
408 const char *raw_tp_name;
410 trigger_test_fn trigger;
413 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
417 id = btf__find_by_name_kind(btf, name, kind);
418 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
424 static int setup_type_id_case_local(struct core_reloc_test_case *test)
426 struct core_reloc_type_id_output *exp = (void *)test->output;
427 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
428 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
429 const struct btf_type *t;
433 if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) {
434 btf__free(local_btf);
439 exp->local_anon_struct = -1;
440 exp->local_anon_union = -1;
441 exp->local_anon_enum = -1;
442 exp->local_anon_func_proto_ptr = -1;
443 exp->local_anon_void_ptr = -1;
444 exp->local_anon_arr = -1;
446 for (i = 1; i < btf__type_cnt(local_btf); i++)
448 t = btf__type_by_id(local_btf, i);
449 /* we are interested only in anonymous types */
453 if (btf_is_struct(t) && btf_vlen(t) &&
454 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
455 strcmp(name, "marker_field") == 0) {
456 exp->local_anon_struct = i;
457 } else if (btf_is_union(t) && btf_vlen(t) &&
458 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
459 strcmp(name, "marker_field") == 0) {
460 exp->local_anon_union = i;
461 } else if (btf_is_enum(t) && btf_vlen(t) &&
462 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
463 strcmp(name, "MARKER_ENUM_VAL") == 0) {
464 exp->local_anon_enum = i;
465 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
466 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
467 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
468 strcmp(name, "_Bool") == 0) {
469 /* ptr -> func_proto -> _Bool */
470 exp->local_anon_func_proto_ptr = i;
471 } else if (btf_is_void(t)) {
473 exp->local_anon_void_ptr = i;
475 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
476 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
477 strcmp(name, "_Bool") == 0) {
479 exp->local_anon_arr = i;
483 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
484 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
485 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
486 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
487 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
488 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
489 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
491 btf__free(local_btf);
496 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
497 struct core_reloc_type_id_output *exp = (void *)test->output;
498 struct btf *targ_btf;
501 err = setup_type_id_case_local(test);
505 targ_btf = btf__parse(test->btf_src_file, NULL);
507 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
508 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
509 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
510 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
511 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
512 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
513 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
519 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
521 struct core_reloc_type_id_output *exp = (void *)test->output;
524 err = setup_type_id_case_local(test);
528 exp->targ_struct = 0;
532 exp->targ_struct_typedef = 0;
533 exp->targ_func_proto_typedef = 0;
534 exp->targ_arr_typedef = 0;
539 static int __trigger_module_test_read(const struct core_reloc_test_case *test)
541 struct core_reloc_module_output *exp = (void *)test->output;
543 trigger_module_test_read(exp->len);
547 static const struct core_reloc_test_case test_cases[] = {
548 /* validate we can find kernel image and use its BTF for relocs */
550 .case_name = "kernel",
551 .bpf_obj_file = "test_core_reloc_kernel.bpf.o",
552 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
555 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
556 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
557 .comm = "test_progs",
558 .comm_len = sizeof("test_progs"),
559 .local_task_struct_matches = true,
561 .output_len = sizeof(struct core_reloc_kernel_output),
562 .raw_tp_name = "sys_enter",
563 .prog_name = "test_core_kernel",
566 /* validate we can find kernel module BTF types for relocs/attach */
567 MODULES_CASE("module_probed", "test_core_module_probed", "bpf_testmod_test_read"),
568 MODULES_CASE("module_direct", "test_core_module_direct", NULL),
570 /* validate BPF program can use multiple flavors to match against
571 * single target BTF type
573 FLAVORS_CASE(flavors),
575 FLAVORS_ERR_CASE(flavors__err_wrong_name),
577 /* various struct/enum nesting and resolution scenarios */
578 NESTING_CASE(nesting),
579 NESTING_CASE(nesting___anon_embed),
580 NESTING_CASE(nesting___struct_union_mixup),
581 NESTING_CASE(nesting___extra_nesting),
582 NESTING_CASE(nesting___dup_compat_types),
584 NESTING_ERR_CASE(nesting___err_missing_field),
585 NESTING_ERR_CASE(nesting___err_array_field),
586 NESTING_ERR_CASE(nesting___err_missing_container),
587 NESTING_ERR_CASE(nesting___err_nonstruct_container),
588 NESTING_ERR_CASE(nesting___err_array_container),
589 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
590 NESTING_ERR_CASE(nesting___err_partial_match_dups),
591 NESTING_ERR_CASE(nesting___err_too_deep),
593 /* various array access relocation scenarios */
595 ARRAYS_CASE(arrays___diff_arr_dim),
596 ARRAYS_CASE(arrays___diff_arr_val_sz),
597 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
598 ARRAYS_CASE(arrays___fixed_arr),
600 ARRAYS_ERR_CASE(arrays___err_too_small),
601 ARRAYS_ERR_CASE(arrays___err_too_shallow),
602 ARRAYS_ERR_CASE(arrays___err_non_array),
603 ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
604 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
606 /* enum/ptr/int handling scenarios */
607 PRIMITIVES_CASE(primitives),
608 PRIMITIVES_CASE(primitives___diff_enum_def),
609 PRIMITIVES_CASE(primitives___diff_func_proto),
610 PRIMITIVES_CASE(primitives___diff_ptr_type),
612 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
613 PRIMITIVES_ERR_CASE(primitives___err_non_int),
614 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
616 /* const/volatile/restrict and typedefs scenarios */
618 MODS_CASE(mods___mod_swap),
619 MODS_CASE(mods___typedefs),
621 /* handling "ptr is an array" semantics */
622 PTR_AS_ARR_CASE(ptr_as_arr),
623 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
625 /* int signedness/sizing/bitfield handling */
627 INTS_CASE(ints___bool),
628 INTS_CASE(ints___reverse_sign),
630 /* validate edge cases of capturing relocations */
633 .bpf_obj_file = "test_core_reloc_misc.bpf.o",
634 .btf_src_file = "btf__core_reloc_misc.bpf.o",
635 .input = (const char *)&(struct core_reloc_misc_extensible[]){
637 { .a = 2 }, /* not read */
640 .input_len = 4 * sizeof(int),
641 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
644 .c = 0, /* BUG in clang, should be 3 */
646 .output_len = sizeof(struct core_reloc_misc_output),
647 .raw_tp_name = "sys_enter",
648 .prog_name = "test_core_misc",
651 /* validate field existence checks */
653 FIELD_EXISTS_CASE_COMMON(existence),
654 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
661 .input_len = sizeof(struct core_reloc_existence),
662 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
674 .output_len = sizeof(struct core_reloc_existence_output),
677 FIELD_EXISTS_CASE_COMMON(existence___minimal),
678 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
681 .input_len = sizeof(struct core_reloc_existence___minimal),
682 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
689 .b_value = 0xff000002u,
690 .c_value = 0xff000003u,
691 .arr_value = 0xff000004u,
692 .s_value = 0xff000005u,
694 .output_len = sizeof(struct core_reloc_existence_output),
697 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
698 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
700 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
701 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
707 .a_value = 0xff000001u,
708 .b_value = 0xff000002u,
709 .c_value = 0xff000003u,
710 .arr_value = 0xff000004u,
711 .s_value = 0xff000005u,
713 .output_len = sizeof(struct core_reloc_existence_output),
716 /* bitfield relocation checks */
717 BITFIELDS_CASE(bitfields, {
726 BITFIELDS_CASE(bitfields___bit_sz_change, {
733 .s32 = -0x3FEDCBA987654321LL,
735 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
736 .ub1 = 0xFEDCBA9876543210LL,
738 .ub7 = -0x7EDCBA987654321LL,
739 .sb4 = -0x6123456789ABCDELL,
742 .s32 = 0x0ADEADBEEFBADB0BLL,
744 BITFIELDS_CASE(bitfields___just_big_enough, {
746 .ub2 = 0x0812345678FEDCBALL,
748 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
750 /* field size and offset relocation checks */
752 SIZE_CASE(size___diff_sz),
753 SIZE_CASE(size___diff_offs),
754 SIZE_ERR_CASE(size___err_ambiguous),
756 /* validate type existence, match, and size relocations */
757 TYPE_BASED_CASE(type_based, {
759 .complex_struct_exists = 1,
762 .typedef_named_struct_exists = 1,
763 .typedef_anon_struct_exists = 1,
764 .typedef_struct_ptr_exists = 1,
765 .typedef_int_exists = 1,
766 .typedef_enum_exists = 1,
767 .typedef_void_ptr_exists = 1,
768 .typedef_restrict_ptr_exists = 1,
769 .typedef_func_proto_exists = 1,
770 .typedef_arr_exists = 1,
773 .complex_struct_matches = 1,
776 .typedef_named_struct_matches = 1,
777 .typedef_anon_struct_matches = 1,
778 .typedef_struct_ptr_matches = 1,
779 .typedef_int_matches = 1,
780 .typedef_enum_matches = 1,
781 .typedef_void_ptr_matches = 1,
782 .typedef_restrict_ptr_matches = 1,
783 .typedef_func_proto_matches = 1,
784 .typedef_arr_matches = 1,
786 .struct_sz = sizeof(struct a_struct),
787 .union_sz = sizeof(union a_union),
788 .enum_sz = sizeof(enum an_enum),
789 .typedef_named_struct_sz = sizeof(named_struct_typedef),
790 .typedef_anon_struct_sz = sizeof(anon_struct_typedef),
791 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
792 .typedef_int_sz = sizeof(int_typedef),
793 .typedef_enum_sz = sizeof(enum_typedef),
794 .typedef_void_ptr_sz = sizeof(void_ptr_typedef),
795 .typedef_func_proto_sz = sizeof(func_proto_typedef),
796 .typedef_arr_sz = sizeof(arr_typedef),
798 TYPE_BASED_CASE(type_based___all_missing, {
801 TYPE_BASED_CASE(type_based___diff, {
803 .complex_struct_exists = 1,
806 .typedef_named_struct_exists = 1,
807 .typedef_anon_struct_exists = 1,
808 .typedef_struct_ptr_exists = 1,
809 .typedef_int_exists = 1,
810 .typedef_enum_exists = 1,
811 .typedef_void_ptr_exists = 1,
812 .typedef_func_proto_exists = 1,
813 .typedef_arr_exists = 1,
816 .complex_struct_matches = 1,
819 .typedef_named_struct_matches = 1,
820 .typedef_anon_struct_matches = 1,
821 .typedef_struct_ptr_matches = 1,
822 .typedef_int_matches = 0,
823 .typedef_enum_matches = 1,
824 .typedef_void_ptr_matches = 1,
825 .typedef_func_proto_matches = 0,
826 .typedef_arr_matches = 0,
828 .struct_sz = sizeof(struct a_struct___diff),
829 .union_sz = sizeof(union a_union___diff),
830 .enum_sz = sizeof(enum an_enum___diff),
831 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff),
832 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff),
833 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff),
834 .typedef_int_sz = sizeof(int_typedef___diff),
835 .typedef_enum_sz = sizeof(enum_typedef___diff),
836 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff),
837 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff),
838 .typedef_arr_sz = sizeof(arr_typedef___diff),
840 TYPE_BASED_CASE(type_based___diff_sz, {
844 .typedef_named_struct_exists = 1,
845 .typedef_anon_struct_exists = 1,
846 .typedef_struct_ptr_exists = 1,
847 .typedef_int_exists = 1,
848 .typedef_enum_exists = 1,
849 .typedef_void_ptr_exists = 1,
850 .typedef_func_proto_exists = 1,
851 .typedef_arr_exists = 1,
856 .typedef_named_struct_matches = 0,
857 .typedef_anon_struct_matches = 0,
858 .typedef_struct_ptr_matches = 1,
859 .typedef_int_matches = 0,
860 .typedef_enum_matches = 0,
861 .typedef_void_ptr_matches = 1,
862 .typedef_func_proto_matches = 0,
863 .typedef_arr_matches = 0,
865 .struct_sz = sizeof(struct a_struct___diff_sz),
866 .union_sz = sizeof(union a_union___diff_sz),
867 .enum_sz = sizeof(enum an_enum___diff_sz),
868 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
869 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
870 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
871 .typedef_int_sz = sizeof(int_typedef___diff_sz),
872 .typedef_enum_sz = sizeof(enum_typedef___diff_sz),
873 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
874 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
875 .typedef_arr_sz = sizeof(arr_typedef___diff_sz),
877 TYPE_BASED_CASE(type_based___incompat, {
880 .enum_sz = sizeof(enum an_enum),
882 TYPE_BASED_CASE(type_based___fn_wrong_args, {
885 .struct_sz = sizeof(struct a_struct),
888 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
889 TYPE_ID_CASE(type_id, setup_type_id_case_success),
890 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
892 /* Enumerator value existence and value relocations */
893 ENUMVAL_CASE(enumval, {
894 .named_val1_exists = true,
895 .named_val2_exists = true,
896 .named_val3_exists = true,
897 .anon_val1_exists = true,
898 .anon_val2_exists = true,
899 .anon_val3_exists = true,
905 ENUMVAL_CASE(enumval___diff, {
906 .named_val1_exists = true,
907 .named_val2_exists = true,
908 .named_val3_exists = true,
909 .anon_val1_exists = true,
910 .anon_val2_exists = true,
911 .anon_val3_exists = true,
917 ENUMVAL_CASE(enumval___val3_missing, {
918 .named_val1_exists = true,
919 .named_val2_exists = true,
920 .named_val3_exists = false,
921 .anon_val1_exists = true,
922 .anon_val2_exists = true,
923 .anon_val3_exists = false,
929 ENUMVAL_ERR_CASE(enumval___err_missing),
931 /* 64bit enumerator value existence and value relocations */
932 ENUM64VAL_CASE(enum64val, {
933 .unsigned_val1_exists = true,
934 .unsigned_val2_exists = true,
935 .unsigned_val3_exists = true,
936 .signed_val1_exists = true,
937 .signed_val2_exists = true,
938 .signed_val3_exists = true,
939 .unsigned_val1 = 0x1ffffffffULL,
940 .unsigned_val2 = 0x2,
941 .signed_val1 = 0x1ffffffffLL,
944 ENUM64VAL_CASE(enum64val___diff, {
945 .unsigned_val1_exists = true,
946 .unsigned_val2_exists = true,
947 .unsigned_val3_exists = true,
948 .signed_val1_exists = true,
949 .signed_val2_exists = true,
950 .signed_val3_exists = true,
951 .unsigned_val1 = 0x101ffffffffULL,
952 .unsigned_val2 = 0x202ffffffffULL,
956 ENUM64VAL_CASE(enum64val___val3_missing, {
957 .unsigned_val1_exists = true,
958 .unsigned_val2_exists = true,
959 .unsigned_val3_exists = false,
960 .signed_val1_exists = true,
961 .signed_val2_exists = true,
962 .signed_val3_exists = false,
963 .unsigned_val1 = 0x111ffffffffULL,
964 .unsigned_val2 = 0x222,
965 .signed_val1 = 0x111ffffffffLL,
968 ENUM64VAL_ERR_CASE(enum64val___err_missing),
975 uint64_t my_pid_tgid;
978 static size_t roundup_page(size_t sz)
980 long page_size = sysconf(_SC_PAGE_SIZE);
981 return (sz + page_size - 1) / page_size * page_size;
984 static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objpath)
989 n = snprintf(command, sizeof(command),
990 "./bpftool gen min_core_btf %s %s %s",
991 src_btf, dst_btf, objpath);
992 if (n < 0 || n >= sizeof(command))
995 return system(command);
998 static void run_core_reloc_tests(bool use_btfgen)
1000 const size_t mmap_sz = roundup_page(sizeof(struct data));
1001 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
1002 struct core_reloc_test_case *test_case, test_case_copy;
1003 const char *tp_name, *probe_name;
1004 int err, i, equal, fd;
1005 struct bpf_link *link = NULL;
1006 struct bpf_map *data_map;
1007 struct bpf_program *prog;
1008 struct bpf_object *obj;
1009 uint64_t my_pid_tgid;
1011 void *mmap_data = NULL;
1013 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
1015 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
1016 char btf_file[] = "/tmp/core_reloc.btf.XXXXXX";
1018 test_case_copy = test_cases[i];
1019 test_case = &test_case_copy;
1021 if (!test__start_subtest(test_case->case_name))
1024 if (test_case->needs_testmod && !env.has_testmod) {
1029 /* generate a "minimal" BTF file and use it as source */
1032 if (!test_case->btf_src_file || test_case->run_btfgen_fails) {
1037 fd = mkstemp(btf_file);
1038 if (!ASSERT_GE(fd, 0, "btf_tmp"))
1040 close(fd); /* we only need the path */
1041 err = run_btfgen(test_case->btf_src_file, btf_file,
1042 test_case->bpf_obj_file);
1043 if (!ASSERT_OK(err, "run_btfgen"))
1046 test_case->btf_src_file = btf_file;
1049 if (test_case->setup) {
1050 err = test_case->setup(test_case);
1051 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
1055 if (test_case->btf_src_file) {
1056 err = access(test_case->btf_src_file, R_OK);
1057 if (!ASSERT_OK(err, "btf_src_file"))
1061 open_opts.btf_custom_path = test_case->btf_src_file;
1062 obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts);
1063 if (!ASSERT_OK_PTR(obj, "obj_open"))
1066 probe_name = test_case->prog_name;
1067 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
1068 prog = bpf_object__find_program_by_name(obj, probe_name);
1069 if (CHECK(!prog, "find_probe",
1070 "prog '%s' not found\n", probe_name))
1073 err = bpf_object__load(obj);
1075 if (!test_case->fails)
1076 ASSERT_OK(err, "obj_load");
1080 data_map = bpf_object__find_map_by_name(obj, ".bss");
1081 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
1084 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
1085 MAP_SHARED, bpf_map__fd(data_map), 0);
1086 if (CHECK(mmap_data == MAP_FAILED, "mmap",
1087 ".bss mmap failed: %d", errno)) {
1093 memset(mmap_data, 0, sizeof(*data));
1094 if (test_case->input_len)
1095 memcpy(data->in, test_case->input, test_case->input_len);
1096 data->my_pid_tgid = my_pid_tgid;
1098 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
1099 if (!ASSERT_OK_PTR(link, "attach_raw_tp"))
1102 /* trigger test run */
1103 if (test_case->trigger) {
1104 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
1115 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
1118 equal = memcmp(data->out, test_case->output,
1119 test_case->output_len) == 0;
1120 if (CHECK(!equal, "check_result",
1121 "input/output data don't match\n")) {
1124 for (j = 0; j < test_case->input_len; j++) {
1125 printf("input byte #%d: 0x%02hhx\n",
1126 j, test_case->input[j]);
1128 for (j = 0; j < test_case->output_len; j++) {
1129 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
1130 j, test_case->output[j], data->out[j]);
1137 CHECK_FAIL(munmap(mmap_data, mmap_sz));
1141 remove(test_case->btf_src_file);
1142 bpf_link__destroy(link);
1144 bpf_object__close(obj);
1148 void test_core_reloc(void)
1150 run_core_reloc_tests(false);
1153 void test_core_reloc_btfgen(void)
1155 run_core_reloc_tests(true);