Commit | Line | Data |
---|---|---|
8c1c9356 AM |
1 | /* |
2 | * test_kprobes.c - simple sanity test for *probes | |
3 | * | |
4 | * Copyright IBM Corp. 2008 | |
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 as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
14 | * the GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/kprobes.h> | |
19 | #include <linux/random.h> | |
20 | ||
21 | #define div_factor 3 | |
22 | ||
23 | static u32 rand1, preh_val, posth_val, jph_val; | |
24 | static int errors, handler_errors, num_tests; | |
25 | ||
26 | static noinline u32 kprobe_target(u32 value) | |
27 | { | |
28 | /* | |
29 | * gcc ignores noinline on some architectures unless we stuff | |
30 | * sufficient lard into the function. The get_kprobe() here is | |
31 | * just for that. | |
32 | * | |
33 | * NOTE: We aren't concerned about the correctness of get_kprobe() | |
34 | * here; hence, this call is neither under !preempt nor with the | |
35 | * kprobe_mutex held. This is fine(tm) | |
36 | */ | |
37 | if (get_kprobe((void *)0xdeadbeef)) | |
38 | printk(KERN_INFO "Kprobe smoke test: probe on 0xdeadbeef!\n"); | |
39 | ||
40 | return (value / div_factor); | |
41 | } | |
42 | ||
43 | static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |
44 | { | |
45 | preh_val = (rand1 / div_factor); | |
46 | return 0; | |
47 | } | |
48 | ||
49 | static void kp_post_handler(struct kprobe *p, struct pt_regs *regs, | |
50 | unsigned long flags) | |
51 | { | |
52 | if (preh_val != (rand1 / div_factor)) { | |
53 | handler_errors++; | |
54 | printk(KERN_ERR "Kprobe smoke test failed: " | |
55 | "incorrect value in post_handler\n"); | |
56 | } | |
57 | posth_val = preh_val + div_factor; | |
58 | } | |
59 | ||
60 | static struct kprobe kp = { | |
61 | .symbol_name = "kprobe_target", | |
62 | .pre_handler = kp_pre_handler, | |
63 | .post_handler = kp_post_handler | |
64 | }; | |
65 | ||
66 | static int test_kprobe(void) | |
67 | { | |
68 | int ret; | |
69 | ||
70 | ret = register_kprobe(&kp); | |
71 | if (ret < 0) { | |
72 | printk(KERN_ERR "Kprobe smoke test failed: " | |
73 | "register_kprobe returned %d\n", ret); | |
74 | return ret; | |
75 | } | |
76 | ||
77 | ret = kprobe_target(rand1); | |
78 | unregister_kprobe(&kp); | |
79 | ||
80 | if (preh_val == 0) { | |
81 | printk(KERN_ERR "Kprobe smoke test failed: " | |
82 | "kprobe pre_handler not called\n"); | |
83 | handler_errors++; | |
84 | } | |
85 | ||
86 | if (posth_val == 0) { | |
87 | printk(KERN_ERR "Kprobe smoke test failed: " | |
88 | "kprobe post_handler not called\n"); | |
89 | handler_errors++; | |
90 | } | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | static u32 j_kprobe_target(u32 value) | |
96 | { | |
97 | if (value != rand1) { | |
98 | handler_errors++; | |
99 | printk(KERN_ERR "Kprobe smoke test failed: " | |
100 | "incorrect value in jprobe handler\n"); | |
101 | } | |
102 | ||
103 | jph_val = rand1; | |
104 | jprobe_return(); | |
105 | return 0; | |
106 | } | |
107 | ||
108 | static struct jprobe jp = { | |
109 | .entry = j_kprobe_target, | |
110 | .kp.symbol_name = "kprobe_target" | |
111 | }; | |
112 | ||
113 | static int test_jprobe(void) | |
114 | { | |
115 | int ret; | |
116 | ||
117 | ret = register_jprobe(&jp); | |
118 | if (ret < 0) { | |
119 | printk(KERN_ERR "Kprobe smoke test failed: " | |
120 | "register_jprobe returned %d\n", ret); | |
121 | return ret; | |
122 | } | |
123 | ||
124 | ret = kprobe_target(rand1); | |
125 | unregister_jprobe(&jp); | |
126 | if (jph_val == 0) { | |
127 | printk(KERN_ERR "Kprobe smoke test failed: " | |
128 | "jprobe handler not called\n"); | |
129 | handler_errors++; | |
130 | } | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | #ifdef CONFIG_KRETPROBES | |
136 | static u32 krph_val; | |
137 | ||
138 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | |
139 | { | |
140 | unsigned long ret = regs_return_value(regs); | |
141 | ||
142 | if (ret != (rand1 / div_factor)) { | |
143 | handler_errors++; | |
144 | printk(KERN_ERR "Kprobe smoke test failed: " | |
145 | "incorrect value in kretprobe handler\n"); | |
146 | } | |
147 | ||
148 | krph_val = (rand1 / div_factor); | |
149 | return 0; | |
150 | } | |
151 | ||
152 | static struct kretprobe rp = { | |
153 | .handler = return_handler, | |
154 | .kp.symbol_name = "kprobe_target" | |
155 | }; | |
156 | ||
157 | static int test_kretprobe(void) | |
158 | { | |
159 | int ret; | |
160 | ||
161 | ret = register_kretprobe(&rp); | |
162 | if (ret < 0) { | |
163 | printk(KERN_ERR "Kprobe smoke test failed: " | |
164 | "register_kretprobe returned %d\n", ret); | |
165 | return ret; | |
166 | } | |
167 | ||
168 | ret = kprobe_target(rand1); | |
169 | unregister_kretprobe(&rp); | |
170 | if (krph_val == 0) { | |
171 | printk(KERN_ERR "Kprobe smoke test failed: " | |
172 | "kretprobe handler not called\n"); | |
173 | handler_errors++; | |
174 | } | |
175 | ||
176 | return 0; | |
177 | } | |
178 | #endif /* CONFIG_KRETPROBES */ | |
179 | ||
180 | int init_test_probes(void) | |
181 | { | |
182 | int ret; | |
183 | ||
184 | do { | |
185 | rand1 = random32(); | |
186 | } while (rand1 <= div_factor); | |
187 | ||
188 | printk(KERN_INFO "Kprobe smoke test started\n"); | |
189 | num_tests++; | |
190 | ret = test_kprobe(); | |
191 | if (ret < 0) | |
192 | errors++; | |
193 | ||
194 | num_tests++; | |
195 | ret = test_jprobe(); | |
196 | if (ret < 0) | |
197 | errors++; | |
198 | ||
199 | #ifdef CONFIG_KRETPROBES | |
200 | num_tests++; | |
201 | ret = test_kretprobe(); | |
202 | if (ret < 0) | |
203 | errors++; | |
204 | #endif /* CONFIG_KRETPROBES */ | |
205 | ||
206 | if (errors) | |
207 | printk(KERN_ERR "BUG: Kprobe smoke test: %d out of " | |
208 | "%d tests failed\n", errors, num_tests); | |
209 | else if (handler_errors) | |
210 | printk(KERN_ERR "BUG: Kprobe smoke test: %d error(s) " | |
211 | "running handlers\n", handler_errors); | |
212 | else | |
213 | printk(KERN_INFO "Kprobe smoke test passed successfully\n"); | |
214 | ||
215 | return 0; | |
216 | } |