linux/arch/arm/probes/uprobes/actions-arm.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/types.h>
  11#include <linux/stddef.h>
  12#include <linux/wait.h>
  13#include <linux/uprobes.h>
  14#include <linux/module.h>
  15
  16#include "../decode.h"
  17#include "../decode-arm.h"
  18#include "core.h"
  19
  20static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
  21{
  22        probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
  23        probes_opcode_t temp;
  24        probes_opcode_t mask;
  25        int freereg;
  26        u32 free = 0xffff;
  27        u32 regs;
  28
  29        for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
  30                if ((regs & 0xf) == REG_TYPE_NONE)
  31                        continue;
  32
  33                free &= ~(1 << (insn & 0xf));
  34        }
  35
  36        /* No PC, no problem */
  37        if (free & (1 << 15))
  38                return 15;
  39
  40        if (!free)
  41                return -1;
  42
  43        /*
  44         * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
  45         * pick LR instead of R1.
  46         */
  47        freereg = free = fls(free) - 1;
  48
  49        temp = __mem_to_opcode_arm(*pinsn);
  50        insn = temp;
  51        regs = oregs;
  52        mask = 0xf;
  53
  54        for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
  55                if ((regs & 0xf) == REG_TYPE_NONE)
  56                        continue;
  57
  58                if ((temp & 0xf) != 15)
  59                        continue;
  60
  61                insn &= ~mask;
  62                insn |= free & mask;
  63        }
  64
  65        *pinsn = __opcode_to_mem_arm(insn);
  66        return freereg;
  67}
  68
  69static void uprobe_set_pc(struct arch_uprobe *auprobe,
  70                          struct arch_uprobe_task *autask,
  71                          struct pt_regs *regs)
  72{
  73        u32 pcreg = auprobe->pcreg;
  74
  75        autask->backup = regs->uregs[pcreg];
  76        regs->uregs[pcreg] = regs->ARM_pc + 8;
  77}
  78
  79static void uprobe_unset_pc(struct arch_uprobe *auprobe,
  80                            struct arch_uprobe_task *autask,
  81                            struct pt_regs *regs)
  82{
  83        /* PC will be taken care of by common code */
  84        regs->uregs[auprobe->pcreg] = autask->backup;
  85}
  86
  87static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
  88                               struct arch_uprobe_task *autask,
  89                               struct pt_regs *regs)
  90{
  91        u32 pcreg = auprobe->pcreg;
  92
  93        alu_write_pc(regs->uregs[pcreg], regs);
  94        regs->uregs[pcreg] = autask->backup;
  95}
  96
  97static void uprobe_write_pc(struct arch_uprobe *auprobe,
  98                            struct arch_uprobe_task *autask,
  99                            struct pt_regs *regs)
 100{
 101        u32 pcreg = auprobe->pcreg;
 102
 103        load_write_pc(regs->uregs[pcreg], regs);
 104        regs->uregs[pcreg] = autask->backup;
 105}
 106
 107enum probes_insn
 108decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
 109             const struct decode_header *d)
 110{
 111        struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
 112                                                   asi);
 113        struct decode_emulate *decode = (struct decode_emulate *) d;
 114        u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
 115        int reg;
 116
 117        reg = uprobes_substitute_pc(&auprobe->ixol[0], regs);
 118        if (reg == 15)
 119                return INSN_GOOD;
 120
 121        if (reg == -1)
 122                return INSN_REJECTED;
 123
 124        auprobe->pcreg = reg;
 125        auprobe->prehandler = uprobe_set_pc;
 126        auprobe->posthandler = uprobe_unset_pc;
 127
 128        return INSN_GOOD;
 129}
 130
 131enum probes_insn
 132decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
 133             const struct decode_header *d, bool alu)
 134{
 135        struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
 136                                                   asi);
 137        enum probes_insn ret = decode_pc_ro(insn, asi, d);
 138
 139        if (((insn >> 12) & 0xf) == 15)
 140                auprobe->posthandler = alu ? uprobe_aluwrite_pc
 141                                           : uprobe_write_pc;
 142
 143        return ret;
 144}
 145
 146enum probes_insn
 147decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
 148                              struct arch_probes_insn *asi,
 149                              const struct decode_header *d)
 150{
 151        return decode_wb_pc(insn, asi, d, true);
 152}
 153
 154enum probes_insn
 155decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi,
 156           const struct decode_header *d)
 157{
 158        return decode_wb_pc(insn, asi, d, false);
 159}
 160
 161enum probes_insn
 162uprobe_decode_ldmstm(probes_opcode_t insn,
 163                     struct arch_probes_insn *asi,
 164                     const struct decode_header *d)
 165{
 166        struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
 167                                                   asi);
 168        unsigned reglist = insn & 0xffff;
 169        int rn = (insn >> 16) & 0xf;
 170        int lbit = insn & (1 << 20);
 171        unsigned used = reglist | (1 << rn);
 172
 173        if (rn == 15)
 174                return INSN_REJECTED;
 175
 176        if (!(used & (1 << 15)))
 177                return INSN_GOOD;
 178
 179        if (used & (1 << 14))
 180                return INSN_REJECTED;
 181
 182        /* Use LR instead of PC */
 183        insn ^= 0xc000;
 184
 185        auprobe->pcreg = 14;
 186        auprobe->ixol[0] = __opcode_to_mem_arm(insn);
 187
 188        auprobe->prehandler = uprobe_set_pc;
 189        if (lbit)
 190                auprobe->posthandler = uprobe_write_pc;
 191        else
 192                auprobe->posthandler = uprobe_unset_pc;
 193
 194        return INSN_GOOD;
 195}
 196
 197const union decode_action uprobes_probes_actions[] = {
 198        [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
 199        [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
 200        [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
 201        [PROBES_MRS] = {.handler = simulate_mrs},
 202        [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
 203        [PROBES_CLZ] = {.handler = probes_simulate_nop},
 204        [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop},
 205        [PROBES_MUL1] = {.handler = probes_simulate_nop},
 206        [PROBES_MUL2] = {.handler = probes_simulate_nop},
 207        [PROBES_SWP] = {.handler = probes_simulate_nop},
 208        [PROBES_LDRSTRD] = {.decoder = decode_pc_ro},
 209        [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
 210        [PROBES_LOAD] = {.decoder = decode_ldr},
 211        [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
 212        [PROBES_STORE] = {.decoder = decode_pc_ro},
 213        [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
 214        [PROBES_DATA_PROCESSING_REG] = {
 215                .decoder = decode_rd12rn16rm0rs8_rwflags},
 216        [PROBES_DATA_PROCESSING_IMM] = {
 217                .decoder = decode_rd12rn16rm0rs8_rwflags},
 218        [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
 219        [PROBES_SEV] = {.handler = probes_simulate_nop},
 220        [PROBES_WFE] = {.handler = probes_simulate_nop},
 221        [PROBES_SATURATE] = {.handler = probes_simulate_nop},
 222        [PROBES_REV] = {.handler = probes_simulate_nop},
 223        [PROBES_MMI] = {.handler = probes_simulate_nop},
 224        [PROBES_PACK] = {.handler = probes_simulate_nop},
 225        [PROBES_EXTEND] = {.handler = probes_simulate_nop},
 226        [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop},
 227        [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop},
 228        [PROBES_MUL_ADD] = {.handler = probes_simulate_nop},
 229        [PROBES_BITFIELD] = {.handler = probes_simulate_nop},
 230        [PROBES_BRANCH] = {.handler = simulate_bbl},
 231        [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm}
 232};
 233