Index: sys/gdb/gdb_int.h =================================================================== --- sys/gdb/gdb_int.h +++ sys/gdb/gdb_int.h @@ -130,6 +130,13 @@ *gdb_txp++ = *s++; } +static __inline void +gdb_tx_hexstr(const char *s) +{ + while (*s) + gdb_tx_hex(*s++, 2); +} + static __inline void gdb_tx_varhex(uintmax_t n) { Index: sys/gdb/gdb_main.c =================================================================== --- sys/gdb/gdb_main.c +++ sys/gdb/gdb_main.c @@ -47,6 +47,10 @@ SYSCTL_NODE(_debug, OID_AUTO, gdb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "GDB settings"); +static bool gdb_can_resume = false; +SYSCTL_BOOL(_debug_gdb, OID_AUTO, can_resume, CTLFLAG_RWTUN, &gdb_can_resume, + 0, "GDB can resume execution"); + static dbbe_init_f gdb_init; static dbbe_trap_f gdb_trap; @@ -608,7 +612,7 @@ gdb_cur->gdb_term(); #ifdef DDB - if (!gdb_return_to_ddb) + if (!gdb_return_to_ddb && gdb_can_resume) return; gdb_return_to_ddb = false; @@ -712,6 +716,48 @@ return; } +/* + * Send a T packet. We currently do not support watchpoints (the awatch, + * rwatch, or watch elements). + */ +static void +gdb_tx_stop(int type, int code, bool full) +{ + gdb_tx_begin('T'); + gdb_tx_hex(gdb_cpu_signal(type, code), 2); + if (full) { + gdb_tx_varhex(GDB_REG_PC); + gdb_tx_char(':'); + gdb_tx_reg(GDB_REG_PC); + gdb_tx_char(';'); + gdb_cpu_stop_reason(type, code); + } + gdb_tx_str("thread:"); + gdb_tx_varhex((long)kdb_thread->td_tid); + gdb_tx_char(';'); + gdb_tx_end(); /* XXX check error condition. */ +} + +static bool +gdb_allow_resume(int type, int code) +{ + if (gdb_can_resume) + return (true); + + gdb_tx_begin('O'); + gdb_tx_hexstr("GDB is not allowed to resume execution.\n"); + gdb_tx_hexstr("Detach and use DDB, or: set gdb_can_resume = 1\n"); + gdb_tx_end(); + + /* + * A strict reading of the protocol spec does not allow an error reply. + * Tell GDB the target stopped in the same way as last time. + */ + gdb_tx_stop(type, code, true); + + return (false); +} + static int gdb_trap(int type, int code) { @@ -731,35 +777,18 @@ gdb_listening = 0; gdb_ackmode = true; - /* - * Send a T packet. We currently do not support watchpoints (the - * awatch, rwatch or watch elements). - */ - gdb_tx_begin('T'); - gdb_tx_hex(gdb_cpu_signal(type, code), 2); - gdb_tx_varhex(GDB_REG_PC); - gdb_tx_char(':'); - gdb_tx_reg(GDB_REG_PC); - gdb_tx_char(';'); - gdb_cpu_stop_reason(type, code); - gdb_tx_str("thread:"); - gdb_tx_varhex((uintmax_t)kdb_thread->td_tid); - gdb_tx_char(';'); - gdb_tx_end(); /* XXX check error condition. */ + gdb_tx_stop(type, code, true); thr_iter = NULL; while (gdb_rx_begin() == 0) { /* printf("GDB: got '%s'\n", gdb_rxp); */ switch (gdb_rx_char()) { case '?': /* Last signal. */ - gdb_tx_begin('T'); - gdb_tx_hex(gdb_cpu_signal(type, code), 2); - gdb_tx_str("thread:"); - gdb_tx_varhex((long)kdb_thread->td_tid); - gdb_tx_char(';'); - gdb_tx_end(); + gdb_tx_stop(type, code, false); break; case 'c': { /* Continue. */ + if (!gdb_allow_resume(type, code)) + break; uintmax_t addr; register_t pc; if (!gdb_rx_varhex(&addr)) { @@ -771,6 +800,8 @@ return (1); } case 'C': { /* Continue with signal. */ + if (!gdb_allow_resume(type, code)) + break; uintmax_t addr, sig; register_t pc; if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' && @@ -929,6 +960,8 @@ gdb_tx_empty(); break; case 's': { /* Step. */ + if (!gdb_allow_resume(type, code)) + break; uintmax_t addr; register_t pc; if (!gdb_rx_varhex(&addr)) { @@ -940,6 +973,8 @@ return (1); } case 'S': { /* Step with signal. */ + if (!gdb_allow_resume(type, code)) + break; uintmax_t addr, sig; register_t pc; if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&