]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/ia64/kernel/traps.c
[PATCH] Kprobes: Use RCU for (un)register synchronization - arch changes
[linux-2.6-omap-h63xx.git] / arch / ia64 / kernel / traps.c
index 1861173bd4f6a7be2d76edeb008e7b83a3231856..f970359e7edf2fbb67117695c2f7b1a25f86b4d0 100644 (file)
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/module.h>       /* for EXPORT_SYMBOL */
 #include <linux/hardirq.h>
+#include <linux/kprobes.h>
 
 #include <asm/fpswa.h>
 #include <asm/ia32.h>
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/kdebug.h>
 
 extern spinlock_t timerlist_lock;
 
 fpswa_interface_t *fpswa_interface;
 EXPORT_SYMBOL(fpswa_interface);
 
+struct notifier_block *ia64die_chain;
+static DEFINE_SPINLOCK(die_notifier_lock);
+
+int register_die_notifier(struct notifier_block *nb)
+{
+       int err = 0;
+       unsigned long flags;
+       spin_lock_irqsave(&die_notifier_lock, flags);
+       err = notifier_chain_register(&ia64die_chain, nb);
+       spin_unlock_irqrestore(&die_notifier_lock, flags);
+       return err;
+}
+
 void __init
 trap_init (void)
 {
@@ -76,14 +91,16 @@ die (const char *str, struct pt_regs *regs, long err)
                .lock_owner_depth =     0
        };
        static int die_counter;
+       int cpu = get_cpu();
 
-       if (die.lock_owner != smp_processor_id()) {
+       if (die.lock_owner != cpu) {
                console_verbose();
                spin_lock_irq(&die.lock);
-               die.lock_owner = smp_processor_id();
+               die.lock_owner = cpu;
                die.lock_owner_depth = 0;
                bust_spinlocks(1);
        }
+       put_cpu();
 
        if (++die.lock_owner_depth < 3) {
                printk("%s[%d]: %s %ld [%d]\n",
@@ -106,7 +123,7 @@ die_if_kernel (char *str, struct pt_regs *regs, long err)
 }
 
 void
-ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
+__kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
 {
        siginfo_t siginfo;
        int sig, code;
@@ -137,6 +154,10 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
 
        switch (break_num) {
              case 0: /* unknown error (used by GCC for __builtin_abort()) */
+               if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
+                               == NOTIFY_STOP) {
+                       return;
+               }
                die_if_kernel("bugcheck!", regs, break_num);
                sig = SIGILL; code = ILL_ILLOPC;
                break;
@@ -189,6 +210,15 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
                sig = SIGILL; code = __ILL_BNDMOD;
                break;
 
+             case 0x80200:
+             case 0x80300:
+               if (notify_die(DIE_BREAK, "kprobe", regs, break_num, TRAP_BRKPT, SIGTRAP)
+                               == NOTIFY_STOP) {
+                       return;
+               }
+               sig = SIGTRAP; code = TRAP_BRKPT;
+               break;
+
              default:
                if (break_num < 0x40000 || break_num > 0x100000)
                        die_if_kernel("Bad break", regs, break_num);
@@ -415,7 +445,7 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
        return rv;
 }
 
-void
+void __kprobes
 ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
            unsigned long iim, unsigned long itir, long arg5, long arg6,
            long arg7, struct pt_regs regs)
@@ -548,7 +578,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
 #endif
                        break;
                      case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
-                     case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+                     case 36:
+                             if (notify_die(DIE_SS, "ss", &regs, vector,
+                                            vector, SIGTRAP) == NOTIFY_STOP)
+                                     return;
+                             siginfo.si_code = TRAP_TRACE; ifa = 0; break;
                }
                siginfo.si_signo = SIGTRAP;
                siginfo.si_errno = 0;