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.
This commit is contained in:
peter 2008-05-04 23:29:38 +00:00
parent 40ba3f0b05
commit 5a3c5f632b
9 changed files with 175 additions and 37 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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);

View File

@ -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_ */