blob: 07cfd9bef34099f530b203822cd2df9effbba32d [file] [log] [blame]
Kyle Swenson8d8f6542021-03-15 11:02:55 -06001/*
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};