xref: /freebsd/sys/gdb/gdb_packet.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1fa521b03SWarner Losh /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
3072d44f31SMarcel Moolenaar #include <sys/systm.h>
3172d44f31SMarcel Moolenaar #include <sys/ctype.h>
3272d44f31SMarcel Moolenaar #include <sys/kdb.h>
3327ecc2adSBenno Rice #include <sys/libkern.h>
343a5d3671SMatthew D Fleming #include <sys/ttydefaults.h>
3572d44f31SMarcel Moolenaar 
3672d44f31SMarcel Moolenaar #include <machine/gdb_machdep.h>
3701bd17ccSMarcel Moolenaar #include <machine/kdb.h>
3872d44f31SMarcel Moolenaar 
3972d44f31SMarcel Moolenaar #include <gdb/gdb.h>
4072d44f31SMarcel Moolenaar #include <gdb/gdb_int.h>
4172d44f31SMarcel Moolenaar 
4272d44f31SMarcel Moolenaar static char gdb_rxbuf[GDB_BUFSZ];
4372d44f31SMarcel Moolenaar char *gdb_rxp = NULL;
4472d44f31SMarcel Moolenaar size_t gdb_rxsz = 0;
45dda17b36SConrad Meyer 
46dda17b36SConrad Meyer /*
47dda17b36SConrad Meyer  * The goal here is to allow in-place framing without making the math around
48dda17b36SConrad Meyer  * 'gdb_txbuf' more complicated.  A generous reading of union special rule for
49dda17b36SConrad Meyer  * "common initial sequence" suggests this may be valid in standard C99 and
50dda17b36SConrad Meyer  * later.
51dda17b36SConrad Meyer  */
52dda17b36SConrad Meyer static union {
53dda17b36SConrad Meyer 	struct _midbuf {
54dda17b36SConrad Meyer 		char mb_pad1;
55dda17b36SConrad Meyer 		char mb_buf[GDB_BUFSZ];
56dda17b36SConrad Meyer 		char mb_pad2[4];
57dda17b36SConrad Meyer 	} __packed txu_midbuf;
58dda17b36SConrad Meyer 	/* sizeof includes trailing nul byte and this is intentional. */
59dda17b36SConrad Meyer 	char txu_fullbuf[GDB_BUFSZ + sizeof("$#..")];
60dda17b36SConrad Meyer } gdb_tx_u;
61dda17b36SConrad Meyer #define	gdb_txbuf	gdb_tx_u.txu_midbuf.mb_buf
62dda17b36SConrad Meyer #define	gdb_tx_fullbuf	gdb_tx_u.txu_fullbuf
63dda17b36SConrad Meyer _Static_assert(sizeof(gdb_tx_u.txu_midbuf) == sizeof(gdb_tx_u.txu_fullbuf) &&
64dda17b36SConrad Meyer     offsetof(struct _midbuf, mb_buf) == 1,
65dda17b36SConrad Meyer     "assertions necessary for correctness");
6672d44f31SMarcel Moolenaar char *gdb_txp = NULL;			/* Used in inline functions. */
6772d44f31SMarcel Moolenaar 
6872d44f31SMarcel Moolenaar #define	C2N(c)	(((c) < 'A') ? (c) - '0' : \
6972d44f31SMarcel Moolenaar 	    10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a'))
7072d44f31SMarcel Moolenaar #define	N2C(n)	(((n) < 10) ? (n) + '0' : (n) + 'a' - 10)
7172d44f31SMarcel Moolenaar 
7272d44f31SMarcel Moolenaar /*
73f346afc4SPoul-Henning Kamp  * Get a single character
74f346afc4SPoul-Henning Kamp  */
75f346afc4SPoul-Henning Kamp 
76f346afc4SPoul-Henning Kamp static int
gdb_getc(void)77f346afc4SPoul-Henning Kamp gdb_getc(void)
78f346afc4SPoul-Henning Kamp {
79f346afc4SPoul-Henning Kamp 	int c;
80f346afc4SPoul-Henning Kamp 
81f346afc4SPoul-Henning Kamp 	do
82f346afc4SPoul-Henning Kamp 		c = gdb_cur->gdb_getc();
83f346afc4SPoul-Henning Kamp 	while (c == -1);
843a5d3671SMatthew D Fleming 
853a5d3671SMatthew D Fleming 	if (c == CTRL('C')) {
863a5d3671SMatthew D Fleming 		printf("Received ^C; trying to switch back to ddb.\n");
873a5d3671SMatthew D Fleming 
88dda17b36SConrad Meyer 		if (gdb_cur->gdb_dbfeatures & GDB_DBGP_FEAT_WANTTERM)
89dda17b36SConrad Meyer 			gdb_cur->gdb_term();
90dda17b36SConrad Meyer 
913a5d3671SMatthew D Fleming 		if (kdb_dbbe_select("ddb") != 0)
923a5d3671SMatthew D Fleming 			printf("The ddb backend could not be selected.\n");
933a5d3671SMatthew D Fleming 		else {
943a5d3671SMatthew D Fleming 			printf("using longjmp, hope it works!\n");
953a5d3671SMatthew D Fleming 			kdb_reenter();
963a5d3671SMatthew D Fleming 		}
973a5d3671SMatthew D Fleming 	}
98f346afc4SPoul-Henning Kamp 	return (c);
99f346afc4SPoul-Henning Kamp }
100f346afc4SPoul-Henning Kamp 
101f346afc4SPoul-Henning Kamp /*
10272d44f31SMarcel Moolenaar  * Functions to receive and extract from a packet.
10372d44f31SMarcel Moolenaar  */
10472d44f31SMarcel Moolenaar 
10572d44f31SMarcel Moolenaar int
gdb_rx_begin(void)10672d44f31SMarcel Moolenaar gdb_rx_begin(void)
10772d44f31SMarcel Moolenaar {
10872d44f31SMarcel Moolenaar 	int c, cksum;
10972d44f31SMarcel Moolenaar 
11072d44f31SMarcel Moolenaar 	gdb_rxp = NULL;
11172d44f31SMarcel Moolenaar 	do {
11272d44f31SMarcel Moolenaar 		/*
11372d44f31SMarcel Moolenaar 		 * Wait for the start character, ignore all others.
11472d44f31SMarcel Moolenaar 		 * XXX needs a timeout.
11572d44f31SMarcel Moolenaar 		 */
116f346afc4SPoul-Henning Kamp 		while ((c = gdb_getc()) != '$')
11772d44f31SMarcel Moolenaar 			;
11872d44f31SMarcel Moolenaar 
11972d44f31SMarcel Moolenaar 		/* Read until a # or end of buffer is found. */
12072d44f31SMarcel Moolenaar 		cksum = 0;
12172d44f31SMarcel Moolenaar 		gdb_rxsz = 0;
12272d44f31SMarcel Moolenaar 		while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) {
123f346afc4SPoul-Henning Kamp 			c = gdb_getc();
12472d44f31SMarcel Moolenaar 			if (c == '#')
12572d44f31SMarcel Moolenaar 				break;
12672d44f31SMarcel Moolenaar 			gdb_rxbuf[gdb_rxsz++] = c;
12772d44f31SMarcel Moolenaar 			cksum += c;
12872d44f31SMarcel Moolenaar 		}
12972d44f31SMarcel Moolenaar 		gdb_rxbuf[gdb_rxsz] = 0;
13072d44f31SMarcel Moolenaar 		cksum &= 0xff;
13172d44f31SMarcel Moolenaar 
13272d44f31SMarcel Moolenaar 		/* Bail out on a buffer overflow. */
13372d44f31SMarcel Moolenaar 		if (c != '#') {
1346310546dSConrad Meyer 			gdb_nack();
13572d44f31SMarcel Moolenaar 			return (ENOSPC);
13672d44f31SMarcel Moolenaar 		}
13772d44f31SMarcel Moolenaar 
1386310546dSConrad Meyer 		/*
1396310546dSConrad Meyer 		 * In Not-AckMode, we can assume reliable transport and neither
1406310546dSConrad Meyer 		 * need to verify checksums nor send Ack/Nack.
1416310546dSConrad Meyer 		 */
1426310546dSConrad Meyer 		if (!gdb_ackmode)
1436310546dSConrad Meyer 			break;
1446310546dSConrad Meyer 
145f346afc4SPoul-Henning Kamp 		c = gdb_getc();
14672d44f31SMarcel Moolenaar 		cksum -= (C2N(c) << 4) & 0xf0;
147f346afc4SPoul-Henning Kamp 		c = gdb_getc();
14872d44f31SMarcel Moolenaar 		cksum -= C2N(c) & 0x0f;
1496310546dSConrad Meyer 		if (cksum == 0) {
1506310546dSConrad Meyer 			gdb_ack();
1516310546dSConrad Meyer 		} else {
1526310546dSConrad Meyer 			gdb_nack();
15372d44f31SMarcel Moolenaar 			printf("GDB: packet `%s' has invalid checksum\n",
15472d44f31SMarcel Moolenaar 			    gdb_rxbuf);
1556310546dSConrad Meyer 		}
15672d44f31SMarcel Moolenaar 	} while (cksum != 0);
15772d44f31SMarcel Moolenaar 
15872d44f31SMarcel Moolenaar 	gdb_rxp = gdb_rxbuf;
15972d44f31SMarcel Moolenaar 	return (0);
16072d44f31SMarcel Moolenaar }
16172d44f31SMarcel Moolenaar 
16272d44f31SMarcel Moolenaar int
gdb_rx_equal(const char * str)16372d44f31SMarcel Moolenaar gdb_rx_equal(const char *str)
16472d44f31SMarcel Moolenaar {
16572d44f31SMarcel Moolenaar 	int len;
16672d44f31SMarcel Moolenaar 
16772d44f31SMarcel Moolenaar 	len = strlen(str);
16872d44f31SMarcel Moolenaar 	if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0)
16972d44f31SMarcel Moolenaar 		return (0);
17072d44f31SMarcel Moolenaar 	gdb_rxp += len;
17172d44f31SMarcel Moolenaar 	gdb_rxsz -= len;
17272d44f31SMarcel Moolenaar 	return (1);
17372d44f31SMarcel Moolenaar }
17472d44f31SMarcel Moolenaar 
17572d44f31SMarcel Moolenaar int
gdb_rx_mem(unsigned char * addr,size_t size)17672d44f31SMarcel Moolenaar gdb_rx_mem(unsigned char *addr, size_t size)
17772d44f31SMarcel Moolenaar {
17801bd17ccSMarcel Moolenaar 	unsigned char *p;
17972d44f31SMarcel Moolenaar 	void *prev;
180beb24065SJonathan T. Looney 	void *wctx;
18172d44f31SMarcel Moolenaar 	jmp_buf jb;
18201bd17ccSMarcel Moolenaar 	size_t cnt;
18372d44f31SMarcel Moolenaar 	int ret;
18472d44f31SMarcel Moolenaar 	unsigned char c;
18572d44f31SMarcel Moolenaar 
18672d44f31SMarcel Moolenaar 	if (size * 2 != gdb_rxsz)
18772d44f31SMarcel Moolenaar 		return (-1);
18872d44f31SMarcel Moolenaar 
189beb24065SJonathan T. Looney 	wctx = gdb_begin_write();
19072d44f31SMarcel Moolenaar 	prev = kdb_jmpbuf(jb);
19172d44f31SMarcel Moolenaar 	ret = setjmp(jb);
19272d44f31SMarcel Moolenaar 	if (ret == 0) {
19301bd17ccSMarcel Moolenaar 		p = addr;
19401bd17ccSMarcel Moolenaar 		cnt = size;
19501bd17ccSMarcel Moolenaar 		while (cnt-- > 0) {
19672d44f31SMarcel Moolenaar 			c = (C2N(gdb_rxp[0]) << 4) & 0xf0;
19772d44f31SMarcel Moolenaar 			c |= C2N(gdb_rxp[1]) & 0x0f;
19801bd17ccSMarcel Moolenaar 			*p++ = c;
19972d44f31SMarcel Moolenaar 			gdb_rxsz -= 2;
20072d44f31SMarcel Moolenaar 			gdb_rxp += 2;
20172d44f31SMarcel Moolenaar 		}
20201bd17ccSMarcel Moolenaar 		kdb_cpu_sync_icache(addr, size);
20372d44f31SMarcel Moolenaar 	}
20472d44f31SMarcel Moolenaar 	(void)kdb_jmpbuf(prev);
205beb24065SJonathan T. Looney 	gdb_end_write(wctx);
20672d44f31SMarcel Moolenaar 	return ((ret == 0) ? 1 : 0);
20772d44f31SMarcel Moolenaar }
20872d44f31SMarcel Moolenaar 
20972d44f31SMarcel Moolenaar int
gdb_rx_varhex(uintmax_t * vp)21072d44f31SMarcel Moolenaar gdb_rx_varhex(uintmax_t *vp)
21172d44f31SMarcel Moolenaar {
21272d44f31SMarcel Moolenaar 	uintmax_t v;
21372d44f31SMarcel Moolenaar 	int c, neg;
21472d44f31SMarcel Moolenaar 
21572d44f31SMarcel Moolenaar 	c = gdb_rx_char();
21672d44f31SMarcel Moolenaar 	neg = (c == '-') ? 1 : 0;
21772d44f31SMarcel Moolenaar 	if (neg == 1)
21872d44f31SMarcel Moolenaar 		c = gdb_rx_char();
21972d44f31SMarcel Moolenaar 	if (!isxdigit(c)) {
22072d44f31SMarcel Moolenaar 		gdb_rxp -= ((c == -1) ? 0 : 1) + neg;
22172d44f31SMarcel Moolenaar 		gdb_rxsz += ((c == -1) ? 0 : 1) + neg;
22272d44f31SMarcel Moolenaar 		return (-1);
22372d44f31SMarcel Moolenaar 	}
22472d44f31SMarcel Moolenaar 	v = 0;
22572d44f31SMarcel Moolenaar 	do {
22672d44f31SMarcel Moolenaar 		v <<= 4;
22772d44f31SMarcel Moolenaar 		v += C2N(c);
22872d44f31SMarcel Moolenaar 		c = gdb_rx_char();
22972d44f31SMarcel Moolenaar 	} while (isxdigit(c));
2305df6fa43SConrad Meyer 	if (c != EOF) {
23172d44f31SMarcel Moolenaar 		gdb_rxp--;
23272d44f31SMarcel Moolenaar 		gdb_rxsz++;
23372d44f31SMarcel Moolenaar 	}
23472d44f31SMarcel Moolenaar 	*vp = (neg) ? -v : v;
23572d44f31SMarcel Moolenaar 	return (0);
23672d44f31SMarcel Moolenaar }
23772d44f31SMarcel Moolenaar 
23872d44f31SMarcel Moolenaar /*
23972d44f31SMarcel Moolenaar  * Function to build and send a package.
24072d44f31SMarcel Moolenaar  */
24172d44f31SMarcel Moolenaar 
24272d44f31SMarcel Moolenaar void
gdb_tx_begin(char tp)24372d44f31SMarcel Moolenaar gdb_tx_begin(char tp)
24472d44f31SMarcel Moolenaar {
24572d44f31SMarcel Moolenaar 
24672d44f31SMarcel Moolenaar 	gdb_txp = gdb_txbuf;
24772d44f31SMarcel Moolenaar 	if (tp != '\0')
24872d44f31SMarcel Moolenaar 		gdb_tx_char(tp);
24972d44f31SMarcel Moolenaar }
25072d44f31SMarcel Moolenaar 
251dda17b36SConrad Meyer /*
252dda17b36SConrad Meyer  * Take raw packet buffer and perform typical GDB packet framing, but not run-
253dda17b36SConrad Meyer  * length encoding, before forwarding to driver ::gdb_sendpacket() routine.
254dda17b36SConrad Meyer  */
255dda17b36SConrad Meyer static void
gdb_tx_sendpacket(void)256dda17b36SConrad Meyer gdb_tx_sendpacket(void)
257dda17b36SConrad Meyer {
258dda17b36SConrad Meyer 	size_t msglen, i;
259dda17b36SConrad Meyer 	unsigned char csum;
260dda17b36SConrad Meyer 
261dda17b36SConrad Meyer 	msglen = gdb_txp - gdb_txbuf;
262dda17b36SConrad Meyer 
263dda17b36SConrad Meyer 	/* Add GDB packet framing */
264dda17b36SConrad Meyer 	gdb_tx_fullbuf[0] = '$';
265dda17b36SConrad Meyer 
266dda17b36SConrad Meyer 	csum = 0;
267dda17b36SConrad Meyer 	for (i = 0; i < msglen; i++)
268dda17b36SConrad Meyer 		csum += (unsigned char)gdb_txbuf[i];
269dda17b36SConrad Meyer 	snprintf(&gdb_tx_fullbuf[1 + msglen], 4, "#%02x", (unsigned)csum);
270dda17b36SConrad Meyer 
271dda17b36SConrad Meyer 	gdb_cur->gdb_sendpacket(gdb_tx_fullbuf, msglen + 4);
272dda17b36SConrad Meyer }
273dda17b36SConrad Meyer 
27472d44f31SMarcel Moolenaar int
gdb_tx_end(void)27572d44f31SMarcel Moolenaar gdb_tx_end(void)
27672d44f31SMarcel Moolenaar {
27772d44f31SMarcel Moolenaar 	const char *p;
27872d44f31SMarcel Moolenaar 	int runlen;
27972d44f31SMarcel Moolenaar 	unsigned char c, cksum;
28072d44f31SMarcel Moolenaar 
28172d44f31SMarcel Moolenaar 	do {
282dda17b36SConrad Meyer 		if (gdb_cur->gdb_sendpacket != NULL) {
283dda17b36SConrad Meyer 			gdb_tx_sendpacket();
284dda17b36SConrad Meyer 			goto getack;
285dda17b36SConrad Meyer 		}
286dda17b36SConrad Meyer 
28772d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc('$');
28872d44f31SMarcel Moolenaar 
28972d44f31SMarcel Moolenaar 		cksum = 0;
29072d44f31SMarcel Moolenaar 		p = gdb_txbuf;
29172d44f31SMarcel Moolenaar 		while (p < gdb_txp) {
29272d44f31SMarcel Moolenaar 			/* Send a character and start run-length encoding. */
29372d44f31SMarcel Moolenaar 			c = *p++;
29472d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc(c);
29572d44f31SMarcel Moolenaar 			cksum += c;
29672d44f31SMarcel Moolenaar 			runlen = 0;
29772d44f31SMarcel Moolenaar 			/* Determine run-length and update checksum. */
29872d44f31SMarcel Moolenaar 			while (p < gdb_txp && *p == c) {
29972d44f31SMarcel Moolenaar 				runlen++;
30072d44f31SMarcel Moolenaar 				p++;
30172d44f31SMarcel Moolenaar 			}
30272d44f31SMarcel Moolenaar 			/* Emit the run-length encoded string. */
30372d44f31SMarcel Moolenaar 			while (runlen >= 97) {
30472d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc('*');
30572d44f31SMarcel Moolenaar 				cksum += '*';
30672d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc(97+29);
30772d44f31SMarcel Moolenaar 				cksum += 97+29;
30872d44f31SMarcel Moolenaar 				runlen -= 97;
30972d44f31SMarcel Moolenaar 				if (runlen > 0) {
31072d44f31SMarcel Moolenaar 					gdb_cur->gdb_putc(c);
31172d44f31SMarcel Moolenaar 					cksum += c;
31272d44f31SMarcel Moolenaar 					runlen--;
31372d44f31SMarcel Moolenaar 				}
31472d44f31SMarcel Moolenaar 			}
315028a372fSMichał Górny 			/* Don't emit '$', '#', '+', '-' or a run length below 3. */
316028a372fSMichał Górny 			while (runlen == 1 || runlen == 2 ||
317028a372fSMichał Górny 			    runlen + 29 == '$' || runlen + 29 == '#' ||
318028a372fSMichał Górny 			    runlen + 29 == '+' || runlen + 29 == '-') {
31972d44f31SMarcel Moolenaar 				gdb_cur->gdb_putc(c);
32072d44f31SMarcel Moolenaar 				cksum += c;
32172d44f31SMarcel Moolenaar 				runlen--;
32272d44f31SMarcel Moolenaar 			}
32372d44f31SMarcel Moolenaar 			if (runlen == 0)
32472d44f31SMarcel Moolenaar 				continue;
32572d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc('*');
32672d44f31SMarcel Moolenaar 			cksum += '*';
32772d44f31SMarcel Moolenaar 			gdb_cur->gdb_putc(runlen+29);
32872d44f31SMarcel Moolenaar 			cksum += runlen+29;
32972d44f31SMarcel Moolenaar 		}
33072d44f31SMarcel Moolenaar 
33172d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc('#');
33272d44f31SMarcel Moolenaar 		c = cksum >> 4;
33372d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc(N2C(c));
33472d44f31SMarcel Moolenaar 		c = cksum & 0x0f;
33572d44f31SMarcel Moolenaar 		gdb_cur->gdb_putc(N2C(c));
33672d44f31SMarcel Moolenaar 
337dda17b36SConrad Meyer getack:
3386310546dSConrad Meyer 		/*
3396310546dSConrad Meyer 		 * In NoAckMode, it is assumed that the underlying transport is
3406310546dSConrad Meyer 		 * reliable and thus neither conservant sends acknowledgements;
3416310546dSConrad Meyer 		 * there is nothing to wait for here.
3426310546dSConrad Meyer 		 */
3436310546dSConrad Meyer 		if (!gdb_ackmode)
3446310546dSConrad Meyer 			break;
3456310546dSConrad Meyer 
346f346afc4SPoul-Henning Kamp 		c = gdb_getc();
34772d44f31SMarcel Moolenaar 	} while (c != '+');
34872d44f31SMarcel Moolenaar 
34972d44f31SMarcel Moolenaar 	return (0);
35072d44f31SMarcel Moolenaar }
35172d44f31SMarcel Moolenaar 
35272d44f31SMarcel Moolenaar int
gdb_tx_mem(const unsigned char * addr,size_t size)35372d44f31SMarcel Moolenaar gdb_tx_mem(const unsigned char *addr, size_t size)
35472d44f31SMarcel Moolenaar {
35572d44f31SMarcel Moolenaar 	void *prev;
35672d44f31SMarcel Moolenaar 	jmp_buf jb;
35772d44f31SMarcel Moolenaar 	int ret;
35872d44f31SMarcel Moolenaar 
35972d44f31SMarcel Moolenaar 	prev = kdb_jmpbuf(jb);
36072d44f31SMarcel Moolenaar 	ret = setjmp(jb);
36172d44f31SMarcel Moolenaar 	if (ret == 0) {
36272d44f31SMarcel Moolenaar 		while (size-- > 0) {
36372d44f31SMarcel Moolenaar 			*gdb_txp++ = N2C(*addr >> 4);
36472d44f31SMarcel Moolenaar 			*gdb_txp++ = N2C(*addr & 0x0f);
36572d44f31SMarcel Moolenaar 			addr++;
36672d44f31SMarcel Moolenaar 		}
36772d44f31SMarcel Moolenaar 	}
36872d44f31SMarcel Moolenaar 	(void)kdb_jmpbuf(prev);
36972d44f31SMarcel Moolenaar 	return ((ret == 0) ? 1 : 0);
37072d44f31SMarcel Moolenaar }
37172d44f31SMarcel Moolenaar 
37272d44f31SMarcel Moolenaar void
gdb_tx_reg(int regnum)37372d44f31SMarcel Moolenaar gdb_tx_reg(int regnum)
37472d44f31SMarcel Moolenaar {
37572d44f31SMarcel Moolenaar 	unsigned char *regp;
37672d44f31SMarcel Moolenaar 	size_t regsz;
37772d44f31SMarcel Moolenaar 
37872d44f31SMarcel Moolenaar 	regp = gdb_cpu_getreg(regnum, &regsz);
37972d44f31SMarcel Moolenaar 	if (regp == NULL) {
38072d44f31SMarcel Moolenaar 		/* Register unavailable. */
38172d44f31SMarcel Moolenaar 		while (regsz--) {
38272d44f31SMarcel Moolenaar 			gdb_tx_char('x');
38372d44f31SMarcel Moolenaar 			gdb_tx_char('x');
38472d44f31SMarcel Moolenaar 		}
38572d44f31SMarcel Moolenaar 	} else
38672d44f31SMarcel Moolenaar 		gdb_tx_mem(regp, regsz);
38772d44f31SMarcel Moolenaar }
38827ecc2adSBenno Rice 
389130ef1adSConrad Meyer bool
gdb_txbuf_has_capacity(size_t req)390130ef1adSConrad Meyer gdb_txbuf_has_capacity(size_t req)
391130ef1adSConrad Meyer {
392130ef1adSConrad Meyer 	return (((char *)gdb_txbuf + sizeof(gdb_txbuf) - gdb_txp) >= req);
393130ef1adSConrad Meyer }
394130ef1adSConrad Meyer 
39527ecc2adSBenno Rice /* Read binary data up until the end of the packet or until we have datalen decoded bytes */
39627ecc2adSBenno Rice int
gdb_rx_bindata(unsigned char * data,size_t datalen,size_t * amt)39727ecc2adSBenno Rice gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt)
39827ecc2adSBenno Rice {
39927ecc2adSBenno Rice 	int c;
40027ecc2adSBenno Rice 
40127ecc2adSBenno Rice 	*amt = 0;
40227ecc2adSBenno Rice 
40327ecc2adSBenno Rice 	while (*amt < datalen) {
40427ecc2adSBenno Rice 		c = gdb_rx_char();
4055df6fa43SConrad Meyer 		if (c == EOF)
40627ecc2adSBenno Rice 			break;
40727ecc2adSBenno Rice 		/* Escaped character up next */
40827ecc2adSBenno Rice 		if (c == '}') {
4095df6fa43SConrad Meyer 			/* Malformed packet. */
4105df6fa43SConrad Meyer 			if ((c = gdb_rx_char()) == EOF)
41127ecc2adSBenno Rice 				return (1);
41227ecc2adSBenno Rice 			c ^= 0x20;
41327ecc2adSBenno Rice 		}
41427ecc2adSBenno Rice 		*(data++) = c & 0xff;
41527ecc2adSBenno Rice 		(*amt)++;
41627ecc2adSBenno Rice 	}
41727ecc2adSBenno Rice 
41827ecc2adSBenno Rice 	return (0);
41927ecc2adSBenno Rice }
42027ecc2adSBenno Rice 
42127ecc2adSBenno Rice int
gdb_search_mem(const unsigned char * addr,size_t size,const unsigned char * pat,size_t patlen,const unsigned char ** found)42227ecc2adSBenno Rice gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found)
42327ecc2adSBenno Rice {
42427ecc2adSBenno Rice 	void *prev;
42527ecc2adSBenno Rice 	jmp_buf jb;
42627ecc2adSBenno Rice 	int ret;
42727ecc2adSBenno Rice 
42827ecc2adSBenno Rice 	prev = kdb_jmpbuf(jb);
42927ecc2adSBenno Rice 	ret = setjmp(jb);
43027ecc2adSBenno Rice 	if (ret == 0)
43127ecc2adSBenno Rice 		*found = memmem(addr, size, pat, patlen);
43227ecc2adSBenno Rice 
43327ecc2adSBenno Rice 	(void)kdb_jmpbuf(prev);
43427ecc2adSBenno Rice 	return ((ret == 0) ? 1 : 0);
43527ecc2adSBenno Rice }
436