diff options
Diffstat (limited to 'tools/testing/selftests/bpf/test_btf_dump.c')
-rw-r--r-- | tools/testing/selftests/bpf/test_btf_dump.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/test_btf_dump.c b/tools/testing/selftests/bpf/test_btf_dump.c new file mode 100644 index 000000000000..8f850823d35f --- /dev/null +++ b/tools/testing/selftests/bpf/test_btf_dump.c | |||
@@ -0,0 +1,143 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | #include <unistd.h> | ||
5 | #include <errno.h> | ||
6 | #include <linux/err.h> | ||
7 | #include <btf.h> | ||
8 | |||
9 | #define CHECK(condition, format...) ({ \ | ||
10 | int __ret = !!(condition); \ | ||
11 | if (__ret) { \ | ||
12 | fprintf(stderr, "%s:%d:FAIL ", __func__, __LINE__); \ | ||
13 | fprintf(stderr, format); \ | ||
14 | } \ | ||
15 | __ret; \ | ||
16 | }) | ||
17 | |||
18 | void btf_dump_printf(void *ctx, const char *fmt, va_list args) | ||
19 | { | ||
20 | vfprintf(ctx, fmt, args); | ||
21 | } | ||
22 | |||
23 | struct btf_dump_test_case { | ||
24 | const char *name; | ||
25 | struct btf_dump_opts opts; | ||
26 | } btf_dump_test_cases[] = { | ||
27 | {.name = "btf_dump_test_case_syntax", .opts = {}}, | ||
28 | {.name = "btf_dump_test_case_ordering", .opts = {}}, | ||
29 | {.name = "btf_dump_test_case_padding", .opts = {}}, | ||
30 | {.name = "btf_dump_test_case_packing", .opts = {}}, | ||
31 | {.name = "btf_dump_test_case_bitfields", .opts = {}}, | ||
32 | {.name = "btf_dump_test_case_multidim", .opts = {}}, | ||
33 | {.name = "btf_dump_test_case_namespacing", .opts = {}}, | ||
34 | }; | ||
35 | |||
36 | static int btf_dump_all_types(const struct btf *btf, | ||
37 | const struct btf_dump_opts *opts) | ||
38 | { | ||
39 | size_t type_cnt = btf__get_nr_types(btf); | ||
40 | struct btf_dump *d; | ||
41 | int err = 0, id; | ||
42 | |||
43 | d = btf_dump__new(btf, NULL, opts, btf_dump_printf); | ||
44 | if (IS_ERR(d)) | ||
45 | return PTR_ERR(d); | ||
46 | |||
47 | for (id = 1; id <= type_cnt; id++) { | ||
48 | err = btf_dump__dump_type(d, id); | ||
49 | if (err) | ||
50 | goto done; | ||
51 | } | ||
52 | |||
53 | done: | ||
54 | btf_dump__free(d); | ||
55 | return err; | ||
56 | } | ||
57 | |||
58 | int test_btf_dump_case(int n, struct btf_dump_test_case *test_case) | ||
59 | { | ||
60 | char test_file[256], out_file[256], diff_cmd[1024]; | ||
61 | struct btf *btf = NULL; | ||
62 | int err = 0, fd = -1; | ||
63 | FILE *f = NULL; | ||
64 | |||
65 | fprintf(stderr, "Test case #%d (%s): ", n, test_case->name); | ||
66 | |||
67 | snprintf(test_file, sizeof(test_file), "%s.o", test_case->name); | ||
68 | |||
69 | btf = btf__parse_elf(test_file, NULL); | ||
70 | if (CHECK(IS_ERR(btf), | ||
71 | "failed to load test BTF: %ld\n", PTR_ERR(btf))) { | ||
72 | err = -PTR_ERR(btf); | ||
73 | btf = NULL; | ||
74 | goto done; | ||
75 | } | ||
76 | |||
77 | snprintf(out_file, sizeof(out_file), | ||
78 | "/tmp/%s.output.XXXXXX", test_case->name); | ||
79 | fd = mkstemp(out_file); | ||
80 | if (CHECK(fd < 0, "failed to create temp output file: %d\n", fd)) { | ||
81 | err = fd; | ||
82 | goto done; | ||
83 | } | ||
84 | f = fdopen(fd, "w"); | ||
85 | if (CHECK(f == NULL, "failed to open temp output file: %s(%d)\n", | ||
86 | strerror(errno), errno)) { | ||
87 | close(fd); | ||
88 | goto done; | ||
89 | } | ||
90 | |||
91 | test_case->opts.ctx = f; | ||
92 | err = btf_dump_all_types(btf, &test_case->opts); | ||
93 | fclose(f); | ||
94 | close(fd); | ||
95 | if (CHECK(err, "failure during C dumping: %d\n", err)) { | ||
96 | goto done; | ||
97 | } | ||
98 | |||
99 | snprintf(test_file, sizeof(test_file), "progs/%s.c", test_case->name); | ||
100 | /* | ||
101 | * Diff test output and expected test output, contained between | ||
102 | * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case. | ||
103 | * For expected output lines, everything before '*' is stripped out. | ||
104 | * Also lines containing comment start and comment end markers are | ||
105 | * ignored. | ||
106 | */ | ||
107 | snprintf(diff_cmd, sizeof(diff_cmd), | ||
108 | "awk '/START-EXPECTED-OUTPUT/{out=1;next} " | ||
109 | "/END-EXPECTED-OUTPUT/{out=0} " | ||
110 | "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */ | ||
111 | "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'", | ||
112 | test_file, out_file); | ||
113 | err = system(diff_cmd); | ||
114 | if (CHECK(err, | ||
115 | "differing test output, output=%s, err=%d, diff cmd:\n%s\n", | ||
116 | out_file, err, diff_cmd)) | ||
117 | goto done; | ||
118 | |||
119 | remove(out_file); | ||
120 | fprintf(stderr, "OK\n"); | ||
121 | |||
122 | done: | ||
123 | btf__free(btf); | ||
124 | return err; | ||
125 | } | ||
126 | |||
127 | int main() { | ||
128 | int test_case_cnt, i, err, failed = 0; | ||
129 | |||
130 | test_case_cnt = sizeof(btf_dump_test_cases) / | ||
131 | sizeof(btf_dump_test_cases[0]); | ||
132 | |||
133 | for (i = 0; i < test_case_cnt; i++) { | ||
134 | err = test_btf_dump_case(i, &btf_dump_test_cases[i]); | ||
135 | if (err) | ||
136 | failed++; | ||
137 | } | ||
138 | |||
139 | fprintf(stderr, "%d tests succeeded, %d tests failed.\n", | ||
140 | test_case_cnt - failed, failed); | ||
141 | |||
142 | return failed; | ||
143 | } | ||