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

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

DEFINITIONS

This source file includes following definitions.
  1. emulate_ldrdstrd
  2. emulate_ldr
  3. emulate_str
  4. emulate_rd12rn16rm0rs8_rwflags
  5. emulate_rd12rn16rm0_rwflags_nopc
  6. emulate_rd16rn12rm0rs8_rwflags_nopc
  7. emulate_rd12rm0_noflags_nopc
  8. emulate_rdlo12rdhi16rn0rm8_rwflags_nopc

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * arch/arm/probes/kprobes/actions-arm.c
   4  *
   5  * Copyright (C) 2006, 2007 Motorola Inc.
   6  */
   7 
   8 /*
   9  * We do not have hardware single-stepping on ARM, This
  10  * effort is further complicated by the ARM not having a
  11  * "next PC" register.  Instructions that change the PC
  12  * can't be safely single-stepped in a MP environment, so
  13  * we have a lot of work to do:
  14  *
  15  * In the prepare phase:
  16  *   *) If it is an instruction that does anything
  17  *      with the CPU mode, we reject it for a kprobe.
  18  *      (This is out of laziness rather than need.  The
  19  *      instructions could be simulated.)
  20  *
  21  *   *) Otherwise, decode the instruction rewriting its
  22  *      registers to take fixed, ordered registers and
  23  *      setting a handler for it to run the instruction.
  24  *
  25  * In the execution phase by an instruction's handler:
  26  *
  27  *   *) If the PC is written to by the instruction, the
  28  *      instruction must be fully simulated in software.
  29  *
  30  *   *) Otherwise, a modified form of the instruction is
  31  *      directly executed.  Its handler calls the
  32  *      instruction in insn[0].  In insn[1] is a
  33  *      "mov pc, lr" to return.
  34  *
  35  *      Before calling, load up the reordered registers
  36  *      from the original instruction's registers.  If one
  37  *      of the original input registers is the PC, compute
  38  *      and adjust the appropriate input register.
  39  *
  40  *      After call completes, copy the output registers to
  41  *      the original instruction's original registers.
  42  *
  43  * We don't use a real breakpoint instruction since that
  44  * would have us in the kernel go from SVC mode to SVC
  45  * mode losing the link register.  Instead we use an
  46  * undefined instruction.  To simplify processing, the
  47  * undefined instruction used for kprobes must be reserved
  48  * exclusively for kprobes use.
  49  *
  50  * TODO: ifdef out some instruction decoding based on architecture.
  51  */
  52 
  53 #include <linux/kernel.h>
  54 #include <linux/kprobes.h>
  55 #include <linux/ptrace.h>
  56 
  57 #include "../decode-arm.h"
  58 #include "core.h"
  59 #include "checkers.h"
  60 
  61 #if  __LINUX_ARM_ARCH__ >= 6
  62 #define BLX(reg)        "blx    "reg"           \n\t"
  63 #else
  64 #define BLX(reg)        "mov    lr, pc          \n\t"   \
  65                         "mov    pc, "reg"       \n\t"
  66 #endif
  67 
  68 static void __kprobes
  69 emulate_ldrdstrd(probes_opcode_t insn,
  70         struct arch_probes_insn *asi, struct pt_regs *regs)
  71 {
  72         unsigned long pc = regs->ARM_pc + 4;
  73         int rt = (insn >> 12) & 0xf;
  74         int rn = (insn >> 16) & 0xf;
  75         int rm = insn & 0xf;
  76 
  77         register unsigned long rtv asm("r0") = regs->uregs[rt];
  78         register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
  79         register unsigned long rnv asm("r2") = (rn == 15) ? pc
  80                                                           : regs->uregs[rn];
  81         register unsigned long rmv asm("r3") = regs->uregs[rm];
  82 
  83         __asm__ __volatile__ (
  84                 BLX("%[fn]")
  85                 : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
  86                 : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
  87                   [fn] "r" (asi->insn_fn)
  88                 : "lr", "memory", "cc"
  89         );
  90 
  91         regs->uregs[rt] = rtv;
  92         regs->uregs[rt+1] = rt2v;
  93         if (is_writeback(insn))
  94                 regs->uregs[rn] = rnv;
  95 }
  96 
  97 static void __kprobes
  98 emulate_ldr(probes_opcode_t insn,
  99         struct arch_probes_insn *asi, struct pt_regs *regs)
 100 {
 101         unsigned long pc = regs->ARM_pc + 4;
 102         int rt = (insn >> 12) & 0xf;
 103         int rn = (insn >> 16) & 0xf;
 104         int rm = insn & 0xf;
 105 
 106         register unsigned long rtv asm("r0");
 107         register unsigned long rnv asm("r2") = (rn == 15) ? pc
 108                                                           : regs->uregs[rn];
 109         register unsigned long rmv asm("r3") = regs->uregs[rm];
 110 
 111         __asm__ __volatile__ (
 112                 BLX("%[fn]")
 113                 : "=r" (rtv), "=r" (rnv)
 114                 : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
 115                 : "lr", "memory", "cc"
 116         );
 117 
 118         if (rt == 15)
 119                 load_write_pc(rtv, regs);
 120         else
 121                 regs->uregs[rt] = rtv;
 122 
 123         if (is_writeback(insn))
 124                 regs->uregs[rn] = rnv;
 125 }
 126 
 127 static void __kprobes
 128 emulate_str(probes_opcode_t insn,
 129         struct arch_probes_insn *asi, struct pt_regs *regs)
 130 {
 131         unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
 132         unsigned long rnpc = regs->ARM_pc + 4;
 133         int rt = (insn >> 12) & 0xf;
 134         int rn = (insn >> 16) & 0xf;
 135         int rm = insn & 0xf;
 136 
 137         register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
 138                                                           : regs->uregs[rt];
 139         register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
 140                                                           : regs->uregs[rn];
 141         register unsigned long rmv asm("r3") = regs->uregs[rm];
 142 
 143         __asm__ __volatile__ (
 144                 BLX("%[fn]")
 145                 : "=r" (rnv)
 146                 : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
 147                 : "lr", "memory", "cc"
 148         );
 149 
 150         if (is_writeback(insn))
 151                 regs->uregs[rn] = rnv;
 152 }
 153 
 154 static void __kprobes
 155 emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
 156         struct arch_probes_insn *asi, struct pt_regs *regs)
 157 {
 158         unsigned long pc = regs->ARM_pc + 4;
 159         int rd = (insn >> 12) & 0xf;
 160         int rn = (insn >> 16) & 0xf;
 161         int rm = insn & 0xf;
 162         int rs = (insn >> 8) & 0xf;
 163 
 164         register unsigned long rdv asm("r0") = regs->uregs[rd];
 165         register unsigned long rnv asm("r2") = (rn == 15) ? pc
 166                                                           : regs->uregs[rn];
 167         register unsigned long rmv asm("r3") = (rm == 15) ? pc
 168                                                           : regs->uregs[rm];
 169         register unsigned long rsv asm("r1") = regs->uregs[rs];
 170         unsigned long cpsr = regs->ARM_cpsr;
 171 
 172         __asm__ __volatile__ (
 173                 "msr    cpsr_fs, %[cpsr]        \n\t"
 174                 BLX("%[fn]")
 175                 "mrs    %[cpsr], cpsr           \n\t"
 176                 : "=r" (rdv), [cpsr] "=r" (cpsr)
 177                 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
 178                   "1" (cpsr), [fn] "r" (asi->insn_fn)
 179                 : "lr", "memory", "cc"
 180         );
 181 
 182         if (rd == 15)
 183                 alu_write_pc(rdv, regs);
 184         else
 185                 regs->uregs[rd] = rdv;
 186         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
 187 }
 188 
 189 static void __kprobes
 190 emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
 191         struct arch_probes_insn *asi, struct pt_regs *regs)
 192 {
 193         int rd = (insn >> 12) & 0xf;
 194         int rn = (insn >> 16) & 0xf;
 195         int rm = insn & 0xf;
 196 
 197         register unsigned long rdv asm("r0") = regs->uregs[rd];
 198         register unsigned long rnv asm("r2") = regs->uregs[rn];
 199         register unsigned long rmv asm("r3") = regs->uregs[rm];
 200         unsigned long cpsr = regs->ARM_cpsr;
 201 
 202         __asm__ __volatile__ (
 203                 "msr    cpsr_fs, %[cpsr]        \n\t"
 204                 BLX("%[fn]")
 205                 "mrs    %[cpsr], cpsr           \n\t"
 206                 : "=r" (rdv), [cpsr] "=r" (cpsr)
 207                 : "0" (rdv), "r" (rnv), "r" (rmv),
 208                   "1" (cpsr), [fn] "r" (asi->insn_fn)
 209                 : "lr", "memory", "cc"
 210         );
 211 
 212         regs->uregs[rd] = rdv;
 213         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
 214 }
 215 
 216 static void __kprobes
 217 emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
 218         struct arch_probes_insn *asi,
 219         struct pt_regs *regs)
 220 {
 221         int rd = (insn >> 16) & 0xf;
 222         int rn = (insn >> 12) & 0xf;
 223         int rm = insn & 0xf;
 224         int rs = (insn >> 8) & 0xf;
 225 
 226         register unsigned long rdv asm("r2") = regs->uregs[rd];
 227         register unsigned long rnv asm("r0") = regs->uregs[rn];
 228         register unsigned long rmv asm("r3") = regs->uregs[rm];
 229         register unsigned long rsv asm("r1") = regs->uregs[rs];
 230         unsigned long cpsr = regs->ARM_cpsr;
 231 
 232         __asm__ __volatile__ (
 233                 "msr    cpsr_fs, %[cpsr]        \n\t"
 234                 BLX("%[fn]")
 235                 "mrs    %[cpsr], cpsr           \n\t"
 236                 : "=r" (rdv), [cpsr] "=r" (cpsr)
 237                 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
 238                   "1" (cpsr), [fn] "r" (asi->insn_fn)
 239                 : "lr", "memory", "cc"
 240         );
 241 
 242         regs->uregs[rd] = rdv;
 243         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
 244 }
 245 
 246 static void __kprobes
 247 emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
 248         struct arch_probes_insn *asi, struct pt_regs *regs)
 249 {
 250         int rd = (insn >> 12) & 0xf;
 251         int rm = insn & 0xf;
 252 
 253         register unsigned long rdv asm("r0") = regs->uregs[rd];
 254         register unsigned long rmv asm("r3") = regs->uregs[rm];
 255 
 256         __asm__ __volatile__ (
 257                 BLX("%[fn]")
 258                 : "=r" (rdv)
 259                 : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
 260                 : "lr", "memory", "cc"
 261         );
 262 
 263         regs->uregs[rd] = rdv;
 264 }
 265 
 266 static void __kprobes
 267 emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
 268         struct arch_probes_insn *asi,
 269         struct pt_regs *regs)
 270 {
 271         int rdlo = (insn >> 12) & 0xf;
 272         int rdhi = (insn >> 16) & 0xf;
 273         int rn = insn & 0xf;
 274         int rm = (insn >> 8) & 0xf;
 275 
 276         register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
 277         register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
 278         register unsigned long rnv asm("r3") = regs->uregs[rn];
 279         register unsigned long rmv asm("r1") = regs->uregs[rm];
 280         unsigned long cpsr = regs->ARM_cpsr;
 281 
 282         __asm__ __volatile__ (
 283                 "msr    cpsr_fs, %[cpsr]        \n\t"
 284                 BLX("%[fn]")
 285                 "mrs    %[cpsr], cpsr           \n\t"
 286                 : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
 287                 : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
 288                   "2" (cpsr), [fn] "r" (asi->insn_fn)
 289                 : "lr", "memory", "cc"
 290         );
 291 
 292         regs->uregs[rdlo] = rdlov;
 293         regs->uregs[rdhi] = rdhiv;
 294         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
 295 }
 296 
 297 const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
 298         [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
 299         [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
 300         [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
 301         [PROBES_MRS] = {.handler = simulate_mrs},
 302         [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
 303         [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
 304         [PROBES_SATURATING_ARITHMETIC] = {
 305                 .handler = emulate_rd12rn16rm0_rwflags_nopc},
 306         [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
 307         [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
 308         [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 309         [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
 310         [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
 311         [PROBES_LOAD] = {.handler = emulate_ldr},
 312         [PROBES_STORE_EXTRA] = {.handler = emulate_str},
 313         [PROBES_STORE] = {.handler = emulate_str},
 314         [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
 315         [PROBES_DATA_PROCESSING_REG] = {
 316                 .handler = emulate_rd12rn16rm0rs8_rwflags},
 317         [PROBES_DATA_PROCESSING_IMM] = {
 318                 .handler = emulate_rd12rn16rm0rs8_rwflags},
 319         [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
 320         [PROBES_SEV] = {.handler = probes_emulate_none},
 321         [PROBES_WFE] = {.handler = probes_simulate_nop},
 322         [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 323         [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
 324         [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 325         [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 326         [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
 327         [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
 328         [PROBES_MUL_ADD_LONG] = {
 329                 .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
 330         [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
 331         [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
 332         [PROBES_BRANCH] = {.handler = simulate_bbl},
 333         [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
 334 };
 335 
 336 const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};

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