MIPS: Clean up notify_die() usage.
[sfrench/cifs-2.6.git] / arch / mips / kernel / traps.c
index 852780868fb4914e4711107e96c388e1ad8ab38d..03ec0019032bc50ebbc9435cdec3c71eeaa9ac70 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/ptrace.h>
 #include <linux/kgdb.h>
 #include <linux/kdebug.h>
+#include <linux/kprobes.h>
 #include <linux/notifier.h>
 #include <linux/kdb.h>
 
@@ -334,7 +335,7 @@ void show_regs(struct pt_regs *regs)
        __show_regs((struct pt_regs *)regs);
 }
 
-void show_registers(const struct pt_regs *regs)
+void show_registers(struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
 
@@ -356,9 +357,14 @@ void show_registers(const struct pt_regs *regs)
        printk("\n");
 }
 
+static int regs_to_trapnr(struct pt_regs *regs)
+{
+       return (regs->cp0_cause >> 2) & 0x1f;
+}
+
 static DEFINE_SPINLOCK(die_lock);
 
-void __noreturn die(const char * str, struct pt_regs * regs)
+void __noreturn die(const char *str, struct pt_regs *regs)
 {
        static int die_counter;
        int sig = SIGSEGV;
@@ -366,7 +372,7 @@ void __noreturn die(const char * str, struct pt_regs * regs)
        unsigned long dvpret = dvpe();
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-       notify_die(DIE_OOPS, str, (struct pt_regs *)regs, SIGSEGV, 0, 0);
+       notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV);
 
        console_verbose();
        spin_lock_irq(&die_lock);
@@ -375,7 +381,7 @@ void __noreturn die(const char * str, struct pt_regs * regs)
        mips_mt_regdump(dvpret);
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-       if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+       if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP)
                sig = 0;
 
        printk("%s[#%d]:\n", str, ++die_counter);
@@ -449,7 +455,7 @@ asmlinkage void do_be(struct pt_regs *regs)
        printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
               data ? "Data" : "Instruction",
               field, regs->cp0_epc, field, regs->regs[31]);
-       if (notify_die(DIE_OOPS, "bus error", regs, SIGBUS, 0, 0)
+       if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS)
            == NOTIFY_STOP)
                return;
 
@@ -650,7 +656,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
        siginfo_t info;
 
-       if (notify_die(DIE_FP, "FP exception", regs, SIGFPE, 0, 0)
+       if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
            == NOTIFY_STOP)
                return;
        die_if_kernel("FP exception in kernel code", regs);
@@ -713,11 +719,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
        char b[40];
 
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
-       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
+       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
                return;
 #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
 
-       if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
+       if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
                return;
 
        /*
@@ -783,6 +789,25 @@ asmlinkage void do_bp(struct pt_regs *regs)
        if (bcode >= (1 << 10))
                bcode >>= 10;
 
+       /*
+        * notify the kprobe handlers, if instruction is likely to
+        * pertain to them.
+        */
+       switch (bcode) {
+       case BRK_KPROBE_BP:
+               if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                       return;
+               else
+                       break;
+       case BRK_KPROBE_SSTEPBP:
+               if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                       return;
+               else
+                       break;
+       default:
+               break;
+       }
+
        do_trap_or_bp(regs, bcode, "Break");
        return;
 
@@ -815,7 +840,7 @@ asmlinkage void do_ri(struct pt_regs *regs)
        unsigned int opcode = 0;
        int status = -1;
 
-       if (notify_die(DIE_RI, "RI Fault", regs, SIGSEGV, 0, 0)
+       if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL)
            == NOTIFY_STOP)
                return;
 
@@ -907,11 +932,6 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
        return NOTIFY_OK;
 }
 
-static struct notifier_block default_cu2_notifier = {
-       .notifier_call  = default_cu2_call,
-       .priority       = 0x80000000,           /* Run last  */
-};
-
 asmlinkage void do_cpu(struct pt_regs *regs)
 {
        unsigned int __user *epc;
@@ -1734,5 +1754,5 @@ void __init trap_init(void)
 
        sort_extable(__start___dbe_table, __stop___dbe_table);
 
-       register_cu2_notifier(&default_cu2_notifier);
+       cu2_notifier(default_cu2_call, 0x80000000);     /* Run last  */
 }