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
254 #define SIZE_OUTPUT_DATA(type) \
255 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \
256 .int_sz = sizeof(((type *)0)->int_field), \
257 .struct_sz = sizeof(((type *)0)->struct_field), \
258 .union_sz = sizeof(((type *)0)->union_field), \
259 .arr_sz = sizeof(((type *)0)->arr_field), \
260 .arr_elem_sz = sizeof(((type *)0)->arr_field[0]), \
261 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \
262 .enum_sz = sizeof(((type *)0)->enum_field), \
263 .float_sz = sizeof(((type *)0)->float_field), \
264 }
265
266 #define SIZE_CASE(name) { \
267 SIZE_CASE_COMMON(name), \
268 .input_len = 0, \
269 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \
270 .output_len = sizeof(struct core_reloc_size_output), \
271 }
272
273 #define SIZE_ERR_CASE(name) { \
274 SIZE_CASE_COMMON(name), \
275 .fails = true, \
276 }
277
278 #define TYPE_BASED_CASE_COMMON(name) \
279 .case_name = #name, \
280 .bpf_obj_file = "test_core_reloc_type_based.o", \
281 .btf_src_file = "btf__core_reloc_" #name ".o" \
282
283 #define TYPE_BASED_CASE(name, ...) { \
284 TYPE_BASED_CASE_COMMON(name), \
285 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \
286 __VA_ARGS__, \
287 .output_len = sizeof(struct core_reloc_type_based_output), \
288 }
289
290 #define TYPE_BASED_ERR_CASE(name) { \
291 TYPE_BASED_CASE_COMMON(name), \
292 .fails = true, \
293 }
294
295 #define TYPE_ID_CASE_COMMON(name) \
296 .case_name = #name, \
297 .bpf_obj_file = "test_core_reloc_type_id.o", \
298 .btf_src_file = "btf__core_reloc_" #name ".o" \
299
300 #define TYPE_ID_CASE(name, setup_fn) { \
301 TYPE_ID_CASE_COMMON(name), \
302 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \
303 .output_len = sizeof(struct core_reloc_type_id_output), \
304 .setup = setup_fn, \
305 }
306
307 #define TYPE_ID_ERR_CASE(name) { \
308 TYPE_ID_CASE_COMMON(name), \
309 .fails = true, \
310 }
311
312 #define ENUMVAL_CASE_COMMON(name) \
313 .case_name = #name, \
314 .bpf_obj_file = "test_core_reloc_enumval.o", \
315 .btf_src_file = "btf__core_reloc_" #name ".o" \
316
317 #define ENUMVAL_CASE(name, ...) { \
318 ENUMVAL_CASE_COMMON(name), \
319 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \
320 __VA_ARGS__, \
321 .output_len = sizeof(struct core_reloc_enumval_output), \
322 }
323
324 #define ENUMVAL_ERR_CASE(name) { \
325 ENUMVAL_CASE_COMMON(name), \
326 .fails = true, \
327 }
328
329 struct core_reloc_test_case;
330
331 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
332 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
333
334 struct core_reloc_test_case {
335 const char *case_name;
336 const char *bpf_obj_file;
337 const char *btf_src_file;
338 const char *input;
339 int input_len;
340 const char *output;
341 int output_len;
342 bool fails;
343 bool needs_testmod;
344 bool relaxed_core_relocs;
345 const char *prog_sec_name;
346 const char *raw_tp_name;
347 setup_test_fn setup;
348 trigger_test_fn trigger;
349 };
350
find_btf_type(const struct btf * btf,const char * name,__u32 kind)351 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
352 {
353 int id;
354
355 id = btf__find_by_name_kind(btf, name, kind);
356 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
357 return -1;
358
359 return id;
360 }
361
setup_type_id_case_local(struct core_reloc_test_case * test)362 static int setup_type_id_case_local(struct core_reloc_test_case *test)
363 {
364 struct core_reloc_type_id_output *exp = (void *)test->output;
365 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
366 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
367 const struct btf_type *t;
368 const char *name;
369 int i;
370
371 if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) {
372 btf__free(local_btf);
373 btf__free(targ_btf);
374 return -EINVAL;
375 }
376
377 exp->local_anon_struct = -1;
378 exp->local_anon_union = -1;
379 exp->local_anon_enum = -1;
380 exp->local_anon_func_proto_ptr = -1;
381 exp->local_anon_void_ptr = -1;
382 exp->local_anon_arr = -1;
383
384 for (i = 1; i < btf__type_cnt(local_btf); i++)
385 {
386 t = btf__type_by_id(local_btf, i);
387 /* we are interested only in anonymous types */
388 if (t->name_off)
389 continue;
390
391 if (btf_is_struct(t) && btf_vlen(t) &&
392 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
393 strcmp(name, "marker_field") == 0) {
394 exp->local_anon_struct = i;
395 } else if (btf_is_union(t) && btf_vlen(t) &&
396 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
397 strcmp(name, "marker_field") == 0) {
398 exp->local_anon_union = i;
399 } else if (btf_is_enum(t) && btf_vlen(t) &&
400 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
401 strcmp(name, "MARKER_ENUM_VAL") == 0) {
402 exp->local_anon_enum = i;
403 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
404 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
405 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
406 strcmp(name, "_Bool") == 0) {
407 /* ptr -> func_proto -> _Bool */
408 exp->local_anon_func_proto_ptr = i;
409 } else if (btf_is_void(t)) {
410 /* ptr -> void */
411 exp->local_anon_void_ptr = i;
412 }
413 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
414 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
415 strcmp(name, "_Bool") == 0) {
416 /* _Bool[] */
417 exp->local_anon_arr = i;
418 }
419 }
420
421 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
422 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
423 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
424 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
425 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
426 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
427 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
428
429 btf__free(local_btf);
430 btf__free(targ_btf);
431 return 0;
432 }
433
setup_type_id_case_success(struct core_reloc_test_case * test)434 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
435 struct core_reloc_type_id_output *exp = (void *)test->output;
436 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
437 int err;
438
439 err = setup_type_id_case_local(test);
440 if (err)
441 return err;
442
443 targ_btf = btf__parse(test->btf_src_file, NULL);
444
445 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
446 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
447 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
448 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
449 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
450 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
451 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
452
453 btf__free(targ_btf);
454 return 0;
455 }
456
setup_type_id_case_failure(struct core_reloc_test_case * test)457 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
458 {
459 struct core_reloc_type_id_output *exp = (void *)test->output;
460 int err;
461
462 err = setup_type_id_case_local(test);
463 if (err)
464 return err;
465
466 exp->targ_struct = 0;
467 exp->targ_union = 0;
468 exp->targ_enum = 0;
469 exp->targ_int = 0;
470 exp->targ_struct_typedef = 0;
471 exp->targ_func_proto_typedef = 0;
472 exp->targ_arr_typedef = 0;
473
474 return 0;
475 }
476
__trigger_module_test_read(const struct core_reloc_test_case * test)477 static int __trigger_module_test_read(const struct core_reloc_test_case *test)
478 {
479 struct core_reloc_module_output *exp = (void *)test->output;
480
481 trigger_module_test_read(exp->len);
482 return 0;
483 }
484
485
486 static struct core_reloc_test_case test_cases[] = {
487 /* validate we can find kernel image and use its BTF for relocs */
488 {
489 .case_name = "kernel",
490 .bpf_obj_file = "test_core_reloc_kernel.o",
491 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
492 .input = "",
493 .input_len = 0,
494 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
495 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
496 .comm = "test_progs",
497 .comm_len = sizeof("test_progs"),
498 },
499 .output_len = sizeof(struct core_reloc_kernel_output),
500 },
501
502 /* validate we can find kernel module BTF types for relocs/attach */
503 MODULES_CASE("module_probed", "raw_tp/bpf_testmod_test_read", "bpf_testmod_test_read"),
504 MODULES_CASE("module_direct", "tp_btf/bpf_testmod_test_read", NULL),
505
506 /* validate BPF program can use multiple flavors to match against
507 * single target BTF type
508 */
509 FLAVORS_CASE(flavors),
510
511 FLAVORS_ERR_CASE(flavors__err_wrong_name),
512
513 /* various struct/enum nesting and resolution scenarios */
514 NESTING_CASE(nesting),
515 NESTING_CASE(nesting___anon_embed),
516 NESTING_CASE(nesting___struct_union_mixup),
517 NESTING_CASE(nesting___extra_nesting),
518 NESTING_CASE(nesting___dup_compat_types),
519
520 NESTING_ERR_CASE(nesting___err_missing_field),
521 NESTING_ERR_CASE(nesting___err_array_field),
522 NESTING_ERR_CASE(nesting___err_missing_container),
523 NESTING_ERR_CASE(nesting___err_nonstruct_container),
524 NESTING_ERR_CASE(nesting___err_array_container),
525 NESTING_ERR_CASE(nesting___err_dup_incompat_types),
526 NESTING_ERR_CASE(nesting___err_partial_match_dups),
527 NESTING_ERR_CASE(nesting___err_too_deep),
528
529 /* various array access relocation scenarios */
530 ARRAYS_CASE(arrays),
531 ARRAYS_CASE(arrays___diff_arr_dim),
532 ARRAYS_CASE(arrays___diff_arr_val_sz),
533 ARRAYS_CASE(arrays___equiv_zero_sz_arr),
534 ARRAYS_CASE(arrays___fixed_arr),
535
536 ARRAYS_ERR_CASE(arrays___err_too_small),
537 ARRAYS_ERR_CASE(arrays___err_too_shallow),
538 ARRAYS_ERR_CASE(arrays___err_non_array),
539 ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
540 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
541
542 /* enum/ptr/int handling scenarios */
543 PRIMITIVES_CASE(primitives),
544 PRIMITIVES_CASE(primitives___diff_enum_def),
545 PRIMITIVES_CASE(primitives___diff_func_proto),
546 PRIMITIVES_CASE(primitives___diff_ptr_type),
547
548 PRIMITIVES_ERR_CASE(primitives___err_non_enum),
549 PRIMITIVES_ERR_CASE(primitives___err_non_int),
550 PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
551
552 /* const/volatile/restrict and typedefs scenarios */
553 MODS_CASE(mods),
554 MODS_CASE(mods___mod_swap),
555 MODS_CASE(mods___typedefs),
556
557 /* handling "ptr is an array" semantics */
558 PTR_AS_ARR_CASE(ptr_as_arr),
559 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
560
561 /* int signedness/sizing/bitfield handling */
562 INTS_CASE(ints),
563 INTS_CASE(ints___bool),
564 INTS_CASE(ints___reverse_sign),
565
566 /* validate edge cases of capturing relocations */
567 {
568 .case_name = "misc",
569 .bpf_obj_file = "test_core_reloc_misc.o",
570 .btf_src_file = "btf__core_reloc_misc.o",
571 .input = (const char *)&(struct core_reloc_misc_extensible[]){
572 { .a = 1 },
573 { .a = 2 }, /* not read */
574 { .a = 3 },
575 },
576 .input_len = 4 * sizeof(int),
577 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
578 .a = 1,
579 .b = 1,
580 .c = 0, /* BUG in clang, should be 3 */
581 },
582 .output_len = sizeof(struct core_reloc_misc_output),
583 },
584
585 /* validate field existence checks */
586 {
587 FIELD_EXISTS_CASE_COMMON(existence),
588 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
589 .a = 1,
590 .b = 2,
591 .c = 3,
592 .arr = { 4 },
593 .s = { .x = 5 },
594 },
595 .input_len = sizeof(struct core_reloc_existence),
596 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
597 .a_exists = 1,
598 .b_exists = 1,
599 .c_exists = 1,
600 .arr_exists = 1,
601 .s_exists = 1,
602 .a_value = 1,
603 .b_value = 2,
604 .c_value = 3,
605 .arr_value = 4,
606 .s_value = 5,
607 },
608 .output_len = sizeof(struct core_reloc_existence_output),
609 },
610 {
611 FIELD_EXISTS_CASE_COMMON(existence___minimal),
612 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
613 .a = 42,
614 },
615 .input_len = sizeof(struct core_reloc_existence___minimal),
616 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
617 .a_exists = 1,
618 .b_exists = 0,
619 .c_exists = 0,
620 .arr_exists = 0,
621 .s_exists = 0,
622 .a_value = 42,
623 .b_value = 0xff000002u,
624 .c_value = 0xff000003u,
625 .arr_value = 0xff000004u,
626 .s_value = 0xff000005u,
627 },
628 .output_len = sizeof(struct core_reloc_existence_output),
629 },
630 {
631 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
632 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
633 },
634 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
635 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
636 .a_exists = 0,
637 .b_exists = 0,
638 .c_exists = 0,
639 .arr_exists = 0,
640 .s_exists = 0,
641 .a_value = 0xff000001u,
642 .b_value = 0xff000002u,
643 .c_value = 0xff000003u,
644 .arr_value = 0xff000004u,
645 .s_value = 0xff000005u,
646 },
647 .output_len = sizeof(struct core_reloc_existence_output),
648 },
649
650 /* bitfield relocation checks */
651 BITFIELDS_CASE(bitfields, {
652 .ub1 = 1,
653 .ub2 = 2,
654 .ub7 = 96,
655 .sb4 = -7,
656 .sb20 = -0x76543,
657 .u32 = 0x80000000,
658 .s32 = -0x76543210,
659 }),
660 BITFIELDS_CASE(bitfields___bit_sz_change, {
661 .ub1 = 6,
662 .ub2 = 0xABCDE,
663 .ub7 = 1,
664 .sb4 = -1,
665 .sb20 = -0x17654321,
666 .u32 = 0xBEEF,
667 .s32 = -0x3FEDCBA987654321LL,
668 }),
669 BITFIELDS_CASE(bitfields___bitfield_vs_int, {
670 .ub1 = 0xFEDCBA9876543210LL,
671 .ub2 = 0xA6,
672 .ub7 = -0x7EDCBA987654321LL,
673 .sb4 = -0x6123456789ABCDELL,
674 .sb20 = 0xD00DLL,
675 .u32 = -0x76543,
676 .s32 = 0x0ADEADBEEFBADB0BLL,
677 }),
678 BITFIELDS_CASE(bitfields___just_big_enough, {
679 .ub1 = 0xFLL,
680 .ub2 = 0x0812345678FEDCBALL,
681 }),
682 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
683
684 /* size relocation checks */
685 SIZE_CASE(size),
686 SIZE_CASE(size___diff_sz),
687 SIZE_ERR_CASE(size___err_ambiguous),
688
689 /* validate type existence and size relocations */
690 TYPE_BASED_CASE(type_based, {
691 .struct_exists = 1,
692 .union_exists = 1,
693 .enum_exists = 1,
694 .typedef_named_struct_exists = 1,
695 .typedef_anon_struct_exists = 1,
696 .typedef_struct_ptr_exists = 1,
697 .typedef_int_exists = 1,
698 .typedef_enum_exists = 1,
699 .typedef_void_ptr_exists = 1,
700 .typedef_func_proto_exists = 1,
701 .typedef_arr_exists = 1,
702 .struct_sz = sizeof(struct a_struct),
703 .union_sz = sizeof(union a_union),
704 .enum_sz = sizeof(enum an_enum),
705 .typedef_named_struct_sz = sizeof(named_struct_typedef),
706 .typedef_anon_struct_sz = sizeof(anon_struct_typedef),
707 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
708 .typedef_int_sz = sizeof(int_typedef),
709 .typedef_enum_sz = sizeof(enum_typedef),
710 .typedef_void_ptr_sz = sizeof(void_ptr_typedef),
711 .typedef_func_proto_sz = sizeof(func_proto_typedef),
712 .typedef_arr_sz = sizeof(arr_typedef),
713 }),
714 TYPE_BASED_CASE(type_based___all_missing, {
715 /* all zeros */
716 }),
717 TYPE_BASED_CASE(type_based___diff_sz, {
718 .struct_exists = 1,
719 .union_exists = 1,
720 .enum_exists = 1,
721 .typedef_named_struct_exists = 1,
722 .typedef_anon_struct_exists = 1,
723 .typedef_struct_ptr_exists = 1,
724 .typedef_int_exists = 1,
725 .typedef_enum_exists = 1,
726 .typedef_void_ptr_exists = 1,
727 .typedef_func_proto_exists = 1,
728 .typedef_arr_exists = 1,
729 .struct_sz = sizeof(struct a_struct___diff_sz),
730 .union_sz = sizeof(union a_union___diff_sz),
731 .enum_sz = sizeof(enum an_enum___diff_sz),
732 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
733 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
734 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
735 .typedef_int_sz = sizeof(int_typedef___diff_sz),
736 .typedef_enum_sz = sizeof(enum_typedef___diff_sz),
737 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
738 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
739 .typedef_arr_sz = sizeof(arr_typedef___diff_sz),
740 }),
741 TYPE_BASED_CASE(type_based___incompat, {
742 .enum_exists = 1,
743 .enum_sz = sizeof(enum an_enum),
744 }),
745 TYPE_BASED_CASE(type_based___fn_wrong_args, {
746 .struct_exists = 1,
747 .struct_sz = sizeof(struct a_struct),
748 }),
749
750 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
751 TYPE_ID_CASE(type_id, setup_type_id_case_success),
752 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
753
754 /* Enumerator value existence and value relocations */
755 ENUMVAL_CASE(enumval, {
756 .named_val1_exists = true,
757 .named_val2_exists = true,
758 .named_val3_exists = true,
759 .anon_val1_exists = true,
760 .anon_val2_exists = true,
761 .anon_val3_exists = true,
762 .named_val1 = 1,
763 .named_val2 = 2,
764 .anon_val1 = 0x10,
765 .anon_val2 = 0x20,
766 }),
767 ENUMVAL_CASE(enumval___diff, {
768 .named_val1_exists = true,
769 .named_val2_exists = true,
770 .named_val3_exists = true,
771 .anon_val1_exists = true,
772 .anon_val2_exists = true,
773 .anon_val3_exists = true,
774 .named_val1 = 101,
775 .named_val2 = 202,
776 .anon_val1 = 0x11,
777 .anon_val2 = 0x22,
778 }),
779 ENUMVAL_CASE(enumval___val3_missing, {
780 .named_val1_exists = true,
781 .named_val2_exists = true,
782 .named_val3_exists = false,
783 .anon_val1_exists = true,
784 .anon_val2_exists = true,
785 .anon_val3_exists = false,
786 .named_val1 = 111,
787 .named_val2 = 222,
788 .anon_val1 = 0x111,
789 .anon_val2 = 0x222,
790 }),
791 ENUMVAL_ERR_CASE(enumval___err_missing),
792 };
793
794 struct data {
795 char in[256];
796 char out[256];
797 bool skip;
798 uint64_t my_pid_tgid;
799 };
800
roundup_page(size_t sz)801 static size_t roundup_page(size_t sz)
802 {
803 long page_size = sysconf(_SC_PAGE_SIZE);
804 return (sz + page_size - 1) / page_size * page_size;
805 }
806
test_core_reloc(void)807 void test_core_reloc(void)
808 {
809 const size_t mmap_sz = roundup_page(sizeof(struct data));
810 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
811 struct core_reloc_test_case *test_case;
812 const char *tp_name, *probe_name;
813 int err, i, equal;
814 struct bpf_link *link = NULL;
815 struct bpf_map *data_map;
816 struct bpf_program *prog;
817 struct bpf_object *obj;
818 uint64_t my_pid_tgid;
819 struct data *data;
820 void *mmap_data = NULL;
821
822 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
823
824 for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
825 test_case = &test_cases[i];
826 if (!test__start_subtest(test_case->case_name))
827 continue;
828
829 if (test_case->needs_testmod && !env.has_testmod) {
830 test__skip();
831 continue;
832 }
833
834 if (test_case->setup) {
835 err = test_case->setup(test_case);
836 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
837 continue;
838 }
839
840 if (test_case->btf_src_file) {
841 err = access(test_case->btf_src_file, R_OK);
842 if (!ASSERT_OK(err, "btf_src_file"))
843 goto cleanup;
844 }
845
846 open_opts.btf_custom_path = test_case->btf_src_file;
847 obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts);
848 if (!ASSERT_OK_PTR(obj, "obj_open"))
849 goto cleanup;
850
851 probe_name = "raw_tracepoint/sys_enter";
852 tp_name = "sys_enter";
853 if (test_case->prog_sec_name) {
854 probe_name = test_case->prog_sec_name;
855 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
856 }
857
858 prog = bpf_object__find_program_by_title(obj, probe_name);
859 if (CHECK(!prog, "find_probe",
860 "prog '%s' not found\n", probe_name))
861 goto cleanup;
862
863 err = bpf_object__load(obj);
864 if (err) {
865 if (!test_case->fails)
866 ASSERT_OK(err, "obj_load");
867 goto cleanup;
868 }
869
870 data_map = bpf_object__find_map_by_name(obj, ".bss");
871 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
872 goto cleanup;
873
874 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
875 MAP_SHARED, bpf_map__fd(data_map), 0);
876 if (CHECK(mmap_data == MAP_FAILED, "mmap",
877 ".bss mmap failed: %d", errno)) {
878 mmap_data = NULL;
879 goto cleanup;
880 }
881 data = mmap_data;
882
883 memset(mmap_data, 0, sizeof(*data));
884 memcpy(data->in, test_case->input, test_case->input_len);
885 data->my_pid_tgid = my_pid_tgid;
886
887 link = bpf_program__attach_raw_tracepoint(prog, tp_name);
888 if (!ASSERT_OK_PTR(link, "attach_raw_tp"))
889 goto cleanup;
890
891 /* trigger test run */
892 if (test_case->trigger) {
893 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
894 goto cleanup;
895 } else {
896 usleep(1);
897 }
898
899 if (data->skip) {
900 test__skip();
901 goto cleanup;
902 }
903
904 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
905 goto cleanup;
906
907 equal = memcmp(data->out, test_case->output,
908 test_case->output_len) == 0;
909 if (CHECK(!equal, "check_result",
910 "input/output data don't match\n")) {
911 int j;
912
913 for (j = 0; j < test_case->input_len; j++) {
914 printf("input byte #%d: 0x%02hhx\n",
915 j, test_case->input[j]);
916 }
917 for (j = 0; j < test_case->output_len; j++) {
918 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
919 j, test_case->output[j], data->out[j]);
920 }
921 goto cleanup;
922 }
923
924 cleanup:
925 if (mmap_data) {
926 CHECK_FAIL(munmap(mmap_data, mmap_sz));
927 mmap_data = NULL;
928 }
929 bpf_link__destroy(link);
930 link = NULL;
931 bpf_object__close(obj);
932 }
933 }
934