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