blob: b9056d649607f359a13a8d9b64bd26d8c780bbcd [file] [log] [blame]
Quentin Barnes35aa1df2007-06-11 22:20:10 +00001/*
Wang Nanfca08f32015-01-09 10:19:49 +08002 * arch/arm/probes/kprobes/actions-arm.c
Quentin Barnes35aa1df2007-06-11 22:20:10 +00003 *
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.
Quentin Barnes35aa1df2007-06-11 22:20:10 +000037 *
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>
David A. Longc18377c2014-03-07 11:16:10 -050063#include <linux/ptrace.h>
Quentin Barnes35aa1df2007-06-11 22:20:10 +000064
Wang Nanfca08f32015-01-09 10:19:49 +080065#include "../decode-arm.h"
66#include "core.h"
Wang Nan6624cf62015-01-05 19:29:21 +080067#include "checkers.h"
Quentin Barnes35aa1df2007-06-11 22:20:10 +000068
Jon Medhurst7be7ee22011-07-07 14:03:08 +010069#if __LINUX_ARM_ARCH__ >= 6
70#define BLX(reg) "blx "reg" \n\t"
71#else
72#define BLX(reg) "mov lr, pc \n\t" \
73 "mov pc, "reg" \n\t"
74#endif
75
David A. Long3e6cd392014-03-06 18:06:43 -050076static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -050077emulate_ldrdstrd(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -050078 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurst87239422011-06-09 17:39:42 +010079{
David A. Long7579f4b32014-03-07 11:19:32 -050080 unsigned long pc = regs->ARM_pc + 4;
Jon Medhurst87239422011-06-09 17:39:42 +010081 int rt = (insn >> 12) & 0xf;
82 int rn = (insn >> 16) & 0xf;
83 int rm = insn & 0xf;
84
85 register unsigned long rtv asm("r0") = regs->uregs[rt];
86 register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
87 register unsigned long rnv asm("r2") = (rn == 15) ? pc
88 : regs->uregs[rn];
89 register unsigned long rmv asm("r3") = regs->uregs[rm];
90
91 __asm__ __volatile__ (
92 BLX("%[fn]")
93 : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
94 : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
David A. Long7579f4b32014-03-07 11:19:32 -050095 [fn] "r" (asi->insn_fn)
Jon Medhurst87239422011-06-09 17:39:42 +010096 : "lr", "memory", "cc"
97 );
98
99 regs->uregs[rt] = rtv;
100 regs->uregs[rt+1] = rt2v;
101 if (is_writeback(insn))
102 regs->uregs[rn] = rnv;
103}
104
David A. Long3e6cd392014-03-06 18:06:43 -0500105static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500106emulate_ldr(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500107 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100108{
David A. Long7579f4b32014-03-07 11:19:32 -0500109 unsigned long pc = regs->ARM_pc + 4;
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100110 int rt = (insn >> 12) & 0xf;
111 int rn = (insn >> 16) & 0xf;
112 int rm = insn & 0xf;
113
114 register unsigned long rtv asm("r0");
115 register unsigned long rnv asm("r2") = (rn == 15) ? pc
116 : regs->uregs[rn];
117 register unsigned long rmv asm("r3") = regs->uregs[rm];
118
119 __asm__ __volatile__ (
120 BLX("%[fn]")
121 : "=r" (rtv), "=r" (rnv)
David A. Long7579f4b32014-03-07 11:19:32 -0500122 : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100123 : "lr", "memory", "cc"
124 );
125
126 if (rt == 15)
127 load_write_pc(rtv, regs);
128 else
129 regs->uregs[rt] = rtv;
130
131 if (is_writeback(insn))
132 regs->uregs[rn] = rnv;
133}
134
David A. Long3e6cd392014-03-06 18:06:43 -0500135static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500136emulate_str(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500137 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100138{
David A. Long7579f4b32014-03-07 11:19:32 -0500139 unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
140 unsigned long rnpc = regs->ARM_pc + 4;
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100141 int rt = (insn >> 12) & 0xf;
142 int rn = (insn >> 16) & 0xf;
143 int rm = insn & 0xf;
144
145 register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
146 : regs->uregs[rt];
147 register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
148 : regs->uregs[rn];
149 register unsigned long rmv asm("r3") = regs->uregs[rm];
150
151 __asm__ __volatile__ (
152 BLX("%[fn]")
153 : "=r" (rnv)
David A. Long7579f4b32014-03-07 11:19:32 -0500154 : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
Jon Medhurst3c48fbb2011-06-11 13:10:49 +0100155 : "lr", "memory", "cc"
156 );
157
158 if (is_writeback(insn))
159 regs->uregs[rn] = rnv;
160}
161
David A. Long3e6cd392014-03-06 18:06:43 -0500162static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500163emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500164 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurst9f596e52011-06-09 17:35:36 +0100165{
David A. Long7579f4b32014-03-07 11:19:32 -0500166 unsigned long pc = regs->ARM_pc + 4;
Jon Medhurst9f596e52011-06-09 17:35:36 +0100167 int rd = (insn >> 12) & 0xf;
168 int rn = (insn >> 16) & 0xf;
169 int rm = insn & 0xf;
170 int rs = (insn >> 8) & 0xf;
171
172 register unsigned long rdv asm("r0") = regs->uregs[rd];
173 register unsigned long rnv asm("r2") = (rn == 15) ? pc
174 : regs->uregs[rn];
175 register unsigned long rmv asm("r3") = (rm == 15) ? pc
176 : regs->uregs[rm];
177 register unsigned long rsv asm("r1") = regs->uregs[rs];
178 unsigned long cpsr = regs->ARM_cpsr;
179
180 __asm__ __volatile__ (
181 "msr cpsr_fs, %[cpsr] \n\t"
182 BLX("%[fn]")
183 "mrs %[cpsr], cpsr \n\t"
184 : "=r" (rdv), [cpsr] "=r" (cpsr)
185 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
David A. Long7579f4b32014-03-07 11:19:32 -0500186 "1" (cpsr), [fn] "r" (asi->insn_fn)
Jon Medhurst9f596e52011-06-09 17:35:36 +0100187 : "lr", "memory", "cc"
188 );
189
190 if (rd == 15)
191 alu_write_pc(rdv, regs);
192 else
193 regs->uregs[rd] = rdv;
194 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
195}
196
David A. Long3e6cd392014-03-06 18:06:43 -0500197static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500198emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500199 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurst0e44e9a2011-06-09 17:23:50 +0100200{
Jon Medhurst0e44e9a2011-06-09 17:23:50 +0100201 int rd = (insn >> 12) & 0xf;
202 int rn = (insn >> 16) & 0xf;
203 int rm = insn & 0xf;
204
205 register unsigned long rdv asm("r0") = regs->uregs[rd];
206 register unsigned long rnv asm("r2") = regs->uregs[rn];
207 register unsigned long rmv asm("r3") = regs->uregs[rm];
208 unsigned long cpsr = regs->ARM_cpsr;
209
210 __asm__ __volatile__ (
211 "msr cpsr_fs, %[cpsr] \n\t"
212 BLX("%[fn]")
213 "mrs %[cpsr], cpsr \n\t"
214 : "=r" (rdv), [cpsr] "=r" (cpsr)
215 : "0" (rdv), "r" (rnv), "r" (rmv),
David A. Long7579f4b32014-03-07 11:19:32 -0500216 "1" (cpsr), [fn] "r" (asi->insn_fn)
Jon Medhurst0e44e9a2011-06-09 17:23:50 +0100217 : "lr", "memory", "cc"
218 );
219
220 regs->uregs[rd] = rdv;
221 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
222}
223
David A. Long3e6cd392014-03-06 18:06:43 -0500224static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500225emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500226 struct arch_probes_insn *asi,
David A. Long7579f4b32014-03-07 11:19:32 -0500227 struct pt_regs *regs)
Jon Medhurst6091dfa2011-06-10 17:35:51 +0100228{
Jon Medhurst6091dfa2011-06-10 17:35:51 +0100229 int rd = (insn >> 16) & 0xf;
230 int rn = (insn >> 12) & 0xf;
231 int rm = insn & 0xf;
232 int rs = (insn >> 8) & 0xf;
233
234 register unsigned long rdv asm("r2") = regs->uregs[rd];
235 register unsigned long rnv asm("r0") = regs->uregs[rn];
236 register unsigned long rmv asm("r3") = regs->uregs[rm];
237 register unsigned long rsv asm("r1") = regs->uregs[rs];
238 unsigned long cpsr = regs->ARM_cpsr;
239
240 __asm__ __volatile__ (
241 "msr cpsr_fs, %[cpsr] \n\t"
242 BLX("%[fn]")
243 "mrs %[cpsr], cpsr \n\t"
244 : "=r" (rdv), [cpsr] "=r" (cpsr)
245 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
David A. Long7579f4b32014-03-07 11:19:32 -0500246 "1" (cpsr), [fn] "r" (asi->insn_fn)
Jon Medhurst6091dfa2011-06-10 17:35:51 +0100247 : "lr", "memory", "cc"
248 );
249
250 regs->uregs[rd] = rdv;
251 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
252}
253
David A. Long3e6cd392014-03-06 18:06:43 -0500254static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500255emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500256 struct arch_probes_insn *asi, struct pt_regs *regs)
Jon Medhurstc82584e2011-06-10 18:10:36 +0100257{
Jon Medhurstc82584e2011-06-10 18:10:36 +0100258 int rd = (insn >> 12) & 0xf;
259 int rm = insn & 0xf;
260
261 register unsigned long rdv asm("r0") = regs->uregs[rd];
262 register unsigned long rmv asm("r3") = regs->uregs[rm];
263
264 __asm__ __volatile__ (
265 BLX("%[fn]")
266 : "=r" (rdv)
David A. Long7579f4b32014-03-07 11:19:32 -0500267 : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
Jon Medhurstc82584e2011-06-10 18:10:36 +0100268 : "lr", "memory", "cc"
269 );
270
271 regs->uregs[rd] = rdv;
272}
273
David A. Long3e6cd392014-03-06 18:06:43 -0500274static void __kprobes
David A. Longf145d662014-03-05 21:17:23 -0500275emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
David A. Longb4cd6052014-03-05 21:41:29 -0500276 struct arch_probes_insn *asi,
David A. Long7579f4b32014-03-07 11:19:32 -0500277 struct pt_regs *regs)
Jon Medhurst12ce5d32011-06-10 18:32:15 +0100278{
Jon Medhurst12ce5d32011-06-10 18:32:15 +0100279 int rdlo = (insn >> 12) & 0xf;
280 int rdhi = (insn >> 16) & 0xf;
281 int rn = insn & 0xf;
282 int rm = (insn >> 8) & 0xf;
283
284 register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
285 register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
286 register unsigned long rnv asm("r3") = regs->uregs[rn];
287 register unsigned long rmv asm("r1") = regs->uregs[rm];
288 unsigned long cpsr = regs->ARM_cpsr;
289
290 __asm__ __volatile__ (
291 "msr cpsr_fs, %[cpsr] \n\t"
292 BLX("%[fn]")
293 "mrs %[cpsr], cpsr \n\t"
294 : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
295 : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
David A. Long7579f4b32014-03-07 11:19:32 -0500296 "2" (cpsr), [fn] "r" (asi->insn_fn)
Jon Medhurst12ce5d32011-06-10 18:32:15 +0100297 : "lr", "memory", "cc"
298 );
299
300 regs->uregs[rdlo] = rdlov;
301 regs->uregs[rdhi] = rdhiv;
302 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
303}
David A. Long3e6cd392014-03-06 18:06:43 -0500304
305const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
David A. Longeb73ea92014-03-05 21:20:25 -0500306 [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
307 [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
David A. Long3e6cd392014-03-06 18:06:43 -0500308 [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
309 [PROBES_MRS] = {.handler = simulate_mrs},
310 [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
311 [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
312 [PROBES_SATURATING_ARITHMETIC] = {
313 .handler = emulate_rd12rn16rm0_rwflags_nopc},
314 [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
315 [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
316 [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
317 [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
318 [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
319 [PROBES_LOAD] = {.handler = emulate_ldr},
320 [PROBES_STORE_EXTRA] = {.handler = emulate_str},
321 [PROBES_STORE] = {.handler = emulate_str},
322 [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
323 [PROBES_DATA_PROCESSING_REG] = {
324 .handler = emulate_rd12rn16rm0rs8_rwflags},
325 [PROBES_DATA_PROCESSING_IMM] = {
326 .handler = emulate_rd12rn16rm0rs8_rwflags},
327 [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
David A. Longeb73ea92014-03-05 21:20:25 -0500328 [PROBES_SEV] = {.handler = probes_emulate_none},
329 [PROBES_WFE] = {.handler = probes_simulate_nop},
David A. Long3e6cd392014-03-06 18:06:43 -0500330 [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
331 [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
332 [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
333 [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
334 [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
335 [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
336 [PROBES_MUL_ADD_LONG] = {
337 .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
338 [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
339 [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
340 [PROBES_BRANCH] = {.handler = simulate_bbl},
341 [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
342};
Wang Nan83803d92015-01-05 19:29:18 +0800343
Wang Nan28a18992015-01-05 19:29:44 +0800344const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};