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