aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/kprobes-test.c340
2 files changed, 342 insertions, 0 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index f7887dc53c1f..c7cbd965af94 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -43,6 +43,8 @@ obj-$(CONFIG_KPROBES) += kprobes-thumb.o
43else 43else
44obj-$(CONFIG_KPROBES) += kprobes-arm.o 44obj-$(CONFIG_KPROBES) += kprobes-arm.o
45endif 45endif
46obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
47test-kprobes-objs := kprobes-test.o
46obj-$(CONFIG_ATAGS_PROC) += atags.o 48obj-$(CONFIG_ATAGS_PROC) += atags.o
47obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o 49obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
48obj-$(CONFIG_ARM_THUMBEE) += thumbee.o 50obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c
new file mode 100644
index 000000000000..9fff0448c320
--- /dev/null
+++ b/arch/arm/kernel/kprobes-test.c
@@ -0,0 +1,340 @@
1/*
2 * arch/arm/kernel/kprobes-test.c
3 *
4 * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/kprobes.h>
14
15#include "kprobes.h"
16
17
18/*
19 * Test basic API
20 */
21
22static bool test_regs_ok;
23static int test_func_instance;
24static int pre_handler_called;
25static int post_handler_called;
26static int jprobe_func_called;
27static int kretprobe_handler_called;
28
29#define FUNC_ARG1 0x12345678
30#define FUNC_ARG2 0xabcdef
31
32
33#ifndef CONFIG_THUMB2_KERNEL
34
35long arm_func(long r0, long r1);
36
37static void __used __naked __arm_kprobes_test_func(void)
38{
39 __asm__ __volatile__ (
40 ".arm \n\t"
41 ".type arm_func, %%function \n\t"
42 "arm_func: \n\t"
43 "adds r0, r0, r1 \n\t"
44 "bx lr \n\t"
45 ".code "NORMAL_ISA /* Back to Thumb if necessary */
46 : : : "r0", "r1", "cc"
47 );
48}
49
50#else /* CONFIG_THUMB2_KERNEL */
51
52long thumb16_func(long r0, long r1);
53long thumb32even_func(long r0, long r1);
54long thumb32odd_func(long r0, long r1);
55
56static void __used __naked __thumb_kprobes_test_funcs(void)
57{
58 __asm__ __volatile__ (
59 ".type thumb16_func, %%function \n\t"
60 "thumb16_func: \n\t"
61 "adds.n r0, r0, r1 \n\t"
62 "bx lr \n\t"
63
64 ".align \n\t"
65 ".type thumb32even_func, %%function \n\t"
66 "thumb32even_func: \n\t"
67 "adds.w r0, r0, r1 \n\t"
68 "bx lr \n\t"
69
70 ".align \n\t"
71 "nop.n \n\t"
72 ".type thumb32odd_func, %%function \n\t"
73 "thumb32odd_func: \n\t"
74 "adds.w r0, r0, r1 \n\t"
75 "bx lr \n\t"
76
77 : : : "r0", "r1", "cc"
78 );
79}
80
81#endif /* CONFIG_THUMB2_KERNEL */
82
83
84static int call_test_func(long (*func)(long, long), bool check_test_regs)
85{
86 long ret;
87
88 ++test_func_instance;
89 test_regs_ok = false;
90
91 ret = (*func)(FUNC_ARG1, FUNC_ARG2);
92 if (ret != FUNC_ARG1 + FUNC_ARG2) {
93 pr_err("FAIL: call_test_func: func returned %lx\n", ret);
94 return false;
95 }
96
97 if (check_test_regs && !test_regs_ok) {
98 pr_err("FAIL: test regs not OK\n");
99 return false;
100 }
101
102 return true;
103}
104
105static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs)
106{
107 pre_handler_called = test_func_instance;
108 if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2)
109 test_regs_ok = true;
110 return 0;
111}
112
113static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs,
114 unsigned long flags)
115{
116 post_handler_called = test_func_instance;
117 if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2)
118 test_regs_ok = false;
119}
120
121static struct kprobe the_kprobe = {
122 .addr = 0,
123 .pre_handler = pre_handler,
124 .post_handler = post_handler
125};
126
127static int test_kprobe(long (*func)(long, long))
128{
129 int ret;
130
131 the_kprobe.addr = (kprobe_opcode_t *)func;
132 ret = register_kprobe(&the_kprobe);
133 if (ret < 0) {
134 pr_err("FAIL: register_kprobe failed with %d\n", ret);
135 return ret;
136 }
137
138 ret = call_test_func(func, true);
139
140 unregister_kprobe(&the_kprobe);
141 the_kprobe.flags = 0; /* Clear disable flag to allow reuse */
142
143 if (!ret)
144 return -EINVAL;
145 if (pre_handler_called != test_func_instance) {
146 pr_err("FAIL: kprobe pre_handler not called\n");
147 return -EINVAL;
148 }
149 if (post_handler_called != test_func_instance) {
150 pr_err("FAIL: kprobe post_handler not called\n");
151 return -EINVAL;
152 }
153 if (!call_test_func(func, false))
154 return -EINVAL;
155 if (pre_handler_called == test_func_instance ||
156 post_handler_called == test_func_instance) {
157 pr_err("FAIL: probe called after unregistering\n");
158 return -EINVAL;
159 }
160
161 return 0;
162}
163
164static void __kprobes jprobe_func(long r0, long r1)
165{
166 jprobe_func_called = test_func_instance;
167 if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
168 test_regs_ok = true;
169 jprobe_return();
170}
171
172static struct jprobe the_jprobe = {
173 .entry = jprobe_func,
174};
175
176static int test_jprobe(long (*func)(long, long))
177{
178 int ret;
179
180 the_jprobe.kp.addr = (kprobe_opcode_t *)func;
181 ret = register_jprobe(&the_jprobe);
182 if (ret < 0) {
183 pr_err("FAIL: register_jprobe failed with %d\n", ret);
184 return ret;
185 }
186
187 ret = call_test_func(func, true);
188
189 unregister_jprobe(&the_jprobe);
190 the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
191
192 if (!ret)
193 return -EINVAL;
194 if (jprobe_func_called != test_func_instance) {
195 pr_err("FAIL: jprobe handler function not called\n");
196 return -EINVAL;
197 }
198 if (!call_test_func(func, false))
199 return -EINVAL;
200 if (jprobe_func_called == test_func_instance) {
201 pr_err("FAIL: probe called after unregistering\n");
202 return -EINVAL;
203 }
204
205 return 0;
206}
207
208static int __kprobes
209kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
210{
211 kretprobe_handler_called = test_func_instance;
212 if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2)
213 test_regs_ok = true;
214 return 0;
215}
216
217static struct kretprobe the_kretprobe = {
218 .handler = kretprobe_handler,
219};
220
221static int test_kretprobe(long (*func)(long, long))
222{
223 int ret;
224
225 the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
226 ret = register_kretprobe(&the_kretprobe);
227 if (ret < 0) {
228 pr_err("FAIL: register_kretprobe failed with %d\n", ret);
229 return ret;
230 }
231
232 ret = call_test_func(func, true);
233
234 unregister_kretprobe(&the_kretprobe);
235 the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
236
237 if (!ret)
238 return -EINVAL;
239 if (kretprobe_handler_called != test_func_instance) {
240 pr_err("FAIL: kretprobe handler not called\n");
241 return -EINVAL;
242 }
243 if (!call_test_func(func, false))
244 return -EINVAL;
245 if (jprobe_func_called == test_func_instance) {
246 pr_err("FAIL: kretprobe called after unregistering\n");
247 return -EINVAL;
248 }
249
250 return 0;
251}
252
253static int run_api_tests(long (*func)(long, long))
254{
255 int ret;
256
257 pr_info(" kprobe\n");
258 ret = test_kprobe(func);
259 if (ret < 0)
260 return ret;
261
262 pr_info(" jprobe\n");
263 ret = test_jprobe(func);
264 if (ret < 0)
265 return ret;
266
267 pr_info(" kretprobe\n");
268 ret = test_kretprobe(func);
269 if (ret < 0)
270 return ret;
271
272 return 0;
273}
274
275
276/*
277 * Top level test functions
278 */
279
280static int __init run_all_tests(void)
281{
282 int ret = 0;
283
284 pr_info("Begining kprobe tests...\n");
285
286#ifndef CONFIG_THUMB2_KERNEL
287
288 pr_info("Probe ARM code\n");
289 ret = run_api_tests(arm_func);
290 if (ret)
291 goto out;
292
293#else /* CONFIG_THUMB2_KERNEL */
294
295 pr_info("Probe 16-bit Thumb code\n");
296 ret = run_api_tests(thumb16_func);
297 if (ret)
298 goto out;
299
300 pr_info("Probe 32-bit Thumb code, even halfword\n");
301 ret = run_api_tests(thumb32even_func);
302 if (ret)
303 goto out;
304
305 pr_info("Probe 32-bit Thumb code, odd halfword\n");
306 ret = run_api_tests(thumb32odd_func);
307 if (ret)
308 goto out;
309
310#endif
311
312out:
313 if (ret == 0)
314 pr_info("Finished kprobe tests OK\n");
315 else
316 pr_err("kprobe tests failed\n");
317
318 return ret;
319}
320
321
322/*
323 * Module setup
324 */
325
326#ifdef MODULE
327
328static void __exit kprobe_test_exit(void)
329{
330}
331
332module_init(run_all_tests)
333module_exit(kprobe_test_exit)
334MODULE_LICENSE("GPL");
335
336#else /* !MODULE */
337
338late_initcall(run_all_tests);
339
340#endif