diff options
author | Ananth N Mavinakayanahalli <ananth@in.ibm.com> | 2005-11-07 04:00:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:45 -0500 |
commit | 8a5c4dc5e5d72b7802f5647082ccf3861a94f013 (patch) | |
tree | 6a152d01d9b9653201a113af9c1ce3f94771bf49 /arch | |
parent | 9a0e3a86837ac7542e601c18346102c9d9e65fa5 (diff) |
[PATCH] Kprobes: Track kprobe on a per_cpu basis - ia64 changes
IA64 changes to track kprobe execution on a per-cpu basis. We now track the
kprobe state machine independently on each cpu using an arch specific kprobe
control block.
Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 83 |
1 files changed, 45 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 | ||