diff options
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/kernel/jprobes.S | 27 | ||||
-rw-r--r-- | arch/ia64/kernel/kprobes.c | 57 |
2 files changed, 84 insertions, 0 deletions
diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S index 2323377e3695..5cd6226f44f2 100644 --- a/arch/ia64/kernel/jprobes.S +++ b/arch/ia64/kernel/jprobes.S | |||
@@ -60,3 +60,30 @@ END(jprobe_break) | |||
60 | GLOBAL_ENTRY(jprobe_inst_return) | 60 | GLOBAL_ENTRY(jprobe_inst_return) |
61 | br.call.sptk.many b0=jprobe_break | 61 | br.call.sptk.many b0=jprobe_break |
62 | END(jprobe_inst_return) | 62 | END(jprobe_inst_return) |
63 | |||
64 | GLOBAL_ENTRY(invalidate_stacked_regs) | ||
65 | movl r16=invalidate_restore_cfm | ||
66 | ;; | ||
67 | mov b6=r16 | ||
68 | ;; | ||
69 | br.ret.sptk.many b6 | ||
70 | ;; | ||
71 | invalidate_restore_cfm: | ||
72 | mov r16=ar.rsc | ||
73 | ;; | ||
74 | mov ar.rsc=r0 | ||
75 | ;; | ||
76 | loadrs | ||
77 | ;; | ||
78 | mov ar.rsc=r16 | ||
79 | ;; | ||
80 | br.cond.sptk.many rp | ||
81 | END(invalidate_stacked_regs) | ||
82 | |||
83 | GLOBAL_ENTRY(flush_register_stack) | ||
84 | // flush dirty regs to backing store (must be first in insn group) | ||
85 | flushrs | ||
86 | ;; | ||
87 | br.ret.sptk.many rp | ||
88 | END(flush_register_stack) | ||
89 | |||
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 346fedf9ea47..50ae8c7d453d 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
@@ -766,11 +766,56 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
766 | return ret; | 766 | return ret; |
767 | } | 767 | } |
768 | 768 | ||
769 | struct param_bsp_cfm { | ||
770 | unsigned long ip; | ||
771 | unsigned long *bsp; | ||
772 | unsigned long cfm; | ||
773 | }; | ||
774 | |||
775 | static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg) | ||
776 | { | ||
777 | unsigned long ip; | ||
778 | struct param_bsp_cfm *lp = arg; | ||
779 | |||
780 | do { | ||
781 | unw_get_ip(info, &ip); | ||
782 | if (ip == 0) | ||
783 | break; | ||
784 | if (ip == lp->ip) { | ||
785 | unw_get_bsp(info, (unsigned long*)&lp->bsp); | ||
786 | unw_get_cfm(info, (unsigned long*)&lp->cfm); | ||
787 | return; | ||
788 | } | ||
789 | } while (unw_unwind(info) >= 0); | ||
790 | lp->bsp = 0; | ||
791 | lp->cfm = 0; | ||
792 | return; | ||
793 | } | ||
794 | |||
769 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 795 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
770 | { | 796 | { |
771 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 797 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
772 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; | 798 | unsigned long addr = ((struct fnptr *)(jp->entry))->ip; |
773 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 799 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
800 | struct param_bsp_cfm pa; | ||
801 | int bytes; | ||
802 | |||
803 | /* | ||
804 | * Callee owns the argument space and could overwrite it, eg | ||
805 | * tail call optimization. So to be absolutely safe | ||
806 | * we save the argument space before transfering the control | ||
807 | * to instrumented jprobe function which runs in | ||
808 | * the process context | ||
809 | */ | ||
810 | pa.ip = regs->cr_iip; | ||
811 | unw_init_running(ia64_get_bsp_cfm, &pa); | ||
812 | bytes = (char *)ia64_rse_skip_regs(pa.bsp, pa.cfm & 0x3f) | ||
813 | - (char *)pa.bsp; | ||
814 | memcpy( kcb->jprobes_saved_stacked_regs, | ||
815 | pa.bsp, | ||
816 | bytes ); | ||
817 | kcb->bsp = pa.bsp; | ||
818 | kcb->cfm = pa.cfm; | ||
774 | 819 | ||
775 | /* save architectural state */ | 820 | /* save architectural state */ |
776 | kcb->jprobe_saved_regs = *regs; | 821 | kcb->jprobe_saved_regs = *regs; |
@@ -792,8 +837,20 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
792 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 837 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
793 | { | 838 | { |
794 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 839 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
840 | int bytes; | ||
795 | 841 | ||
842 | /* restoring architectural state */ | ||
796 | *regs = kcb->jprobe_saved_regs; | 843 | *regs = kcb->jprobe_saved_regs; |
844 | |||
845 | /* restoring the original argument space */ | ||
846 | flush_register_stack(); | ||
847 | bytes = (char *)ia64_rse_skip_regs(kcb->bsp, kcb->cfm & 0x3f) | ||
848 | - (char *)kcb->bsp; | ||
849 | memcpy( kcb->bsp, | ||
850 | kcb->jprobes_saved_stacked_regs, | ||
851 | bytes ); | ||
852 | invalidate_stacked_regs(); | ||
853 | |||
797 | preempt_enable_no_resched(); | 854 | preempt_enable_no_resched(); |
798 | return 1; | 855 | return 1; |
799 | } | 856 | } |