aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-02 11:13:29 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:44 -0400
commitfd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477 (patch)
treebbd1a7e1064a7e0be52ed8ba7cb2fab3a5c1d820
parent32818f31f8ed811ea7ef924f24642580a63a7c85 (diff)
ARM: kprobes: Decode 16-bit Thumb PUSH and POP instructions
These instructions are equivalent to stmdb sp!,{r0-r7,lr} ldmdb sp!,{r0-r7,pc} and we emulate them by transforming them into the 32-bit Thumb instructions stmdb r9!,{r0-r7,r8} ldmdb r9!,{r0-r7,r8} This is simpler, and almost certainly executes faster, than writing simulation functions. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
-rw-r--r--arch/arm/kernel/kprobes-thumb.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index a5bdb2dc39e7..e0289493b4c6 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -187,6 +187,87 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi)
187 return INSN_GOOD; 187 return INSN_GOOD;
188} 188}
189 189
190static void __kprobes
191t16_emulate_push(struct kprobe *p, struct pt_regs *regs)
192{
193 __asm__ __volatile__ (
194 "ldr r9, [%[regs], #13*4] \n\t"
195 "ldr r8, [%[regs], #14*4] \n\t"
196 "ldmia %[regs], {r0-r7} \n\t"
197 "blx %[fn] \n\t"
198 "str r9, [%[regs], #13*4] \n\t"
199 :
200 : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn)
201 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
202 "lr", "memory", "cc"
203 );
204}
205
206static enum kprobe_insn __kprobes
207t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi)
208{
209 /*
210 * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
211 * and call it with R9=SP and LR in the register list represented
212 * by R8.
213 */
214 ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */
215 ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
216 asi->insn_handler = t16_emulate_push;
217 return INSN_GOOD;
218}
219
220static void __kprobes
221t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs)
222{
223 __asm__ __volatile__ (
224 "ldr r9, [%[regs], #13*4] \n\t"
225 "ldmia %[regs], {r0-r7} \n\t"
226 "blx %[fn] \n\t"
227 "stmia %[regs], {r0-r7} \n\t"
228 "str r9, [%[regs], #13*4] \n\t"
229 :
230 : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn)
231 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
232 "lr", "memory", "cc"
233 );
234}
235
236static void __kprobes
237t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs)
238{
239 register unsigned long pc asm("r8");
240
241 __asm__ __volatile__ (
242 "ldr r9, [%[regs], #13*4] \n\t"
243 "ldmia %[regs], {r0-r7} \n\t"
244 "blx %[fn] \n\t"
245 "stmia %[regs], {r0-r7} \n\t"
246 "str r9, [%[regs], #13*4] \n\t"
247 : "=r" (pc)
248 : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn)
249 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
250 "lr", "memory", "cc"
251 );
252
253 bx_write_pc(pc, regs);
254}
255
256static enum kprobe_insn __kprobes
257t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi)
258{
259 /*
260 * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
261 * and call it with R9=SP and PC in the register list represented
262 * by R8.
263 */
264 ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */
265 ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
266 asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
267 : t16_emulate_pop_nopc;
268 return INSN_GOOD;
269}
270
190static const union decode_item t16_table_1011[] = { 271static const union decode_item t16_table_1011[] = {
191 /* Miscellaneous 16-bit instructions */ 272 /* Miscellaneous 16-bit instructions */
192 273
@@ -209,6 +290,11 @@ static const union decode_item t16_table_1011[] = {
209 DECODE_REJECT (0xffc0, 0xba80), 290 DECODE_REJECT (0xffc0, 0xba80),
210 DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), 291 DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags),
211 292
293 /* PUSH 1011 010x xxxx xxxx */
294 DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push),
295 /* POP 1011 110x xxxx xxxx */
296 DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop),
297
212 /* 298 /*
213 * If-Then, and hints 299 * If-Then, and hints
214 * 1011 1111 xxxx xxxx 300 * 1011 1111 xxxx xxxx