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 <sys/mman.h>
6 #include <sys/syscall.h>
7 #include <bpf/btf.h>
8
9 static int duration = 0;
10
11 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
12
13 #define MODULES_CASE(name, sec_name, tp_name) { \
14 .case_name = name, \
15 .bpf_obj_file = "test_core_reloc_module.o", \
16 .btf_src_file = NULL, /* find in kernel module BTFs */ \
17 .input = "", \
18 .input_len = 0, \
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, \
22 .buf_exists = true, \
23 .len_exists = true, \
24 .off_exists = true, \
25 .len = 123, \
26 .off = 0, \
27 .comm = "test_progs", \
28 .comm_len = sizeof("test_progs"), \
29 }, \
30 .output_len = sizeof(struct core_reloc_module_output), \
31 .prog_sec_name = sec_name, \
32 .raw_tp_name = tp_name, \
33 .trigger = trigger_module_test_read, \
34 .needs_testmod = true, \
35 }
36
37 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
38 .a = 42, \
39 .b = 0xc001, \
40 .c = 0xbeef, \
41 }
42
43 #define FLAVORS_CASE_COMMON(name) \
44 .case_name = #name, \
45 .bpf_obj_file = "test_core_reloc_flavors.o", \
46 .btf_src_file = "btf__core_reloc_" #name ".o" \
47
48 #define FLAVORS_CASE(name) { \
49 FLAVORS_CASE_COMMON(name), \
50 .input = FLAVORS_DATA(core_reloc_##name), \
51 .input_len = sizeof(struct core_reloc_##name), \
52 .output = FLAVORS_DATA(core_reloc_flavors), \
53 .output_len = sizeof(struct core_reloc_flavors), \
54 }
55
56 #define FLAVORS_ERR_CASE(name) { \
57 FLAVORS_CASE_COMMON(name), \
58 .fails = true, \
59 }
60
61 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
62 .a = { .a = { .a = 42 } }, \
63 .b = { .b = { .b = 0xc001 } }, \
64 }
65
66 #define NESTING_CASE_COMMON(name) \
67 .case_name = #name, \
68 .bpf_obj_file = "test_core_reloc_nesting.o", \
69 .btf_src_file = "btf__core_reloc_" #name ".o"
70
71 #define NESTING_CASE(name) { \
72 NESTING_CASE_COMMON(name), \
73 .input = NESTING_DATA(core_reloc_##name), \
74 .input_len = sizeof(struct core_reloc_##name), \
75 .output = NESTING_DATA(core_reloc_nesting), \
76 .output_len = sizeof(struct core_reloc_nesting) \
77 }
78
79 #define NESTING_ERR_CASE(name) { \
80 NESTING_CASE_COMMON(name), \
81 .fails = true, \
82 }
83
84 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
85 .a = { [2] = 1 }, \
86 .b = { [1] = { [2] = { [3] = 2 } } }, \
87 .c = { [1] = { .c = 3 } }, \
88 .d = { [0] = { [0] = { .d = 4 } } }, \
89 }
90
91 #define ARRAYS_CASE_COMMON(name) \
92 .case_name = #name, \
93 .bpf_obj_file = "test_core_reloc_arrays.o", \
94 .btf_src_file = "btf__core_reloc_" #name ".o"
95
96 #define ARRAYS_CASE(name) { \
97 ARRAYS_CASE_COMMON(name), \
98 .input = ARRAYS_DATA(core_reloc_##name), \
99 .input_len = sizeof(struct core_reloc_##name), \
100 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \
101 .a2 = 1, \
102 .b123 = 2, \
103 .c1c = 3, \
104 .d00d = 4, \
105 .f10c = 0, \
106 }, \
107 .output_len = sizeof(struct core_reloc_arrays_output) \
108 }
109
110 #define ARRAYS_ERR_CASE(name) { \
111 ARRAYS_CASE_COMMON(name), \
112 .fails = true, \
113 }
114
115 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
116 .a = 1, \
117 .b = 2, \
118 .c = 3, \
119 .d = (void *)4, \
120 .f = (void *)5, \
121 }
122
123 #define PRIMITIVES_CASE_COMMON(name) \
124 .case_name = #name, \
125 .bpf_obj_file = "test_core_reloc_primitives.o", \
126 .btf_src_file = "btf__core_reloc_" #name ".o"
127
128 #define PRIMITIVES_CASE(name) { \
129 PRIMITIVES_CASE_COMMON(name), \
130 .input = PRIMITIVES_DATA(core_reloc_##name), \
131 .input_len = sizeof(struct core_reloc_##name), \
132 .output = PRIMITIVES_DATA(core_reloc_primitives), \
133 .output_len = sizeof(struct core_reloc_primitives), \
134 }
135
136 #define PRIMITIVES_ERR_CASE(name) { \
137 PRIMITIVES_CASE_COMMON(name), \
138 .fails = true, \
139 }
140
141 #define MODS_CASE(name) { \
142 .case_name = #name, \
143 .bpf_obj_file = "test_core_reloc_mods.o", \
144 .btf_src_file = "btf__core_reloc_" #name ".o", \
145 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \
146 .a = 1, \
147 .b = 2, \
148 .c = (void *)3, \
149 .d = (void *)4, \
150 .e = { [2] = 5 }, \
151 .f = { [1] = 6 }, \
152 .g = { .x = 7 }, \
153 .h = { .y = 8 }, \
154 }, \
155 .input_len = sizeof(struct core_reloc_##name), \
156 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \
157 .a = 1, .b = 2, .c = 3, .d = 4, \
158 .e = 5, .f = 6, .g = 7, .h = 8, \
159 }, \
160 .output_len = sizeof(struct core_reloc_mods_output), \
161 }
162
163 #define PTR_AS_ARR_CASE(name) { \
164 .case_name = #name, \
165 .bpf_obj_file = "test_core_reloc_ptr_as_arr.o", \
166 .btf_src_file = "btf__core_reloc_" #name ".o", \
167 .input = (const char *)&(struct core_reloc_##name []){ \
168 { .a = 1 }, \
169 { .a = 2 }, \
170 { .a = 3 }, \
171 }, \
172 .input_len = 3 * sizeof(struct core_reloc_##name), \
173 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \
174 .a = 3, \
175 }, \
176 .output_len = sizeof(struct core_reloc_ptr_as_arr), \
177 }
178
179 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
180 .u8_field = 1, \
181 .s8_field = 2, \
182 .u16_field = 3, \
183 .s16_field = 4, \
184 .u32_field = 5, \
185 .s32_field = 6, \
186 .u64_field = 7, \
187 .s64_field = 8, \
188 }
189
190 #define INTS_CASE_COMMON(name) \
191 .case_name = #name, \
192 .bpf_obj_file = "test_core_reloc_ints.o", \
193 .btf_src_file = "btf__core_reloc_" #name ".o"
194
195 #define INTS_CASE(name) { \
196 INTS_CASE_COMMON(name), \
197 .input = INTS_DATA(core_reloc_##name), \
198 .input_len = sizeof(struct core_reloc_##name), \
199 .output = INTS_DATA(core_reloc_ints), \
200 .output_len = sizeof(struct core_reloc_ints), \
201 }
202
203 #define INTS_ERR_CASE(name) { \
204 INTS_CASE_COMMON(name), \
205 .fails = true, \
206 }
207
208 #define FIELD_EXISTS_CASE_COMMON(name) \
209 .case_name = #name, \
210 .bpf_obj_file = "test_core_reloc_existence.o", \
211 .btf_src_file = "btf__core_reloc_" #name ".o" \
212
213 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \
214 .case_name = test_name_prefix#name, \
215 .bpf_obj_file = objfile, \
216 .btf_src_file = "btf__core_reloc_" #name ".o"
217
218 #define BITFIELDS_CASE(name, ...) { \
219 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
220 "probed:", name), \
221 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
222 .input_len = sizeof(struct core_reloc_##name), \
223 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
224 __VA_ARGS__, \
225 .output_len = sizeof(struct core_reloc_bitfields_output), \
226 }, { \
227 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
228 "direct:", name), \
229 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \
230 .input_len = sizeof(struct core_reloc_##name), \
231 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \
232 __VA_ARGS__, \
233 .output_len = sizeof(struct core_reloc_bitfields_output), \
234 .prog_sec_name = "tp_btf/sys_enter", \
235 }
236
237
238 #define BITFIELDS_ERR_CASE(name) { \
239 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \
240 "probed:", name), \
241 .fails = true, \
242 }, { \
243 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \
244 "direct:", name), \
245 .prog_sec_name = "tp_btf/sys_enter", \
246 .fails = true, \
247 }
248
249 #define SIZE_CASE_COMMON(name) \
250 .case_name = #name, \
251 .bpf_obj_file = "test_core_reloc_size.o", \
252 .btf_src_file = "btf__core_reloc_" #name ".o", \
253 .relaxed_core_relocs = true
254
255 #define SIZE_OUTPUT_DATA(type) \
256 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
257 .int_sz = sizeof(((type *)0)->int_field), \
258 .struct_sz = sizeof(((type *)0)->struct_field), \
259 .union_sz = sizeof(((type *)0)->union_field), \
260 .arr_sz = sizeof(((type *)0)->arr_field), \
261 .arr_elem_sz = sizeof(((type *)0)->arr_field[0]), \
262 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \
263 .enum_sz = sizeof(((type *)0)->enum_field), \
264 .float_sz = sizeof(((type *)0)->float_field), \
265 }
266
267 #define SIZE_CASE(name) { \
268 SIZE_CASE_COMMON(name), \
269 .input_len = 0, \
270 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
271 .output_len = sizeof(struct core_reloc_size_output), \
272 }
273
274 #define SIZE_ERR_CASE(name) { \
275 SIZE_CASE_COMMON(name), \
276 .fails = true, \
277 }
278
279 #define TYPE_BASED_CASE_COMMON(name) \
280 .case_name = #name, \
281 .bpf_obj_file = "test_core_reloc_type_based.o", \
282 .btf_src_file = "btf__core_reloc_" #name ".o" \
283
284 #define TYPE_BASED_CASE(name, ...) { \
285 TYPE_BASED_CASE_COMMON(name), \
286 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \
287 __VA_ARGS__, \
288 .output_len = sizeof(struct core_reloc_type_based_output), \
289 }
290
291 #define TYPE_BASED_ERR_CASE(name) { \
292 TYPE_BASED_CASE_COMMON(name), \
293 .fails = true, \
294 }
295
296 #define TYPE_ID_CASE_COMMON(name) \
297 .case_name = #name, \
298 .bpf_obj_file = "test_core_reloc_type_id.o", \
299 .btf_src_file = "btf__core_reloc_" #name ".o" \
300
301 #define TYPE_ID_CASE(name, setup_fn) { \
302 TYPE_ID_CASE_COMMON(name), \
303 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \
304 .output_len = sizeof(struct core_reloc_type_id_output), \
305 .setup = setup_fn, \
306 }
307
308 #define TYPE_ID_ERR_CASE(name) { \
309 TYPE_ID_CASE_COMMON(name), \
310 .fails = true, \
311 }
312
313 #define ENUMVAL_CASE_COMMON(name) \
314 .case_name = #name, \
315 .bpf_obj_file = "test_core_reloc_enumval.o", \
316 .btf_src_file = "btf__core_reloc_" #name ".o" \
317
318 #define ENUMVAL_CASE(name, ...) { \
319 ENUMVAL_CASE_COMMON(name), \
320 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \
321 __VA_ARGS__, \
322 .output_len = sizeof(struct core_reloc_enumval_output), \
323 }
324
325 #define ENUMVAL_ERR_CASE(name) { \
326 ENUMVAL_CASE_COMMON(name), \
327 .fails = true, \
328 }
329
330 struct core_reloc_test_case;
331
332 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
333 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
334
335 struct core_reloc_test_case {
336 const char *case_name;
337 const char *bpf_obj_file;
338 const char *btf_src_file;
339 const char *input;
340 int input_len;
341 const char *output;
342 int output_len;
343 bool fails;
344 bool needs_testmod;
345 bool relaxed_core_relocs;
346 const char *prog_sec_name;
347 const char *raw_tp_name;
348 setup_test_fn setup;
349 trigger_test_fn trigger;
350 };
351
find_btf_type(const struct btf * btf,const char * name,__u32 kind)352 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
353 {
354 int id;
355
356 id = btf__find_by_name_kind(btf, name, kind);
357 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
358 return -1;
359
360 return id;
361 }
362
setup_type_id_case_local(struct core_reloc_test_case * test)363 static int setup_type_id_case_local(struct core_reloc_test_case *test)
364 {
365 struct core_reloc_type_id_output *exp = (void *)test->output;
366 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
367 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
368 const struct btf_type *t;
369 const char *name;
370 int i;
371
372 if (CHECK(IS_ERR(local_btf), "local_btf", "failed: %ld\n", PTR_ERR(local_btf)) ||
373 CHECK(IS_ERR(targ_btf), "targ_btf", "failed: %ld\n", PTR_ERR(targ_btf))) {
374 btf__free(local_btf);
375 btf__free(targ_btf);
376 return -EINVAL;
377 }
378
379 exp->local_anon_struct = -1;
380 exp->local_anon_union = -1;
381 exp->local_anon_enum = -1;
382 exp->local_anon_func_proto_ptr = -1;
383 exp->local_anon_void_ptr = -1;
384 exp->local_anon_arr = -1;
385
386 for (i = 1; i <= btf__get_nr_types(local_btf); i++)
387 {
388 t = btf__type_by_id(local_btf, i);
389 /* we are interested only in anonymous types */
390 if (t->name_off)
391 continue;
392
393 if (btf_is_struct(t) && btf_vlen(t) &&
394 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
395 strcmp(name, "marker_field") == 0) {
396 exp->local_anon_struct = i;
397 } else if (btf_is_union(t) && btf_vlen(t) &&
398 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
399 strcmp(name, "marker_field") == 0) {
400 exp->local_anon_union = i;
401 } else if (btf_is_enum(t) && btf_vlen(t) &&
402 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
403 strcmp(name, "MARKER_ENUM_VAL") == 0) {
404 exp->local_anon_enum = i;
405 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
406 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
407 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
408 strcmp(name, "_Bool") == 0) {
409 /* ptr -> func_proto -> _Bool */
410 exp->local_anon_func_proto_ptr = i;
411 } else if (btf_is_void(t)) {
412 /* ptr -> void */
413 exp->local_anon_void_ptr = i;
414 }
415 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
416 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
417 strcmp(name, "_Bool") == 0) {
418 /* _Bool[] */
419 exp->local_anon_arr = i;
420 }
421 }
422
423 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
424 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
425 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
426 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
427 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
428 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
429 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
430
431 btf__free(local_btf);
432 btf__free(targ_btf);
433 return 0;
434 }
435
setup_type_id_case_success(struct core_reloc_test_case * test)436 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
437 struct core_reloc_type_id_output *exp = (void *)test->output;
438 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
439 int err;
440
441 err = setup_type_id_case_local(test);
442 if (err)
443 return err;
444
445 targ_btf = btf__parse(test->btf_src_file, NULL);
446
447 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
448 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
449 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
450 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
451 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
452 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
453 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
454
455 btf__free(targ_btf);
456 return 0;
457 }
458
setup_type_id_case_failure(struct core_reloc_test_case * test)459 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
460 {
461 struct core_reloc_type_id_output *exp = (void *)test->output;
462 int err;
463
464 err = setup_type_id_case_local(test);
465 if (err)
466 return err;
467
468 exp->targ_struct = 0;
469 exp->targ_union = 0;
470 exp->targ_enum = 0;
471 exp->targ_int = 0;
472 exp->targ_struct_typedef = 0;
473 exp->targ_func_proto_typedef = 0;
474 exp->targ_arr_typedef = 0;
475
476 return 0;
477 }
478
trigger_module_test_read(const struct core_reloc_test_case * test)479 static int trigger_module_test_read(const struct core_reloc_test_case *test)
480 {
481 struct core_reloc_module_output *exp = (void *)test->output;
482 int fd, err;
483
484 fd = open("/sys/kernel/bpf_testmod", O_RDONLY);
485 err = -errno;
486 if (CHECK(fd < 0, "testmod_file_open", "failed: %d\n", err))
487 return err;
488
489 read(fd, NULL, exp->len); /* request expected number of bytes */
490 close(fd);
491
492 return 0;
493 }
494
495
496 static struct core_reloc_test_case test_cases[] = {
497 /* validate we can find kernel image and use its BTF for relocs */
498 {
499 .case_name = "kernel",
500 .bpf_obj_file = "test_core_reloc_kernel.o",
501 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
502 .input = "",
503 .input_len = 0,
504 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
505 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
506 .comm = "test_progs",
507 .comm_len = sizeof("test_progs"),
508 },
509 .output_len = sizeof(struct core_reloc_kernel_output),
510 },
511
512 /* validate we can find kernel module BTF types for relocs/attach */
513 MODULES_CASE("module_probed", "raw_tp/bpf_testmod_test_read", "bpf_testmod_test_read"),
514 MODULES_CASE("module_direct", "tp_btf/bpf_testmod_test_read", NULL),
515
516 /* validate BPF program can use multiple flavors to match against
517 * single target BTF type
518 */
519 FLAVORS_CASE(flavors),
520
521 FLAVORS_ERR_CASE(flavors__err_wrong_name),
522
523 /* various struct/enum nesting and resolution scenarios */
524 NESTING_CASE(nesting),
525 NESTING_CASE(nesting___anon_embed),
526 NESTING_CASE(nesting___struct_union_mixup),
527 NESTING_CASE(nesting___extra_nesting),
528 NESTING_CASE(nesting___dup_compat_types),
529
530 NESTING_ERR_CASE(nesting___err_missing_field),
531 NESTING_ERR_CASE(nesting___err_array_field),
532 NESTING_ERR_CASE(nesting___err_missing_container),
533 NESTING_ERR_CASE(nesting___err_nonstruct_container),
534 NESTING_ERR_CASE(nesting___err_array_container),
535 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
536 NESTING_ERR_CASE(nesting___err_partial_match_dups),
537 NESTING_ERR_CASE(nesting___err_too_deep),
538
539 /* various array access relocation scenarios */
540 ARRAYS_CASE(arrays),
541 ARRAYS_CASE(arrays___diff_arr_dim),
542 ARRAYS_CASE(arrays___diff_arr_val_sz),
543 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
544 ARRAYS_CASE(arrays___fixed_arr),
545
546 ARRAYS_ERR_CASE(arrays___err_too_small),
547 ARRAYS_ERR_CASE(arrays___err_too_shallow),
548 ARRAYS_ERR_CASE(arrays___err_non_array),
549 ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
550 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
551
552 /* enum/ptr/int handling scenarios */
553 PRIMITIVES_CASE(primitives),
554 PRIMITIVES_CASE(primitives___diff_enum_def),
555 PRIMITIVES_CASE(primitives___diff_func_proto),
556 PRIMITIVES_CASE(primitives___diff_ptr_type),
557
558 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
559 PRIMITIVES_ERR_CASE(primitives___err_non_int),
560 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
561
562 /* const/volatile/restrict and typedefs scenarios */
563 MODS_CASE(mods),
564 MODS_CASE(mods___mod_swap),
565 MODS_CASE(mods___typedefs),
566
567 /* handling "ptr is an array" semantics */
568 PTR_AS_ARR_CASE(ptr_as_arr),
569 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
570
571 /* int signedness/sizing/bitfield handling */
572 INTS_CASE(ints),
573 INTS_CASE(ints___bool),
574 INTS_CASE(ints___reverse_sign),
575
576 /* validate edge cases of capturing relocations */
577 {
578 .case_name = "misc",
579 .bpf_obj_file = "test_core_reloc_misc.o",
580 .btf_src_file = "btf__core_reloc_misc.o",
581 .input = (const char *)&(struct core_reloc_misc_extensible[]){
582 { .a = 1 },
583 { .a = 2 }, /* not read */
584 { .a = 3 },
585 },
586 .input_len = 4 * sizeof(int),
587 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
588 .a = 1,
589 .b = 1,
590 .c = 0, /* BUG in clang, should be 3 */
591 },
592 .output_len = sizeof(struct core_reloc_misc_output),
593 },
594
595 /* validate field existence checks */
596 {
597 FIELD_EXISTS_CASE_COMMON(existence),
598 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
599 .a = 1,
600 .b = 2,
601 .c = 3,
602 .arr = { 4 },
603 .s = { .x = 5 },
604 },
605 .input_len = sizeof(struct core_reloc_existence),
606 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
607 .a_exists = 1,
608 .b_exists = 1,
609 .c_exists = 1,
610 .arr_exists = 1,
611 .s_exists = 1,
612 .a_value = 1,
613 .b_value = 2,
614 .c_value = 3,
615 .arr_value = 4,
616 .s_value = 5,
617 },
618 .output_len = sizeof(struct core_reloc_existence_output),
619 },
620 {
621 FIELD_EXISTS_CASE_COMMON(existence___minimal),
622 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
623 .a = 42,
624 },
625 .input_len = sizeof(struct core_reloc_existence___minimal),
626 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
627 .a_exists = 1,
628 .b_exists = 0,
629 .c_exists = 0,
630 .arr_exists = 0,
631 .s_exists = 0,
632 .a_value = 42,
633 .b_value = 0xff000002u,
634 .c_value = 0xff000003u,
635 .arr_value = 0xff000004u,
636 .s_value = 0xff000005u,
637 },
638 .output_len = sizeof(struct core_reloc_existence_output),
639 },
640 {
641 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
642 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
643 },
644 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
645 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
646 .a_exists = 0,
647 .b_exists = 0,
648 .c_exists = 0,
649 .arr_exists = 0,
650 .s_exists = 0,
651 .a_value = 0xff000001u,
652 .b_value = 0xff000002u,
653 .c_value = 0xff000003u,
654 .arr_value = 0xff000004u,
655 .s_value = 0xff000005u,
656 },
657 .output_len = sizeof(struct core_reloc_existence_output),
658 },
659
660 /* bitfield relocation checks */
661 BITFIELDS_CASE(bitfields, {
662 .ub1 = 1,
663 .ub2 = 2,
664 .ub7 = 96,
665 .sb4 = -7,
666 .sb20 = -0x76543,
667 .u32 = 0x80000000,
668 .s32 = -0x76543210,
669 }),
670 BITFIELDS_CASE(bitfields___bit_sz_change, {
671 .ub1 = 6,
672 .ub2 = 0xABCDE,
673 .ub7 = 1,
674 .sb4 = -1,
675 .sb20 = -0x17654321,
676 .u32 = 0xBEEF,
677 .s32 = -0x3FEDCBA987654321LL,
678 }),
679 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
680 .ub1 = 0xFEDCBA9876543210LL,
681 .ub2 = 0xA6,
682 .ub7 = -0x7EDCBA987654321LL,
683 .sb4 = -0x6123456789ABCDELL,
684 .sb20 = 0xD00DLL,
685 .u32 = -0x76543,
686 .s32 = 0x0ADEADBEEFBADB0BLL,
687 }),
688 BITFIELDS_CASE(bitfields___just_big_enough, {
689 .ub1 = 0xFLL,
690 .ub2 = 0x0812345678FEDCBALL,
691 }),
692 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
693
694 /* size relocation checks */
695 SIZE_CASE(size),
696 SIZE_CASE(size___diff_sz),
697 SIZE_ERR_CASE(size___err_ambiguous),
698
699 /* validate type existence and size relocations */
700 TYPE_BASED_CASE(type_based, {
701 .struct_exists = 1,
702 .union_exists = 1,
703 .enum_exists = 1,
704 .typedef_named_struct_exists = 1,
705 .typedef_anon_struct_exists = 1,
706 .typedef_struct_ptr_exists = 1,
707 .typedef_int_exists = 1,
708 .typedef_enum_exists = 1,
709 .typedef_void_ptr_exists = 1,
710 .typedef_func_proto_exists = 1,
711 .typedef_arr_exists = 1,
712 .struct_sz = sizeof(struct a_struct),
713 .union_sz = sizeof(union a_union),
714 .enum_sz = sizeof(enum an_enum),
715 .typedef_named_struct_sz = sizeof(named_struct_typedef),
716 .typedef_anon_struct_sz = sizeof(anon_struct_typedef),
717 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
718 .typedef_int_sz = sizeof(int_typedef),
719 .typedef_enum_sz = sizeof(enum_typedef),
720 .typedef_void_ptr_sz = sizeof(void_ptr_typedef),
721 .typedef_func_proto_sz = sizeof(func_proto_typedef),
722 .typedef_arr_sz = sizeof(arr_typedef),
723 }),
724 TYPE_BASED_CASE(type_based___all_missing, {
725 /* all zeros */
726 }),
727 TYPE_BASED_CASE(type_based___diff_sz, {
728 .struct_exists = 1,
729 .union_exists = 1,
730 .enum_exists = 1,
731 .typedef_named_struct_exists = 1,
732 .typedef_anon_struct_exists = 1,
733 .typedef_struct_ptr_exists = 1,
734 .typedef_int_exists = 1,
735 .typedef_enum_exists = 1,
736 .typedef_void_ptr_exists = 1,
737 .typedef_func_proto_exists = 1,
738 .typedef_arr_exists = 1,
739 .struct_sz = sizeof(struct a_struct___diff_sz),
740 .union_sz = sizeof(union a_union___diff_sz),
741 .enum_sz = sizeof(enum an_enum___diff_sz),
742 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
743 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
744 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
745 .typedef_int_sz = sizeof(int_typedef___diff_sz),
746 .typedef_enum_sz = sizeof(enum_typedef___diff_sz),
747 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
748 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
749 .typedef_arr_sz = sizeof(arr_typedef___diff_sz),
750 }),
751 TYPE_BASED_CASE(type_based___incompat, {
752 .enum_exists = 1,
753 .enum_sz = sizeof(enum an_enum),
754 }),
755 TYPE_BASED_CASE(type_based___fn_wrong_args, {
756 .struct_exists = 1,
757 .struct_sz = sizeof(struct a_struct),
758 }),
759
760 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
761 TYPE_ID_CASE(type_id, setup_type_id_case_success),
762 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
763
764 /* Enumerator value existence and value relocations */
765 ENUMVAL_CASE(enumval, {
766 .named_val1_exists = true,
767 .named_val2_exists = true,
768 .named_val3_exists = true,
769 .anon_val1_exists = true,
770 .anon_val2_exists = true,
771 .anon_val3_exists = true,
772 .named_val1 = 1,
773 .named_val2 = 2,
774 .anon_val1 = 0x10,
775 .anon_val2 = 0x20,
776 }),
777 ENUMVAL_CASE(enumval___diff, {
778 .named_val1_exists = true,
779 .named_val2_exists = true,
780 .named_val3_exists = true,
781 .anon_val1_exists = true,
782 .anon_val2_exists = true,
783 .anon_val3_exists = true,
784 .named_val1 = 101,
785 .named_val2 = 202,
786 .anon_val1 = 0x11,
787 .anon_val2 = 0x22,
788 }),
789 ENUMVAL_CASE(enumval___val3_missing, {
790 .named_val1_exists = true,
791 .named_val2_exists = true,
792 .named_val3_exists = false,
793 .anon_val1_exists = true,
794 .anon_val2_exists = true,
795 .anon_val3_exists = false,
796 .named_val1 = 111,
797 .named_val2 = 222,
798 .anon_val1 = 0x111,
799 .anon_val2 = 0x222,
800 }),
801 ENUMVAL_ERR_CASE(enumval___err_missing),
802 };
803
804 struct data {
805 char in[256];
806 char out[256];
807 bool skip;
808 uint64_t my_pid_tgid;
809 };
810
roundup_page(size_t sz)811 static size_t roundup_page(size_t sz)
812 {
813 long page_size = sysconf(_SC_PAGE_SIZE);
814 return (sz + page_size - 1) / page_size * page_size;
815 }
816
test_core_reloc(void)817 void test_core_reloc(void)
818 {
819 const size_t mmap_sz = roundup_page(sizeof(struct data));
820 struct bpf_object_load_attr load_attr = {};
821 struct core_reloc_test_case *test_case;
822 const char *tp_name, *probe_name;
823 int err, i, equal;
824 struct bpf_link *link = NULL;
825 struct bpf_map *data_map;
826 struct bpf_program *prog;
827 struct bpf_object *obj;
828 uint64_t my_pid_tgid;
829 struct data *data;
830 void *mmap_data = NULL;
831
832 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
833
834 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
835 test_case = &test_cases[i];
836 if (!test__start_subtest(test_case->case_name))
837 continue;
838
839 if (test_case->needs_testmod && !env.has_testmod) {
840 test__skip();
841 continue;
842 }
843
844 if (test_case->setup) {
845 err = test_case->setup(test_case);
846 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
847 continue;
848 }
849
850 obj = bpf_object__open_file(test_case->bpf_obj_file, NULL);
851 if (CHECK(IS_ERR(obj), "obj_open", "failed to open '%s': %ld\n",
852 test_case->bpf_obj_file, PTR_ERR(obj)))
853 continue;
854
855 probe_name = "raw_tracepoint/sys_enter";
856 tp_name = "sys_enter";
857 if (test_case->prog_sec_name) {
858 probe_name = test_case->prog_sec_name;
859 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
860 }
861
862 prog = bpf_object__find_program_by_title(obj, probe_name);
863 if (CHECK(!prog, "find_probe",
864 "prog '%s' not found\n", probe_name))
865 goto cleanup;
866
867
868 if (test_case->btf_src_file) {
869 err = access(test_case->btf_src_file, R_OK);
870 if (!ASSERT_OK(err, "btf_src_file"))
871 goto cleanup;
872 }
873
874 load_attr.obj = obj;
875 load_attr.log_level = 0;
876 load_attr.target_btf_path = test_case->btf_src_file;
877 err = bpf_object__load_xattr(&load_attr);
878 if (err) {
879 if (!test_case->fails)
880 ASSERT_OK(err, "obj_load");
881 goto cleanup;
882 }
883
884 data_map = bpf_object__find_map_by_name(obj, "test_cor.bss");
885 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
886 goto cleanup;
887
888 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
889 MAP_SHARED, bpf_map__fd(data_map), 0);
890 if (CHECK(mmap_data == MAP_FAILED, "mmap",
891 ".bss mmap failed: %d", errno)) {
892 mmap_data = NULL;
893 goto cleanup;
894 }
895 data = mmap_data;
896
897 memset(mmap_data, 0, sizeof(*data));
898 memcpy(data->in, test_case->input, test_case->input_len);
899 data->my_pid_tgid = my_pid_tgid;
900
901 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
902 if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n",
903 PTR_ERR(link)))
904 goto cleanup;
905
906 /* trigger test run */
907 if (test_case->trigger) {
908 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
909 goto cleanup;
910 } else {
911 usleep(1);
912 }
913
914 if (data->skip) {
915 test__skip();
916 goto cleanup;
917 }
918
919 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
920 goto cleanup;
921
922 equal = memcmp(data->out, test_case->output,
923 test_case->output_len) == 0;
924 if (CHECK(!equal, "check_result",
925 "input/output data don't match\n")) {
926 int j;
927
928 for (j = 0; j < test_case->input_len; j++) {
929 printf("input byte #%d: 0x%02hhx\n",
930 j, test_case->input[j]);
931 }
932 for (j = 0; j < test_case->output_len; j++) {
933 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
934 j, test_case->output[j], data->out[j]);
935 }
936 goto cleanup;
937 }
938
939 cleanup:
940 if (mmap_data) {
941 CHECK_FAIL(munmap(mmap_data, mmap_sz));
942 mmap_data = NULL;
943 }
944 if (!IS_ERR_OR_NULL(link)) {
945 bpf_link__destroy(link);
946 link = NULL;
947 }
948 bpf_object__close(obj);
949 }
950 }
951