aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes-arm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/kprobes-arm.c')
-rw-r--r--arch/arm/kernel/kprobes-arm.c343
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
75static void __kprobes
76emulate_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
104static void __kprobes
105emulate_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
134static void __kprobes
135emulate_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
161static void __kprobes
162emulate_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
196static void __kprobes
197emulate_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
223static void __kprobes
224emulate_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
253static void __kprobes
254emulate_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
273static void __kprobes
274emulate_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
304const 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};