actions-arm.c (6090B)
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};