diff options
Diffstat (limited to 'arch/arm/kernel/kprobes-arm.c')
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 343 |
1 files changed, 0 insertions, 343 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c deleted file mode 100644 index ac300c60d656..000000000000 --- a/arch/arm/kernel/kprobes-arm.c +++ /dev/null | |||
@@ -1,343 +0,0 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-decode.c | ||
3 | * | ||
4 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * We do not have hardware single-stepping on ARM, This | ||
18 | * effort is further complicated by the ARM not having a | ||
19 | * "next PC" register. Instructions that change the PC | ||
20 | * can't be safely single-stepped in a MP environment, so | ||
21 | * we have a lot of work to do: | ||
22 | * | ||
23 | * In the prepare phase: | ||
24 | * *) If it is an instruction that does anything | ||
25 | * with the CPU mode, we reject it for a kprobe. | ||
26 | * (This is out of laziness rather than need. The | ||
27 | * instructions could be simulated.) | ||
28 | * | ||
29 | * *) Otherwise, decode the instruction rewriting its | ||
30 | * registers to take fixed, ordered registers and | ||
31 | * setting a handler for it to run the instruction. | ||
32 | * | ||
33 | * In the execution phase by an instruction's handler: | ||
34 | * | ||
35 | * *) If the PC is written to by the instruction, the | ||
36 | * instruction must be fully simulated in software. | ||
37 | * | ||
38 | * *) Otherwise, a modified form of the instruction is | ||
39 | * directly executed. Its handler calls the | ||
40 | * instruction in insn[0]. In insn[1] is a | ||
41 | * "mov pc, lr" to return. | ||
42 | * | ||
43 | * Before calling, load up the reordered registers | ||
44 | * from the original instruction's registers. If one | ||
45 | * of the original input registers is the PC, compute | ||
46 | * and adjust the appropriate input register. | ||
47 | * | ||
48 | * After call completes, copy the output registers to | ||
49 | * the original instruction's original registers. | ||
50 | * | ||
51 | * We don't use a real breakpoint instruction since that | ||
52 | * would have us in the kernel go from SVC mode to SVC | ||
53 | * mode losing the link register. Instead we use an | ||
54 | * undefined instruction. To simplify processing, the | ||
55 | * undefined instruction used for kprobes must be reserved | ||
56 | * exclusively for kprobes use. | ||
57 | * | ||
58 | * TODO: ifdef out some instruction decoding based on architecture. | ||
59 | */ | ||
60 | |||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/kprobes.h> | ||
63 | #include <linux/ptrace.h> | ||
64 | |||
65 | #include "kprobes.h" | ||
66 | #include "probes-arm.h" | ||
67 | |||
68 | #if __LINUX_ARM_ARCH__ >= 6 | ||
69 | #define BLX(reg) "blx "reg" \n\t" | ||
70 | #else | ||
71 | #define BLX(reg) "mov lr, pc \n\t" \ | ||
72 | "mov pc, "reg" \n\t" | ||
73 | #endif | ||
74 | |||
75 | static void __kprobes | ||
76 | emulate_ldrdstrd(probes_opcode_t insn, | ||
77 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
78 | { | ||
79 | unsigned long pc = regs->ARM_pc + 4; | ||
80 | int rt = (insn >> 12) & 0xf; | ||
81 | int rn = (insn >> 16) & 0xf; | ||
82 | int rm = insn & 0xf; | ||
83 | |||
84 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
85 | register unsigned long rt2v asm("r1") = regs->uregs[rt+1]; | ||
86 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
87 | : regs->uregs[rn]; | ||
88 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
89 | |||
90 | __asm__ __volatile__ ( | ||
91 | BLX("%[fn]") | ||
92 | : "=r" (rtv), "=r" (rt2v), "=r" (rnv) | ||
93 | : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), | ||
94 | [fn] "r" (asi->insn_fn) | ||
95 | : "lr", "memory", "cc" | ||
96 | ); | ||
97 | |||
98 | regs->uregs[rt] = rtv; | ||
99 | regs->uregs[rt+1] = rt2v; | ||
100 | if (is_writeback(insn)) | ||
101 | regs->uregs[rn] = rnv; | ||
102 | } | ||
103 | |||
104 | static void __kprobes | ||
105 | emulate_ldr(probes_opcode_t insn, | ||
106 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
107 | { | ||
108 | unsigned long pc = regs->ARM_pc + 4; | ||
109 | int rt = (insn >> 12) & 0xf; | ||
110 | int rn = (insn >> 16) & 0xf; | ||
111 | int rm = insn & 0xf; | ||
112 | |||
113 | register unsigned long rtv asm("r0"); | ||
114 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
115 | : regs->uregs[rn]; | ||
116 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
117 | |||
118 | __asm__ __volatile__ ( | ||
119 | BLX("%[fn]") | ||
120 | : "=r" (rtv), "=r" (rnv) | ||
121 | : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) | ||
122 | : "lr", "memory", "cc" | ||
123 | ); | ||
124 | |||
125 | if (rt == 15) | ||
126 | load_write_pc(rtv, regs); | ||
127 | else | ||
128 | regs->uregs[rt] = rtv; | ||
129 | |||
130 | if (is_writeback(insn)) | ||
131 | regs->uregs[rn] = rnv; | ||
132 | } | ||
133 | |||
134 | static void __kprobes | ||
135 | emulate_str(probes_opcode_t insn, | ||
136 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
137 | { | ||
138 | unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; | ||
139 | unsigned long rnpc = regs->ARM_pc + 4; | ||
140 | int rt = (insn >> 12) & 0xf; | ||
141 | int rn = (insn >> 16) & 0xf; | ||
142 | int rm = insn & 0xf; | ||
143 | |||
144 | register unsigned long rtv asm("r0") = (rt == 15) ? rtpc | ||
145 | : regs->uregs[rt]; | ||
146 | register unsigned long rnv asm("r2") = (rn == 15) ? rnpc | ||
147 | : regs->uregs[rn]; | ||
148 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
149 | |||
150 | __asm__ __volatile__ ( | ||
151 | BLX("%[fn]") | ||
152 | : "=r" (rnv) | ||
153 | : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) | ||
154 | : "lr", "memory", "cc" | ||
155 | ); | ||
156 | |||
157 | if (is_writeback(insn)) | ||
158 | regs->uregs[rn] = rnv; | ||
159 | } | ||
160 | |||
161 | static void __kprobes | ||
162 | emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, | ||
163 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
164 | { | ||
165 | unsigned long pc = regs->ARM_pc + 4; | ||
166 | int rd = (insn >> 12) & 0xf; | ||
167 | int rn = (insn >> 16) & 0xf; | ||
168 | int rm = insn & 0xf; | ||
169 | int rs = (insn >> 8) & 0xf; | ||
170 | |||
171 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
172 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
173 | : regs->uregs[rn]; | ||
174 | register unsigned long rmv asm("r3") = (rm == 15) ? pc | ||
175 | : regs->uregs[rm]; | ||
176 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
177 | unsigned long cpsr = regs->ARM_cpsr; | ||
178 | |||
179 | __asm__ __volatile__ ( | ||
180 | "msr cpsr_fs, %[cpsr] \n\t" | ||
181 | BLX("%[fn]") | ||
182 | "mrs %[cpsr], cpsr \n\t" | ||
183 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
184 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
185 | "1" (cpsr), [fn] "r" (asi->insn_fn) | ||
186 | : "lr", "memory", "cc" | ||
187 | ); | ||
188 | |||
189 | if (rd == 15) | ||
190 | alu_write_pc(rdv, regs); | ||
191 | else | ||
192 | regs->uregs[rd] = rdv; | ||
193 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
194 | } | ||
195 | |||
196 | static void __kprobes | ||
197 | emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, | ||
198 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
199 | { | ||
200 | int rd = (insn >> 12) & 0xf; | ||
201 | int rn = (insn >> 16) & 0xf; | ||
202 | int rm = insn & 0xf; | ||
203 | |||
204 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
205 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
206 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
207 | unsigned long cpsr = regs->ARM_cpsr; | ||
208 | |||
209 | __asm__ __volatile__ ( | ||
210 | "msr cpsr_fs, %[cpsr] \n\t" | ||
211 | BLX("%[fn]") | ||
212 | "mrs %[cpsr], cpsr \n\t" | ||
213 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
214 | : "0" (rdv), "r" (rnv), "r" (rmv), | ||
215 | "1" (cpsr), [fn] "r" (asi->insn_fn) | ||
216 | : "lr", "memory", "cc" | ||
217 | ); | ||
218 | |||
219 | regs->uregs[rd] = rdv; | ||
220 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
221 | } | ||
222 | |||
223 | static void __kprobes | ||
224 | emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, | ||
225 | struct arch_probes_insn *asi, | ||
226 | struct pt_regs *regs) | ||
227 | { | ||
228 | int rd = (insn >> 16) & 0xf; | ||
229 | int rn = (insn >> 12) & 0xf; | ||
230 | int rm = insn & 0xf; | ||
231 | int rs = (insn >> 8) & 0xf; | ||
232 | |||
233 | register unsigned long rdv asm("r2") = regs->uregs[rd]; | ||
234 | register unsigned long rnv asm("r0") = regs->uregs[rn]; | ||
235 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
236 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
237 | unsigned long cpsr = regs->ARM_cpsr; | ||
238 | |||
239 | __asm__ __volatile__ ( | ||
240 | "msr cpsr_fs, %[cpsr] \n\t" | ||
241 | BLX("%[fn]") | ||
242 | "mrs %[cpsr], cpsr \n\t" | ||
243 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
244 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
245 | "1" (cpsr), [fn] "r" (asi->insn_fn) | ||
246 | : "lr", "memory", "cc" | ||
247 | ); | ||
248 | |||
249 | regs->uregs[rd] = rdv; | ||
250 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
251 | } | ||
252 | |||
253 | static void __kprobes | ||
254 | emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, | ||
255 | struct arch_probes_insn *asi, struct pt_regs *regs) | ||
256 | { | ||
257 | int rd = (insn >> 12) & 0xf; | ||
258 | int rm = insn & 0xf; | ||
259 | |||
260 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
261 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
262 | |||
263 | __asm__ __volatile__ ( | ||
264 | BLX("%[fn]") | ||
265 | : "=r" (rdv) | ||
266 | : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn) | ||
267 | : "lr", "memory", "cc" | ||
268 | ); | ||
269 | |||
270 | regs->uregs[rd] = rdv; | ||
271 | } | ||
272 | |||
273 | static void __kprobes | ||
274 | emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, | ||
275 | struct arch_probes_insn *asi, | ||
276 | struct pt_regs *regs) | ||
277 | { | ||
278 | int rdlo = (insn >> 12) & 0xf; | ||
279 | int rdhi = (insn >> 16) & 0xf; | ||
280 | int rn = insn & 0xf; | ||
281 | int rm = (insn >> 8) & 0xf; | ||
282 | |||
283 | register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; | ||
284 | register unsigned long rdhiv asm("r2") = regs->uregs[rdhi]; | ||
285 | register unsigned long rnv asm("r3") = regs->uregs[rn]; | ||
286 | register unsigned long rmv asm("r1") = regs->uregs[rm]; | ||
287 | unsigned long cpsr = regs->ARM_cpsr; | ||
288 | |||
289 | __asm__ __volatile__ ( | ||
290 | "msr cpsr_fs, %[cpsr] \n\t" | ||
291 | BLX("%[fn]") | ||
292 | "mrs %[cpsr], cpsr \n\t" | ||
293 | : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) | ||
294 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), | ||
295 | "2" (cpsr), [fn] "r" (asi->insn_fn) | ||
296 | : "lr", "memory", "cc" | ||
297 | ); | ||
298 | |||
299 | regs->uregs[rdlo] = rdlov; | ||
300 | regs->uregs[rdhi] = rdhiv; | ||
301 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
302 | } | ||
303 | |||
304 | const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { | ||
305 | [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none}, | ||
306 | [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, | ||
307 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, | ||
308 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, | ||
309 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, | ||
310 | [PROBES_MRS] = {.handler = simulate_mrs}, | ||
311 | [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, | ||
312 | [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc}, | ||
313 | [PROBES_SATURATING_ARITHMETIC] = { | ||
314 | .handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
315 | [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, | ||
316 | [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, | ||
317 | [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
318 | [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd}, | ||
319 | [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr}, | ||
320 | [PROBES_LOAD] = {.handler = emulate_ldr}, | ||
321 | [PROBES_STORE_EXTRA] = {.handler = emulate_str}, | ||
322 | [PROBES_STORE] = {.handler = emulate_str}, | ||
323 | [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, | ||
324 | [PROBES_DATA_PROCESSING_REG] = { | ||
325 | .handler = emulate_rd12rn16rm0rs8_rwflags}, | ||
326 | [PROBES_DATA_PROCESSING_IMM] = { | ||
327 | .handler = emulate_rd12rn16rm0rs8_rwflags}, | ||
328 | [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, | ||
329 | [PROBES_SEV] = {.handler = probes_emulate_none}, | ||
330 | [PROBES_WFE] = {.handler = probes_simulate_nop}, | ||
331 | [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
332 | [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, | ||
333 | [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
334 | [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
335 | [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc}, | ||
336 | [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, | ||
337 | [PROBES_MUL_ADD_LONG] = { | ||
338 | .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, | ||
339 | [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, | ||
340 | [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc}, | ||
341 | [PROBES_BRANCH] = {.handler = simulate_bbl}, | ||
342 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} | ||
343 | }; | ||