sh: kgdb: Rework breakpoint handling on top of notifier chain.
[sfrench/cifs-2.6.git] / arch / sh / kernel / kgdb.c
index 3e532d0d4a5cde48288b5d7081405ada2590860e..70c69659b8466b50ce8f3f4773f42320e765f176 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SuperH KGDB support
  *
- * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008 - 2009  Paul Mundt
  *
  * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
  *
@@ -251,24 +251,60 @@ BUILD_TRAP_HANDLER(singlestep)
        local_irq_restore(flags);
 }
 
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+       int ret;
+
+       switch (cmd) {
+       case DIE_BREAKPOINT:
+               /*
+                * This means a user thread is single stepping
+                * a system call which should be ignored
+                */
+               if (test_thread_flag(TIF_SINGLESTEP))
+                       return NOTIFY_DONE;
+
+               ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr,
+                                           args->err, args->regs);
+               if (ret)
+                       return NOTIFY_DONE;
+
+               break;
+       }
 
-BUILD_TRAP_HANDLER(breakpoint)
+       return NOTIFY_STOP;
+}
+
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
 {
        unsigned long flags;
-       TRAP_HANDLER_DECL;
+       int ret;
 
        local_irq_save(flags);
-       kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs);
+       ret = __kgdb_notify(ptr, cmd);
        local_irq_restore(flags);
+
+       return ret;
 }
 
+static struct notifier_block kgdb_notifier = {
+       .notifier_call  = kgdb_notify,
+
+       /*
+        * Lowest-prio notifier priority, we want to be notified last:
+        */
+       .priority       = -INT_MAX,
+};
+
 int kgdb_arch_init(void)
 {
-       return 0;
+       return register_die_notifier(&kgdb_notifier);
 }
 
 void kgdb_arch_exit(void)
 {
+       unregister_die_notifier(&kgdb_notifier);
 }
 
 struct kgdb_arch arch_kgdb_ops = {