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