aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-08-28 11:02:38 -0400
committerJon Medhurst <tixy@yxit.co.uk>2011-09-20 14:17:43 -0400
commit9eed1797720ae633cf17b03dd804d8744f1d3b5c (patch)
treec57a2a32f8129b602bda54f58afe9c723cf661c2 /arch/arm
parent4189bc71ff2cd3c1920b69a01f6796caf3f1edb3 (diff)
ARM: kprobes: Add basic API tests
These test that the different kinds of probes can be successfully placed into ARM and Thumb code and that the handlers are called correctly when this code is executed. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm')
-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