diff options
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 83 | ||||
-rw-r--r-- | include/asm-ia64/kprobes.h | 13 |
2 files changed, 58 insertions, 38 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 1e80ec80dd21..17e70b1b8d79 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -38,13 +38,8 @@ | |||
38 | 38 | ||
39 | extern void jprobe_inst_return(void); | 39 | extern void jprobe_inst_return(void); |
40 | 40 | ||
41 | /* kprobe_status settings */ | 41 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
42 | #define KPROBE_HIT_ACTIVE 0x00000001 | 42 | 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 | 43 | ||
49 | enum instruction_type {A, I, M, F, B, L, X, u}; | 44 | enum instruction_type {A, I, M, F, B, L, X, u}; |
50 | static enum instruction_type bundle_encoding[32][3] = { | 45 | static enum instruction_type bundle_encoding[32][3] = { |
@@ -313,21 +308,22 @@ static int __kprobes valid_kprobe_addr(int template, int slot, | |||
313 | return 0; | 308 | return 0; |
314 | } | 309 | } |
315 | 310 | ||
316 | static inline void save_previous_kprobe(void) | 311 | static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) |
317 | { | 312 | { |
318 | kprobe_prev = current_kprobe; | 313 | kcb->prev_kprobe.kp = kprobe_running(); |
319 | kprobe_status_prev = kprobe_status; | 314 | kcb->prev_kprobe.status = kcb->kprobe_status; |
320 | } | 315 | } |
321 | 316 | ||
322 | static inline void restore_previous_kprobe(void) | 317 | static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) |
323 | { | 318 | { |
324 | current_kprobe = kprobe_prev; | 319 | __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; |
325 | kprobe_status = kprobe_status_prev; | 320 | kcb->kprobe_status = kcb->prev_kprobe.status; |
326 | } | 321 | } |
327 | 322 | ||
328 | static inline void set_current_kprobe(struct kprobe *p) | 323 | static inline void set_current_kprobe(struct kprobe *p, |
324 | struct kprobe_ctlblk *kcb) | ||
329 | { | 325 | { |
330 | current_kprobe = p; | 326 | __get_cpu_var(current_kprobe) = p; |
331 | } | 327 | } |
332 | 328 | ||
333 | static void kretprobe_trampoline(void) | 329 | static void kretprobe_trampoline(void) |
@@ -389,6 +385,7 @@ 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 | ||
388 | reset_current_kprobe(); | ||
392 | unlock_kprobes(); | 389 | unlock_kprobes(); |
393 | preempt_enable_no_resched(); | 390 | preempt_enable_no_resched(); |
394 | 391 | ||
@@ -606,12 +603,13 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
606 | int ret = 0; | 603 | int ret = 0; |
607 | struct pt_regs *regs = args->regs; | 604 | struct pt_regs *regs = args->regs; |
608 | kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs); | 605 | kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs); |
606 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
609 | 607 | ||
610 | /* Handle recursion cases */ | 608 | /* Handle recursion cases */ |
611 | if (kprobe_running()) { | 609 | if (kprobe_running()) { |
612 | p = get_kprobe(addr); | 610 | p = get_kprobe(addr); |
613 | if (p) { | 611 | if (p) { |
614 | if ( (kprobe_status == KPROBE_HIT_SS) && | 612 | if ((kcb->kprobe_status == KPROBE_HIT_SS) && |
615 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { | 613 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { |
616 | ia64_psr(regs)->ss = 0; | 614 | ia64_psr(regs)->ss = 0; |
617 | unlock_kprobes(); | 615 | unlock_kprobes(); |
@@ -623,17 +621,17 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
623 | * just single step on the instruction of the new probe | 621 | * just single step on the instruction of the new probe |
624 | * without calling any user handlers. | 622 | * without calling any user handlers. |
625 | */ | 623 | */ |
626 | save_previous_kprobe(); | 624 | save_previous_kprobe(kcb); |
627 | set_current_kprobe(p); | 625 | set_current_kprobe(p, kcb); |
628 | p->nmissed++; | 626 | p->nmissed++; |
629 | prepare_ss(p, regs); | 627 | prepare_ss(p, regs); |
630 | kprobe_status = KPROBE_REENTER; | 628 | kcb->kprobe_status = KPROBE_REENTER; |
631 | return 1; | 629 | return 1; |
632 | } else if (args->err == __IA64_BREAK_JPROBE) { | 630 | } else if (args->err == __IA64_BREAK_JPROBE) { |
633 | /* | 631 | /* |
634 | * jprobe instrumented function just completed | 632 | * jprobe instrumented function just completed |
635 | */ | 633 | */ |
636 | p = current_kprobe; | 634 | p = __get_cpu_var(current_kprobe); |
637 | if (p->break_handler && p->break_handler(p, regs)) { | 635 | if (p->break_handler && p->break_handler(p, regs)) { |
638 | goto ss_probe; | 636 | goto ss_probe; |
639 | } | 637 | } |
@@ -668,8 +666,8 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
668 | * in post_kprobes_handler() | 666 | * in post_kprobes_handler() |
669 | */ | 667 | */ |
670 | preempt_disable(); | 668 | preempt_disable(); |
671 | kprobe_status = KPROBE_HIT_ACTIVE; | 669 | set_current_kprobe(p, kcb); |
672 | set_current_kprobe(p); | 670 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
673 | 671 | ||
674 | if (p->pre_handler && p->pre_handler(p, regs)) | 672 | if (p->pre_handler && p->pre_handler(p, regs)) |
675 | /* | 673 | /* |
@@ -681,7 +679,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
681 | 679 | ||
682 | ss_probe: | 680 | ss_probe: |
683 | prepare_ss(p, regs); | 681 | prepare_ss(p, regs); |
684 | kprobe_status = KPROBE_HIT_SS; | 682 | kcb->kprobe_status = KPROBE_HIT_SS; |
685 | return 1; | 683 | return 1; |
686 | 684 | ||
687 | no_kprobe: | 685 | no_kprobe: |
@@ -690,22 +688,25 @@ no_kprobe: | |||
690 | 688 | ||
691 | static int __kprobes post_kprobes_handler(struct pt_regs *regs) | 689 | static int __kprobes post_kprobes_handler(struct pt_regs *regs) |
692 | { | 690 | { |
693 | if (!kprobe_running()) | 691 | struct kprobe *cur = kprobe_running(); |
692 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
693 | |||
694 | if (!cur) | ||
694 | return 0; | 695 | return 0; |
695 | 696 | ||
696 | if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { | 697 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { |
697 | kprobe_status = KPROBE_HIT_SSDONE; | 698 | kcb->kprobe_status = KPROBE_HIT_SSDONE; |
698 | current_kprobe->post_handler(current_kprobe, regs, 0); | 699 | cur->post_handler(cur, regs, 0); |
699 | } | 700 | } |
700 | 701 | ||
701 | resume_execution(current_kprobe, regs); | 702 | resume_execution(cur, regs); |
702 | 703 | ||
703 | /*Restore back the original saved kprobes variables and continue. */ | 704 | /*Restore back the original saved kprobes variables and continue. */ |
704 | if (kprobe_status == KPROBE_REENTER) { | 705 | if (kcb->kprobe_status == KPROBE_REENTER) { |
705 | restore_previous_kprobe(); | 706 | restore_previous_kprobe(kcb); |
706 | goto out; | 707 | goto out; |
707 | } | 708 | } |
708 | 709 | reset_current_kprobe(); | |
709 | unlock_kprobes(); | 710 | unlock_kprobes(); |
710 | 711 | ||
711 | out: | 712 | out: |
@@ -715,15 +716,18 @@ out: | |||
715 | 716 | ||
716 | 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) |
717 | { | 718 | { |
718 | if (!kprobe_running()) | 719 | struct kprobe *cur = kprobe_running(); |
720 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
721 | |||
722 | if (!cur) | ||
719 | return 0; | 723 | return 0; |
720 | 724 | ||
721 | if (current_kprobe->fault_handler && | 725 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) |
722 | current_kprobe->fault_handler(current_kprobe, regs, trapnr)) | ||
723 | return 1; | 726 | return 1; |
724 | 727 | ||
725 | if (kprobe_status & KPROBE_HIT_SS) { | 728 | if (kcb->kprobe_status & KPROBE_HIT_SS) { |
726 | resume_execution(current_kprobe, regs); | 729 | resume_execution(cur, regs); |
730 | reset_current_kprobe(); | ||
727 | unlock_kprobes(); | 731 | unlock_kprobes(); |
728 | preempt_enable_no_resched(); | 732 | preempt_enable_no_resched(); |
729 | } | 733 | } |
@@ -761,9 +765,10 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
761 | { | 765 | { |
762 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 766 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
763 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; | 767 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; |
768 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
764 | 769 | ||
765 | /* save architectural state */ | 770 | /* save architectural state */ |
766 | jprobe_saved_regs = *regs; | 771 | kcb->jprobe_saved_regs = *regs; |
767 | 772 | ||
768 | /* after rfi, execute the jprobe instrumented function */ | 773 | /* after rfi, execute the jprobe instrumented function */ |
769 | regs->cr_iip = addr & ~0xFULL; | 774 | regs->cr_iip = addr & ~0xFULL; |
@@ -781,7 +786,9 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
781 | 786 | ||
782 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 787 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
783 | { | 788 | { |
784 | *regs = jprobe_saved_regs; | 789 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
790 | |||
791 | *regs = kcb->jprobe_saved_regs; | ||
785 | return 1; | 792 | return 1; |
786 | } | 793 | } |
787 | 794 | ||
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 573a3574a24f..592abb000e29 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/ptrace.h> | 28 | #include <linux/ptrace.h> |
29 | #include <linux/percpu.h> | ||
29 | #include <asm/break.h> | 30 | #include <asm/break.h> |
30 | 31 | ||
31 | #define MAX_INSN_SIZE 16 | 32 | #define MAX_INSN_SIZE 16 |
@@ -62,6 +63,18 @@ typedef struct _bundle { | |||
62 | } quad1; | 63 | } quad1; |
63 | } __attribute__((__aligned__(16))) bundle_t; | 64 | } __attribute__((__aligned__(16))) bundle_t; |
64 | 65 | ||
66 | struct prev_kprobe { | ||
67 | struct kprobe *kp; | ||
68 | unsigned long status; | ||
69 | }; | ||
70 | |||
71 | /* per-cpu kprobe control block */ | ||
72 | struct kprobe_ctlblk { | ||
73 | unsigned long kprobe_status; | ||
74 | struct pt_regs jprobe_saved_regs; | ||
75 | struct prev_kprobe prev_kprobe; | ||
76 | }; | ||
77 | |||
65 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry | 78 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry |
66 | 79 | ||
67 | #define ARCH_SUPPORTS_KRETPROBES | 80 | #define ARCH_SUPPORTS_KRETPROBES |