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