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