aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-04-08 10:32:56 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-04-28 23:40:57 -0400
commit5c6b76fc7d8220e8f00e7a49fb56ca852d7fb661 (patch)
tree3e43c40877512fde3921351e59c38446ae70e400 /arch/arm/kernel
parent54823accfcfc715e9e757a621afb40dabc01d033 (diff)
ARM: kprobes: Fix emulation of LDRD and STRD instructions
The decoding of these instructions got the register indexed and immediate indexed forms the wrong way around, causing incorrect emulation. Instructions like "LDRD Rx, [Rx]" were corrupting Rx because the base register writeback was being performed unconditionally, overwriting the value just loaded from memory. The fix is to only writeback the base register when that form of the instruction is used. Note, now that we reject probing writeback with PC the emulation code doesn't need the check rn!=15. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/kprobes-decode.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index a4dba1f7c87b..826abc16e670 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -560,8 +560,8 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
560 [i_fn] "r" (i_fn) 560 [i_fn] "r" (i_fn)
561 : "r0", "r1", "r2", "r3", "lr", "cc" 561 : "r0", "r1", "r2", "r3", "lr", "cc"
562 ); 562 );
563 if (rn != 15) 563 if (is_writeback(insn))
564 regs->uregs[rn] = rnv; /* Save Rn in case of writeback. */ 564 regs->uregs[rn] = rnv;
565} 565}
566 566
567static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) 567static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
@@ -580,8 +580,8 @@ static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
580 rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], 580 rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
581 regs->uregs[rd+1], 581 regs->uregs[rd+1],
582 regs->ARM_cpsr, i_fn); 582 regs->ARM_cpsr, i_fn);
583 if (rn != 15) 583 if (is_writeback(insn))
584 regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ 584 regs->uregs[rn] = rnv_wb;
585} 585}
586 586
587static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) 587static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)
@@ -1183,8 +1183,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1183 1183
1184 insn &= 0xfff00fff; 1184 insn &= 0xfff00fff;
1185 insn |= 0x00002000; /* Rn = r0, Rd = r2 */ 1185 insn |= 0x00002000; /* Rn = r0, Rd = r2 */
1186 if (insn & (1 << 22)) { 1186 if (!(insn & (1 << 22))) {
1187 /* I bit */ 1187 /* Register index */
1188 insn &= ~0xf; 1188 insn &= ~0xf;
1189 insn |= 1; /* Rm = r1 */ 1189 insn |= 1; /* Rm = r1 */
1190 } 1190 }