Linux Audio

Check our new training course

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