summaryrefslogtreecommitdiffstats
path: root/sys/gdb/gdb_packet.c
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2004-07-10 17:47:22 +0000
committermarcel <marcel@FreeBSD.org>2004-07-10 17:47:22 +0000
commit6e0dcca8a9676834e327681abedbeca81a0907f2 (patch)
tree787a3c6916bdd82a49a07a8288119d62dd89055b /sys/gdb/gdb_packet.c
parent1ff719505763720315217ca8b7eb6d6f03c49222 (diff)
downloadFreeBSD-src-6e0dcca8a9676834e327681abedbeca81a0907f2.zip
FreeBSD-src-6e0dcca8a9676834e327681abedbeca81a0907f2.tar.gz
Introduce the GDB debugger backend for the new KDB framework. The
backend improves over the old GDB support in the following ways: o Unified implementation with minimal MD code. o A simple interface for devices to register themselves as debug ports, ala consoles. o Compression by using run-length encoding. o Implements GDB threading support.
Diffstat (limited to 'sys/gdb/gdb_packet.c')
-rw-r--r--sys/gdb/gdb_packet.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/sys/gdb/gdb_packet.c b/sys/gdb/gdb_packet.c
new file mode 100644
index 0000000..703d2e0
--- /dev/null
+++ b/sys/gdb/gdb_packet.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ctype.h>
+#include <sys/kdb.h>
+
+#include <machine/gdb_machdep.h>
+
+#include <gdb/gdb.h>
+#include <gdb/gdb_int.h>
+
+static char gdb_rxbuf[GDB_BUFSZ];
+char *gdb_rxp = NULL;
+size_t gdb_rxsz = 0;
+static char gdb_txbuf[GDB_BUFSZ];
+char *gdb_txp = NULL; /* Used in inline functions. */
+
+#define C2N(c) (((c) < 'A') ? (c) - '0' : \
+ 10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a'))
+#define N2C(n) (((n) < 10) ? (n) + '0' : (n) + 'a' - 10)
+
+/*
+ * Functions to receive and extract from a packet.
+ */
+
+int
+gdb_rx_begin(void)
+{
+ int c, cksum;
+
+ gdb_rxp = NULL;
+ do {
+ /*
+ * Wait for the start character, ignore all others.
+ * XXX needs a timeout.
+ */
+ while ((c = gdb_cur->gdb_getc()) != '$')
+ ;
+
+ /* Read until a # or end of buffer is found. */
+ cksum = 0;
+ gdb_rxsz = 0;
+ while (gdb_rxsz < sizeof(gdb_rxbuf) - 1) {
+ c = gdb_cur->gdb_getc();
+ if (c == '#')
+ break;
+ gdb_rxbuf[gdb_rxsz++] = c;
+ cksum += c;
+ }
+ gdb_rxbuf[gdb_rxsz] = 0;
+ cksum &= 0xff;
+
+ /* Bail out on a buffer overflow. */
+ if (c != '#') {
+ gdb_cur->gdb_putc('-');
+ return (ENOSPC);
+ }
+
+ c = gdb_cur->gdb_getc();
+ cksum -= (C2N(c) << 4) & 0xf0;
+ c = gdb_cur->gdb_getc();
+ cksum -= C2N(c) & 0x0f;
+ gdb_cur->gdb_putc((cksum == 0) ? '+' : '-');
+ if (cksum != 0)
+ printf("GDB: packet `%s' has invalid checksum\n",
+ gdb_rxbuf);
+ } while (cksum != 0);
+
+ gdb_rxp = gdb_rxbuf;
+ return (0);
+}
+
+int
+gdb_rx_equal(const char *str)
+{
+ int len;
+
+ len = strlen(str);
+ if (len > gdb_rxsz || strncmp(str, gdb_rxp, len) != 0)
+ return (0);
+ gdb_rxp += len;
+ gdb_rxsz -= len;
+ return (1);
+}
+
+int
+gdb_rx_mem(unsigned char *addr, size_t size)
+{
+ void *prev;
+ jmp_buf jb;
+ int ret;
+ unsigned char c;
+
+ if (size * 2 != gdb_rxsz)
+ return (-1);
+
+ prev = kdb_jmpbuf(jb);
+ ret = setjmp(jb);
+ if (ret == 0) {
+ while (size-- > 0) {
+ c = (C2N(gdb_rxp[0]) << 4) & 0xf0;
+ c |= C2N(gdb_rxp[1]) & 0x0f;
+ *addr++ = c;
+ gdb_rxsz -= 2;
+ gdb_rxp += 2;
+ }
+ }
+ (void)kdb_jmpbuf(prev);
+ return ((ret == 0) ? 1 : 0);
+}
+
+int
+gdb_rx_varhex(uintmax_t *vp)
+{
+ uintmax_t v;
+ int c, neg;
+
+ c = gdb_rx_char();
+ neg = (c == '-') ? 1 : 0;
+ if (neg == 1)
+ c = gdb_rx_char();
+ if (!isxdigit(c)) {
+ gdb_rxp -= ((c == -1) ? 0 : 1) + neg;
+ gdb_rxsz += ((c == -1) ? 0 : 1) + neg;
+ return (-1);
+ }
+ v = 0;
+ do {
+ v <<= 4;
+ v += C2N(c);
+ c = gdb_rx_char();
+ } while (isxdigit(c));
+ if (c != -1) {
+ gdb_rxp--;
+ gdb_rxsz++;
+ }
+ *vp = (neg) ? -v : v;
+ return (0);
+}
+
+/*
+ * Function to build and send a package.
+ */
+
+void
+gdb_tx_begin(char tp)
+{
+
+ gdb_txp = gdb_txbuf;
+ if (tp != '\0')
+ gdb_tx_char(tp);
+}
+
+int
+gdb_tx_end(void)
+{
+ const char *p;
+ int runlen;
+ unsigned char c, cksum;
+
+ do {
+ gdb_cur->gdb_putc('$');
+
+ cksum = 0;
+ p = gdb_txbuf;
+ while (p < gdb_txp) {
+ /* Send a character and start run-length encoding. */
+ c = *p++;
+ gdb_cur->gdb_putc(c);
+ cksum += c;
+ runlen = 0;
+ /* Determine run-length and update checksum. */
+ while (p < gdb_txp && *p == c) {
+ runlen++;
+ p++;
+ }
+ /* Emit the run-length encoded string. */
+ while (runlen >= 97) {
+ gdb_cur->gdb_putc('*');
+ cksum += '*';
+ gdb_cur->gdb_putc(97+29);
+ cksum += 97+29;
+ runlen -= 97;
+ if (runlen > 0) {
+ gdb_cur->gdb_putc(c);
+ cksum += c;
+ runlen--;
+ }
+ }
+ if (runlen == 1) {
+ gdb_cur->gdb_putc(c);
+ cksum += c;
+ runlen--;
+ }
+ if (runlen == 0)
+ continue;
+ /* Don't emit '$', '#', '+' or '-'. */
+ if (runlen == 7) {
+ gdb_cur->gdb_putc(c);
+ cksum += c;
+ runlen--;
+ }
+ if (runlen == 6 || runlen == 14 || runlen == 16) {
+ gdb_cur->gdb_putc(c);
+ cksum += c;
+ runlen--;
+ }
+ gdb_cur->gdb_putc('*');
+ cksum += '*';
+ gdb_cur->gdb_putc(runlen+29);
+ cksum += runlen+29;
+ }
+
+ gdb_cur->gdb_putc('#');
+ c = cksum >> 4;
+ gdb_cur->gdb_putc(N2C(c));
+ c = cksum & 0x0f;
+ gdb_cur->gdb_putc(N2C(c));
+
+ c = gdb_cur->gdb_getc();
+ } while (c != '+');
+
+ return (0);
+}
+
+int
+gdb_tx_mem(const unsigned char *addr, size_t size)
+{
+ void *prev;
+ jmp_buf jb;
+ int ret;
+
+ prev = kdb_jmpbuf(jb);
+ ret = setjmp(jb);
+ if (ret == 0) {
+ while (size-- > 0) {
+ *gdb_txp++ = N2C(*addr >> 4);
+ *gdb_txp++ = N2C(*addr & 0x0f);
+ addr++;
+ }
+ }
+ (void)kdb_jmpbuf(prev);
+ return ((ret == 0) ? 1 : 0);
+}
+
+void
+gdb_tx_reg(int regnum)
+{
+ unsigned char *regp;
+ size_t regsz;
+
+ regp = gdb_cpu_getreg(regnum, &regsz);
+ if (regp == NULL) {
+ /* Register unavailable. */
+ while (regsz--) {
+ gdb_tx_char('x');
+ gdb_tx_char('x');
+ }
+ } else
+ gdb_tx_mem(regp, regsz);
+}
OpenPOWER on IntegriCloud