Merge tag 'asm-generic-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd...
[linux-2.6-microblaze.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                                     unsigned long ret_ip,
43                                     struct pt_regs *regs, void *data)
44 {
45         KUNIT_EXPECT_FALSE(current_test, preemptible());
46         /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */
47         if (ip != target_ip)
48                 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
49         entry_val = (rand1 / div_factor);
50         if (fp->entry_data_size) {
51                 KUNIT_EXPECT_NOT_NULL(current_test, data);
52                 if (data)
53                         *(u32 *)data = entry_val;
54         } else
55                 KUNIT_EXPECT_NULL(current_test, data);
56
57         return entry_return_value;
58 }
59
60 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
61                                     unsigned long ret_ip,
62                                     struct pt_regs *regs, void *data)
63 {
64         unsigned long ret = regs_return_value(regs);
65
66         KUNIT_EXPECT_FALSE(current_test, preemptible());
67         if (ip != target_ip) {
68                 KUNIT_EXPECT_EQ(current_test, ip, target2_ip);
69                 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor) + 1);
70         } else
71                 KUNIT_EXPECT_EQ(current_test, ret, (rand1 / div_factor));
72         KUNIT_EXPECT_EQ(current_test, entry_val, (rand1 / div_factor));
73         exit_val = entry_val + div_factor;
74         if (fp->entry_data_size) {
75                 KUNIT_EXPECT_NOT_NULL(current_test, data);
76                 if (data)
77                         KUNIT_EXPECT_EQ(current_test, *(u32 *)data, entry_val);
78         } else
79                 KUNIT_EXPECT_NULL(current_test, data);
80 }
81
82 static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
83                                       unsigned long ret_ip,
84                                       struct pt_regs *regs, void *data)
85 {
86         KUNIT_EXPECT_FALSE(current_test, preemptible());
87         return 0;
88 }
89
90 static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip,
91                                       unsigned long ret_ip,
92                                       struct pt_regs *regs, void *data)
93 {
94         KUNIT_EXPECT_FALSE(current_test, preemptible());
95         KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip);
96 }
97
98 /* Test entry only (no rethook) */
99 static void test_fprobe_entry(struct kunit *test)
100 {
101         struct fprobe fp_entry = {
102                 .entry_handler = fp_entry_handler,
103         };
104
105         current_test = test;
106
107         /* Before register, unregister should be failed. */
108         KUNIT_EXPECT_NE(test, 0, unregister_fprobe(&fp_entry));
109         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp_entry, "fprobe_selftest_target*", NULL));
110
111         entry_val = 0;
112         exit_val = 0;
113         target(rand1);
114         KUNIT_EXPECT_NE(test, 0, entry_val);
115         KUNIT_EXPECT_EQ(test, 0, exit_val);
116
117         entry_val = 0;
118         exit_val = 0;
119         target2(rand1);
120         KUNIT_EXPECT_NE(test, 0, entry_val);
121         KUNIT_EXPECT_EQ(test, 0, exit_val);
122
123         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp_entry));
124 }
125
126 static void test_fprobe(struct kunit *test)
127 {
128         struct fprobe fp = {
129                 .entry_handler = fp_entry_handler,
130                 .exit_handler = fp_exit_handler,
131         };
132
133         current_test = test;
134         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target*", NULL));
135
136         entry_val = 0;
137         exit_val = 0;
138         target(rand1);
139         KUNIT_EXPECT_NE(test, 0, entry_val);
140         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
141
142         entry_val = 0;
143         exit_val = 0;
144         target2(rand1);
145         KUNIT_EXPECT_NE(test, 0, entry_val);
146         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
147
148         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
149 }
150
151 static void test_fprobe_syms(struct kunit *test)
152 {
153         static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_target2"};
154         struct fprobe fp = {
155                 .entry_handler = fp_entry_handler,
156                 .exit_handler = fp_exit_handler,
157         };
158
159         current_test = test;
160         KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
161
162         entry_val = 0;
163         exit_val = 0;
164         target(rand1);
165         KUNIT_EXPECT_NE(test, 0, entry_val);
166         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
167
168         entry_val = 0;
169         exit_val = 0;
170         target2(rand1);
171         KUNIT_EXPECT_NE(test, 0, entry_val);
172         KUNIT_EXPECT_EQ(test, entry_val + div_factor, exit_val);
173
174         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
175 }
176
177 /* Test private entry_data */
178 static void test_fprobe_data(struct kunit *test)
179 {
180         struct fprobe fp = {
181                 .entry_handler = fp_entry_handler,
182                 .exit_handler = fp_exit_handler,
183                 .entry_data_size = sizeof(u32),
184         };
185
186         current_test = test;
187         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
188
189         target(rand1);
190
191         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
192 }
193
194 /* Test nr_maxactive */
195 static void test_fprobe_nest(struct kunit *test)
196 {
197         static const char *syms[] = {"fprobe_selftest_target", "fprobe_selftest_nest_target"};
198         struct fprobe fp = {
199                 .entry_handler = nest_entry_handler,
200                 .exit_handler = nest_exit_handler,
201                 .nr_maxactive = 1,
202         };
203
204         current_test = test;
205         KUNIT_EXPECT_EQ(test, 0, register_fprobe_syms(&fp, syms, 2));
206
207         target_nest(rand1, target);
208         KUNIT_EXPECT_EQ(test, 1, fp.nmissed);
209
210         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
211 }
212
213 static void test_fprobe_skip(struct kunit *test)
214 {
215         struct fprobe fp = {
216                 .entry_handler = fp_entry_handler,
217                 .exit_handler = fp_exit_handler,
218         };
219
220         current_test = test;
221         KUNIT_EXPECT_EQ(test, 0, register_fprobe(&fp, "fprobe_selftest_target", NULL));
222
223         entry_return_value = 1;
224         entry_val = 0;
225         exit_val = 0;
226         target(rand1);
227         KUNIT_EXPECT_NE(test, 0, entry_val);
228         KUNIT_EXPECT_EQ(test, 0, exit_val);
229         KUNIT_EXPECT_EQ(test, 0, fp.nmissed);
230         entry_return_value = 0;
231
232         KUNIT_EXPECT_EQ(test, 0, unregister_fprobe(&fp));
233 }
234
235 static unsigned long get_ftrace_location(void *func)
236 {
237         unsigned long size, addr = (unsigned long)func;
238
239         if (!kallsyms_lookup_size_offset(addr, &size, NULL) || !size)
240                 return 0;
241
242         return ftrace_location_range(addr, addr + size - 1);
243 }
244
245 static int fprobe_test_init(struct kunit *test)
246 {
247         rand1 = get_random_u32_above(div_factor);
248         target = fprobe_selftest_target;
249         target2 = fprobe_selftest_target2;
250         target_nest = fprobe_selftest_nest_target;
251         target_ip = get_ftrace_location(target);
252         target2_ip = get_ftrace_location(target2);
253         target_nest_ip = get_ftrace_location(target_nest);
254
255         return 0;
256 }
257
258 static struct kunit_case fprobe_testcases[] = {
259         KUNIT_CASE(test_fprobe_entry),
260         KUNIT_CASE(test_fprobe),
261         KUNIT_CASE(test_fprobe_syms),
262         KUNIT_CASE(test_fprobe_data),
263         KUNIT_CASE(test_fprobe_nest),
264         KUNIT_CASE(test_fprobe_skip),
265         {}
266 };
267
268 static struct kunit_suite fprobe_test_suite = {
269         .name = "fprobe_test",
270         .init = fprobe_test_init,
271         .test_cases = fprobe_testcases,
272 };
273
274 kunit_test_suites(&fprobe_test_suite);
275