summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2008-05-04 23:29:38 +0000
committerpeter <peter@FreeBSD.org>2008-05-04 23:29:38 +0000
commit5a3c5f632b4461dbf60ab538e16453104b937231 (patch)
treedec162871c2e0c2defef809d28858069fac12065
parent40ba3f0b054237aea1c061c7ae1d4a9b1b5dd800 (diff)
downloadFreeBSD-src-5a3c5f632b4461dbf60ab538e16453104b937231.zip
FreeBSD-src-5a3c5f632b4461dbf60ab538e16453104b937231.tar.gz
Expand kdb_alt_break a little, most commonly used with the option
ALT_BREAK_TO_DEBUGGER. In addition to "Enter ~ ctrl-B" (to enter the debugger), there is now "Enter ~ ctrl-P" (force panic) and "Enter ~ ctrl-R" (request clean reboot, ala ctrl-alt-del on syscons). We've used variations of this at work. The force panic sequence is best used with KDB_UNATTENDED for when you just want it to dump and get on with it. The reboot request is a safer way of getting into single user than a power cycle. eg: you've hosed the ability to log in (pam, rtld, etc). It gives init the reboot signal, which causes an orderly reboot. I've taken my best guess at what the !x86 and non-sio code changes should be. This also makes sio release its spinlock before calling KDB/DDB.
-rw-r--r--sys/arm/at91/uart_dev_at91usart.c15
-rw-r--r--sys/dev/dcons/dcons_os.c34
-rw-r--r--sys/dev/ofw/ofw_console.c19
-rw-r--r--sys/dev/sio/sio.c26
-rw-r--r--sys/dev/uart/uart_core.c20
-rw-r--r--sys/kern/subr_kdb.c46
-rw-r--r--sys/pc98/cbus/sio.c27
-rw-r--r--sys/sun4v/sun4v/hvcons.c18
-rw-r--r--sys/sys/kdb.h7
9 files changed, 175 insertions, 37 deletions
diff --git a/sys/arm/at91/uart_dev_at91usart.c b/sys/arm/at91/uart_dev_at91usart.c
index f87dcaa..8a7644f 100644
--- a/sys/arm/at91/uart_dev_at91usart.c
+++ b/sys/arm/at91/uart_dev_at91usart.c
@@ -506,9 +506,20 @@ static __inline void
at91_rx_put(struct uart_softc *sc, int key)
{
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
+ int kdb_brk;
+
if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
- if (kdb_alt_break(key, &sc->sc_altbrk))
- kdb_enter(KDB_WHY_BREAK, "Break sequence to console");
+ if ((kdb_brk = kdb_alt_break(key, &sc->sc_altbrk)) != 0) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("Panic sequence on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+ }
}
#endif
uart_rx_put(sc, key);
diff --git a/sys/dev/dcons/dcons_os.c b/sys/dev/dcons/dcons_os.c
index 7eb89aa..5715343 100644
--- a/sys/dev/dcons/dcons_os.c
+++ b/sys/dev/dcons/dcons_os.c
@@ -198,22 +198,36 @@ extern struct gdb_dbgport *gdb_cur;
static int
dcons_check_break(struct dcons_softc *dc, int c)
{
+#if __FreeBSD_version >= 502122
+ int kdb_brk;
+#endif
if (c < 0)
return (c);
#if __FreeBSD_version >= 502122
- if (kdb_alt_break(c, &dc->brk_state)) {
- if ((dc->flags & DC_GDB) != 0) {
+ if ((kdb_brk = kdb_alt_break(c, &dc->brk_state)) != 0) {
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+
+ if ((dc->flags & DC_GDB) != 0) {
#ifdef GDB
- if (gdb_cur == &dcons_gdb_dbgport) {
- kdb_dbbe_select("gdb");
- kdb_enter(KDB_WHY_BREAK,
- "Break sequence on dcons gdb port");
- }
+ if (gdb_cur == &dcons_gdb_dbgport) {
+ kdb_dbbe_select("gdb");
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on dcons gdb port");
+ }
#endif
- } else
- kdb_enter(KDB_WHY_BREAK,
- "Break sequence on dcons console port");
+ } else
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on dcons console port");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("Panic sequence on dcons console port");
+ break;
+ case KDB_REQ_BREAK:
+ kdb_reboot();
+ break;
+ }
}
#else
switch (dc->brk_state) {
diff --git a/sys/dev/ofw/ofw_console.c b/sys/dev/ofw/ofw_console.c
index 154bcc5..156f121 100644
--- a/sys/dev/ofw/ofw_console.c
+++ b/sys/dev/ofw/ofw_console.c
@@ -281,8 +281,23 @@ ofw_cngetc(struct consdev *cp)
if (OF_read(stdin, &ch, 1) > 0) {
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
- if (kdb_alt_break(ch, &alt_break_state))
- kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
+ int kdb_brk;
+
+ if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) {
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("Panic sequence on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+
+ }
+ }
#endif
return (ch);
}
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
index a62b411..a4cca4d 100644
--- a/sys/dev/sio/sio.c
+++ b/sys/dev/sio/sio.c
@@ -1469,6 +1469,11 @@ siointr1(com)
u_char modem_status;
u_char *ioptr;
u_char recv_data;
+#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
+ int kdb_brk;
+
+again:
+#endif
if (COM_IIR_TXRDYBUG(com->flags)) {
int_ctl = inb(com->int_ctl_port);
@@ -1501,9 +1506,24 @@ siointr1(com)
#ifdef KDB
#ifdef ALT_BREAK_TO_DEBUGGER
if (com->unit == comconsole &&
- kdb_alt_break(recv_data, &com->alt_brk_state) != 0)
- kdb_enter(KDB_WHY_BREAK,
- "Break sequence on console");
+ (kdb_brk = kdb_alt_break(recv_data,
+ &com->alt_brk_state)) != 0) {
+ mtx_unlock_spin(&sio_lock);
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("panic on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+ }
+ mtx_lock_spin(&sio_lock);
+ goto again;
+ }
#endif /* ALT_BREAK_TO_DEBUGGER */
#endif /* KDB */
if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index b4730418..3b0d64c 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -175,9 +175,23 @@ uart_intr_rxready(void *arg)
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
while (rxp != sc->sc_rxput) {
- if (kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk))
- kdb_enter(KDB_WHY_BREAK,
- "Break sequence on console");
+ int kdb_brk;
+
+ if ((kdb_brk = kdb_alt_break(sc->sc_rxbuf[rxp++],
+ &sc->sc_altbrk)) != 0) {
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("Panic sequence on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+ }
+ }
if (rxp == sc->sc_rxbufsz)
rxp = 0;
}
diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c
index 8b66a58..602093b 100644
--- a/sys/kern/subr_kdb.c
+++ b/sys/kern/subr_kdb.c
@@ -221,6 +221,25 @@ kdb_sysctl_trap_code(SYSCTL_HANDLER_ARGS)
return (0);
}
+void
+kdb_panic(const char *msg)
+{
+
+#ifdef SMP
+ stop_cpus(PCPU_GET(other_cpus));
+#endif
+ printf("KDB: panic\n");
+ panic(msg);
+}
+
+void
+kdb_reboot(void)
+{
+
+ printf("KDB: reboot requested\n");
+ shutdown_nice(0);
+}
+
/*
* Solaris implements a new BREAK which is initiated by a character sequence
* CR ~ ^b which is similar to a familiar pattern used on Sun servers by the
@@ -235,6 +254,8 @@ kdb_sysctl_trap_code(SYSCTL_HANDLER_ARGS)
#define KEY_CR 13 /* CR '\r' */
#define KEY_TILDE 126 /* ~ */
#define KEY_CRTLB 2 /* ^B */
+#define KEY_CRTLP 16 /* ^P */
+#define KEY_CRTLR 18 /* ^R */
int
kdb_alt_break(int key, int *state)
@@ -242,20 +263,23 @@ kdb_alt_break(int key, int *state)
int brk;
brk = 0;
- switch (key) {
- case KEY_CR:
- *state = KEY_TILDE;
+ switch (*state) {
+ case 0:
+ if (key == KEY_CR)
+ *state = 1;
break;
- case KEY_TILDE:
- *state = (*state == KEY_TILDE) ? KEY_CRTLB : 0;
+ case 1:
+ if (key == KEY_TILDE)
+ *state = 2;
break;
- case KEY_CRTLB:
- if (*state == KEY_CRTLB)
- brk = 1;
- /* FALLTHROUGH */
- default:
+ case 2:
+ if (key == KEY_CRTLB)
+ brk = KDB_REQ_DEBUGGER;
+ else if (key == KEY_CRTLP)
+ brk = KDB_REQ_PANIC;
+ else if (key == KEY_CRTLR)
+ brk = KDB_REQ_REBOOT;
*state = 0;
- break;
}
return (brk);
}
diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c
index d0173af..7089578 100644
--- a/sys/pc98/cbus/sio.c
+++ b/sys/pc98/cbus/sio.c
@@ -2268,12 +2268,16 @@ siointr1(com)
u_char modem_status;
u_char *ioptr;
u_char recv_data;
-
#ifdef PC98
u_char tmp = 0;
u_char rsa_buf_status = 0;
int rsa_tx_fifo_size = 0;
#endif /* PC98 */
+#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
+ int kdb_brk;
+
+again:
+#endif
if (COM_IIR_TXRDYBUG(com->flags)) {
int_ctl = inb(com->int_ctl_port);
@@ -2368,9 +2372,24 @@ more_intr:
#ifdef KDB
#ifdef ALT_BREAK_TO_DEBUGGER
if (com->unit == comconsole &&
- kdb_alt_break(recv_data, &com->alt_brk_state) != 0)
- kdb_enter(KDB_WHY_BREAK,
- "Break sequence on console");
+ (kdb_brk = kdb_alt_break(recv_data,
+ &com->alt_brk_state)) != 0) {
+ mtx_unlock_spin(&sio_lock);
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("panic on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+ }
+ mtx_lock_spin(&sio_lock);
+ goto again;
+ }
#endif /* ALT_BREAK_TO_DEBUGGER */
#endif /* KDB */
if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
diff --git a/sys/sun4v/sun4v/hvcons.c b/sys/sun4v/sun4v/hvcons.c
index 3329d05..0217a85 100644
--- a/sys/sun4v/sun4v/hvcons.c
+++ b/sys/sun4v/sun4v/hvcons.c
@@ -223,11 +223,25 @@ hvcn_cngetc(struct consdev *cp)
while ((l = hv_cons_getchar(&ch)) != H_EOK) {
#if defined(KDB)
+ int kdb_brk;
+
if (l == H_BREAK || l == H_HUP)
kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
- if (kdb_alt_break(ch, &alt_break_state))
- kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
+ if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) {
+ switch (kdb_brk) {
+ case KDB_REQ_DEBUGGER:
+ kdb_enter(KDB_WHY_BREAK,
+ "Break sequence on console");
+ break;
+ case KDB_REQ_PANIC:
+ kdb_panic("Panic sequence on console");
+ break;
+ case KDB_REQ_REBOOT:
+ kdb_reboot();
+ break;
+ }
+ }
#endif
if (l != -2 && l != 0) {
return (-1);
diff --git a/sys/sys/kdb.h b/sys/sys/kdb.h
index 0f989f5..c162852 100644
--- a/sys/sys/kdb.h
+++ b/sys/sys/kdb.h
@@ -69,6 +69,8 @@ int kdb_dbbe_select(const char *);
void kdb_enter(const char *, const char *);
void kdb_init(void);
void * kdb_jmpbuf(jmp_buf);
+void kdb_panic(const char *);
+void kdb_reboot(void);
void kdb_reenter(void);
struct pcb *kdb_thr_ctx(struct thread *);
struct thread *kdb_thr_first(void);
@@ -105,4 +107,9 @@ extern const char * volatile kdb_why;
#define KDB_WHY_POWERPC "powerpc" /* Unhandled powerpc intr. */
#define KDB_WHY_UNIONFS "unionfs" /* Unionfs bug. */
+/* Return values for kdb_alt_break */
+#define KDB_REQ_DEBUGGER 1 /* User requested Debugger */
+#define KDB_REQ_PANIC 2 /* User requested a panic */
+#define KDB_REQ_REBOOT 3 /* User requested a clean reboot */
+
#endif /* !_SYS_KDB_H_ */
OpenPOWER on IntegriCloud