1
2#include <test_progs.h>
3#include "progs/core_reloc_types.h"
4#include <sys/mman.h>
5#include <sys/syscall.h>
6
7#define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
8
9#define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
10 .a = 42, \
11 .b = 0xc001, \
12 .c = 0xbeef, \
13}
14
15#define FLAVORS_CASE_COMMON(name) \
16 .case_name = #name, \
17 .bpf_obj_file = "test_core_reloc_flavors.o", \
18 .btf_src_file = "btf__core_reloc_" #name ".o" \
19
20#define FLAVORS_CASE(name) { \
21 FLAVORS_CASE_COMMON(name), \
22 .input = FLAVORS_DATA(core_reloc_##name), \
23 .input_len = sizeof(struct core_reloc_##name), \
24 .output = FLAVORS_DATA(core_reloc_flavors), \
25 .output_len = sizeof(struct core_reloc_flavors), \
26}
27
28#define FLAVORS_ERR_CASE(name) { \
29 FLAVORS_CASE_COMMON(name), \
30 .fails = true, \
31}
32
33#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
34 .a = { .a = { .a = 42 } }, \
35 .b = { .b = { .b = 0xc001 } }, \
36}
37
38#define NESTING_CASE_COMMON(name) \
39 .case_name = #name, \
40 .bpf_obj_file = "test_core_reloc_nesting.o", \
41 .btf_src_file = "btf__core_reloc_" #name ".o"
42
43#define NESTING_CASE(name) { \
44 NESTING_CASE_COMMON(name), \
45 .input = NESTING_DATA(core_reloc_##name), \
46 .input_len = sizeof(struct core_reloc_##name), \
47 .output = NESTING_DATA(core_reloc_nesting), \
48 .output_len = sizeof(struct core_reloc_nesting) \
49}
50
51#define NESTING_ERR_CASE(name) { \
52 NESTING_CASE_COMMON(name), \
53 .fails = true, \
54}
55
56#define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
57 .a = { [2] = 1 }, \
58 .b = { [1] = { [2] = { [3] = 2 } } }, \
59 .c = { [1] = { .c = 3 } }, \
60 .d = { [0] = { [0] = { .d = 4 } } }, \
61}
62
63#define ARRAYS_CASE_COMMON(name) \
64 .case_name = #name, \
65 .bpf_obj_file = "test_core_reloc_arrays.o", \
66 .btf_src_file = "btf__core_reloc_" #name ".o"
67
68#define ARRAYS_CASE(name) { \
69 ARRAYS_CASE_COMMON(name), \
70 .input = ARRAYS_DATA(core_reloc_##name), \
71 .input_len = sizeof(struct core_reloc_##name), \
72 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
73 .a2 = 1, \
74 .b123 = 2, \
75 .c1c = 3, \
76 .d00d = 4, \
77 .f10c = 0, \
78 }, \
79 .output_len = sizeof(struct core_reloc_arrays_output) \
80}
81
82#define ARRAYS_ERR_CASE(name) { \
83 ARRAYS_CASE_COMMON(name), \
84 .fails = true, \
85}
86
87#define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
88 .a = 1, \
89 .b = 2, \
90 .c = 3, \
91 .d = (void *)4, \
92 .f = (void *)5, \
93}
94
95#define PRIMITIVES_CASE_COMMON(name) \
96 .case_name = #name, \
97 .bpf_obj_file = "test_core_reloc_primitives.o", \
98 .btf_src_file = "btf__core_reloc_" #name ".o"
99
100#define PRIMITIVES_CASE(name) { \
101 PRIMITIVES_CASE_COMMON(name), \
102 .input = PRIMITIVES_DATA(core_reloc_##name), \
103 .input_len = sizeof(struct core_reloc_##name), \
104 .output = PRIMITIVES_DATA(core_reloc_primitives), \
105 .output_len = sizeof(struct core_reloc_primitives), \
106}
107
108#define PRIMITIVES_ERR_CASE(name) { \
109 PRIMITIVES_CASE_COMMON(name), \
110 .fails = true, \
111}
112
113#define MODS_CASE(name) { \
114 .case_name = #name, \
115 .bpf_obj_file = "test_core_reloc_mods.o", \
116 .btf_src_file = "btf__core_reloc_" #name ".o", \
117 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
118 .a = 1, \
119 .b = 2, \
120 .c = (void *)3, \
121 .d = (void *)4, \
122 .e = { [2] = 5 }, \
123 .f = { [1] = 6 }, \
124 .g = { .x = 7 }, \
125 .h = { .y = 8 }, \
126 }, \
127 .input_len = sizeof(struct core_reloc_##name), \
128 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
129 .a = 1, .b = 2, .c = 3, .d = 4, \
130 .e = 5, .f = 6, .g = 7, .h = 8, \
131 }, \
132 .output_len = sizeof(struct core_reloc_mods_output), \
133}
134
135#define PTR_AS_ARR_CASE(name) { \
136 .case_name = #name, \
137 .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
138 .btf_src_file = "btf__core_reloc_" #name ".o", \
139 .input = (const char *)&(struct core_reloc_##name []){ \
140 { .a = 1 }, \
141 { .a = 2 }, \
142 { .a = 3 }, \
143 }, \
144 .input_len = 3 * sizeof(struct core_reloc_##name), \
145 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
146 .a = 3, \
147 }, \
148 .output_len = sizeof(struct core_reloc_ptr_as_arr), \
149}
150
151#define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
152 .u8_field = 1, \
153 .s8_field = 2, \
154 .u16_field = 3, \
155 .s16_field = 4, \
156 .u32_field = 5, \
157 .s32_field = 6, \
158 .u64_field = 7, \
159 .s64_field = 8, \
160}
161
162#define INTS_CASE_COMMON(name) \
163 .case_name = #name, \
164 .bpf_obj_file = "test_core_reloc_ints.o", \
165 .btf_src_file = "btf__core_reloc_" #name ".o"
166
167#define INTS_CASE(name) { \
168 INTS_CASE_COMMON(name), \
169 .input = INTS_DATA(core_reloc_##name), \
170 .input_len = sizeof(struct core_reloc_##name), \
171 .output = INTS_DATA(core_reloc_ints), \
172 .output_len = sizeof(struct core_reloc_ints), \
173}
174
175#define INTS_ERR_CASE(name) { \
176 INTS_CASE_COMMON(name), \
177 .fails = true, \
178}
179
180#define EXISTENCE_CASE_COMMON(name) \
181 .case_name = #name, \
182 .bpf_obj_file = "test_core_reloc_existence.o", \
183 .btf_src_file = "btf__core_reloc_" #name ".o", \
184 .relaxed_core_relocs = true
185
186#define EXISTENCE_ERR_CASE(name) { \
187 EXISTENCE_CASE_COMMON(name), \
188 .fails = true, \
189}
190
191#define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
192 .case_name = test_name_prefix#name, \
193 .bpf_obj_file = objfile, \
194 .btf_src_file = "btf__core_reloc_" #name ".o"
195
196#define BITFIELDS_CASE(name, ...) { \
197 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
198 "direct:", name), \
199 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
200 .input_len = sizeof(struct core_reloc_##name), \
201 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
202 __VA_ARGS__, \
203 .output_len = sizeof(struct core_reloc_bitfields_output), \
204}, { \
205 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
206 "probed:", name), \
207 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
208 .input_len = sizeof(struct core_reloc_##name), \
209 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
210 __VA_ARGS__, \
211 .output_len = sizeof(struct core_reloc_bitfields_output), \
212 .direct_raw_tp = true, \
213}
214
215
216#define BITFIELDS_ERR_CASE(name) { \
217 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
218 "probed:", name), \
219 .fails = true, \
220}, { \
221 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
222 "direct:", name), \
223 .direct_raw_tp = true, \
224 .fails = true, \
225}
226
227#define SIZE_CASE_COMMON(name) \
228 .case_name = #name, \
229 .bpf_obj_file = "test_core_reloc_size.o", \
230 .btf_src_file = "btf__core_reloc_" #name ".o", \
231 .relaxed_core_relocs = true
232
233#define SIZE_OUTPUT_DATA(type) \
234 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
235 .int_sz = sizeof(((type *)0)->int_field), \
236 .struct_sz = sizeof(((type *)0)->struct_field), \
237 .union_sz = sizeof(((type *)0)->union_field), \
238 .arr_sz = sizeof(((type *)0)->arr_field), \
239 .arr_elem_sz = sizeof(((type *)0)->arr_field[0]), \
240 .ptr_sz = 8, \
241 .enum_sz = sizeof(((type *)0)->enum_field), \
242 }
243
244#define SIZE_CASE(name) { \
245 SIZE_CASE_COMMON(name), \
246 .input_len = 0, \
247 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
248 .output_len = sizeof(struct core_reloc_size_output), \
249}
250
251#define SIZE_ERR_CASE(name) { \
252 SIZE_CASE_COMMON(name), \
253 .fails = true, \
254}
255
256struct core_reloc_test_case {
257 const char *case_name;
258 const char *bpf_obj_file;
259 const char *btf_src_file;
260 const char *input;
261 int input_len;
262 const char *output;
263 int output_len;
264 bool fails;
265 bool relaxed_core_relocs;
266 bool direct_raw_tp;
267};
268
269static struct core_reloc_test_case test_cases[] = {
270
271 {
272 .case_name = "kernel",
273 .bpf_obj_file = "test_core_reloc_kernel.o",
274 .btf_src_file = NULL,
275 .input = "",
276 .input_len = 0,
277 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
278 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
279 .comm = "test_progs",
280 .comm_len = sizeof("test_progs"),
281 },
282 .output_len = sizeof(struct core_reloc_kernel_output),
283 },
284
285
286
287
288 FLAVORS_CASE(flavors),
289
290 FLAVORS_ERR_CASE(flavors__err_wrong_name),
291
292
293 NESTING_CASE(nesting),
294 NESTING_CASE(nesting___anon_embed),
295 NESTING_CASE(nesting___struct_union_mixup),
296 NESTING_CASE(nesting___extra_nesting),
297 NESTING_CASE(nesting___dup_compat_types),
298
299 NESTING_ERR_CASE(nesting___err_missing_field),
300 NESTING_ERR_CASE(nesting___err_array_field),
301 NESTING_ERR_CASE(nesting___err_missing_container),
302 NESTING_ERR_CASE(nesting___err_nonstruct_container),
303 NESTING_ERR_CASE(nesting___err_array_container),
304 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
305 NESTING_ERR_CASE(nesting___err_partial_match_dups),
306 NESTING_ERR_CASE(nesting___err_too_deep),
307
308
309 ARRAYS_CASE(arrays),
310 ARRAYS_CASE(arrays___diff_arr_dim),
311 ARRAYS_CASE(arrays___diff_arr_val_sz),
312 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
313 ARRAYS_CASE(arrays___fixed_arr),
314
315 ARRAYS_ERR_CASE(arrays___err_too_small),
316 ARRAYS_ERR_CASE(arrays___err_too_shallow),
317 ARRAYS_ERR_CASE(arrays___err_non_array),
318 ARRAYS_ERR_CASE(arrays___err_wrong_val_type1),
319 ARRAYS_ERR_CASE(arrays___err_wrong_val_type2),
320 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
321
322
323 PRIMITIVES_CASE(primitives),
324 PRIMITIVES_CASE(primitives___diff_enum_def),
325 PRIMITIVES_CASE(primitives___diff_func_proto),
326 PRIMITIVES_CASE(primitives___diff_ptr_type),
327
328 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
329 PRIMITIVES_ERR_CASE(primitives___err_non_int),
330 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
331
332
333 MODS_CASE(mods),
334 MODS_CASE(mods___mod_swap),
335 MODS_CASE(mods___typedefs),
336
337
338 PTR_AS_ARR_CASE(ptr_as_arr),
339 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
340
341
342 INTS_CASE(ints),
343 INTS_CASE(ints___bool),
344 INTS_CASE(ints___reverse_sign),
345
346
347 {
348 .case_name = "misc",
349 .bpf_obj_file = "test_core_reloc_misc.o",
350 .btf_src_file = "btf__core_reloc_misc.o",
351 .input = (const char *)&(struct core_reloc_misc_extensible[]){
352 { .a = 1 },
353 { .a = 2 },
354 { .a = 3 },
355 },
356 .input_len = 4 * sizeof(int),
357 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
358 .a = 1,
359 .b = 1,
360 .c = 0,
361 },
362 .output_len = sizeof(struct core_reloc_misc_output),
363 },
364
365
366 {
367 EXISTENCE_CASE_COMMON(existence),
368 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
369 .a = 1,
370 .b = 2,
371 .c = 3,
372 .arr = { 4 },
373 .s = { .x = 5 },
374 },
375 .input_len = sizeof(struct core_reloc_existence),
376 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
377 .a_exists = 1,
378 .b_exists = 1,
379 .c_exists = 1,
380 .arr_exists = 1,
381 .s_exists = 1,
382 .a_value = 1,
383 .b_value = 2,
384 .c_value = 3,
385 .arr_value = 4,
386 .s_value = 5,
387 },
388 .output_len = sizeof(struct core_reloc_existence_output),
389 },
390 {
391 EXISTENCE_CASE_COMMON(existence___minimal),
392 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
393 .a = 42,
394 },
395 .input_len = sizeof(struct core_reloc_existence___minimal),
396 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
397 .a_exists = 1,
398 .b_exists = 0,
399 .c_exists = 0,
400 .arr_exists = 0,
401 .s_exists = 0,
402 .a_value = 42,
403 .b_value = 0xff000002u,
404 .c_value = 0xff000003u,
405 .arr_value = 0xff000004u,
406 .s_value = 0xff000005u,
407 },
408 .output_len = sizeof(struct core_reloc_existence_output),
409 },
410
411 EXISTENCE_ERR_CASE(existence__err_int_sz),
412 EXISTENCE_ERR_CASE(existence__err_int_type),
413 EXISTENCE_ERR_CASE(existence__err_int_kind),
414 EXISTENCE_ERR_CASE(existence__err_arr_kind),
415 EXISTENCE_ERR_CASE(existence__err_arr_value_type),
416 EXISTENCE_ERR_CASE(existence__err_struct_type),
417
418
419 BITFIELDS_CASE(bitfields, {
420 .ub1 = 1,
421 .ub2 = 2,
422 .ub7 = 96,
423 .sb4 = -7,
424 .sb20 = -0x76543,
425 .u32 = 0x80000000,
426 .s32 = -0x76543210,
427 }),
428 BITFIELDS_CASE(bitfields___bit_sz_change, {
429 .ub1 = 6,
430 .ub2 = 0xABCDE,
431 .ub7 = 1,
432 .sb4 = -1,
433 .sb20 = -0x17654321,
434 .u32 = 0xBEEF,
435 .s32 = -0x3FEDCBA987654321LL,
436 }),
437 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
438 .ub1 = 0xFEDCBA9876543210LL,
439 .ub2 = 0xA6,
440 .ub7 = -0x7EDCBA987654321LL,
441 .sb4 = -0x6123456789ABCDELL,
442 .sb20 = 0xD00DLL,
443 .u32 = -0x76543,
444 .s32 = 0x0ADEADBEEFBADB0BLL,
445 }),
446 BITFIELDS_CASE(bitfields___just_big_enough, {
447 .ub1 = 0xFLL,
448 .ub2 = 0x0812345678FEDCBALL,
449 }),
450 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
451
452
453 SIZE_CASE(size),
454 SIZE_CASE(size___diff_sz),
455};
456
457struct data {
458 char in[256];
459 char out[256];
460 uint64_t my_pid_tgid;
461};
462
463static size_t roundup_page(size_t sz)
464{
465 long page_size = sysconf(_SC_PAGE_SIZE);
466 return (sz + page_size - 1) / page_size * page_size;
467}
468
469void test_core_reloc(void)
470{
471 const size_t mmap_sz = roundup_page(sizeof(struct data));
472 struct bpf_object_load_attr load_attr = {};
473 struct core_reloc_test_case *test_case;
474 const char *tp_name, *probe_name;
475 int err, duration = 0, i, equal;
476 struct bpf_link *link = NULL;
477 struct bpf_map *data_map;
478 struct bpf_program *prog;
479 struct bpf_object *obj;
480 uint64_t my_pid_tgid;
481 struct data *data;
482 void *mmap_data = NULL;
483
484 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
485
486 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
487 test_case = &test_cases[i];
488 if (!test__start_subtest(test_case->case_name))
489 continue;
490
491 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
492 .relaxed_core_relocs = test_case->relaxed_core_relocs,
493 );
494
495 obj = bpf_object__open_file(test_case->bpf_obj_file, &opts);
496 if (CHECK(IS_ERR(obj), "obj_open", "failed to open '%s': %ld\n",
497 test_case->bpf_obj_file, PTR_ERR(obj)))
498 continue;
499
500
501 if (test_case->direct_raw_tp) {
502 probe_name = "tp_btf/sys_enter";
503 tp_name = NULL;
504 } else {
505 probe_name = "raw_tracepoint/sys_enter";
506 tp_name = "sys_enter";
507 }
508
509 prog = bpf_object__find_program_by_title(obj, probe_name);
510 if (CHECK(!prog, "find_probe",
511 "prog '%s' not found\n", probe_name))
512 goto cleanup;
513
514 load_attr.obj = obj;
515 load_attr.log_level = 0;
516 load_attr.target_btf_path = test_case->btf_src_file;
517 err = bpf_object__load_xattr(&load_attr);
518 if (test_case->fails) {
519 CHECK(!err, "obj_load_fail",
520 "should fail to load prog '%s'\n", probe_name);
521 goto cleanup;
522 } else {
523 if (CHECK(err, "obj_load",
524 "failed to load prog '%s': %d\n",
525 probe_name, err))
526 goto cleanup;
527 }
528
529 data_map = bpf_object__find_map_by_name(obj, "test_cor.bss");
530 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
531 goto cleanup;
532
533 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
534 MAP_SHARED, bpf_map__fd(data_map), 0);
535 if (CHECK(mmap_data == MAP_FAILED, "mmap",
536 ".bss mmap failed: %d", errno)) {
537 mmap_data = NULL;
538 goto cleanup;
539 }
540 data = mmap_data;
541
542 memset(mmap_data, 0, sizeof(*data));
543 memcpy(data->in, test_case->input, test_case->input_len);
544 data->my_pid_tgid = my_pid_tgid;
545
546 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
547 if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n",
548 PTR_ERR(link)))
549 goto cleanup;
550
551
552 usleep(1);
553
554 equal = memcmp(data->out, test_case->output,
555 test_case->output_len) == 0;
556 if (CHECK(!equal, "check_result",
557 "input/output data don't match\n")) {
558 int j;
559
560 for (j = 0; j < test_case->input_len; j++) {
561 printf("input byte #%d: 0x%02hhx\n",
562 j, test_case->input[j]);
563 }
564 for (j = 0; j < test_case->output_len; j++) {
565 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
566 j, test_case->output[j], data->out[j]);
567 }
568 goto cleanup;
569 }
570
571cleanup:
572 if (mmap_data) {
573 CHECK_FAIL(munmap(mmap_data, mmap_sz));
574 mmap_data = NULL;
575 }
576 if (!IS_ERR_OR_NULL(link)) {
577 bpf_link__destroy(link);
578 link = NULL;
579 }
580 bpf_object__close(obj);
581 }
582}
583