gdb(4): Pack 'info threads' responses into fewer packets

We suffer at least one round trip ACK latency every command / packet that
GDB has to send and receive, and the response format for 'info threads'
supports packing many threads IDs into a single packet, so do so.

Adds and uses a new API, gdb_txbuf_has_capacity(), which checks for a
certain number of bytes available in the outgoing txbuf.

On an example amd64 VM, the number of RTTs to transmit this list is reduced
by a factor of 110x.  This is especially beneficial with recent GDB, which
seems to request the list at least twice during attach.
This commit is contained in:
Conrad Meyer 2019-08-19 22:57:03 +00:00
parent 2b0ebb77e4
commit 130ef1ad11
3 changed files with 48 additions and 16 deletions

View File

@ -62,6 +62,7 @@ void gdb_tx_begin(char);
int gdb_tx_end(void);
int gdb_tx_mem(const unsigned char *, size_t);
void gdb_tx_reg(int);
bool gdb_txbuf_has_capacity(size_t);
int gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt);
int gdb_search_mem(const unsigned char *addr, size_t size,
const unsigned char *pat, size_t patlen, const unsigned char **found);

View File

@ -123,6 +123,45 @@ gdb_do_mem_search(void)
gdb_tx_err(EIO);
}
static void
gdb_do_threadinfo(struct thread **thr_iter)
{
static struct thread * const done_sentinel = (void *)(uintptr_t)1;
static const size_t tidsz_hex = sizeof(lwpid_t) * 2;
size_t tds_sent;
if (*thr_iter == NULL) {
gdb_tx_err(ENXIO);
return;
}
if (*thr_iter == done_sentinel) {
gdb_tx_begin('l');
*thr_iter = NULL;
goto sendit;
}
gdb_tx_begin('m');
for (tds_sent = 0;
*thr_iter != NULL && gdb_txbuf_has_capacity(tidsz_hex + 1);
*thr_iter = kdb_thr_next(*thr_iter), tds_sent++) {
if (tds_sent > 0)
gdb_tx_char(',');
gdb_tx_varhex((*thr_iter)->td_tid);
}
/*
* Can't send EOF and "some" in same packet, so set a sentinel to send
* EOF when GDB asks us next.
*/
if (*thr_iter == NULL && tds_sent > 0)
*thr_iter = done_sentinel;
sendit:
gdb_tx_end();
}
static int
gdb_trap(int type, int code)
{
@ -268,23 +307,9 @@ gdb_trap(int type, int code)
case 'q': /* General query. */
if (gdb_rx_equal("fThreadInfo")) {
thr_iter = kdb_thr_first();
gdb_tx_begin('m');
gdb_tx_hex((long)thr_iter->td_tid, 8);
gdb_tx_end();
gdb_do_threadinfo(&thr_iter);
} else if (gdb_rx_equal("sThreadInfo")) {
if (thr_iter == NULL) {
gdb_tx_err(ENXIO);
break;
}
thr_iter = kdb_thr_next(thr_iter);
if (thr_iter != NULL) {
gdb_tx_begin('m');
gdb_tx_hex((long)thr_iter->td_tid, 8);
gdb_tx_end();
} else {
gdb_tx_begin('l');
gdb_tx_end();
}
gdb_do_threadinfo(&thr_iter);
} else if (gdb_rx_equal("Search:memory:")) {
gdb_do_mem_search();
} else if (!gdb_cpu_query())

View File

@ -327,6 +327,12 @@ gdb_tx_reg(int regnum)
gdb_tx_mem(regp, regsz);
}
bool
gdb_txbuf_has_capacity(size_t req)
{
return (((char *)gdb_txbuf + sizeof(gdb_txbuf) - gdb_txp) >= req);
}
/* Read binary data up until the end of the packet or until we have datalen decoded bytes */
int
gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt)