sparc: Fix debugger syscall restart interactions.
[deliverable/linux.git] / arch / sparc / kernel / signal.c
index 368157926d2410f6d426ea131359eb987c75331d..3fd1df9f9ba7e849609f5018d443378a301fb2e4 100644 (file)
@@ -145,6 +145,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 +202,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)
@@ -507,26 +513,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)
+asmlinkage 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
@@ -538,16 +554,16 @@ asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int rest
                        clear_thread_flag(TIF_RESTORE_SIGMASK);
                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;
@@ -599,27 +615,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;
-       }
-}
This page took 0.026644 seconds and 5 git commands to generate.