]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/mips/kernel/traps.c
[MIPS] Fix check for valid stack pointer during backtrace
[karo-tx-linux.git] / arch / mips / kernel / traps.c
index 88185cd40c3b5eb04c1c6f2318df575f4db1400c..f9165d1a17bfbccec9d64a9a07148696fcf1784c 100644 (file)
@@ -88,15 +88,17 @@ static void show_raw_backtrace(unsigned long reg29)
 #ifdef CONFIG_KALLSYMS
        printk("\n");
 #endif
-#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000)
-       if (IS_KVA01(sp)) {
-               while (!kstack_end(sp)) {
-                       addr = *sp++;
-                       if (__kernel_text_address(addr))
-                               print_ip_sym(addr);
+       while (!kstack_end(sp)) {
+               unsigned long __user *p =
+                       (unsigned long __user *)(unsigned long)sp++;
+               if (__get_user(addr, p)) {
+                       printk(" (Bad stack address)");
+                       break;
                }
-               printk("\n");
+               if (__kernel_text_address(addr))
+                       print_ip_sym(addr);
        }
+       printk("\n");
 }
 
 #ifdef CONFIG_KALLSYMS
@@ -675,35 +677,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        force_sig_info(SIGFPE, &info, current);
 }
 
-asmlinkage void do_bp(struct pt_regs *regs)
+static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
+       const char *str)
 {
-       unsigned int opcode, bcode;
        siginfo_t info;
-
-       if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
-               goto out_sigsegv;
-
-       /*
-        * There is the ancient bug in the MIPS assemblers that the break
-        * code starts left to bit 16 instead to bit 6 in the opcode.
-        * Gas is bug-compatible, but not always, grrr...
-        * We handle both cases with a simple heuristics.  --macro
-        */
-       bcode = ((opcode >> 6) & ((1 << 20) - 1));
-       if (bcode < (1 << 10))
-               bcode <<= 10;
+       char b[40];
 
        /*
-        * (A short test says that IRIX 5.3 sends SIGTRAP for all break
-        * insns, even for break codes that indicate arithmetic failures.
-        * Weird ...)
+        * A short test says that IRIX 5.3 sends SIGTRAP for all trap
+        * insns, even for trap and break codes that indicate arithmetic
+        * failures.  Weird ...
         * But should we continue the brokenness???  --macro
         */
-       switch (bcode) {
-       case BRK_OVERFLOW << 10:
-       case BRK_DIVZERO << 10:
-               die_if_kernel("Break instruction in kernel code", regs);
-               if (bcode == (BRK_DIVZERO << 10))
+       switch (code) {
+       case BRK_OVERFLOW:
+       case BRK_DIVZERO:
+               scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
+               die_if_kernel(b, regs);
+               if (code == BRK_DIVZERO)
                        info.si_code = FPE_INTDIV;
                else
                        info.si_code = FPE_INTOVF;
@@ -713,12 +704,34 @@ asmlinkage void do_bp(struct pt_regs *regs)
                force_sig_info(SIGFPE, &info, current);
                break;
        case BRK_BUG:
-               die("Kernel bug detected", regs);
+               die_if_kernel("Kernel bug detected", regs);
+               force_sig(SIGTRAP, current);
                break;
        default:
-               die_if_kernel("Break instruction in kernel code", regs);
+               scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
+               die_if_kernel(b, regs);
                force_sig(SIGTRAP, current);
        }
+}
+
+asmlinkage void do_bp(struct pt_regs *regs)
+{
+       unsigned int opcode, bcode;
+
+       if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+               goto out_sigsegv;
+
+       /*
+        * There is the ancient bug in the MIPS assemblers that the break
+        * code starts left to bit 16 instead to bit 6 in the opcode.
+        * Gas is bug-compatible, but not always, grrr...
+        * We handle both cases with a simple heuristics.  --macro
+        */
+       bcode = ((opcode >> 6) & ((1 << 20) - 1));
+       if (bcode >= (1 << 10))
+               bcode >>= 10;
+
+       do_trap_or_bp(regs, bcode, "Break");
        return;
 
 out_sigsegv:
@@ -728,7 +741,6 @@ out_sigsegv:
 asmlinkage void do_tr(struct pt_regs *regs)
 {
        unsigned int opcode, tcode = 0;
-       siginfo_t info;
 
        if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
                goto out_sigsegv;
@@ -737,32 +749,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
        if (!(opcode & OPCODE))
                tcode = ((opcode >> 6) & ((1 << 10) - 1));
 
-       /*
-        * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
-        * insns, even for trap codes that indicate arithmetic failures.
-        * Weird ...)
-        * But should we continue the brokenness???  --macro
-        */
-       switch (tcode) {
-       case BRK_OVERFLOW:
-       case BRK_DIVZERO:
-               die_if_kernel("Trap instruction in kernel code", regs);
-               if (tcode == BRK_DIVZERO)
-                       info.si_code = FPE_INTDIV;
-               else
-                       info.si_code = FPE_INTOVF;
-               info.si_signo = SIGFPE;
-               info.si_errno = 0;
-               info.si_addr = (void __user *) regs->cp0_epc;
-               force_sig_info(SIGFPE, &info, current);
-               break;
-       case BRK_BUG:
-               die("Kernel bug detected", regs);
-               break;
-       default:
-               die_if_kernel("Trap instruction in kernel code", regs);
-               force_sig(SIGTRAP, current);
-       }
+       do_trap_or_bp(regs, tcode, "Trap");
        return;
 
 out_sigsegv: