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 | ||
f47cd9b5 AS |
138 | static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
139 | { | |
140 | krph_val = (rand1 / div_factor); | |
141 | return 0; | |
142 | } | |
143 | ||
8c1c9356 AM |
144 | static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
145 | { | |
146 | unsigned long ret = regs_return_value(regs); | |
147 | ||
148 | if (ret != (rand1 / div_factor)) { | |
149 | handler_errors++; | |
150 | printk(KERN_ERR "Kprobe smoke test failed: " | |
151 | "incorrect value in kretprobe handler\n"); | |
152 | } | |
f47cd9b5 AS |
153 | if (krph_val == 0) { |
154 | handler_errors++; | |
155 | printk(KERN_ERR "Kprobe smoke test failed: " | |
156 | "call to kretprobe entry handler failed\n"); | |
157 | } | |
8c1c9356 | 158 | |
f47cd9b5 | 159 | krph_val = rand1; |
8c1c9356 AM |
160 | return 0; |
161 | } | |
162 | ||
163 | static struct kretprobe rp = { | |
164 | .handler = return_handler, | |
f47cd9b5 | 165 | .entry_handler = entry_handler, |
8c1c9356 AM |
166 | .kp.symbol_name = "kprobe_target" |
167 | }; | |
168 | ||
169 | static int test_kretprobe(void) | |
170 | { | |
171 | int ret; | |
172 | ||
173 | ret = register_kretprobe(&rp); | |
174 | if (ret < 0) { | |
175 | printk(KERN_ERR "Kprobe smoke test failed: " | |
176 | "register_kretprobe returned %d\n", ret); | |
177 | return ret; | |
178 | } | |
179 | ||
180 | ret = kprobe_target(rand1); | |
181 | unregister_kretprobe(&rp); | |
f47cd9b5 | 182 | if (krph_val != rand1) { |
8c1c9356 AM |
183 | printk(KERN_ERR "Kprobe smoke test failed: " |
184 | "kretprobe handler not called\n"); | |
185 | handler_errors++; | |
186 | } | |
187 | ||
188 | return 0; | |
189 | } | |
190 | #endif /* CONFIG_KRETPROBES */ | |
191 | ||
192 | int init_test_probes(void) | |
193 | { | |
194 | int ret; | |
195 | ||
196 | do { | |
197 | rand1 = random32(); | |
198 | } while (rand1 <= div_factor); | |
199 | ||
200 | printk(KERN_INFO "Kprobe smoke test started\n"); | |
201 | num_tests++; | |
202 | ret = test_kprobe(); | |
203 | if (ret < 0) | |
204 | errors++; | |
205 | ||
206 | num_tests++; | |
207 | ret = test_jprobe(); | |
208 | if (ret < 0) | |
209 | errors++; | |
210 | ||
211 | #ifdef CONFIG_KRETPROBES | |
212 | num_tests++; | |
213 | ret = test_kretprobe(); | |
214 | if (ret < 0) | |
215 | errors++; | |
216 | #endif /* CONFIG_KRETPROBES */ | |
217 | ||
218 | if (errors) | |
219 | printk(KERN_ERR "BUG: Kprobe smoke test: %d out of " | |
220 | "%d tests failed\n", errors, num_tests); | |
221 | else if (handler_errors) | |
222 | printk(KERN_ERR "BUG: Kprobe smoke test: %d error(s) " | |
223 | "running handlers\n", handler_errors); | |
224 | else | |
225 | printk(KERN_INFO "Kprobe smoke test passed successfully\n"); | |
226 | ||
227 | return 0; | |
228 | } |