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