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