]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/sparc/kernel/signal.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / arch / sparc / kernel / signal.c
index 3c312290c3c288eda469d5272e71c3ae46226321..c94f91c8b6e0996dba7f057a815d0005376925d7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/binfmts.h>     /* do_coredum */
 #include <linux/bitops.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
@@ -145,6 +146,9 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
        regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
                  | (regs->psr & (PSR_ICC | PSR_EF));
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if (fpu_save)
@@ -199,6 +203,9 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 
        regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC);
 
+       /* Prevent syscall restart.  */
+       pt_regs_clear_syscall(regs);
+
        err |= __get_user(fpu_save, &sf->fpu_save);
 
        if (fpu_save)
@@ -245,15 +252,29 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen)
 
 static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
 {
-       unsigned long sp;
+       unsigned long sp = regs->u_regs[UREG_FP];
 
-       sp = regs->u_regs[UREG_FP];
+       /*
+        * If we are on the alternate signal stack and would overflow it, don't.
+        * Return an always-bogus address instead so we will die with SIGSEGV.
+        */
+       if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
+               return (void __user *) -1L;
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if (sa->sa_flags & SA_ONSTACK) {
-               if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
+               if (sas_ss_flags(sp) == 0)
                        sp = current->sas_ss_sp + current->sas_ss_size;
        }
+
+       /* Always align the stack frame.  This handles two cases.  First,
+        * sigaltstack need not be mindful of platform specific stack
+        * alignment.  Second, if we took this signal because the stack
+        * is not aligned properly, we'd like to take the signal cleanly
+        * and report that.
+        */
+       sp &= ~7UL;
+
        return (void __user *)(sp - framesize);
 }
 
@@ -493,26 +514,36 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall)
+static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
 {
-       siginfo_t info;
-       struct sparc_deliver_cookie cookie;
        struct k_sigaction ka;
-       int signr;
+       int restart_syscall;
        sigset_t *oldset;
+       siginfo_t info;
+       int signr;
 
-       cookie.restart_syscall = restart_syscall;
-       cookie.orig_i0 = orig_i0;
+       if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
+               restart_syscall = 1;
+       else
+               restart_syscall = 0;
 
        if (test_thread_flag(TIF_RESTORE_SIGMASK))
                oldset = &current->saved_sigmask;
        else
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+       /* If the debugger messes with the program counter, it clears
+        * the software "in syscall" bit, directing us to not perform
+        * a syscall restart.
+        */
+       if (restart_syscall && !pt_regs_is_syscall(regs))
+               restart_syscall = 0;
+
        if (signr > 0) {
-               if (cookie.restart_syscall)
-                       syscall_restart(cookie.orig_i0, regs, &ka.sa);
+               if (restart_syscall)
+                       syscall_restart(orig_i0, regs, &ka.sa);
                handle_signal(signr, &ka, &info, oldset, regs);
 
                /* a signal was successfully delivered; the saved
@@ -522,18 +553,20 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest
                 */
                if (test_thread_flag(TIF_RESTORE_SIGMASK))
                        clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               tracehook_signal_handler(signr, &info, &ka, regs, 0);
                return;
        }
-       if (cookie.restart_syscall &&
+       if (restart_syscall &&
            (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
             regs->u_regs[UREG_I0] == ERESTARTSYS ||
             regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
                /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = cookie.orig_i0;
+               regs->u_regs[UREG_I0] = orig_i0;
                regs->pc -= 4;
                regs->npc -= 4;
        }
-       if (cookie.restart_syscall &&
+       if (restart_syscall &&
            regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
                regs->u_regs[UREG_G1] = __NR_restart_syscall;
                regs->pc -= 4;
@@ -549,6 +582,17 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest
        }
 }
 
+void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
+                     unsigned long thread_info_flags)
+{
+       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+               do_signal(regs, orig_i0);
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+       }
+}
+
 asmlinkage int
 do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
                unsigned long sp)
@@ -585,27 +629,3 @@ do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr,
 out:
        return ret;
 }
-
-void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
-{
-       struct sparc_deliver_cookie *cp = cookie;
-
-       if (cp->restart_syscall &&
-           (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-            regs->u_regs[UREG_I0] == ERESTARTSYS ||
-            regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
-               /* replay the system call when we are done */
-               regs->u_regs[UREG_I0] = cp->orig_i0;
-               regs->pc -= 4;
-               regs->npc -= 4;
-               cp->restart_syscall = 0;
-       }
-
-       if (cp->restart_syscall &&
-           regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
-               regs->u_regs[UREG_G1] = __NR_restart_syscall;
-               regs->pc -= 4;
-               regs->npc -= 4;
-               cp->restart_syscall = 0;
-       }
-}