Deliberately breaking into DDB, e.g. via serial console BREAK, can lead
to an abrupt end of the debugging session once the hardware watchdog
reboots the machine. This is because all CPUs are IPL_HIGH. None of them
tickles the watchdog anymore.

The same is true on panic, when the system enters DDB. If you really
want the system to reboot on panic, set ddb.panic to 0.

So stop the watchdog timer when entering DDB. Restart it after the
debugging session finished.
---
 sys/ddb/db_interface.h   |  4 ++++
 sys/ddb/db_trap.c        |  2 ++
 sys/kern/kern_watchdog.c | 25 +++++++++++++++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/sys/ddb/db_interface.h b/sys/ddb/db_interface.h
index 77602d2..5728764 100644
--- a/sys/ddb/db_interface.h
+++ b/sys/ddb/db_interface.h
@@ -45,6 +45,10 @@ void db_show_all_procs(db_expr_t, int, db_expr_t, char *);
 /* kern/kern_timeout.c */
 void db_show_callout(db_expr_t, int, db_expr_t, char *);
 
+/* kern/kern_watchdog.c */
+void db_wdog_disable(void);
+void db_wdog_enable(void);
+
 struct mount;
 
 /* kern/vfs_subr.c */
diff --git a/sys/ddb/db_trap.c b/sys/ddb/db_trap.c
index 85e5c8a..d347ede 100644
--- a/sys/ddb/db_trap.c
+++ b/sys/ddb/db_trap.c
@@ -53,6 +53,7 @@ db_trap(int type, int code)
        boolean_t       watchpt;
 
        db_is_active = 1;
+       db_wdog_disable();
        bkpt = IS_BREAKPOINT_TRAP(type, code);
        watchpt = IS_WATCHPOINT_TRAP(type, code);
 
@@ -94,5 +95,6 @@ db_trap(int type, int code)
        }
 
        db_restart_at_pc(&ddb_regs, watchpt);
+       db_wdog_enable();
        db_is_active = 0;
 }
diff --git a/sys/kern/kern_watchdog.c b/sys/kern/kern_watchdog.c
index 5c27b17..e848e24 100644
--- a/sys/kern/kern_watchdog.c
+++ b/sys/kern/kern_watchdog.c
@@ -106,3 +106,28 @@ sysctl_wdog(int *name, u_int namelen, void *oldp, size_t 
*oldlenp, void *newp,
 
        return (error);
 }
+
+#ifdef DDB
+#include <machine/db_machdep.h>
+#include <ddb/db_interface.h>
+
+void
+db_wdog_disable(void)
+{
+       if (wdog_ctl_cb == NULL || wdog_period == 0)
+               return;
+
+       timeout_del(&wdog_timeout);
+       (void) (*wdog_ctl_cb)(wdog_ctl_cb_arg, 0);
+}
+
+void
+db_wdog_enable(void)
+{
+       if (wdog_ctl_cb == NULL || wdog_period == 0)
+               return;
+
+       (void) (*wdog_ctl_cb)(wdog_ctl_cb_arg, wdog_period);
+       timeout_add(&wdog_timeout, wdog_period * hz / 2);
+}
+#endif
-- 
2.1.4

Reply via email to