aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/kprobes-common.c
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-07 03:57:22 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:45 -0400
commit235a4ce79feb8d5351f9164981bc57d5e29f974b (patch)
treec3dd0e698781faf592b2b01880103cf0d57d8a92 /arch/arm/kernel/kprobes-common.c
parent263e368a2f1f960db07d7524a4a3e7df951f1f72 (diff)
ARM: kprobes: Add common decoding function for LDM and STM
The encoding of these instructions is substantially the same for both ARM and Thumb, so we can have common decoding and simulation functions. This patch moves the simulation functions from kprobes-arm.c to kprobes-common.c. It also adds a new simulation function (simulate_ldm1_pc) for the case where we load into PC because this may need to interwork. The instruction decoding is done by a custom function (kprobe_decode_ldmstm) rather than just relying on decoding table entries because we will later be adding optimisation code. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes-common.c')
-rw-r--r--arch/arm/kernel/kprobes-common.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 86fdc4c4c2ce..43d663cafdd1 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -166,6 +166,76 @@ void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
166 p->ainsn.insn_fn(); 166 p->ainsn.insn_fn();
167} 167}
168 168
169static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
170{
171 kprobe_opcode_t insn = p->opcode;
172 int rn = (insn >> 16) & 0xf;
173 int lbit = insn & (1 << 20);
174 int wbit = insn & (1 << 21);
175 int ubit = insn & (1 << 23);
176 int pbit = insn & (1 << 24);
177 long *addr = (long *)regs->uregs[rn];
178 int reg_bit_vector;
179 int reg_count;
180
181 reg_count = 0;
182 reg_bit_vector = insn & 0xffff;
183 while (reg_bit_vector) {
184 reg_bit_vector &= (reg_bit_vector - 1);
185 ++reg_count;
186 }
187
188 if (!ubit)
189 addr -= reg_count;
190 addr += (!pbit == !ubit);
191
192 reg_bit_vector = insn & 0xffff;
193 while (reg_bit_vector) {
194 int reg = __ffs(reg_bit_vector);
195 reg_bit_vector &= (reg_bit_vector - 1);
196 if (lbit)
197 regs->uregs[reg] = *addr++;
198 else
199 *addr++ = regs->uregs[reg];
200 }
201
202 if (wbit) {
203 if (!ubit)
204 addr -= reg_count;
205 addr -= (!pbit == !ubit);
206 regs->uregs[rn] = (long)addr;
207 }
208}
209
210static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
211{
212 regs->ARM_pc = (long)p->addr + str_pc_offset;
213 simulate_ldm1stm1(p, regs);
214 regs->ARM_pc = (long)p->addr + 4;
215}
216
217static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
218{
219 simulate_ldm1stm1(p, regs);
220 load_write_pc(regs->ARM_pc, regs);
221}
222
223enum kprobe_insn __kprobes
224kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
225{
226 kprobe_insn_handler_t *handler = 0;
227 unsigned reglist = insn & 0xffff;
228 int is_ldm = insn & 0x100000;
229
230 if (reglist & 0x8000)
231 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
232 else
233 handler = simulate_ldm1stm1;
234 asi->insn_handler = handler;
235 return INSN_GOOD_NO_SLOT;
236}
237
238
169/* 239/*
170 * Prepare an instruction slot to receive an instruction for emulating. 240 * Prepare an instruction slot to receive an instruction for emulating.
171 * This is done by placing a subroutine return after the location where the 241 * This is done by placing a subroutine return after the location where the