vserver 1.9.5.x5
[linux-2.6.git] / arch / x86_64 / kernel / signal.c
index d814db6..9cf7038 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/compiler.h>
-#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
@@ -40,7 +39,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
             sigset_t *set, struct pt_regs * regs); 
 
 asmlinkage long
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs regs)
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
 {
        sigset_t saveset, newset;
 
@@ -59,21 +58,22 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs re
        spin_unlock_irq(&current->sighand->siglock);
 #ifdef DEBUG_SIG
        printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
-               saveset, newset, &regs, regs.rip);
+               saveset, newset, regs, regs->rip);
 #endif 
-       regs.rax = -EINTR;
+       regs->rax = -EINTR;
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                schedule();
-               if (do_signal(&regs, &saveset))
+               if (do_signal(regs, &saveset))
                        return -EINTR;
        }
 }
 
 asmlinkage long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs regs)
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+               struct pt_regs *regs)
 {
-       return do_sigaltstack(uss, uoss, regs.rsp);
+       return do_sigaltstack(uss, uoss, regs->rsp);
 }
 
 
@@ -124,6 +124,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned
                        if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
                                goto badframe;
                        err |= restore_i387(buf);
+               } else {
+                       struct task_struct *me = current;
+                       if (used_math()) {
+                               clear_fpu(me);
+                               clear_used_math();
+                       }
                }
        }
 
@@ -134,13 +140,13 @@ badframe:
        return 1;
 }
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
        sigset_t set;
-       long eax;
+       unsigned long eax;
 
-       frame = (struct rt_sigframe __user *)(regs.rsp - 8);
+       frame = (struct rt_sigframe __user *)(regs->rsp - 8);
        if (verify_area(VERIFY_READ, frame, sizeof(*frame))) { 
                goto badframe;
        } 
@@ -154,7 +160,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
        
-       if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax)) { 
+       if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) {
                goto badframe;
        } 
 
@@ -162,13 +168,13 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
        printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
 #endif
 
-       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs.rsp) == -EFAULT)
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT)
                goto badframe;
 
        return eax;
 
 badframe:
-       signal_fault(&regs,frame,"sigreturn");
+       signal_fault(regs,frame,"sigreturn");
        return 0;
 }      
 
@@ -180,6 +186,7 @@ static inline int
 setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, struct task_struct *me)
 {
        int err = 0;
+       unsigned long eflags;
 
        err |= __put_user(0, &sc->gs);
        err |= __put_user(0, &sc->fs);
@@ -203,7 +210,11 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo
        err |= __put_user(me->thread.trap_no, &sc->trapno);
        err |= __put_user(me->thread.error_code, &sc->err);
        err |= __put_user(regs->rip, &sc->rip);
-       err |= __put_user(regs->eflags, &sc->eflags);
+       eflags = regs->eflags;
+       if (current->ptrace & PT_PTRACED) {
+               eflags &= ~TF_MASK;
+       }
+       err |= __put_user(eflags, &sc->eflags);
        err |= __put_user(mask, &sc->oldmask);
        err |= __put_user(me->thread.cr2, &sc->cr2);
 
@@ -240,9 +251,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        int err = 0;
        struct task_struct *me = current;
 
-       if (me->used_math) {
+       if (used_math()) {
                fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
-               frame = (void __user *)round_down((u64)fp - sizeof(struct rt_sigframe), 16) - 8;
+               frame = (void __user *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
                if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
                goto give_sigsegv;
@@ -287,7 +298,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_RESTORER) {
                err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
        } else {
-               printk("%s forgot to set SA_RESTORER for signal %d.\n", me->comm, sig); 
+               /* could use a vstub here */
                goto give_sigsegv; 
        }
 
@@ -318,7 +329,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->rsp = (unsigned long)frame;
 
        set_fs(USER_DS);
-       regs->eflags &= ~TF_MASK;
+       if (regs->eflags & TF_MASK) {
+               if ((current->ptrace & (PT_PTRACED | PT_DTRACE)) == (PT_PTRACED | PT_DTRACE)) {
+                       ptrace_notify(SIGTRAP);
+               } else {
+                       regs->eflags &= ~TF_MASK;
+               }
+       }
 
 #ifdef DEBUG_SIG
        printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
@@ -328,9 +345,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        return;
 
 give_sigsegv:
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       signal_fault(regs,frame,"signal deliver");
+       force_sigsegv(sig, current);
 }
 
 /*
@@ -338,18 +353,16 @@ give_sigsegv:
  */    
 
 static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
-       struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+               sigset_t *oldset, struct pt_regs *regs)
 {
-       struct k_sigaction *ka = &current->sighand->action[sig-1];
-
 #ifdef DEBUG_SIG
        printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig, 
                regs->rip, regs->rsp, regs);
 #endif
 
        /* Are we from a system call? */
-       if (regs->orig_rax >= 0) {
+       if ((long)regs->orig_rax >= 0) {
                /* If so, check system call restarting.. */
                switch (regs->rax) {
                        case -ERESTART_RESTARTBLOCK:
@@ -379,9 +392,6 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
 #endif
        setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
-
        if (!(ka->sa.sa_flags & SA_NODEFER)) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -398,6 +408,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
  */
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
+       struct k_sigaction ka;
        siginfo_t info;
        int signr;
 
@@ -411,15 +422,13 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                return 1;
        }       
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze(0))
                goto no_signal;
-       }
 
        if (!oldset)
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Reenable any watchpoints before delivering the
                 * signal to user space. The processor register will
@@ -430,13 +439,13 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                        asm volatile("movq %0,%%db7"    : : "r" (current->thread.debugreg7));
 
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, oldset, regs);
+               handle_signal(signr, &info, &ka, oldset, regs);
                return 1;
        }
 
  no_signal:
        /* Did we come from a system call? */
-       if (regs->orig_rax >= 0) {
+       if ((long)regs->orig_rax >= 0) {
                /* Restart the system call - no handlers present */
                long res = regs->rax;
                if (res == -ERESTARTNOHAND ||