aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/kprobes.c
diff options
context:
space:
mode:
authorZhang Yanmin <yanmin.zhang@intel.com>2006-01-13 17:45:21 -0500
committerTony Luck <tony.luck@intel.com>2006-01-13 17:45:21 -0500
commitd3ef1f5aafcf7a4129eb2078c70bc9e577bc3af1 (patch)
tree619647d90b0a51d39e80bbc20b59e7e7dccbf510 /arch/ia64/kernel/kprobes.c
parente026cca0f2c09c4c28c902db6384fd8a412671d6 (diff)
[IA64] prevent accidental modification of args in jprobe handler
When jprobe is hit, the function parameters of the original function should be saved before jprobe handler is executed, and restored it after jprobe handler is executed, because jprobe handler might change the register values due to tail call optimization by the gcc. Signed-off-by: Zhang Yanmin <yanmin.zhang@intel.com> Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/kernel/kprobes.c')
-rw-r--r--arch/ia64/kernel/kprobes.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 346fedf9ea4..50ae8c7d453 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}