kgdb,debug-core,gdbstub: Hook the reboot notifier for debugger detach
authorJason Wessel <jason.wessel@windriver.com>
Fri, 16 Mar 2012 19:20:41 +0000 (14:20 -0500)
committerJason Wessel <jason.wessel@windriver.com>
Thu, 22 Mar 2012 20:07:15 +0000 (15:07 -0500)
The gdbstub and kdb should get detached if the system is rebooting.
Calling gdbstub_exit() will set the proper debug core state and send a
message to any debugger that is connected to correctly detach.

An attached debugger will receive the exit code from
include/linux/reboot.h based on SYS_HALT, SYS_REBOOT, etc...

Reported-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
kernel/debug/debug_core.c
kernel/debug/gdbstub.c

index 0d7c08784efbdd11da5634bf1d4158641089e0b3..3c1ad4e0354382067c027d154f9ba5e75ecdc19f 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/sysrq.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/kdb.h>
@@ -784,6 +785,20 @@ void __init dbg_late_init(void)
        kdb_init(KDB_INIT_FULL);
 }
 
+static int
+dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+       if (!dbg_kdb_mode)
+               gdbstub_exit(code);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block dbg_reboot_notifier = {
+       .notifier_call          = dbg_notify_reboot,
+       .next                   = NULL,
+       .priority               = INT_MAX,
+};
+
 static void kgdb_register_callbacks(void)
 {
        if (!kgdb_io_module_registered) {
@@ -791,6 +806,7 @@ static void kgdb_register_callbacks(void)
                kgdb_arch_init();
                if (!dbg_is_early)
                        kgdb_arch_late();
+               register_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_register(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -812,6 +828,7 @@ static void kgdb_unregister_callbacks(void)
         */
        if (kgdb_io_module_registered) {
                kgdb_io_module_registered = 0;
+               unregister_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_unregister(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
                kgdb_arch_exit();
index 5a155742ae969c8f6a6e27e4bff49845ab751d71..ce615e064482c00fcfb6c98cd4b3f4fa98435ba6 100644 (file)
@@ -1111,6 +1111,13 @@ void gdbstub_exit(int status)
        unsigned char checksum, ch, buffer[3];
        int loop;
 
+       if (!kgdb_connected)
+               return;
+       kgdb_connected = 0;
+
+       if (!dbg_io_ops || dbg_kdb_mode)
+               return;
+
        buffer[0] = 'W';
        buffer[1] = hex_asc_hi(status);
        buffer[2] = hex_asc_lo(status);