diff options
| -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 | ||
