aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/kernel/jprobes.S27
-rw-r--r--arch/ia64/kernel/kprobes.c57
-rw-r--r--include/asm-ia64/kprobes.h6
3 files changed, 90 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)
60GLOBAL_ENTRY(jprobe_inst_return) 60GLOBAL_ENTRY(jprobe_inst_return)
61 br.call.sptk.many b0=jprobe_break 61 br.call.sptk.many b0=jprobe_break
62END(jprobe_inst_return) 62END(jprobe_inst_return)
63
64GLOBAL_ENTRY(invalidate_stacked_regs)
65 movl r16=invalidate_restore_cfm
66 ;;
67 mov b6=r16
68 ;;
69 br.ret.sptk.many b6
70 ;;
71invalidate_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
81END(invalidate_stacked_regs)
82
83GLOBAL_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
88END(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
769struct param_bsp_cfm {
770 unsigned long ip;
771 unsigned long *bsp;
772 unsigned long cfm;
773};
774
775static 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
769int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 795int __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)
792int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 837int __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}
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index a74b68104559..8c0fc227f0fb 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -68,10 +68,14 @@ struct prev_kprobe {
68 unsigned long status; 68 unsigned long status;
69}; 69};
70 70
71#define MAX_PARAM_RSE_SIZE (0x60+0x60/0x3f)
71/* per-cpu kprobe control block */ 72/* per-cpu kprobe control block */
72struct kprobe_ctlblk { 73struct kprobe_ctlblk {
73 unsigned long kprobe_status; 74 unsigned long kprobe_status;
74 struct pt_regs jprobe_saved_regs; 75 struct pt_regs jprobe_saved_regs;
76 unsigned long jprobes_saved_stacked_regs[MAX_PARAM_RSE_SIZE];
77 unsigned long *bsp;
78 unsigned long cfm;
75 struct prev_kprobe prev_kprobe; 79 struct prev_kprobe prev_kprobe;
76}; 80};
77 81
@@ -118,5 +122,7 @@ extern int kprobe_exceptions_notify(struct notifier_block *self,
118static inline void jprobe_return(void) 122static inline void jprobe_return(void)
119{ 123{
120} 124}
125extern void invalidate_stacked_regs(void);
126extern void flush_register_stack(void);
121 127
122#endif /* _ASM_KPROBES_H */ 128#endif /* _ASM_KPROBES_H */