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