aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorViktor Rosendahl <viktor.rosendahl@nokia.com>2011-03-28 11:56:05 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-04-28 23:40:54 -0400
commitcf3cc1aa9b6d0bf1750143af65829f4368d77492 (patch)
treecc9027ad2b4a7c7d77afa28049ebf7f97abb14d7 /arch/arm
parent6221f222c0ebf1acdf7abcf927178f40e1a65e2a (diff)
kprobes/arm: Fix ldrd/strd emulation
Currently emulate_ldrd and emulate_strd don't even have the adjustment of the PC value, so in case of Rn == PC, it will not update the PC incorrectly but instead load/store from the wrong address. Let's add both the adjustment of the PC value and the check for PC == PC. Signed-off-by: Viktor Rosendahl <viktor.rosendahl@nokia.com> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/kprobes-decode.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index 23891317dc4b..3b0cf90cb449 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -540,9 +540,12 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
540{ 540{
541 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; 541 insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
542 kprobe_opcode_t insn = p->opcode; 542 kprobe_opcode_t insn = p->opcode;
543 long ppc = (long)p->addr + 8;
543 int rd = (insn >> 12) & 0xf; 544 int rd = (insn >> 12) & 0xf;
544 int rn = (insn >> 16) & 0xf; 545 int rn = (insn >> 16) & 0xf;
545 int rm = insn & 0xf; /* rm may be invalid, don't care. */ 546 int rm = insn & 0xf; /* rm may be invalid, don't care. */
547 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
548 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
546 549
547 /* Not following the C calling convention here, so need asm(). */ 550 /* Not following the C calling convention here, so need asm(). */
548 __asm__ __volatile__ ( 551 __asm__ __volatile__ (
@@ -554,29 +557,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
554 "str r0, %[rn] \n\t" /* in case of writeback */ 557 "str r0, %[rn] \n\t" /* in case of writeback */
555 "str r2, %[rd0] \n\t" 558 "str r2, %[rd0] \n\t"
556 "str r3, %[rd1] \n\t" 559 "str r3, %[rd1] \n\t"
557 : [rn] "+m" (regs->uregs[rn]), 560 : [rn] "+m" (rnv),
558 [rd0] "=m" (regs->uregs[rd]), 561 [rd0] "=m" (regs->uregs[rd]),
559 [rd1] "=m" (regs->uregs[rd+1]) 562 [rd1] "=m" (regs->uregs[rd+1])
560 : [rm] "m" (regs->uregs[rm]), 563 : [rm] "m" (rmv),
561 [cpsr] "r" (regs->ARM_cpsr), 564 [cpsr] "r" (regs->ARM_cpsr),
562 [i_fn] "r" (i_fn) 565 [i_fn] "r" (i_fn)
563 : "r0", "r1", "r2", "r3", "lr", "cc" 566 : "r0", "r1", "r2", "r3", "lr", "cc"
564 ); 567 );
568 if (rn != 15)
569 regs->uregs[rn] = rnv; /* Save Rn in case of writeback. */
565} 570}
566 571
567static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) 572static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
568{ 573{
569 insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; 574 insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0];
570 kprobe_opcode_t insn = p->opcode; 575 kprobe_opcode_t insn = p->opcode;
576 long ppc = (long)p->addr + 8;
571 int rd = (insn >> 12) & 0xf; 577 int rd = (insn >> 12) & 0xf;
572 int rn = (insn >> 16) & 0xf; 578 int rn = (insn >> 16) & 0xf;
573 int rm = insn & 0xf; 579 int rm = insn & 0xf;
574 long rnv = regs->uregs[rn]; 580 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
575 long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ 581 /* rm/rmv may be invalid, don't care. */
582 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
583 long rnv_wb;
576 584
577 regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], 585 rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
578 regs->uregs[rd+1], 586 regs->uregs[rd+1],
579 regs->ARM_cpsr, i_fn); 587 regs->ARM_cpsr, i_fn);
588 if (rn != 15)
589 regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */
580} 590}
581 591
582static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) 592static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)