root/arch/arm/probes/kprobes/actions-thumb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. t32_simulate_table_branch
  2. t32_simulate_mrs
  3. t32_simulate_cond_branch
  4. t32_decode_cond_branch
  5. t32_simulate_branch
  6. t32_simulate_ldr_literal
  7. t32_decode_ldmstm
  8. t32_emulate_ldrdstrd
  9. t32_emulate_ldrstr
  10. t32_emulate_rd8rn16rm0_rwflags
  11. t32_emulate_rd8pc16_noflags
  12. t32_emulate_rd8rn16_noflags
  13. t32_emulate_rdlo12rdhi8rn16rm0_noflags
  14. t16_simulate_bxblx
  15. t16_simulate_ldr_literal
  16. t16_simulate_ldrstr_sp_relative
  17. t16_simulate_reladr
  18. t16_simulate_add_sp_imm
  19. t16_simulate_cbz
  20. t16_simulate_it
  21. t16_singlestep_it
  22. t16_decode_it
  23. t16_simulate_cond_branch
  24. t16_decode_cond_branch
  25. t16_simulate_branch
  26. t16_emulate_loregs
  27. t16_emulate_loregs_rwflags
  28. t16_emulate_loregs_noitrwflags
  29. t16_emulate_hiregs
  30. t16_decode_hiregs
  31. t16_emulate_push
  32. t16_decode_push
  33. t16_emulate_pop_nopc
  34. t16_emulate_pop_pc
  35. t16_decode_pop

   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 
  23 static void __kprobes
  24 t32_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 
  43 static void __kprobes
  44 t32_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 
  52 static void __kprobes
  53 t32_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 
  67 static enum probes_insn __kprobes
  68 t32_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 
  77 static void __kprobes
  78 t32_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 
 105 static void __kprobes
 106 t32_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 
 143 static enum probes_insn __kprobes
 144 t32_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 
 157 static void __kprobes
 158 t32_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 
 184 static void __kprobes
 185 t32_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 
 210 static void __kprobes
 211 t32_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 
 237 static void __kprobes
 238 t32_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 
 257 static void __kprobes
 258 t32_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 
 277 static void __kprobes
 278 t32_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 
 305 static void __kprobes
 306 t16_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 
 319 static void __kprobes
 320 t16_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 
 329 static void __kprobes
 330 t16_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 
 342 static void __kprobes
 343 t16_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 
 353 static void __kprobes
 354 t16_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 
 364 static void __kprobes
 365 t16_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 
 378 static void __kprobes
 379 t16_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 
 395 static void __kprobes
 396 t16_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 
 403 static enum probes_insn __kprobes
 404 t16_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 
 411 static void __kprobes
 412 t16_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 
 421 static enum probes_insn __kprobes
 422 t16_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 
 431 static void __kprobes
 432 t16_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 
 441 static unsigned long __kprobes
 442 t16_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 
 464 static void __kprobes
 465 t16_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 
 471 static void __kprobes
 472 t16_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 
 480 static void __kprobes
 481 t16_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 
 511 static enum probes_insn __kprobes
 512 t16_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 
 522 static void __kprobes
 523 t16_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 
 539 static enum probes_insn __kprobes
 540 t16_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 
 556 static void __kprobes
 557 t16_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 
 573 static void __kprobes
 574 t16_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 
 594 static enum probes_insn __kprobes
 595 t16_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 
 612 const 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 
 635 const 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 
 666 const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
 667 const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};

/* [<][>][^][v][top][bottom][index][help] */