diff options
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 126 |
1 files changed, 69 insertions, 57 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 471086b808a4..96736a119c91 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/config.h> | 26 | #include <linux/config.h> |
27 | #include <linux/kprobes.h> | 27 | #include <linux/kprobes.h> |
28 | #include <linux/ptrace.h> | 28 | #include <linux/ptrace.h> |
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/string.h> | 29 | #include <linux/string.h> |
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
32 | #include <linux/preempt.h> | 31 | #include <linux/preempt.h> |
@@ -38,13 +37,8 @@ | |||
38 | 37 | ||
39 | extern void jprobe_inst_return(void); | 38 | extern void jprobe_inst_return(void); |
40 | 39 | ||
41 | /* kprobe_status settings */ | 40 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
42 | #define KPROBE_HIT_ACTIVE 0x00000001 | 41 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
43 | #define KPROBE_HIT_SS 0x00000002 | ||
44 | |||
45 | static struct kprobe *current_kprobe, *kprobe_prev; | ||
46 | static unsigned long kprobe_status, kprobe_status_prev; | ||
47 | static struct pt_regs jprobe_saved_regs; | ||
48 | 42 | ||
49 | enum instruction_type {A, I, M, F, B, L, X, u}; | 43 | enum instruction_type {A, I, M, F, B, L, X, u}; |
50 | static enum instruction_type bundle_encoding[32][3] = { | 44 | static enum instruction_type bundle_encoding[32][3] = { |
@@ -313,21 +307,22 @@ static int __kprobes valid_kprobe_addr(int template, int slot, | |||
313 | return 0; | 307 | return 0; |
314 | } | 308 | } |
315 | 309 | ||
316 | static inline void save_previous_kprobe(void) | 310 | static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) |
317 | { | 311 | { |
318 | kprobe_prev = current_kprobe; | 312 | kcb->prev_kprobe.kp = kprobe_running(); |
319 | kprobe_status_prev = kprobe_status; | 313 | kcb->prev_kprobe.status = kcb->kprobe_status; |
320 | } | 314 | } |
321 | 315 | ||
322 | static inline void restore_previous_kprobe(void) | 316 | static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) |
323 | { | 317 | { |
324 | current_kprobe = kprobe_prev; | 318 | __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; |
325 | kprobe_status = kprobe_status_prev; | 319 | kcb->kprobe_status = kcb->prev_kprobe.status; |
326 | } | 320 | } |
327 | 321 | ||
328 | static inline void set_current_kprobe(struct kprobe *p) | 322 | static inline void set_current_kprobe(struct kprobe *p, |
323 | struct kprobe_ctlblk *kcb) | ||
329 | { | 324 | { |
330 | current_kprobe = p; | 325 | __get_cpu_var(current_kprobe) = p; |
331 | } | 326 | } |
332 | 327 | ||
333 | static void kretprobe_trampoline(void) | 328 | static void kretprobe_trampoline(void) |
@@ -347,10 +342,11 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
347 | struct kretprobe_instance *ri = NULL; | 342 | struct kretprobe_instance *ri = NULL; |
348 | struct hlist_head *head; | 343 | struct hlist_head *head; |
349 | struct hlist_node *node, *tmp; | 344 | struct hlist_node *node, *tmp; |
350 | unsigned long orig_ret_address = 0; | 345 | unsigned long flags, orig_ret_address = 0; |
351 | unsigned long trampoline_address = | 346 | unsigned long trampoline_address = |
352 | ((struct fnptr *)kretprobe_trampoline)->ip; | 347 | ((struct fnptr *)kretprobe_trampoline)->ip; |
353 | 348 | ||
349 | spin_lock_irqsave(&kretprobe_lock, flags); | ||
354 | head = kretprobe_inst_table_head(current); | 350 | head = kretprobe_inst_table_head(current); |
355 | 351 | ||
356 | /* | 352 | /* |
@@ -389,17 +385,19 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
389 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); | 385 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); |
390 | regs->cr_iip = orig_ret_address; | 386 | regs->cr_iip = orig_ret_address; |
391 | 387 | ||
392 | unlock_kprobes(); | 388 | reset_current_kprobe(); |
389 | spin_unlock_irqrestore(&kretprobe_lock, flags); | ||
393 | preempt_enable_no_resched(); | 390 | preempt_enable_no_resched(); |
394 | 391 | ||
395 | /* | 392 | /* |
396 | * By returning a non-zero value, we are telling | 393 | * By returning a non-zero value, we are telling |
397 | * kprobe_handler() that we have handled unlocking | 394 | * kprobe_handler() that we don't want the post_handler |
398 | * and re-enabling preemption. | 395 | * to run (and have re-enabled preemption) |
399 | */ | 396 | */ |
400 | return 1; | 397 | return 1; |
401 | } | 398 | } |
402 | 399 | ||
400 | /* Called with kretprobe_lock held */ | ||
403 | void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, | 401 | void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, |
404 | struct pt_regs *regs) | 402 | struct pt_regs *regs) |
405 | { | 403 | { |
@@ -606,17 +604,22 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
606 | int ret = 0; | 604 | int ret = 0; |
607 | struct pt_regs *regs = args->regs; | 605 | struct pt_regs *regs = args->regs; |
608 | kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs); | 606 | kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs); |
607 | struct kprobe_ctlblk *kcb; | ||
609 | 608 | ||
609 | /* | ||
610 | * We don't want to be preempted for the entire | ||
611 | * duration of kprobe processing | ||
612 | */ | ||
610 | preempt_disable(); | 613 | preempt_disable(); |
614 | kcb = get_kprobe_ctlblk(); | ||
611 | 615 | ||
612 | /* Handle recursion cases */ | 616 | /* Handle recursion cases */ |
613 | if (kprobe_running()) { | 617 | if (kprobe_running()) { |
614 | p = get_kprobe(addr); | 618 | p = get_kprobe(addr); |
615 | if (p) { | 619 | if (p) { |
616 | if ( (kprobe_status == KPROBE_HIT_SS) && | 620 | if ((kcb->kprobe_status == KPROBE_HIT_SS) && |
617 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { | 621 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { |
618 | ia64_psr(regs)->ss = 0; | 622 | ia64_psr(regs)->ss = 0; |
619 | unlock_kprobes(); | ||
620 | goto no_kprobe; | 623 | goto no_kprobe; |
621 | } | 624 | } |
622 | /* We have reentered the pre_kprobe_handler(), since | 625 | /* We have reentered the pre_kprobe_handler(), since |
@@ -625,17 +628,17 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
625 | * just single step on the instruction of the new probe | 628 | * just single step on the instruction of the new probe |
626 | * without calling any user handlers. | 629 | * without calling any user handlers. |
627 | */ | 630 | */ |
628 | save_previous_kprobe(); | 631 | save_previous_kprobe(kcb); |
629 | set_current_kprobe(p); | 632 | set_current_kprobe(p, kcb); |
630 | p->nmissed++; | 633 | p->nmissed++; |
631 | prepare_ss(p, regs); | 634 | prepare_ss(p, regs); |
632 | kprobe_status = KPROBE_REENTER; | 635 | kcb->kprobe_status = KPROBE_REENTER; |
633 | return 1; | 636 | return 1; |
634 | } else if (args->err == __IA64_BREAK_JPROBE) { | 637 | } else if (args->err == __IA64_BREAK_JPROBE) { |
635 | /* | 638 | /* |
636 | * jprobe instrumented function just completed | 639 | * jprobe instrumented function just completed |
637 | */ | 640 | */ |
638 | p = current_kprobe; | 641 | p = __get_cpu_var(current_kprobe); |
639 | if (p->break_handler && p->break_handler(p, regs)) { | 642 | if (p->break_handler && p->break_handler(p, regs)) { |
640 | goto ss_probe; | 643 | goto ss_probe; |
641 | } | 644 | } |
@@ -645,10 +648,8 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
645 | } | 648 | } |
646 | } | 649 | } |
647 | 650 | ||
648 | lock_kprobes(); | ||
649 | p = get_kprobe(addr); | 651 | p = get_kprobe(addr); |
650 | if (!p) { | 652 | if (!p) { |
651 | unlock_kprobes(); | ||
652 | if (!is_ia64_break_inst(regs)) { | 653 | if (!is_ia64_break_inst(regs)) { |
653 | /* | 654 | /* |
654 | * The breakpoint instruction was removed right | 655 | * The breakpoint instruction was removed right |
@@ -665,8 +666,8 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
665 | goto no_kprobe; | 666 | goto no_kprobe; |
666 | } | 667 | } |
667 | 668 | ||
668 | kprobe_status = KPROBE_HIT_ACTIVE; | 669 | set_current_kprobe(p, kcb); |
669 | set_current_kprobe(p); | 670 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
670 | 671 | ||
671 | if (p->pre_handler && p->pre_handler(p, regs)) | 672 | if (p->pre_handler && p->pre_handler(p, regs)) |
672 | /* | 673 | /* |
@@ -678,7 +679,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
678 | 679 | ||
679 | ss_probe: | 680 | ss_probe: |
680 | prepare_ss(p, regs); | 681 | prepare_ss(p, regs); |
681 | kprobe_status = KPROBE_HIT_SS; | 682 | kcb->kprobe_status = KPROBE_HIT_SS; |
682 | return 1; | 683 | return 1; |
683 | 684 | ||
684 | no_kprobe: | 685 | no_kprobe: |
@@ -688,23 +689,25 @@ no_kprobe: | |||
688 | 689 | ||
689 | static int __kprobes post_kprobes_handler(struct pt_regs *regs) | 690 | static int __kprobes post_kprobes_handler(struct pt_regs *regs) |
690 | { | 691 | { |
691 | if (!kprobe_running()) | 692 | struct kprobe *cur = kprobe_running(); |
693 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
694 | |||
695 | if (!cur) | ||
692 | return 0; | 696 | return 0; |
693 | 697 | ||
694 | if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { | 698 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { |
695 | kprobe_status = KPROBE_HIT_SSDONE; | 699 | kcb->kprobe_status = KPROBE_HIT_SSDONE; |
696 | current_kprobe->post_handler(current_kprobe, regs, 0); | 700 | cur->post_handler(cur, regs, 0); |
697 | } | 701 | } |
698 | 702 | ||
699 | resume_execution(current_kprobe, regs); | 703 | resume_execution(cur, regs); |
700 | 704 | ||
701 | /*Restore back the original saved kprobes variables and continue. */ | 705 | /*Restore back the original saved kprobes variables and continue. */ |
702 | if (kprobe_status == KPROBE_REENTER) { | 706 | if (kcb->kprobe_status == KPROBE_REENTER) { |
703 | restore_previous_kprobe(); | 707 | restore_previous_kprobe(kcb); |
704 | goto out; | 708 | goto out; |
705 | } | 709 | } |
706 | 710 | reset_current_kprobe(); | |
707 | unlock_kprobes(); | ||
708 | 711 | ||
709 | out: | 712 | out: |
710 | preempt_enable_no_resched(); | 713 | preempt_enable_no_resched(); |
@@ -713,16 +716,15 @@ out: | |||
713 | 716 | ||
714 | static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr) | 717 | static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr) |
715 | { | 718 | { |
716 | if (!kprobe_running()) | 719 | struct kprobe *cur = kprobe_running(); |
717 | return 0; | 720 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
718 | 721 | ||
719 | if (current_kprobe->fault_handler && | 722 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) |
720 | current_kprobe->fault_handler(current_kprobe, regs, trapnr)) | ||
721 | return 1; | 723 | return 1; |
722 | 724 | ||
723 | if (kprobe_status & KPROBE_HIT_SS) { | 725 | if (kcb->kprobe_status & KPROBE_HIT_SS) { |
724 | resume_execution(current_kprobe, regs); | 726 | resume_execution(cur, regs); |
725 | unlock_kprobes(); | 727 | reset_current_kprobe(); |
726 | preempt_enable_no_resched(); | 728 | preempt_enable_no_resched(); |
727 | } | 729 | } |
728 | 730 | ||
@@ -733,31 +735,38 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
733 | unsigned long val, void *data) | 735 | unsigned long val, void *data) |
734 | { | 736 | { |
735 | struct die_args *args = (struct die_args *)data; | 737 | struct die_args *args = (struct die_args *)data; |
738 | int ret = NOTIFY_DONE; | ||
739 | |||
736 | switch(val) { | 740 | switch(val) { |
737 | case DIE_BREAK: | 741 | case DIE_BREAK: |
738 | if (pre_kprobes_handler(args)) | 742 | if (pre_kprobes_handler(args)) |
739 | return NOTIFY_STOP; | 743 | ret = NOTIFY_STOP; |
740 | break; | 744 | break; |
741 | case DIE_SS: | 745 | case DIE_SS: |
742 | if (post_kprobes_handler(args->regs)) | 746 | if (post_kprobes_handler(args->regs)) |
743 | return NOTIFY_STOP; | 747 | ret = NOTIFY_STOP; |
744 | break; | 748 | break; |
745 | case DIE_PAGE_FAULT: | 749 | case DIE_PAGE_FAULT: |
746 | if (kprobes_fault_handler(args->regs, args->trapnr)) | 750 | /* kprobe_running() needs smp_processor_id() */ |
747 | return NOTIFY_STOP; | 751 | preempt_disable(); |
752 | if (kprobe_running() && | ||
753 | kprobes_fault_handler(args->regs, args->trapnr)) | ||
754 | ret = NOTIFY_STOP; | ||
755 | preempt_enable(); | ||
748 | default: | 756 | default: |
749 | break; | 757 | break; |
750 | } | 758 | } |
751 | return NOTIFY_DONE; | 759 | return ret; |
752 | } | 760 | } |
753 | 761 | ||
754 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 762 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
755 | { | 763 | { |
756 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 764 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
757 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; | 765 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; |
766 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
758 | 767 | ||
759 | /* save architectural state */ | 768 | /* save architectural state */ |
760 | jprobe_saved_regs = *regs; | 769 | kcb->jprobe_saved_regs = *regs; |
761 | 770 | ||
762 | /* after rfi, execute the jprobe instrumented function */ | 771 | /* after rfi, execute the jprobe instrumented function */ |
763 | regs->cr_iip = addr & ~0xFULL; | 772 | regs->cr_iip = addr & ~0xFULL; |
@@ -775,7 +784,10 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
775 | 784 | ||
776 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 785 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
777 | { | 786 | { |
778 | *regs = jprobe_saved_regs; | 787 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
788 | |||
789 | *regs = kcb->jprobe_saved_regs; | ||
790 | preempt_enable_no_resched(); | ||
779 | return 1; | 791 | return 1; |
780 | } | 792 | } |
781 | 793 | ||