aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKeshavamurthy Anil S <anil.s.keshavamurthy@intel.com>2005-09-06 18:19:32 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:58:00 -0400
commit661e5a3d9958dc83d610992da85625c0ada9bb06 (patch)
tree914bff2285c3eee9324d0d0a8eb633926ef47008 /arch
parent83005161c84efa70f3d4dc193eb1024a40b650dc (diff)
[PATCH] Kprobes/IA64: fix race when break hits and kprobe not found
This patch addresses a potential race condition for a case where Kprobe has been removed right after another CPU has taken a break hit. The way this is addressed here is when the CPU that has taken a break hit does not find its corresponding kprobe, then we check to see if the original instruction got replaced with other than break. If it got replaced with other than break instruction, then we continue to execute from the replaced instruction, else if we find that it is still a break, then we let the kernel handle this, as this might be the break instruction inserted by other than kprobe(may be kernel debugger). Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/kernel/kprobes.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 82a41ac29386..4b1bd539ec47 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -554,6 +554,38 @@ static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
554 ia64_psr(regs)->ss = 1; 554 ia64_psr(regs)->ss = 1;
555} 555}
556 556
557static int __kprobes is_ia64_break_inst(struct pt_regs *regs)
558{
559 unsigned int slot = ia64_psr(regs)->ri;
560 unsigned int template, major_opcode;
561 unsigned long kprobe_inst;
562 unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip;
563 bundle_t bundle;
564
565 memcpy(&bundle, kprobe_addr, sizeof(bundle_t));
566 template = bundle.quad0.template;
567
568 /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
569 if (slot == 1 && bundle_encoding[template][1] == L)
570 slot++;
571
572 /* Get Kprobe probe instruction at given slot*/
573 get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
574
575 /* For break instruction,
576 * Bits 37:40 Major opcode to be zero
577 * Bits 27:32 X6 to be zero
578 * Bits 32:35 X3 to be zero
579 */
580 if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) {
581 /* Not a break instruction */
582 return 0;
583 }
584
585 /* Is a break instruction */
586 return 1;
587}
588
557static int __kprobes pre_kprobes_handler(struct die_args *args) 589static int __kprobes pre_kprobes_handler(struct die_args *args)
558{ 590{
559 struct kprobe *p; 591 struct kprobe *p;
@@ -601,6 +633,19 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
601 p = get_kprobe(addr); 633 p = get_kprobe(addr);
602 if (!p) { 634 if (!p) {
603 unlock_kprobes(); 635 unlock_kprobes();
636 if (!is_ia64_break_inst(regs)) {
637 /*
638 * The breakpoint instruction was removed right
639 * after we hit it. Another cpu has removed
640 * either a probepoint or a debugger breakpoint
641 * at this address. In either case, no further
642 * handling of this interrupt is appropriate.
643 */
644 ret = 1;
645
646 }
647
648 /* Not one of our break, let kernel handle it */
604 goto no_kprobe; 649 goto no_kprobe;
605 } 650 }
606 651