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