linux/arch/arm/probes/kprobes/actions-thumb.c
<<
>>
Prefs
   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