diff options
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 45 |
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 | ||
557 | static 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 | |||
557 | static int __kprobes pre_kprobes_handler(struct die_args *args) | 589 | static 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 | ||