xref: /freebsd/sys/gdb/gdb_packet.c (revision 028a372fe2658ccf72ed481b9e942b28a59cb178)
1fa521b03SWarner Losh /*-
2497b6b2aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3497b6b2aSPedro F. Giffuni  *
472d44f31SMarcel Moolenaar  * Copyright (c) 2004 Marcel Moolenaar
572d44f31SMarcel Moolenaar  * All rights reserved.
672d44f31SMarcel Moolenaar  *
772d44f31SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
872d44f31SMarcel Moolenaar  * modification, are permitted provided that the following conditions
972d44f31SMarcel Moolenaar  * are met:
1072d44f31SMarcel Moolenaar  *
1172d44f31SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
1272d44f31SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
1372d44f31SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
1472d44f31SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
1572d44f31SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
1672d44f31SMarcel Moolenaar  *
1772d44f31SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1872d44f31SMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1972d44f31SMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2072d44f31SMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2172d44f31SMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2272d44f31SMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2372d44f31SMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2472d44f31SMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2572d44f31SMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2672d44f31SMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2772d44f31SMarcel Moolenaar  */
2872d44f31SMarcel Moolenaar 
2972d44f31SMarcel Moolenaar #include <sys/cdefs.h>
3072d44f31SMarcel Moolenaar __FBSDID("$FreeBSD$");
3172d44f31SMarcel Moolenaar 
3272d44f31SMarcel Moolenaar #include <sys/param.h>
3372d44f31SMarcel Moolenaar #include <sys/systm.h>
3472d44f31SMarcel Moolenaar #include <sys/ctype.h>
3572d44f31SMarcel Moolenaar #include <sys/kdb.h>
3627ecc2adSBenno Rice #include <sys/libkern.h>
373a5d3671SMatthew D Fleming #include <sys/ttydefaults.h>
3872d44f31SMarcel Moolenaar 
3972d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h>
4001bd17ccSMarcel Moolenaar #include <machine/kdb.h>
4172d44f31SMarcel Moolenaar 
4272d44f31SMarcel Moolenaar #include <gdb/gdb.h>
4372d44f31SMarcel Moolenaar #include <gdb/gdb_int.h>
4472d44f31SMarcel Moolenaar 
4572d44f31SMarcel Moolenaar static char gdb_rxbuf[GDB_BUFSZ];
4672d44f31SMarcel Moolenaar char *gdb_rxp = NULL;
4772d44f31SMarcel Moolenaar size_t gdb_rxsz = 0;
48dda17b36SConrad Meyer 
49dda17b36SConrad Meyer /*
50dda17b36SConrad Meyer  * The goal here is to allow in-place framing without making the math around
51dda17b36SConrad Meyer  * 'gdb_txbuf' more complicated.  A generous reading of union special rule for
52dda17b36SConrad Meyer  * "common initial sequence" suggests this may be valid in standard C99 and
53dda17b36SConrad Meyer  * later.
54dda17b36SConrad Meyer  */
55dda17b36SConrad Meyer static union {
56dda17b36SConrad Meyer 	struct _midbuf {
57dda17b36SConrad Meyer 		char mb_pad1;
58dda17b36SConrad Meyer 		char mb_buf[GDB_BUFSZ];
59dda17b36SConrad Meyer 		char mb_pad2[4];
60dda17b36SConrad Meyer 	} __packed txu_midbuf;
61dda17b36SConrad Meyer 	/* sizeof includes trailing nul byte and this is intentional. */
62dda17b36SConrad Meyer 	char txu_fullbuf[GDB_BUFSZ + sizeof("$#..")];
63dda17b36SConrad Meyer } gdb_tx_u;
64dda17b36SConrad Meyer #define	gdb_txbuf	gdb_tx_u.txu_midbuf.mb_buf
65dda17b36SConrad Meyer #define	gdb_tx_fullbuf	gdb_tx_u.txu_fullbuf
66dda17b36SConrad Meyer _Static_assert(sizeof(gdb_tx_u.txu_midbuf) == sizeof(gdb_tx_u.txu_fullbuf) &&
67dda17b36SConrad Meyer     offsetof(struct _midbuf, mb_buf) == 1,
68dda17b36SConrad Meyer     "assertions necessary for correctness");
6972d44f31SMarcel Moolenaar char *gdb_txp = NULL;			/* Used in inline functions. */
7072d44f31SMarcel Moolenaar 
7172d44f31SMarcel Moolenaar #define	C2N(c)	(((c) < 'A') ? (c) - '0' : \
7272d44f31SMarcel Moolenaar 	    10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a'))
7372d44f31SMarcel Moolenaar #define	N2C(n)	(((n) < 10) ? (n) + '0' : (n) + 'a' - 10)
7472d44f31SMarcel Moolenaar 
7572d44f31SMarcel Moolenaar /*
76f346afc4SPoul-Henning Kamp  * Get a single character
77f346afc4SPoul-Henning Kamp  */
78f346afc4SPoul-Henning Kamp 
79f346afc4SPoul-Henning Kamp static int
80f346afc4SPoul-Henning Kamp gdb_getc(void)
81f346afc4SPoul-Henning Kamp {
82f346afc4SPoul-Henning Kamp 	int c;
83f346afc4SPoul-Henning Kamp 
84f346afc4SPoul-Henning Kamp 	do
85f346afc4SPoul-Henning Kamp 		c = gdb_cur->gdb_getc();
86f346afc4SPoul-Henning Kamp 	while (c == -1);
873a5d3671SMatthew D Fleming 
883a5d3671SMatthew D Fleming 	if (c == CTRL('C')) {
893a5d3671SMatthew D Fleming 		printf("Received ^C; trying to switch back to ddb.\n");
903a5d3671SMatthew D Fleming 
91dda17b36SConrad Meyer 		if (gdb_cur->gdb_dbfeatures & GDB_DBGP_FEAT_WANTTERM)
92dda17b36SConrad Meyer 			gdb_cur->gdb_term();
93dda17b36SConrad Meyer 
943a5d3671SMatthew D Fleming 		if (kdb_dbbe_select("ddb") != 0)
953a5d3671SMatthew D Fleming 			printf("The ddb backend could not be selected.\n");
963a5d3671SMatthew D Fleming 		else {
973a5d3671SMatthew D Fleming 			printf("using longjmp, hope it works!\n");
983a5d3671SMatthew D Fleming 			kdb_reenter();
993a5d3671SMatthew D Fleming 		}
1003a5d3671SMatthew D Fleming 	}
101f346afc4SPoul-Henning Kamp 	return (c);
102f346afc4SPoul-Henning Kamp }
103f346afc4SPoul-Henning Kamp 
104f346afc4SPoul-Henning Kamp /*
10572d44f31SMarcel Moolenaar  * Functions to receive and extract from a packet.
10672d44f31SMarcel Moolenaar  */
10772d44f31SMarcel Moolenaar 
10872d44f31SMarcel Moolenaar int
10972d44f31SMarcel Moolenaar gdb_rx_begin(void)
11072d44f31SMarcel Moolenaar {
11172d44f31SMarcel Moolenaar 	int c, cksum;
11272d44f31SMarcel Moolenaar 
11372d44f31SMarcel Moolenaar 	gdb_rxp = NULL;
11472d44f31SMarcel Moolenaar 	do {
11572d44f31SMarcel Moolenaar 		/*
11672d44f31SMarcel Moolenaar 		 * Wait for the start character, ignore all others.
11772d44f31SMarcel Moolenaar 		 * XXX needs a timeout.
11872d44f31SMarcel Moolenaar 		 */
119f346afc4SPoul-Henning Kamp 		while ((c = gdb_getc()) != '$')
12072d44f31SMarcel Moolenaar 			;
12172d44f31SMarcel Moolenaar 
12272d44f31SMarcel Moolenaar 		/* Read until a # or end of buffer is found. */
12372d44f31SMarcel Moolenaar 		cksum = 0;
12472d44f31SMarcel Moolenaar 		gdb_rxsz = 0;
12572d44f31SMarcel Moolenaar 		while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) {
126f346afc4SPoul-Henning Kamp 			c = gdb_getc();
12772d44f31SMarcel Moolenaar 			if (c == '#')
12872d44f31SMarcel Moolenaar 				break;
12972d44f31SMarcel Moolenaar 			gdb_rxbuf[gdb_rxsz++] = c;
13072d44f31SMarcel Moolenaar 			cksum += c;
13172d44f31SMarcel Moolenaar 		}
13272d44f31SMarcel Moolenaar 		gdb_rxbuf[gdb_rxsz] = 0;
13372d44f31SMarcel Moolenaar 		cksum &= 0xff;
13472d44f31SMarcel Moolenaar 
13572d44f31SMarcel Moolenaar 		/* Bail out on a buffer overflow. */
13672d44f31SMarcel Moolenaar 		if (c != '#') {
1376310546dSConrad Meyer 			gdb_nack();
13872d44f31SMarcel Moolenaar 			return (ENOSPC);
13972d44f31SMarcel Moolenaar 		}
14072d44f31SMarcel Moolenaar 
1416310546dSConrad Meyer 		/*
1426310546dSConrad Meyer 		 * In Not-AckMode, we can assume reliable transport and neither
1436310546dSConrad Meyer 		 * need to verify checksums nor send Ack/Nack.
1446310546dSConrad Meyer 		 */
1456310546dSConrad Meyer 		if (!gdb_ackmode)
1466310546dSConrad Meyer 			break;
1476310546dSConrad Meyer 
148f346afc4SPoul-Henning Kamp 		c = gdb_getc();
14972d44f31SMarcel Moolenaar 		cksum -= (C2N(c) << 4) & 0xf0;
150f346afc4SPoul-Henning Kamp 		c = gdb_getc();
15172d44f31SMarcel Moolenaar 		cksum -= C2N(c) & 0x0f;
1526310546dSConrad Meyer 		if (cksum == 0) {
1536310546dSConrad Meyer 			gdb_ack();
1546310546dSConrad Meyer 		} else {
1556310546dSConrad Meyer 			gdb_nack();
15672d44f31SMarcel Moolenaar 			printf("GDB: packet `%s' has invalid checksum\n",
15772d44f31SMarcel Moolenaar 			    gdb_rxbuf);
1586310546dSConrad Meyer 		}
15972d44f31SMarcel Moolenaar 	} while (cksum != 0);
16072d44f31SMarcel Moolenaar 
16172d44f31SMarcel Moolenaar 	gdb_rxp = gdb_rxbuf;
16272d44f31SMarcel Moolenaar 	return (0);
16372d44f31SMarcel Moolenaar }
16472d44f31SMarcel Moolenaar 
16572d44f31SMarcel Moolenaar int
16672d44f31SMarcel Moolenaar gdb_rx_equal(const char *str)
16772d44f31SMarcel Moolenaar {
16872d44f31SMarcel Moolenaar 	int len;
16972d44f31SMarcel Moolenaar 
17072d44f31SMarcel Moolenaar 	len = strlen(str);
17172d44f31SMarcel Moolenaar 	if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0)
17272d44f31SMarcel Moolenaar 		return (0);
17372d44f31SMarcel Moolenaar 	gdb_rxp += len;
17472d44f31SMarcel Moolenaar 	gdb_rxsz -= len;
17572d44f31SMarcel Moolenaar 	return (1);
17672d44f31SMarcel Moolenaar }
17772d44f31SMarcel Moolenaar 
17872d44f31SMarcel Moolenaar int
17972d44f31SMarcel Moolenaar gdb_rx_mem(unsigned char *addr, size_t size)
18072d44f31SMarcel Moolenaar {
18101bd17ccSMarcel Moolenaar 	unsigned char *p;
18272d44f31SMarcel Moolenaar 	void *prev;
183beb24065SJonathan T. Looney 	void *wctx;
18472d44f31SMarcel Moolenaar 	jmp_buf jb;
18501bd17ccSMarcel Moolenaar 	size_t cnt;
18672d44f31SMarcel Moolenaar 	int ret;
18772d44f31SMarcel Moolenaar 	unsigned char c;
18872d44f31SMarcel Moolenaar 
18972d44f31SMarcel Moolenaar 	if (size * 2 != gdb_rxsz)
19072d44f31SMarcel Moolenaar 		return (-1);
19172d44f31SMarcel Moolenaar 
192beb24065SJonathan T. Looney 	wctx = gdb_begin_write();
19372d44f31SMarcel Moolenaar 	prev = kdb_jmpbuf(jb);
19472d44f31SMarcel Moolenaar 	ret = setjmp(jb);
19572d44f31SMarcel Moolenaar 	if (ret == 0) {
19601bd17ccSMarcel Moolenaar 		p = addr;
19701bd17ccSMarcel Moolenaar 		cnt = size;
19801bd17ccSMarcel Moolenaar 		while (cnt-- > 0) {
19972d44f31SMarcel Moolenaar 			c = (C2N(gdb_rxp[0]) << 4) & 0xf0;
20072d44f31SMarcel Moolenaar 			c |= C2N(gdb_rxp[1]) & 0x0f;
20101bd17ccSMarcel Moolenaar 			*p++ = c;
20272d44f31SMarcel Moolenaar 			gdb_rxsz -= 2;
20372d44f31SMarcel Moolenaar 			gdb_rxp += 2;
20472d44f31SMarcel Moolenaar 		}
20501bd17ccSMarcel Moolenaar 		kdb_cpu_sync_icache(addr, size);
20672d44f31SMarcel Moolenaar 	}
20772d44f31SMarcel Moolenaar 	(void)kdb_jmpbuf(prev);
208beb24065SJonathan T. Looney 	gdb_end_write(wctx);
20972d44f31SMarcel Moolenaar 	return ((ret == 0) ? 1 : 0);
21072d44f31SMarcel Moolenaar }
21172d44f31SMarcel Moolenaar 
21272d44f31SMarcel Moolenaar int
21372d44f31SMarcel Moolenaar gdb_rx_varhex(uintmax_t *vp)
21472d44f31SMarcel Moolenaar {
21572d44f31SMarcel Moolenaar 	uintmax_t v;
21672d44f31SMarcel Moolenaar 	int c, neg;
21772d44f31SMarcel Moolenaar 
21872d44f31SMarcel Moolenaar 	c = gdb_rx_char();
21972d44f31SMarcel Moolenaar 	neg = (c == '-') ? 1 : 0;
22072d44f31SMarcel Moolenaar 	if (neg == 1)
22172d44f31SMarcel Moolenaar 		c = gdb_rx_char();
22272d44f31SMarcel Moolenaar 	if (!isxdigit(c)) {
22372d44f31SMarcel Moolenaar 		gdb_rxp -= ((c == -1) ? 0 : 1) + neg;
22472d44f31SMarcel Moolenaar 		gdb_rxsz += ((c == -1) ? 0 : 1) + neg;
22572d44f31SMarcel Moolenaar 		return (-1);
22672d44f31SMarcel Moolenaar 	}
22772d44f31SMarcel Moolenaar 	v = 0;
22872d44f31SMarcel Moolenaar 	do {
22972d44f31SMarcel Moolenaar 		v <<= 4;
23072d44f31SMarcel Moolenaar 		v += C2N(c);
23172d44f31SMarcel Moolenaar 		c = gdb_rx_char();
23272d44f31SMarcel Moolenaar 	} while (isxdigit(c));
2335df6fa43SConrad Meyer 	if (c != EOF) {
23472d44f31SMarcel Moolenaar 		gdb_rxp--;
23572d44f31SMarcel Moolenaar 		gdb_rxsz++;
23672d44f31SMarcel Moolenaar 	}
23772d44f31SMarcel Moolenaar 	*vp = (neg) ? -v : v;
23872d44f31SMarcel Moolenaar 	return (0);
23972d44f31SMarcel Moolenaar }
24072d44f31SMarcel Moolenaar 
24172d44f31SMarcel Moolenaar /*
24272d44f31SMarcel Moolenaar  * Function to build and send a package.
24372d44f31SMarcel Moolenaar  */
24472d44f31SMarcel Moolenaar 
24572d44f31SMarcel Moolenaar void
24672d44f31SMarcel Moolenaar gdb_tx_begin(char tp)
24772d44f31SMarcel Moolenaar {
24872d44f31SMarcel Moolenaar 
24972d44f31SMarcel Moolenaar 	gdb_txp = gdb_txbuf;
25072d44f31SMarcel Moolenaar 	if (tp != '\0')
25172d44f31SMarcel Moolenaar 		gdb_tx_char(tp);
25272d44f31SMarcel Moolenaar }
25372d44f31SMarcel Moolenaar 
254dda17b36SConrad Meyer /*
255dda17b36SConrad Meyer  * Take raw packet buffer and perform typical GDB packet framing, but not run-
256dda17b36SConrad Meyer  * length encoding, before forwarding to driver ::gdb_sendpacket() routine.
257dda17b36SConrad Meyer  */
258dda17b36SConrad Meyer static void
259dda17b36SConrad Meyer gdb_tx_sendpacket(void)
260dda17b36SConrad Meyer {
261dda17b36SConrad Meyer 	size_t msglen, i;
262dda17b36SConrad Meyer 	unsigned char csum;
263dda17b36SConrad Meyer 
264dda17b36SConrad Meyer 	msglen = gdb_txp - gdb_txbuf;
265dda17b36SConrad Meyer 
266dda17b36SConrad Meyer 	/* Add GDB packet framing */
267dda17b36SConrad Meyer 	gdb_tx_fullbuf[0] = '$';
268dda17b36SConrad Meyer 
269dda17b36SConrad Meyer 	csum = 0;
270dda17b36SConrad Meyer 	for (i = 0; i < msglen; i++)
271dda17b36SConrad Meyer 		csum += (unsigned char)gdb_txbuf[i];
272dda17b36SConrad Meyer 	snprintf(&gdb_tx_fullbuf[1 + msglen], 4, "#%02x", (unsigned)csum);
273dda17b36SConrad Meyer 
274dda17b36SConrad Meyer 	gdb_cur->gdb_sendpacket(gdb_tx_fullbuf, msglen + 4);
275dda17b36SConrad Meyer }
276dda17b36SConrad Meyer 
27772d44f31SMarcel Moolenaar int
27872d44f31SMarcel Moolenaar gdb_tx_end(void)
27972d44f31SMarcel Moolenaar {
28072d44f31SMarcel Moolenaar 	const char *p;
28172d44f31SMarcel Moolenaar 	int runlen;
28272d44f31SMarcel Moolenaar 	unsigned char c, cksum;
28372d44f31SMarcel Moolenaar 
28472d44f31SMarcel Moolenaar 	do {
285dda17b36SConrad Meyer 		if (gdb_cur->gdb_sendpacket != NULL) {
286dda17b36SConrad Meyer 			gdb_tx_sendpacket();
287dda17b36SConrad Meyer 			goto getack;
288dda17b36SConrad Meyer 		}
289dda17b36SConrad Meyer 
29072d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc('$');
29172d44f31SMarcel Moolenaar 
29272d44f31SMarcel Moolenaar 		cksum = 0;
29372d44f31SMarcel Moolenaar 		p = gdb_txbuf;
29472d44f31SMarcel Moolenaar 		while (p < gdb_txp) {
29572d44f31SMarcel Moolenaar 			/* Send a character and start run-length encoding. */
29672d44f31SMarcel Moolenaar 			c = *p++;
29772d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc(c);
29872d44f31SMarcel Moolenaar 			cksum += c;
29972d44f31SMarcel Moolenaar 			runlen = 0;
30072d44f31SMarcel Moolenaar 			/* Determine run-length and update checksum. */
30172d44f31SMarcel Moolenaar 			while (p < gdb_txp && *p == c) {
30272d44f31SMarcel Moolenaar 				runlen++;
30372d44f31SMarcel Moolenaar 				p++;
30472d44f31SMarcel Moolenaar 			}
30572d44f31SMarcel Moolenaar 			/* Emit the run-length encoded string. */
30672d44f31SMarcel Moolenaar 			while (runlen >= 97) {
30772d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc('*');
30872d44f31SMarcel Moolenaar 				cksum += '*';
30972d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc(97+29);
31072d44f31SMarcel Moolenaar 				cksum += 97+29;
31172d44f31SMarcel Moolenaar 				runlen -= 97;
31272d44f31SMarcel Moolenaar 				if (runlen > 0) {
31372d44f31SMarcel Moolenaar 					gdb_cur->gdb_putc(c);
31472d44f31SMarcel Moolenaar 					cksum += c;
31572d44f31SMarcel Moolenaar 					runlen--;
31672d44f31SMarcel Moolenaar 				}
31772d44f31SMarcel Moolenaar 			}
318*028a372fSMichał Górny 			/* Don't emit '$', '#', '+', '-' or a run length below 3. */
319*028a372fSMichał Górny 			while (runlen == 1 || runlen == 2 ||
320*028a372fSMichał Górny 			    runlen + 29 == '$' || runlen + 29 == '#' ||
321*028a372fSMichał Górny 			    runlen + 29 == '+' || runlen + 29 == '-') {
32272d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc(c);
32372d44f31SMarcel Moolenaar 				cksum += c;
32472d44f31SMarcel Moolenaar 				runlen--;
32572d44f31SMarcel Moolenaar 			}
32672d44f31SMarcel Moolenaar 			if (runlen == 0)
32772d44f31SMarcel Moolenaar 				continue;
32872d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc('*');
32972d44f31SMarcel Moolenaar 			cksum += '*';
33072d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc(runlen+29);
33172d44f31SMarcel Moolenaar 			cksum += runlen+29;
33272d44f31SMarcel Moolenaar 		}
33372d44f31SMarcel Moolenaar 
33472d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc('#');
33572d44f31SMarcel Moolenaar 		c = cksum >> 4;
33672d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc(N2C(c));
33772d44f31SMarcel Moolenaar 		c = cksum & 0x0f;
33872d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc(N2C(c));
33972d44f31SMarcel Moolenaar 
340dda17b36SConrad Meyer getack:
3416310546dSConrad Meyer 		/*
3426310546dSConrad Meyer 		 * In NoAckMode, it is assumed that the underlying transport is
3436310546dSConrad Meyer 		 * reliable and thus neither conservant sends acknowledgements;
3446310546dSConrad Meyer 		 * there is nothing to wait for here.
3456310546dSConrad Meyer 		 */
3466310546dSConrad Meyer 		if (!gdb_ackmode)
3476310546dSConrad Meyer 			break;
3486310546dSConrad Meyer 
349f346afc4SPoul-Henning Kamp 		c = gdb_getc();
35072d44f31SMarcel Moolenaar 	} while (c != '+');
35172d44f31SMarcel Moolenaar 
35272d44f31SMarcel Moolenaar 	return (0);
35372d44f31SMarcel Moolenaar }
35472d44f31SMarcel Moolenaar 
35572d44f31SMarcel Moolenaar int
35672d44f31SMarcel Moolenaar gdb_tx_mem(const unsigned char *addr, size_t size)
35772d44f31SMarcel Moolenaar {
35872d44f31SMarcel Moolenaar 	void *prev;
35972d44f31SMarcel Moolenaar 	jmp_buf jb;
36072d44f31SMarcel Moolenaar 	int ret;
36172d44f31SMarcel Moolenaar 
36272d44f31SMarcel Moolenaar 	prev = kdb_jmpbuf(jb);
36372d44f31SMarcel Moolenaar 	ret = setjmp(jb);
36472d44f31SMarcel Moolenaar 	if (ret == 0) {
36572d44f31SMarcel Moolenaar 		while (size-- > 0) {
36672d44f31SMarcel Moolenaar 			*gdb_txp++ = N2C(*addr >> 4);
36772d44f31SMarcel Moolenaar 			*gdb_txp++ = N2C(*addr & 0x0f);
36872d44f31SMarcel Moolenaar 			addr++;
36972d44f31SMarcel Moolenaar 		}
37072d44f31SMarcel Moolenaar 	}
37172d44f31SMarcel Moolenaar 	(void)kdb_jmpbuf(prev);
37272d44f31SMarcel Moolenaar 	return ((ret == 0) ? 1 : 0);
37372d44f31SMarcel Moolenaar }
37472d44f31SMarcel Moolenaar 
37572d44f31SMarcel Moolenaar void
37672d44f31SMarcel Moolenaar gdb_tx_reg(int regnum)
37772d44f31SMarcel Moolenaar {
37872d44f31SMarcel Moolenaar 	unsigned char *regp;
37972d44f31SMarcel Moolenaar 	size_t regsz;
38072d44f31SMarcel Moolenaar 
38172d44f31SMarcel Moolenaar 	regp = gdb_cpu_getreg(regnum, &regsz);
38272d44f31SMarcel Moolenaar 	if (regp == NULL) {
38372d44f31SMarcel Moolenaar 		/* Register unavailable. */
38472d44f31SMarcel Moolenaar 		while (regsz--) {
38572d44f31SMarcel Moolenaar 			gdb_tx_char('x');
38672d44f31SMarcel Moolenaar 			gdb_tx_char('x');
38772d44f31SMarcel Moolenaar 		}
38872d44f31SMarcel Moolenaar 	} else
38972d44f31SMarcel Moolenaar 		gdb_tx_mem(regp, regsz);
39072d44f31SMarcel Moolenaar }
39127ecc2adSBenno Rice 
392130ef1adSConrad Meyer bool
393130ef1adSConrad Meyer gdb_txbuf_has_capacity(size_t req)
394130ef1adSConrad Meyer {
395130ef1adSConrad Meyer 	return (((char *)gdb_txbuf + sizeof(gdb_txbuf) - gdb_txp) >= req);
396130ef1adSConrad Meyer }
397130ef1adSConrad Meyer 
39827ecc2adSBenno Rice /* Read binary data up until the end of the packet or until we have datalen decoded bytes */
39927ecc2adSBenno Rice int
40027ecc2adSBenno Rice gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt)
40127ecc2adSBenno Rice {
40227ecc2adSBenno Rice 	int c;
40327ecc2adSBenno Rice 
40427ecc2adSBenno Rice 	*amt = 0;
40527ecc2adSBenno Rice 
40627ecc2adSBenno Rice 	while (*amt < datalen) {
40727ecc2adSBenno Rice 		c = gdb_rx_char();
4085df6fa43SConrad Meyer 		if (c == EOF)
40927ecc2adSBenno Rice 			break;
41027ecc2adSBenno Rice 		/* Escaped character up next */
41127ecc2adSBenno Rice 		if (c == '}') {
4125df6fa43SConrad Meyer 			/* Malformed packet. */
4135df6fa43SConrad Meyer 			if ((c = gdb_rx_char()) == EOF)
41427ecc2adSBenno Rice 				return (1);
41527ecc2adSBenno Rice 			c ^= 0x20;
41627ecc2adSBenno Rice 		}
41727ecc2adSBenno Rice 		*(data++) = c & 0xff;
41827ecc2adSBenno Rice 		(*amt)++;
41927ecc2adSBenno Rice 	}
42027ecc2adSBenno Rice 
42127ecc2adSBenno Rice 	return (0);
42227ecc2adSBenno Rice }
42327ecc2adSBenno Rice 
42427ecc2adSBenno Rice int
42527ecc2adSBenno Rice gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found)
42627ecc2adSBenno Rice {
42727ecc2adSBenno Rice 	void *prev;
42827ecc2adSBenno Rice 	jmp_buf jb;
42927ecc2adSBenno Rice 	int ret;
43027ecc2adSBenno Rice 
43127ecc2adSBenno Rice 	prev = kdb_jmpbuf(jb);
43227ecc2adSBenno Rice 	ret = setjmp(jb);
43327ecc2adSBenno Rice 	if (ret == 0)
43427ecc2adSBenno Rice 		*found = memmem(addr, size, pat, patlen);
43527ecc2adSBenno Rice 
43627ecc2adSBenno Rice 	(void)kdb_jmpbuf(prev);
43727ecc2adSBenno Rice 	return ((ret == 0) ? 1 : 0);
43827ecc2adSBenno Rice }
439