Attempt to make break-to-debugger and alternative break-to-debugger more

accessible:

(1) Always compile in support for breaking into the debugger if options
    KDB is present in the kernel.

(2) Disable both by default, but allow them to be enabled via tunables
    and sysctls debug.kdb.break_to_debugger and
    debug.kdb.alt_break_to_debugger.

(3) options BREAK_TO_DEBUGGER and options ALT_BREAK_TO_DEBUGGER continue
    to behave as before -- only now instead of compiling in
    break-to-debugger support, they change the default values of the
    above sysctls to enable those features by default.  Current kernel
    configurations should, therefore, continue to behave as expected.

(4) Migrate alternative break-to-debugger state machine logic out of
    individual device drivers into centralised KDB code.  This has a
    number of upsides, but also one downside: it's now tricky to release
    sio spin locks when entering the debugger, so we don't.  However,
    similar logic does not exist in other device drivers, including uart.

(5) dcons requires some special handling; unlike other console types, it
    allows overriding KDB's own debugger selection, so we need a new
    interface to KDB to allow that to work.

GENERIC kernels in -CURRENT will now support break-to-debugger as long as
appropriate boot/run-time options are set, which should improve the
debuggability of BETA kernels significantly.

MFC after:	3 weeks
Reviewed by:	kib, nwhitehorn
Approved by:	re (bz)
This commit is contained in:
rwatson 2011-08-26 21:46:36 +00:00
parent dd0f1f95e2
commit 3f14675cff
10 changed files with 117 additions and 155 deletions

View File

@ -67,7 +67,7 @@ static int polltime;
static struct callout_handle cfe_timeouthandle
= CALLOUT_HANDLE_INITIALIZER(&cfe_timeouthandle);
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
#if defined(KDB)
static int alt_break_state;
#endif
@ -191,24 +191,8 @@ cfe_cngetc(struct consdev *cp)
unsigned char ch;
if (cfe_read(conhandle, &ch, 1) == 1) {
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
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;
}
}
#if defined(KDB)
kdb_alt_break(ch, &alt_break_state);
#endif
return (ch);
}

View File

@ -133,38 +133,21 @@ static struct ttydevsw dcons_ttydevsw = {
.tsw_outwakeup = dcons_outwakeup,
};
#if (defined(GDB) || defined(DDB)) && defined(ALT_BREAK_TO_DEBUGGER)
#if (defined(GDB) || defined(DDB))
static int
dcons_check_break(struct dcons_softc *dc, int c)
{
int kdb_brk;
if (c < 0)
return (c);
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 ((dc->flags & DC_GDB) != 0 && gdb_cur == &dcons_gdb_dbgport)
kdb_alt_break_gdb(c, &dc->brk_state);
else
#endif
} 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_REBOOT:
kdb_reboot();
break;
}
}
kdb_alt_break(c, &dc->brk_state);
return (c);
}
#else

View File

@ -64,7 +64,7 @@ static int polltime;
static struct callout_handle ofw_timeouthandle
= CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
#if defined(KDB)
static int alt_break_state;
#endif
@ -199,24 +199,8 @@ ofw_cngetc(struct consdev *cp)
unsigned char ch;
if (OF_read(stdin, &ch, 1) > 0) {
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
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;
}
}
#if defined(KDB)
kdb_alt_break(ch, &alt_break_state);
#endif
return (ch);
}

View File

