Merge branch 'siginfo-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
[linux-2.6-microblaze.git] / arch / x86 / kernel / traps.c
index 5bd0a99..8f6dcd8 100644 (file)
@@ -189,7 +189,7 @@ int fixup_bug(struct pt_regs *regs, int trapnr)
 }
 
 static nokprobe_inline int
-do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
+do_trap_no_signal(struct task_struct *tsk, int trapnr, const char *str,
                  struct pt_regs *regs, long error_code)
 {
        if (v8086_mode(regs)) {
@@ -202,10 +202,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
                                                error_code, trapnr))
                                return 0;
                }
-               return -1;
-       }
-
-       if (!user_mode(regs)) {
+       } else if (!user_mode(regs)) {
                if (fixup_exception(regs, trapnr, error_code, 0))
                        return 0;
 
@@ -214,49 +211,6 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
                die(str, regs, error_code);
        }
 
-       return -1;
-}
-
-static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr,
-                               siginfo_t *info)
-{
-       unsigned long siaddr;
-       int sicode;
-
-       switch (trapnr) {
-       default:
-               return SEND_SIG_PRIV;
-
-       case X86_TRAP_DE:
-               sicode = FPE_INTDIV;
-               siaddr = uprobe_get_trap_addr(regs);
-               break;
-       case X86_TRAP_UD:
-               sicode = ILL_ILLOPN;
-               siaddr = uprobe_get_trap_addr(regs);
-               break;
-       case X86_TRAP_AC:
-               sicode = BUS_ADRALN;
-               siaddr = 0;
-               break;
-       }
-
-       info->si_signo = signr;
-       info->si_errno = 0;
-       info->si_code = sicode;
-       info->si_addr = (void __user *)siaddr;
-       return info;
-}
-
-static void
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
-       long error_code, siginfo_t *info)
-{
-       struct task_struct *tsk = current;
-
-
-       if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
-               return;
        /*
         * We want error_code and trap_nr set for userspace faults and
         * kernelspace faults which result in die(), but not
@@ -269,24 +223,45 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
        tsk->thread.error_code = error_code;
        tsk->thread.trap_nr = trapnr;
 
+       return -1;
+}
+
+static void show_signal(struct task_struct *tsk, int signr,
+                       const char *type, const char *desc,
+                       struct pt_regs *regs, long error_code)
+{
        if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
            printk_ratelimit()) {
-               pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-                       tsk->comm, tsk->pid, str,
+               pr_info("%s[%d] %s%s ip:%lx sp:%lx error:%lx",
+                       tsk->comm, task_pid_nr(tsk), type, desc,
                        regs->ip, regs->sp, error_code);
                print_vma_addr(KERN_CONT " in ", regs->ip);
                pr_cont("\n");
        }
+}
+
+static void
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
+       long error_code, int sicode, void __user *addr)
+{
+       struct task_struct *tsk = current;
+
+
+       if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
+               return;
+
+       show_signal(tsk, signr, "trap ", str, regs, error_code);
 
-       force_sig_info(signr, info ?: SEND_SIG_PRIV, tsk);
+       if (!sicode)
+               force_sig(signr, tsk);
+       else
+               force_sig_fault(signr, sicode, addr, tsk);
 }
 NOKPROBE_SYMBOL(do_trap);
 
 static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
-                         unsigned long trapnr, int signr)
+       unsigned long trapnr, int signr, int sicode, void __user *addr)
 {
-       siginfo_t info;
-
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
 
        /*
@@ -299,26 +274,26 @@ static void do_error_trap(struct pt_regs *regs, long error_code, char *str,
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
                        NOTIFY_STOP) {
                cond_local_irq_enable(regs);
-               clear_siginfo(&info);
-               do_trap(trapnr, signr, str, regs, error_code,
-                       fill_trap_info(regs, signr, trapnr, &info));
+               do_trap(trapnr, signr, str, regs, error_code, sicode, addr);
        }
 }
 
-#define DO_ERROR(trapnr, signr, str, name)                             \
-dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
-{                                                                      \
-       do_error_trap(regs, error_code, str, trapnr, signr);            \
+#define IP ((void __user *)uprobe_get_trap_addr(regs))
+#define DO_ERROR(trapnr, signr, sicode, addr, str, name)                  \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code)       \
+{                                                                         \
+       do_error_trap(regs, error_code, str, trapnr, signr, sicode, addr); \
 }
 
-DO_ERROR(X86_TRAP_DE,     SIGFPE,  "divide error",             divide_error)
-DO_ERROR(X86_TRAP_OF,     SIGSEGV, "overflow",                 overflow)
-DO_ERROR(X86_TRAP_UD,     SIGILL,  "invalid opcode",           invalid_op)
-DO_ERROR(X86_TRAP_OLD_MF, SIGFPE,  "coprocessor segment overrun",coprocessor_segment_overrun)
-DO_ERROR(X86_TRAP_TS,     SIGSEGV, "invalid TSS",              invalid_TSS)
-DO_ERROR(X86_TRAP_NP,     SIGBUS,  "segment not present",      segment_not_present)
-DO_ERROR(X86_TRAP_SS,     SIGBUS,  "stack segment",            stack_segment)
-DO_ERROR(X86_TRAP_AC,     SIGBUS,  "alignment check",          alignment_check)
+DO_ERROR(X86_TRAP_DE,     SIGFPE,  FPE_INTDIV,   IP, "divide error",        divide_error)
+DO_ERROR(X86_TRAP_OF,     SIGSEGV,          0, NULL, "overflow",            overflow)
+DO_ERROR(X86_TRAP_UD,     SIGILL,  ILL_ILLOPN,   IP, "invalid opcode",      invalid_op)
+DO_ERROR(X86_TRAP_OLD_MF, SIGFPE,           0, NULL, "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(X86_TRAP_TS,     SIGSEGV,          0, NULL, "invalid TSS",         invalid_TSS)
+DO_ERROR(X86_TRAP_NP,     SIGBUS,           0, NULL, "segment not present", segment_not_present)
+DO_ERROR(X86_TRAP_SS,     SIGBUS,           0, NULL, "stack segment",       stack_segment)
+DO_ERROR(X86_TRAP_AC,     SIGBUS,  BUS_ADRALN, NULL, "alignment check",     alignment_check)
+#undef IP
 
 #ifdef CONFIG_VMAP_STACK
 __visible void __noreturn handle_stack_overflow(const char *message,
@@ -459,7 +434,6 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
 dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
 {
        const struct mpx_bndcsr *bndcsr;
-       siginfo_t *info;
 
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
        if (notify_die(DIE_TRAP, "bounds", regs, error_code,
@@ -497,8 +471,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                        goto exit_trap;
                break; /* Success, it was handled */
        case 1: /* Bound violation. */
-               info = mpx_generate_siginfo(regs);
-               if (IS_ERR(info)) {
+       {
+               struct task_struct *tsk = current;
+               struct mpx_fault_info mpx;
+
+               if (mpx_fault_info(&mpx, regs)) {
                        /*
                         * We failed to decode the MPX instruction.  Act as if
                         * the exception was not caused by MPX.
@@ -507,14 +484,20 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
                }
                /*
                 * Success, we decoded the instruction and retrieved
-                * an 'info' containing the address being accessed
+                * an 'mpx' containing the address being accessed
                 * which caused the exception.  This information
                 * allows and application to possibly handle the
                 * #BR exception itself.
                 */
-               do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
-               kfree(info);
+               if (!do_trap_no_signal(tsk, X86_TRAP_BR, "bounds", regs,
+                                      error_code))
+                       break;
+
+               show_signal(tsk, SIGSEGV, "trap ", "bounds", regs, error_code);
+
+               force_sig_bnderr(mpx.addr, mpx.lower, mpx.upper);
                break;
+       }
        case 0: /* No exception caused by Intel MPX operations. */
                goto exit_trap;
        default:
@@ -531,12 +514,13 @@ exit_trap:
         * up here if the kernel has MPX turned off at compile
         * time..
         */
-       do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
+       do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, 0, NULL);
 }
 
 dotraplinkage void
 do_general_protection(struct pt_regs *regs, long error_code)
 {
+       const char *desc = "general protection fault";
        struct task_struct *tsk;
 
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
@@ -570,25 +554,18 @@ do_general_protection(struct pt_regs *regs, long error_code)
                    kprobe_fault_handler(regs, X86_TRAP_GP))
                        return;
 
-               if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
+               if (notify_die(DIE_GPF, desc, regs, error_code,
                               X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
-                       die("general protection fault", regs, error_code);
+                       die(desc, regs, error_code);
                return;
        }
 
        tsk->thread.error_code = error_code;
        tsk->thread.trap_nr = X86_TRAP_GP;
 
-       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-                       printk_ratelimit()) {
-               pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                       tsk->comm, task_pid_nr(tsk),
-                       regs->ip, regs->sp, error_code);
-               print_vma_addr(KERN_CONT " in ", regs->ip);
-               pr_cont("\n");
-       }
+       show_signal(tsk, SIGSEGV, "", desc, regs, error_code);
 
