Index: head/sys/gdb/gdb.h =================================================================== --- head/sys/gdb/gdb.h +++ head/sys/gdb/gdb.h @@ -55,6 +55,9 @@ deadcode and never invoked for so long I don't want to just blindly start invoking it without opt-in. */ +#define GDB_DBGP_FEAT_RELIABLE 0x2 /* The debugport promises it is a + reliable transport, which allows GDB + acks to be turned off. */ #define GDB_DBGPORT(name, probe, init, term, getc, putc) \ static struct gdb_dbgport name##_gdb_dbgport = { \ Index: head/sys/gdb/gdb_int.h =================================================================== --- head/sys/gdb/gdb_int.h +++ head/sys/gdb/gdb_int.h @@ -54,6 +54,8 @@ extern size_t gdb_rxsz; extern char *gdb_txp; +extern bool gdb_ackmode; + #ifdef DDB /* If set, return to DDB when controlling GDB detaches. */ extern bool gdb_return_to_ddb; @@ -132,6 +134,20 @@ gdb_tx_varhex(uintmax_t n) { gdb_txp += sprintf(gdb_txp, "%jx", n); +} + +static __inline void +gdb_nack(void) +{ + if (gdb_ackmode) + gdb_cur->gdb_putc('-'); +} + +static __inline void +gdb_ack(void) +{ + if (gdb_ackmode) + gdb_cur->gdb_putc('+'); } #endif /* !_GDB_GDB_INT_H_ */ Index: head/sys/gdb/gdb_main.c =================================================================== --- head/sys/gdb/gdb_main.c +++ head/sys/gdb/gdb_main.c @@ -57,6 +57,7 @@ struct gdb_dbgport *gdb_cur = NULL; int gdb_listening = 0; +bool gdb_ackmode = true; static unsigned char gdb_bindata[64]; @@ -262,6 +263,14 @@ gdb_tx_str(";qXfer:threads:read+"); /* + * If the debugport is a reliable transport, request No Ack mode from + * the server. The server may or may not choose to enter No Ack mode. + * https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html + */ + if (gdb_cur->gdb_dbfeatures & GDB_DBGP_FEAT_RELIABLE) + gdb_tx_str(";QStartNoAckMode+"); + + /* * Future consideration: * - vCont * - multiprocess @@ -610,6 +619,8 @@ } gdb_listening = 0; + gdb_ackmode = true; + /* * Send a T packet. We currently do not support watchpoints (the * awatch, rwatch or watch elements). @@ -759,6 +770,22 @@ } else if (gdb_rx_equal("Search:memory:")) { gdb_do_mem_search(); } else if (!gdb_cpu_query()) + gdb_tx_empty(); + break; + case 'Q': + if (gdb_rx_equal("StartNoAckMode")) { + if ((gdb_cur->gdb_dbfeatures & + GDB_DBGP_FEAT_RELIABLE) == 0) { + /* + * Shouldn't happen if we didn't + * advertise support. Reject. + */ + gdb_tx_empty(); + break; + } + gdb_ackmode = false; + gdb_tx_ok(); + } else gdb_tx_empty(); break; case 's': { /* Step. */ Index: head/sys/gdb/gdb_packet.c =================================================================== --- head/sys/gdb/gdb_packet.c +++ head/sys/gdb/gdb_packet.c @@ -134,18 +134,28 @@ /* Bail out on a buffer overflow. */ if (c != '#') { - gdb_cur->gdb_putc('-'); + gdb_nack(); return (ENOSPC); } + /* + * In Not-AckMode, we can assume reliable transport and neither + * need to verify checksums nor send Ack/Nack. + */ + if (!gdb_ackmode) + break; + c = gdb_getc(); cksum -= (C2N(c) << 4) & 0xf0; c = gdb_getc(); cksum -= C2N(c) & 0x0f; - gdb_cur->gdb_putc((cksum == 0) ? '+' : '-'); - if (cksum != 0) + if (cksum == 0) { + gdb_ack(); + } else { + gdb_nack(); printf("GDB: packet `%s' has invalid checksum\n", gdb_rxbuf); + } } while (cksum != 0); gdb_rxp = gdb_rxbuf; @@ -336,6 +346,14 @@ gdb_cur->gdb_putc(N2C(c)); getack: + /* + * In NoAckMode, it is assumed that the underlying transport is + * reliable and thus neither conservant sends acknowledgements; + * there is nothing to wait for here. + */ + if (!gdb_ackmode) + break; + c = gdb_getc(); } while (c != '+'); Index: head/sys/gdb/netgdb.c =================================================================== --- head/sys/gdb/netgdb.c +++ head/sys/gdb/netgdb.c @@ -272,7 +272,7 @@ .gdb_putc = netgdb_dbg_putc, .gdb_term = netgdb_fini, .gdb_sendpacket = netgdb_dbg_sendpacket, - .gdb_dbfeatures = GDB_DBGP_FEAT_WANTTERM, + .gdb_dbfeatures = GDB_DBGP_FEAT_WANTTERM | GDB_DBGP_FEAT_RELIABLE, }; static void