@ -228,7 +228,7 @@ struct com_s {
struct pps_state pps;
int pps_bit;
#ifdef ALT_BREAK_TO_DEBUGGER
#ifdef KDB
int alt_brk_state;
#endif
@ -1102,8 +1102,7 @@ determined_type: ;
}
if (ret)
device_printf(dev, "could not activate interrupt\n");
#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
defined(ALT_BREAK_TO_DEBUGGER))
#if defined(KDB)
/*
* Enable interrupts for early break-to-debugger support
* on the console.
@ -1196,8 +1195,7 @@ comclose(tp)
com->poll_output = FALSE;
sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
defined(ALT_BREAK_TO_DEBUGGER))
#if defined(KDB)
/*
* Leave interrupts enabled and don't clear DTR if this is the
* console. This allows us to detect break-to-debugger events
@ -1483,9 +1481,8 @@ siointr1(com)
u_char modem_status;
u_char *ioptr;
u_char recv_data;
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
int kdb_brk;
#ifdef KDB
again:
#endif
@ -1518,27 +1515,9 @@ again:
else
recv_data = inb(com->data_port);
#ifdef KDB
#ifdef ALT_BREAK_TO_DEBUGGER
if (com->unit == comconsole &&
(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);
kdb_alt_break(recv_data, &com->alt_brk_state) != 0)
goto again;
}
#endif /* ALT_BREAK_TO_DEBUGGER */
#endif /* KDB */
if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
/*
@ -1554,10 +1533,9 @@ again:
* Note: BI together with FE/PE means just BI.
*/
if (line_status & LSR_BI) {
#if defined(KDB) && defined(BREAK_TO_DEBUGGER)
#if defined(KDB)
if (com->unit == comconsole) {
kdb_enter(KDB_WHY_BREAK,
"Line break on console");
kdb_break();
goto cont;
}
#endif

View File

@ -3514,7 +3514,7 @@ next_code:
case DBG:
#ifndef SC_DISABLE_KDBKEY
if (enable_kdbkey)
kdb_enter(KDB_WHY_BREAK, "manual escape to debugger");
kdb_break();
#endif
break;

View File

@ -118,10 +118,10 @@ uart_intr_break(void *arg)
{
struct uart_softc *sc = arg;
#if defined(KDB) && defined(BREAK_TO_DEBUGGER)
#if defined(KDB)
if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
kdb_enter(KDB_WHY_BREAK, "Line break on console");
return (0);
if (kdb_break())
return (0);
}
#endif
if (sc->sc_opened)
@ -170,26 +170,10 @@ uart_intr_rxready(void *arg)
rxp = sc->sc_rxput;
UART_RECEIVE(sc);
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
#if defined(KDB)
if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
while (rxp != sc->sc_rxput) {
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;
}
}
kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk);
if (rxp == sc->sc_rxbufsz)
rxp = 0;
}

View File

