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