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