@ -57,6 +57,21 @@ struct pcb *kdb_thrctx = NULL;
struct thread *kdb_thread = NULL;
struct trapframe *kdb_frame = NULL;
#ifdef BREAK_TO_DEBUGGER
#define KDB_BREAK_TO_DEBUGGER 1
#else
#define KDB_BREAK_TO_DEBUGGER 0
#endif
#ifdef ALT_BREAK_TO_DEBUGGER
#define KDB_ALT_BREAK_TO_DEBUGGER 1
#else
#define KDB_ALT_BREAK_TO_DEBUGGER 0
#endif
static int kdb_break_to_debugger = KDB_BREAK_TO_DEBUGGER;
static int kdb_alt_break_to_debugger = KDB_ALT_BREAK_TO_DEBUGGER;
KDB_BACKEND(null, NULL, NULL, NULL);
SET_DECLARE(kdb_dbbe_set, struct kdb_dbbe);
@ -87,6 +102,15 @@ SYSCTL_PROC(_debug_kdb, OID_AUTO, trap, CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
SYSCTL_PROC(_debug_kdb, OID_AUTO, trap_code, CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
kdb_sysctl_trap_code, "I", "set to cause a page fault via code access");
SYSCTL_INT(_debug_kdb, OID_AUTO, break_to_debugger, CTLTYPE_INT | CTLFLAG_RW |
CTLFLAG_TUN, &kdb_break_to_debugger, 0, "Enable break to debugger");
TUNABLE_INT("debug.kdb.break_to_debugger", &kdb_break_to_debugger);
SYSCTL_INT(_debug_kdb, OID_AUTO, alt_break_to_debugger, CTLTYPE_INT |
CTLFLAG_RW | CTLFLAG_TUN, &kdb_alt_break_to_debugger, 0,
"Enable alternative break to debugger");
TUNABLE_INT("debug.kdb.alt_break_to_debugger", &kdb_alt_break_to_debugger);
/*
* Flag to indicate to debuggers why the debugger was entered.
*/
@ -241,7 +265,17 @@ enum {
};
int
kdb_alt_break(int key, int *state)
kdb_break(void)
{
if (!kdb_break_to_debugger)
return (0);
kdb_enter(KDB_WHY_BREAK, "Break to debugger");
return (KDB_REQ_DEBUGGER);
}
static int
kdb_alt_break_state(int key, int *state)
{
int brk;
@ -275,6 +309,53 @@ kdb_alt_break(int key, int *state)
return (brk);
}
static int
kdb_alt_break_internal(int key, int *state, int force_gdb)
{
int brk;
if (!kdb_alt_break_to_debugger)
return (0);
brk = kdb_alt_break_state(key, state);
switch (brk) {
case KDB_REQ_DEBUGGER:
if (force_gdb)
kdb_dbbe_select("gdb");
kdb_enter(KDB_WHY_BREAK, "Break to debugger");
break;
case KDB_REQ_PANIC:
if (force_gdb)
kdb_dbbe_select("gdb");
kdb_panic("Panic sequence on console");
break;
case KDB_REQ_REBOOT:
kdb_reboot();
break;
}
return (0);
}
int
kdb_alt_break(int key, int *state)
{
return (kdb_alt_break_internal(key, state, 0));
}
/*
* This variation on kdb_alt_break() is used only by dcons, which has its own
* configuration flag to force GDB use regardless of the global KDB
* configuration.
*/
int
kdb_alt_break_gdb(int key, int *state)
{
return (kdb_alt_break_internal(key, state, 1));
}
/*
* Print a backtrace of the calling thread. The backtrace is generated by
* the selected debugger, provided it supports backtraces. If no debugger

View File

@ -310,7 +310,7 @@ struct com_s {
struct pps_state pps;
int pps_bit;
#ifdef ALT_BREAK_TO_DEBUGGER
#ifdef KDB
int alt_brk_state;
#endif
@ -1752,8 +1752,7 @@ determined_type: ;
}
if (ret)
device_printf(dev, "could not activate interrupt\n");
#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
defined(ALT_BREAK_TO_DEBUGGER))
#if defined(KDB)
/*
* Enable interrupts for early break-to-debugger support
* on the console.
@ -1896,8 +1895,7 @@ comclose(tp)
sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#endif
#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
defined(ALT_BREAK_TO_DEBUGGER))
#if defined(KDB)
/*
* Leave interrupts enabled and don't clear DTR if this is the
* console. This allows us to detect break-to-debugger events
@ -2272,7 +2270,7 @@ siointr1(com)
u_char rsa_buf_status = 0;
int rsa_tx_fifo_size = 0;
#endif /* PC98 */
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
#if defined(KDB)
int kdb_brk;
again:
@ -2369,27 +2367,11 @@ more_intr:
else
recv_data = inb(com->data_port);
#ifdef KDB
#ifdef ALT_BREAK_TO_DEBUGGER
if (com->unit == comconsole &&
(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)) {
/*
@ -2405,7 +2387,7 @@ more_intr:
* Note: BI together with FE/PE means just BI.
*/
if (line_status & LSR_BI) {
#if defined(KDB) && defined(BREAK_TO_DEBUGGER)
#if defined(KDB)
if (com->unit == comconsole) {
kdb_enter(KDB_WHY_BREAK,
"Line break on console");

View File

@ -60,7 +60,7 @@ static int polltime;
static struct callout mambo_callout;
static struct tty *tp = NULL;
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
#if defined(KDB)
static int alt_break_state;
#endif
@ -156,24 +156,8 @@ mambo_cngetc(struct consdev *cp)
ch = mambocall(MAMBO_CONSOLE_READ);
if (ch > 0 && ch < 0xff) {
#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
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;
}
}
#if defined(KDB)
kdb_alt_break(ch, &alt_break_state);
#endif
return (ch);
}

View File

@ -64,6 +64,8 @@ extern struct pcb *kdb_thrctx; /* Current context. */
extern struct thread *kdb_thread; /* Current thread. */
int kdb_alt_break(int, int *);
int kdb_alt_break_gdb(int, int *);
int kdb_break(void);
void kdb_backtrace(void);
int kdb_dbbe_select(const char *);
void kdb_enter(const char *, const char *);