1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004 Marcel Moolenaar
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/ctype.h>
32 #include <sys/kdb.h>
33 #include <sys/libkern.h>
34 #include <sys/ttydefaults.h>
35
36 #include <machine/gdb_machdep.h>
37 #include <machine/kdb.h>
38
39 #include <gdb/gdb.h>
40 #include <gdb/gdb_int.h>
41
42 static char gdb_rxbuf[GDB_BUFSZ];
43 char *gdb_rxp = NULL;
44 size_t gdb_rxsz = 0;
45
46 /*
47 * The goal here is to allow in-place framing without making the math around
48 * 'gdb_txbuf' more complicated. A generous reading of union special rule for
49 * "common initial sequence" suggests this may be valid in standard C99 and
50 * later.
51 */
52 static union {
53 struct _midbuf {
54 char mb_pad1;
55 char mb_buf[GDB_BUFSZ];
56 char mb_pad2[4];
57 } __packed txu_midbuf;
58 /* sizeof includes trailing nul byte and this is intentional. */
59 char txu_fullbuf[GDB_BUFSZ + sizeof("$#..")];
60 } gdb_tx_u;
61 #define gdb_txbuf gdb_tx_u.txu_midbuf.mb_buf
62 #define gdb_tx_fullbuf gdb_tx_u.txu_fullbuf
63 _Static_assert(sizeof(gdb_tx_u.txu_midbuf) == sizeof(gdb_tx_u.txu_fullbuf) &&
64 offsetof(struct _midbuf, mb_buf) == 1,
65 "assertions necessary for correctness");
66 char *gdb_txp = NULL; /* Used in inline functions. */
67
68 #define C2N(c) (((c) < 'A') ? (c) - '0' : \
69 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a'))
70 #define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10)
71
72 /*
73 * Get a single character
74 */
75
76 static int
gdb_getc(void)77 gdb_getc(void)
78 {
79 int c;
80
81 do
82 c = gdb_cur->gdb_getc();
83 while (c == -1);
84
85 if (c == CTRL('C')) {
86 printf("Received ^C; trying to switch back to ddb.\n");
87
88 if (gdb_cur->gdb_dbfeatures & GDB_DBGP_FEAT_WANTTERM)
89 gdb_cur->gdb_term();
90
91 if (kdb_dbbe_select("ddb") != 0)
92 printf("The ddb backend could not be selected.\n");
93 else {
94 printf("using longjmp, hope it works!\n");
95 kdb_reenter();
96 }
97 }
98 return (c);
99 }
100
101 /*
102 * Functions to receive and extract from a packet.
103 */
104
105 int
gdb_rx_begin(void)106 gdb_rx_begin(void)
107 {
108 int c, cksum;
109
110 gdb_rxp = NULL;
111 do {
112 /*
113 * Wait for the start character, ignore all others.
114 * XXX needs a timeout.
115 */
116 while ((c = gdb_getc()) != '$')
117 ;
118
119 /* Read until a # or end of buffer is found. */
120 cksum = 0;
121 gdb_rxsz = 0;
122 while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) {
123 c = gdb_getc();
124 if (c == '#')
125 break;
126 gdb_rxbuf[gdb_rxsz++] = c;
127 cksum += c;
128 }
129 gdb_rxbuf[gdb_rxsz] = 0;
130 cksum &= 0xff;
131
132 /* Bail out on a buffer overflow. */
133 if (c != '#') {
134 gdb_nack();
135 return (ENOSPC);
136 }
137
138 /*
139 * In Not-AckMode, we can assume reliable transport and neither
140 * need to verify checksums nor send Ack/Nack.
141 */
142 if (!gdb_ackmode)
143 break;
144
145 c = gdb_getc();
146 cksum -= (C2N(c) << 4) & 0xf0;
147 c = gdb_getc();
148 cksum -= C2N(c) & 0x0f;
149 if (cksum == 0) {
150 gdb_ack();
151 } else {
152 gdb_nack();
153 printf("GDB: packet `%s' has invalid checksum\n",
154 gdb_rxbuf);
155 }
156 } while (cksum != 0);
157
158 gdb_rxp = gdb_rxbuf;
159 return (0);
160 }
161
162 int
gdb_rx_equal(const char * str)163 gdb_rx_equal(const char *str)
164 {
165 int len;
166
167 len = strlen(str);
168 if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0)
169 return (0);
170 gdb_rxp += len;
171 gdb_rxsz -= len;
172 return (1);
173 }
174
175 int
gdb_rx_mem(unsigned char * addr,size_t size)176 gdb_rx_mem(unsigned char *addr, size_t size)
177 {
178 unsigned char *p;
179 void *prev;
180 void *wctx;
181 jmp_buf jb;
182 size_t cnt;
183 int ret;
184 unsigned char c;
185
186 if (size * 2 != gdb_rxsz)
187 return (-1);
188
189 wctx = gdb_begin_write();
190 prev = kdb_jmpbuf(jb);
191 ret = setjmp(jb);
192 if (ret == 0) {
193 p = addr;
194 cnt = size;
195 while (cnt-- > 0) {
196 c = (C2N(gdb_rxp[0]) << 4) & 0xf0;
197 c |= C2N(gdb_rxp[1]) & 0x0f;
198 *p++ = c;
199 gdb_rxsz -= 2;
200 gdb_rxp += 2;
201 }
202 kdb_cpu_sync_icache(addr, size);
203 }
204 (void)kdb_jmpbuf(prev);
205 gdb_end_write(wctx);
206 return ((ret == 0) ? 1 : 0);
207 }
208
209 int
gdb_rx_varhex(uintmax_t * vp)210 gdb_rx_varhex(uintmax_t *vp)
211 {
212 uintmax_t v;
213 int c, neg;
214
215 c = gdb_rx_char();
216 neg = (c == '-') ? 1 : 0;
217 if (neg == 1)
218 c = gdb_rx_char();
219 if (!isxdigit(c)) {
220 gdb_rxp -= ((c == -1) ? 0 : 1) + neg;
221 gdb_rxsz += ((c == -1) ? 0 : 1) + neg;
222 return (-1);
223 }
224 v = 0;
225 do {
226 v <<= 4;
227 v += C2N(c);
228 c = gdb_rx_char();
229 } while (isxdigit(c));
230 if (c != EOF) {
231 gdb_rxp--;
232 gdb_rxsz++;
233 }
234 *vp = (neg) ? -v : v;
235 return (0);
236 }
237
238 /*
239 * Function to build and send a package.
240 */
241
242 void
gdb_tx_begin(char tp)243 gdb_tx_begin(char tp)
244 {
245
246 gdb_txp = gdb_txbuf;
247 if (tp != '\0')
248 gdb_tx_char(tp);
249 }
250
251 /*
252 * Take raw packet buffer and perform typical GDB packet framing, but not run-
253 * length encoding, before forwarding to driver ::gdb_sendpacket() routine.
254 */
255 static void
gdb_tx_sendpacket(void)256 gdb_tx_sendpacket(void)
257 {
258 size_t msglen, i;
259 unsigned char csum;
260
261 msglen = gdb_txp - gdb_txbuf;
262
263 /* Add GDB packet framing */
264 gdb_tx_fullbuf[0] = '$';
265
266 csum = 0;
267 for (i = 0; i < msglen; i++)
268 csum += (unsigned char)gdb_txbuf[i];
269 snprintf(&gdb_tx_fullbuf[1 + msglen], 4, "#%02x", (unsigned)csum);
270
271 gdb_cur->gdb_sendpacket(gdb_tx_fullbuf, msglen + 4);
272 }
273
274 int
gdb_tx_end(void)275 gdb_tx_end(void)
276 {
277 const char *p;
278 int runlen;
279 unsigned char c, cksum;
280
281 do {
282 if (gdb_cur->gdb_sendpacket != NULL) {
283 gdb_tx_sendpacket();
284 goto getack;
285 }
286
287 gdb_cur->gdb_putc('$');
288
289 cksum = 0;
290 p = gdb_txbuf;
291 while (p < gdb_txp) {
292 /* Send a character and start run-length encoding. */
293 c = *p++;
294 gdb_cur->gdb_putc(c);
295 cksum += c;
296 runlen = 0;
297 /* Determine run-length and update checksum. */
298 while (p < gdb_txp && *p == c) {
299 runlen++;
300 p++;
301 }
302 /* Emit the run-length encoded string. */
303 while (runlen >= 97) {
304 gdb_cur->gdb_putc('*');
305 cksum += '*';
306 gdb_cur->gdb_putc(97+29);
307 cksum += 97+29;
308 runlen -= 97;
309 if (runlen > 0) {
310 gdb_cur->gdb_putc(c);
311 cksum += c;
312 runlen--;
313 }
314 }
315 /* Don't emit '$', '#', '+', '-' or a run length below 3. */
316 while (runlen == 1 || runlen == 2 ||
317 runlen + 29 == '$' || runlen + 29 == '#' ||
318 runlen + 29 == '+' || runlen + 29 == '-') {
319 gdb_cur->gdb_putc(c);
320 cksum += c;
321 runlen--;
322 }
323 if (runlen == 0)
324 continue;
325 gdb_cur->gdb_putc('*');
326 cksum += '*';
327 gdb_cur->gdb_putc(runlen+29);
328 cksum += runlen+29;
329 }
330
331 gdb_cur->gdb_putc('#');
332 c = cksum >> 4;
333 gdb_cur->gdb_putc(N2C(c));
334 c = cksum & 0x0f;
335 gdb_cur->gdb_putc(N2C(c));
336
337 getack:
338 /*
339 * In NoAckMode, it is assumed that the underlying transport is
340 * reliable and thus neither conservant sends acknowledgements;
341 * there is nothing to wait for here.
342 */
343 if (!gdb_ackmode)
344 break;
345
346 c = gdb_getc();
347 } while (c != '+');
348
349 return (0);
350 }
351
352 int
gdb_tx_mem(const unsigned char * addr,size_t size)353 gdb_tx_mem(const unsigned char *addr, size_t size)
354 {
355 void *prev;
356 jmp_buf jb;
357 int ret;
358
359 prev = kdb_jmpbuf(jb);
360 ret = setjmp(jb);
361 if (ret == 0) {
362 while (size-- > 0) {
363 *gdb_txp++ = N2C(*addr >> 4);
364 *gdb_txp++ = N2C(*addr & 0x0f);
365 addr++;
366 }
367 }
368 (void)kdb_jmpbuf(prev);
369 return ((ret == 0) ? 1 : 0);
370 }
371
372 void
gdb_tx_reg(int regnum)373 gdb_tx_reg(int regnum)
374 {
375 unsigned char *regp;
376 size_t regsz;
377
378 regp = gdb_cpu_getreg(regnum, ®sz);
379 if (regp == NULL) {
380 /* Register unavailable. */
381 while (regsz--) {
382 gdb_tx_char('x');
383 gdb_tx_char('x');
384 }
385 } else
386 gdb_tx_mem(regp, regsz);
387 }
388
389 bool
gdb_txbuf_has_capacity(size_t req)390 gdb_txbuf_has_capacity(size_t req)
391 {
392 return (((char *)gdb_txbuf + sizeof(gdb_txbuf) - gdb_txp) >= req);
393 }
394
395 /* Read binary data up until the end of the packet or until we have datalen decoded bytes */
396 int
gdb_rx_bindata(unsigned char * data,size_t datalen,size_t * amt)397 gdb_rx_bindata(unsigned char *data, size_t datalen, size_t *amt)
398 {
399 int c;
400
401 *amt = 0;
402
403 while (*amt < datalen) {
404 c = gdb_rx_char();
405 if (c == EOF)
406 break;
407 /* Escaped character up next */
408 if (c == '}') {
409 /* Malformed packet. */
410 if ((c = gdb_rx_char()) == EOF)
411 return (1);
412 c ^= 0x20;
413 }
414 *(data++) = c & 0xff;
415 (*amt)++;
416 }
417
418 return (0);
419 }
420
421 int
gdb_search_mem(const unsigned char * addr,size_t size,const unsigned char * pat,size_t patlen,const unsigned char ** found)422 gdb_search_mem(const unsigned char *addr, size_t size, const unsigned char *pat, size_t patlen, const unsigned char **found)
423 {
424 void *prev;
425 jmp_buf jb;
426 int ret;
427
428 prev = kdb_jmpbuf(jb);
429 ret = setjmp(jb);
430 if (ret == 0)
431 *found = memmem(addr, size, pat, patlen);
432
433 (void)kdb_jmpbuf(prev);
434 return ((ret == 0) ? 1 : 0);
435 }
436