Merge tag 'ntfs3_for_6.4' of https://github.com/Paragon-Software-Group/linux-ntfs3
[platform/kernel/linux-starfive.git] / lib / test_fprobe.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * test_fprobe.c - simple sanity test for fprobe
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/fprobe.h>
8 #include <linux/random.h>
9 #include <kunit/test.h>
10
11 #define div_factor 3
12
13 static struct kunit *current_test;
14
15 static u32 rand1, entry_val, exit_val;
16
17 /* Use indirect calls to avoid inlining the target functions */
18 static u32 (*target)(u32 value);
19 static u32 (*target2)(u32 value);
20 static u32 (*target_nest)(u32 value, u32 (*nest)(u32));
21 static unsigned long target_ip;
22 static unsigned long target2_ip;
23 static unsigned long target_nest_ip;
24 static int entry_return_value;
25
26 static noinline u32 fprobe_selftest_target(u32 value)
27 {
28         return (value / div_factor);
29 }
30
31 static noinline u32 fprobe_selftest_target2(u32 value)
32 {
33         return (value / div_factor) + 1;
34 }
35
36 static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32))
37 {
38         return nest(value + 2);
39 }
40
41 static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
42                                      struct pt_regs *regs, void *data)
43 {
44         KUNIT_EXPECT_FALSE(current_test, preemptible());
45         /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
46         if (ip != target_ip)
47                 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
48         entry_val = (rand1 / div_factor);
49         if (fp->entry_data_size) {
50                 KUNIT_EXPECT_NOT_NULL(current_test, data);
51                 if (data)
52                         *(u32 *)data = entry_val;
53         } else
54                 KUNIT_EXPECT_NULL(current_test, data);
55
56         return entry_return_value;
57 }
58
59 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
60                                     struct pt_regs *regs, void *data)
61 {
62         unsigned long ret = regs_return_value(regs);
63
64         KUNIT_EXPECT_FALSE(current_test, preemptible());
65         if (ip != target_ip) {
66                 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
67                 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
68         } else
69                 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
70         KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
71         exit_val = entry_val + div_factor;
72         if (fp->entry_data_size) {
73                 KUNIT_EXPECT_NOT_NULL(current_test, data);
74                 if (data)
75                         KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val);
76         } else
77                 KUNIT_EXPECT_NULL(current_test, data);
78 }
79
80 static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
81                                      struct pt_regs *regs, void *data)
82 {
83         KUNIT_EXPECT_FALSE(current_test, preemptible());
84         return 0;
85 }
86
87 static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip,
88                                     struct pt_regs *regs, void *data)
89 {
90         KUNIT_EXPECT_FALSE(current_test, preemptible());
91         KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip);
92 }
93
94 /* Test entry only (no rethook) */
95 static void test_fprobe_entry(struct kunit *test)
96 {
97         struct fprobe fp_entry = {
98                 .entry_handler = fp_entry_handler,
99         };
100
101         current_test = test;
102
103         /* Before register, unregister should be failed. */
104         KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
105         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
106
107         entry_val = 0;
108         exit_val = 0;
109         target(rand1);
110         KUNIT_EXPECT_NE(test, 0, entry_val);
111         KUNIT_EXPECT_EQ(test, 0, exit_val);
112
113         entry_val = 0;
114         exit_val = 0;
115         target2(rand1);
116         KUNIT_EXPECT_NE(test, 0, entry_val);
117         KUNIT_EXPECT_EQ(test, 0, exit_val);
118
119         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
120 }
121
122 static void test_fprobe(struct kunit *test)
123 {
124         struct fprobe fp = {
125                 .entry_handler = fp_entry_handler,
126                 .exit_handler = fp_exit_handler,
127         };
128
129         current_test = test;
130         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
131
132         entry_val = 0;
133         exit_val = 0;
134         target(rand1);
135         KUNIT_EXPECT_NE(test, 0, entry_val);
136         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
137
138         entry_val = 0;
139         exit_val = 0;
140         target2(rand1);
141         KUNIT_EXPECT_NE(test, 0, entry_val);
142         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
143
144         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
145 }
146
147 static void test_fprobe_syms(struct kunit *test)
148 {
149         static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
150         struct fprobe fp = {
151                 .entry_handler = fp_entry_handler,
152                 .exit_handler = fp_exit_handler,
153         };
154
155         current_test = test;
156         KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
157
158         entry_val = 0;
159         exit_val = 0;
160         target(rand1);
161         KUNIT_EXPECT_NE(test, 0, entry_val);
162         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
163
164         entry_val = 0;
165         exit_val = 0;
166         target2(rand1);
167         KUNIT_EXPECT_NE(test, 0, entry_val);
168         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
169
170         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
171 }
172
173 /* Test private entry_data */
174 static void test_fprobe_data(struct kunit *test)
175 {
176         struct fprobe fp = {
177                 .entry_handler = fp_entry_handler,
178                 .exit_handler = fp_exit_handler,
179                 .entry_data_size = sizeof(u32),
180         };
181
182         current_test = test;
183         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
184
185         target(rand1);
186
187         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
188 }
189
190 /* Test nr_maxactive */
191 static void test_fprobe_nest(struct kunit *test)
192 {
193         static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_nest_target"};
194         struct fprobe fp = {
195                 .entry_handler = nest_entry_handler,
196                 .exit_handler = nest_exit_handler,
197                 .nr_maxactive = 1,
198         };
199
200         current_test = test;
201         KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
202
203         target_nest(rand1, target);
204         KUNIT_EXPECT_EQ(test, 1, fp.nmissed);
205
206         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
207 }
208
209 static void test_fprobe_skip(struct kunit *test)
210 {
211         struct fprobe fp = {
212                 .entry_handler = fp_entry_handler,
213                 .exit_handler = fp_exit_handler,
214         };
215
216         current_test = test;
217         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
218
219         entry_return_value = 1;
220         entry_val = 0;
221         exit_val = 0;
222         target(rand1);
223         KUNIT_EXPECT_NE(test, 0, entry_val);
224         KUNIT_EXPECT_EQ(test, 0, exit_val);
225         KUNIT_EXPECT_EQ(test, 0, fp.nmissed);
226         entry_return_value = 0;
227
228         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
229 }
230
231 static unsigned long get_ftrace_location(void *func)
232 {
233         unsigned long size, addr = (unsigned long)func;
234
235         if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
236                 return 0;
237
238         return ftrace_location_range(addr, addr + size - 1);
239 }
240
241 static int fprobe_test_init(struct kunit *test)
242 {
243         rand1 = get_random_u32_above(div_factor);
244         target = fprobe_selftest_target;
245         target2 = fprobe_selftest_target2;
246         target_nest = fprobe_selftest_nest_target;
247         target_ip = get_ftrace_location(target);
248         target2_ip = get_ftrace_location(target2);
249         target_nest_ip = get_ftrace_location(target_nest);
250
251         return 0;
252 }
253
254 static struct kunit_case fprobe_testcases[] = {
255         KUNIT_CASE(test_fprobe_entry),
256         KUNIT_CASE(test_fprobe),
257         KUNIT_CASE(test_fprobe_syms),
258         KUNIT_CASE(test_fprobe_data),
259         KUNIT_CASE(test_fprobe_nest),
260         KUNIT_CASE(test_fprobe_skip),
261         {}
262 };
263
264 static struct kunit_suite fprobe_test_suite = {
265         .name = "fprobe_test",
266         .init = fprobe_test_init,
267         .test_cases = fprobe_testcases,
268 };
269
270 kunit_test_suites(&fprobe_test_suite);
271