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