1/*
2 * arch/arm/probes/kprobes/actions-thumb.c
3 *
4 * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
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
11#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/ptrace.h>
14#include <linux/kprobes.h>
15
16#include "../decode-thumb.h"
17#include "core.h"
18#include "checkers.h"
19
20/* These emulation encodings are functionally equivalent... */
21#define t32_emulate_rd8rn16rm0ra12_noflags \
22		t32_emulate_rdlo12rdhi8rn16rm0_noflags
23
24/* t32 thumb actions */
25
26static void __kprobes
27t32_simulate_table_branch(probes_opcode_t insn,
28		struct arch_probes_insn *asi, struct pt_regs *regs)
29{
30	unsigned long pc = regs->ARM_pc;
31	int rn = (insn >> 16) & 0xf;
32	int rm = insn & 0xf;
33
34	unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
35	unsigned long rmv = regs->uregs[rm];
36	unsigned int halfwords;
37
38	if (insn & 0x10) /* TBH */
39		halfwords = ((u16 *)rnv)[rmv];
40	else /* TBB */
41		halfwords = ((u8 *)rnv)[rmv];
42
43	regs->ARM_pc = pc + 2 * halfwords;
44}
45
46static void __kprobes
47t32_simulate_mrs(probes_opcode_t insn,
48		struct arch_probes_insn *asi, struct pt_regs *regs)
49{
50	int rd = (insn >> 8) & 0xf;
51	unsigned long mask = 0xf8ff03df; /* Mask out execution state */
52	regs->uregs[rd] = regs->ARM_cpsr & mask;
53}
54
55static void __kprobes
56t32_simulate_cond_branch(probes_opcode_t insn,
57		struct arch_probes_insn *asi, struct pt_regs *regs)
58{
59	unsigned long pc = regs->ARM_pc;
60
61	long offset = insn & 0x7ff;		/* imm11 */
62	offset += (insn & 0x003f0000) >> 5;	/* imm6 */
63	offset += (insn & 0x00002000) << 4;	/* J1 */
64	offset += (insn & 0x00000800) << 7;	/* J2 */
65	offset -= (insn & 0x04000000) >> 7;	/* Apply sign bit */
66
67	regs->ARM_pc = pc + (offset * 2);
68}
69
70static enum probes_insn __kprobes
71t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
72		const struct decode_header *d)
73{
74	int cc = (insn >> 22) & 0xf;
75	asi->insn_check_cc = probes_condition_checks[cc];
76	asi->insn_handler = t32_simulate_cond_branch;
77	return INSN_GOOD_NO_SLOT;
78}
79
80static void __kprobes
81t32_simulate_branch(probes_opcode_t insn,
82		    struct arch_probes_insn *asi, struct pt_regs *regs)
83{
84	unsigned long pc = regs->ARM_pc;
85
86	long offset = insn & 0x7ff;		/* imm11 */
87	offset += (insn & 0x03ff0000) >> 5;	/* imm10 */
88	offset += (insn & 0x00002000) << 9;	/* J1 */
89	offset += (insn & 0x00000800) << 10;	/* J2 */
90	if (insn & 0x04000000)
91		offset -= 0x00800000; /* Apply sign bit */
92	else
93		offset ^= 0x00600000; /* Invert J1 and J2 */
94
95	if (insn & (1 << 14)) {
96		/* BL or BLX */
97		regs->ARM_lr = regs->ARM_pc | 1;
98		if (!(insn & (1 << 12))) {
99			/* BLX so switch to ARM mode */
100			regs->ARM_cpsr &= ~PSR_T_BIT;
101			pc &= ~3;
102		}
103	}
104
105	regs->ARM_pc = pc + (offset * 2);
106}
107
108static void __kprobes
109t32_simulate_ldr_literal(probes_opcode_t insn,
110		struct arch_probes_insn *asi, struct pt_regs *regs)
111{
112	unsigned long addr = regs->ARM_pc & ~3;
113	int rt = (insn >> 12) & 0xf;
114	unsigned long rtv;
115
116	long offset = insn & 0xfff;
117	if (insn & 0x00800000)
118		addr += offset;
119	else
120		addr -= offset;
121
122	if (insn & 0x00400000) {
123		/* LDR */
124		rtv = *(unsigned long *)addr;
125		if (rt == 15) {
126			bx_write_pc(rtv, regs);
127			return;
128		}
129	} else if (insn & 0x00200000) {
130		/* LDRH */
131		if (insn & 0x01000000)
132			rtv = *(s16 *)addr;
133		else
134			rtv = *(u16 *)addr;
135	} else {
136		/* LDRB */
137		if (insn & 0x01000000)
138			rtv = *(s8 *)addr;
139		else
140			rtv = *(u8 *)addr;
141	}
142
143	regs->uregs[rt] = rtv;
144}
145
146static enum probes_insn __kprobes
147t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
148		const struct decode_header *d)
149{
150	enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
151
152	/* Fixup modified instruction to have halfwords in correct order...*/
153	insn = __mem_to_opcode_arm(asi->insn[0]);
154	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
155	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
156
157	return ret;
158}
159
160static void __kprobes
161t32_emulate_ldrdstrd(probes_opcode_t insn,
162		struct arch_probes_insn *asi, struct pt_regs *regs)
163{
164	unsigned long pc = regs->ARM_pc & ~3;
165	int rt1 = (insn >> 12) & 0xf;
166	int rt2 = (insn >> 8) & 0xf;
167	int rn = (insn >> 16) & 0xf;
168
169	register unsigned long rt1v asm("r0") = regs->uregs[rt1];
170	register unsigned long rt2v asm("r1") = regs->uregs[rt2];
171	register unsigned long rnv asm("r2") = (rn == 15) ? pc
172							  : regs->uregs[rn];
173
174	__asm__ __volatile__ (
175		"blx    %[fn]"
176		: "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
177		: "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
178		: "lr", "memory", "cc"
179	);
180
181	if (rn != 15)
182		regs->uregs[rn] = rnv; /* Writeback base register */
183	regs->uregs[rt1] = rt1v;
184	regs->uregs[rt2] = rt2v;
185}
186
187static void __kprobes
188t32_emulate_ldrstr(probes_opcode_t insn,
189		struct arch_probes_insn *asi, struct pt_regs *regs)
190{
191	int rt = (insn >> 12) & 0xf;
192	int rn = (insn >> 16) & 0xf;
193	int rm = insn & 0xf;
194
195	register unsigned long rtv asm("r0") = regs->uregs[rt];
196	register unsigned long rnv asm("r2") = regs->uregs[rn];
197	register unsigned long rmv asm("r3") = regs->uregs[rm];
198
199	__asm__ __volatile__ (
200		"blx    %[fn]"
201		: "=r" (rtv), "=r" (rnv)
202		: "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
203		: "lr", "memory", "cc"
204	);
205
206	regs->uregs[rn] = rnv; /* Writeback base register */
207	if (rt == 15) /* Can't be true for a STR as they aren't allowed */
208		bx_write_pc(rtv, regs);
209	else
210		regs->uregs[rt] = rtv;
211}
212
213static void __kprobes
214t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
215		struct arch_probes_insn *asi, struct pt_regs *regs)
216{
217	int rd = (insn >> 8) & 0xf;
218	int rn = (insn >> 16) & 0xf;
219	int rm = insn & 0xf;
220
221	register unsigned long rdv asm("r1") = regs->uregs[rd];
222	register unsigned long rnv asm("r2") = regs->uregs[rn];
223	register unsigned long rmv asm("r3") = regs->uregs[rm];
224	unsigned long cpsr = regs->ARM_cpsr;
225
226	__asm__ __volatile__ (
227		"msr	cpsr_fs, %[cpsr]	\n\t"
228		"blx    %[fn]			\n\t"
229		"mrs	%[cpsr], cpsr		\n\t"
230		: "=r" (rdv), [cpsr] "=r" (cpsr)
231		: "0" (rdv), "r" (rnv), "r" (rmv),
232		  "1" (cpsr), [fn] "r" (asi->insn_fn)
233		: "lr", "memory", "cc"
234	);
235
236	regs->uregs[rd] = rdv;
237	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
238}
239
240static void __kprobes
241t32_emulate_rd8pc16_noflags(probes_opcode_t insn,
242		struct arch_probes_insn *asi, struct pt_regs *regs)
243{
244	unsigned long pc = regs->ARM_pc;
245	int rd = (insn >> 8) & 0xf;
246
247	register unsigned long rdv asm("r1") = regs->uregs[rd];
248	register unsigned long rnv asm("r2") = pc & ~3;
249
250	__asm__ __volatile__ (
251		"blx    %[fn]"
252		: "=r" (rdv)
253		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
254		: "lr", "memory", "cc"
255	);
256
257	regs->uregs[rd] = rdv;
258}
259
260static void __kprobes
261t32_emulate_rd8rn16_noflags(probes_opcode_t insn,
262		struct arch_probes_insn *asi, struct pt_regs *regs)
263{
264	int rd = (insn >> 8) & 0xf;
265	int rn = (insn >> 16) & 0xf;
266
267	register unsigned long rdv asm("r1") = regs->uregs[rd];
268	register unsigned long rnv asm("r2") = regs->uregs[rn];
269
270	__asm__ __volatile__ (
271		"blx    %[fn]"
272		: "=r" (rdv)
273		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
274		: "lr", "memory", "cc"
275	);
276
277	regs->uregs[rd] = rdv;
278}
279
280static void __kprobes
281t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
282		struct arch_probes_insn *asi,
283		struct pt_regs *regs)
284{
285	int rdlo = (insn >> 12) & 0xf;
286	int rdhi = (insn >> 8) & 0xf;
287	int rn = (insn >> 16) & 0xf;
288	int rm = insn & 0xf;
289
290	register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
291	register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
292	register unsigned long rnv asm("r2") = regs->uregs[rn];
293	register unsigned long rmv asm("r3") = regs->uregs[rm];
294
295	__asm__ __volatile__ (
296		"blx    %[fn]"
297		: "=r" (rdlov), "=r" (rdhiv)
298		: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
299		  [fn] "r" (asi->insn_fn)
300		: "lr", "memory", "cc"
301	);
302
303	regs->uregs[rdlo] = rdlov;
304	regs->uregs[rdhi] = rdhiv;
305}
306/* t16 thumb actions */
307
308static void __kprobes
309t16_simulate_bxblx(probes_opcode_t insn,
310		struct arch_probes_insn *asi, struct pt_regs *regs)
311{
312	unsigned long pc = regs->ARM_pc + 2;
313	int rm = (insn >> 3) & 0xf;
314	unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
315
316	if (insn & (1 << 7)) /* BLX ? */
317		regs->ARM_lr = regs->ARM_pc | 1;
318
319	bx_write_pc(rmv, regs);
320}
321
322static void __kprobes
323t16_simulate_ldr_literal(probes_opcode_t insn,
324		struct arch_probes_insn *asi, struct pt_regs *regs)
325{
326	unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
327	long index = insn & 0xff;
328	int rt = (insn >> 8) & 0x7;
329	regs->uregs[rt] = base[index];
330}
331
332static void __kprobes
333t16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
334		struct arch_probes_insn *asi, struct pt_regs *regs)
335{
336	unsigned long* base = (unsigned long *)regs->ARM_sp;
337	long index = insn & 0xff;
338	int rt = (insn >> 8) & 0x7;
339	if (insn & 0x800) /* LDR */
340		regs->uregs[rt] = base[index];
341	else /* STR */
342		base[index] = regs->uregs[rt];
343}
344
345static void __kprobes
346t16_simulate_reladr(probes_opcode_t insn,
347		struct arch_probes_insn *asi, struct pt_regs *regs)
348{
349	unsigned long base = (insn & 0x800) ? regs->ARM_sp
350					    : ((regs->ARM_pc + 2) & ~3);
351	long offset = insn & 0xff;
352	int rt = (insn >> 8) & 0x7;
353	regs->uregs[rt] = base + offset * 4;
354}
355
356static void __kprobes
357t16_simulate_add_sp_imm(probes_opcode_t insn,
358		struct arch_probes_insn *asi, struct pt_regs *regs)
359{
360	long imm = insn & 0x7f;
361	if (insn & 0x80) /* SUB */
362		regs->ARM_sp -= imm * 4;
363	else /* ADD */
364		regs->ARM_sp += imm * 4;
365}
366
367static void __kprobes
368t16_simulate_cbz(probes_opcode_t insn,
369		struct arch_probes_insn *asi, struct pt_regs *regs)
370{
371	int rn = insn & 0x7;
372	probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
373	if (nonzero & 0x800) {
374		long i = insn & 0x200;
375		long imm5 = insn & 0xf8;
376		unsigned long pc = regs->ARM_pc + 2;
377		regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
378	}
379}
380
381static void __kprobes
382t16_simulate_it(probes_opcode_t insn,
383		struct arch_probes_insn *asi, struct pt_regs *regs)
384{
385	/*
386	 * The 8 IT state bits are split into two parts in CPSR:
387	 *	ITSTATE<1:0> are in CPSR<26:25>
388	 *	ITSTATE<7:2> are in CPSR<15:10>
389	 * The new IT state is in the lower byte of insn.
390	 */
391	unsigned long cpsr = regs->ARM_cpsr;
392	cpsr &= ~PSR_IT_MASK;
393	cpsr |= (insn & 0xfc) << 8;
394	cpsr |= (insn & 0x03) << 25;
395	regs->ARM_cpsr = cpsr;
396}
397
398static void __kprobes
399t16_singlestep_it(probes_opcode_t insn,
400		  struct arch_probes_insn *asi, struct pt_regs *regs)
401{
402	regs->ARM_pc += 2;
403	t16_simulate_it(insn, asi, regs);
404}
405
406static enum probes_insn __kprobes
407t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
408		const struct decode_header *d)
409{
410	asi->insn_singlestep = t16_singlestep_it;
411	return INSN_GOOD_NO_SLOT;
412}
413
414static void __kprobes
415t16_simulate_cond_branch(probes_opcode_t insn,
416		struct arch_probes_insn *asi, struct pt_regs *regs)
417{
418	unsigned long pc = regs->ARM_pc + 2;
419	long offset = insn & 0x7f;
420	offset -= insn & 0x80; /* Apply sign bit */
421	regs->ARM_pc = pc + (offset * 2);
422}
423
424static enum probes_insn __kprobes
425t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
426		const struct decode_header *d)
427{
428	int cc = (insn >> 8) & 0xf;
429	asi->insn_check_cc = probes_condition_checks[cc];
430	asi->insn_handler = t16_simulate_cond_branch;
431	return INSN_GOOD_NO_SLOT;
432}
433
434static void __kprobes
435t16_simulate_branch(probes_opcode_t insn,
436		   struct arch_probes_insn *asi, struct pt_regs *regs)
437{
438	unsigned long pc = regs->ARM_pc + 2;
439	long offset = insn & 0x3ff;
440	offset -= insn & 0x400; /* Apply sign bit */
441	regs->ARM_pc = pc + (offset * 2);
442}
443
444static unsigned long __kprobes
445t16_emulate_loregs(probes_opcode_t insn,
446		   struct arch_probes_insn *asi, struct pt_regs *regs)
447{
448	unsigned long oldcpsr = regs->ARM_cpsr;
449	unsigned long newcpsr;
450
451	__asm__ __volatile__ (
452		"msr	cpsr_fs, %[oldcpsr]	\n\t"
453		"ldmia	%[regs], {r0-r7}	\n\t"
454		"blx	%[fn]			\n\t"
455		"stmia	%[regs], {r0-r7}	\n\t"
456		"mrs	%[newcpsr], cpsr	\n\t"
457		: [newcpsr] "=r" (newcpsr)
458		: [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
459		  [fn] "r" (asi->insn_fn)
460		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
461		  "lr", "memory", "cc"
462		);
463
464	return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
465}
466
467static void __kprobes
468t16_emulate_loregs_rwflags(probes_opcode_t insn,
469		struct arch_probes_insn *asi, struct pt_regs *regs)
470{
471	regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
472}
473
474static void __kprobes
475t16_emulate_loregs_noitrwflags(probes_opcode_t insn,
476		struct arch_probes_insn *asi, struct pt_regs *regs)
477{
478	unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
479	if (!in_it_block(cpsr))
480		regs->ARM_cpsr = cpsr;
481}
482
483static void __kprobes
484t16_emulate_hiregs(probes_opcode_t insn,
485		struct arch_probes_insn *asi, struct pt_regs *regs)
486{
487	unsigned long pc = regs->ARM_pc + 2;
488	int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
489	int rm = (insn >> 3) & 0xf;
490
491	register unsigned long rdnv asm("r1");
492	register unsigned long rmv asm("r0");
493	unsigned long cpsr = regs->ARM_cpsr;
494
495	rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
496	rmv = (rm == 15) ? pc : regs->uregs[rm];
497
498	__asm__ __volatile__ (
499		"msr	cpsr_fs, %[cpsr]	\n\t"
500		"blx    %[fn]			\n\t"
501		"mrs	%[cpsr], cpsr		\n\t"
502		: "=r" (rdnv), [cpsr] "=r" (cpsr)
503		: "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
504		: "lr", "memory", "cc"
505	);
506
507	if (rdn == 15)
508		rdnv &= ~1;
509
510	regs->uregs[rdn] = rdnv;
511	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
512}
513
514static enum probes_insn __kprobes
515t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
516		const struct decode_header *d)
517{
518	insn &= ~0x00ff;
519	insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
520	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
521	asi->insn_handler = t16_emulate_hiregs;
522	return INSN_GOOD;
523}
524
525static void __kprobes
526t16_emulate_push(probes_opcode_t insn,
527		struct arch_probes_insn *asi, struct pt_regs *regs)
528{
529	__asm__ __volatile__ (
530		"ldr	r9, [%[regs], #13*4]	\n\t"
531		"ldr	r8, [%[regs], #14*4]	\n\t"
532		"ldmia	%[regs], {r0-r7}	\n\t"
533		"blx	%[fn]			\n\t"
534		"str	r9, [%[regs], #13*4]	\n\t"
535		:
536		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
537		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
538		  "lr", "memory", "cc"
539		);
540}
541
542static enum probes_insn __kprobes
543t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
544		const struct decode_header *d)
545{
546	/*
547	 * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
548	 * and call it with R9=SP and LR in the register list represented
549	 * by R8.
550	 */
551	/* 1st half STMDB R9!,{} */
552	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
553	/* 2nd half (register list) */
554	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
555	asi->insn_handler = t16_emulate_push;
556	return INSN_GOOD;
557}
558
559static void __kprobes
560t16_emulate_pop_nopc(probes_opcode_t insn,
561		struct arch_probes_insn *asi, struct pt_regs *regs)
562{
563	__asm__ __volatile__ (
564		"ldr	r9, [%[regs], #13*4]	\n\t"
565		"ldmia	%[regs], {r0-r7}	\n\t"
566		"blx	%[fn]			\n\t"
567		"stmia	%[regs], {r0-r7}	\n\t"
568		"str	r9, [%[regs], #13*4]	\n\t"
569		:
570		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
571		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
572		  "lr", "memory", "cc"
573		);
574}
575
576static void __kprobes
577t16_emulate_pop_pc(probes_opcode_t insn,
578		struct arch_probes_insn *asi, struct pt_regs *regs)
579{
580	register unsigned long pc asm("r8");
581
582	__asm__ __volatile__ (
583		"ldr	r9, [%[regs], #13*4]	\n\t"
584		"ldmia	%[regs], {r0-r7}	\n\t"
585		"blx	%[fn]			\n\t"
586		"stmia	%[regs], {r0-r7}	\n\t"
587		"str	r9, [%[regs], #13*4]	\n\t"
588		: "=r" (pc)
589		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
590		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
591		  "lr", "memory", "cc"
592		);
593
594	bx_write_pc(pc, regs);
595}
596
597static enum probes_insn __kprobes
598t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
599		const struct decode_header *d)
600{
601	/*
602	 * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
603	 * and call it with R9=SP and PC in the register list represented
604	 * by R8.
605	 */
606	/* 1st half LDMIA R9!,{} */
607	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
608	/* 2nd half (register list) */
609	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
610	asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
611					 : t16_emulate_pop_nopc;
612	return INSN_GOOD;
613}
614
615const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
616	[PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
617	[PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
618	[PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
619	[PROBES_T16_PUSH] = {.decoder = t16_decode_push},
620	[PROBES_T16_POP] = {.decoder = t16_decode_pop},
621	[PROBES_T16_SEV] = {.handler = probes_emulate_none},
622	[PROBES_T16_WFE] = {.handler = probes_simulate_nop},
623	[PROBES_T16_IT] = {.decoder = t16_decode_it},
624	[PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
625	[PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
626	[PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
627	[PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
628	[PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
629	[PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
630	[PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
631	[PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
632	[PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
633	[PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
634	[PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
635	[PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
636};
637
638const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
639	[PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
640	[PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
641	[PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
642	[PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
643	[PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
644	[PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
645	[PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
646	[PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
647	[PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
648	[PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
649	[PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
650	[PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
651	[PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
652	[PROBES_T32_SEV] = {.handler = probes_emulate_none},
653	[PROBES_T32_WFE] = {.handler = probes_simulate_nop},
654	[PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
655	[PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
656	[PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
657	[PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
658	[PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
659	[PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
660	[PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
661	[PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
662	[PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
663	[PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
664	[PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
665	[PROBES_T32_MUL_ADD_LONG] = {
666		.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
667};
668
669const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
670const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};
671