-       force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
+       force_sig(SIGSEGV, tsk);
 }
 NOKPROBE_SYMBOL(do_general_protection);
 
@@ -631,7 +608,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
                goto exit;
 
        cond_local_irq_enable(regs);
-       do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
+       do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, 0, NULL);
        cond_local_irq_disable(regs);
 
 exit:
@@ -845,7 +822,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
 {
        struct task_struct *task = current;
        struct fpu *fpu = &task->thread.fpu;
-       siginfo_t info;
+       int si_code;
        char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" :
                                                "simd exception";
 
@@ -871,18 +848,14 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
 
        task->thread.trap_nr    = trapnr;
        task->thread.error_code = error_code;
-       clear_siginfo(&info);
-       info.si_signo           = SIGFPE;
-       info.si_errno           = 0;
-       info.si_addr            = (void __user *)uprobe_get_trap_addr(regs);
-
-       info.si_code = fpu__exception_code(fpu, trapnr);
 
+       si_code = fpu__exception_code(fpu, trapnr);
        /* Retry when we get spurious exceptions: */
-       if (!info.si_code)
+       if (!si_code)
                return;
 
-       force_sig_info(SIGFPE, &info, task);
+       force_sig_fault(SIGFPE, si_code,
+                       (void __user *)uprobe_get_trap_addr(regs), task);
 }
 
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
@@ -942,20 +915,13 @@ NOKPROBE_SYMBOL(do_device_not_available);
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
 {
-       siginfo_t info;
-
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
        local_irq_enable();
 
-       clear_siginfo(&info);
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_BADSTK;
-       info.si_addr = NULL;
        if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
                        X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
                do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
-                       &info);
+                       ILL_BADSTK, (void __user *)NULL);
        }
 }
 #endif