commit e9c16becb9194b91b806518f90a0a37905117cdf
parent 7625ee543ba3e133ded6f049221161a390bcb260
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 21 Jun 2015 20:28:53 -0700
gdb-bridge: improve command and response processing
Diffstat:
M | tools/gdb-bridge.c | | | 307 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
1 file changed, 168 insertions(+), 139 deletions(-)
diff --git a/tools/gdb-bridge.c b/tools/gdb-bridge.c
@@ -34,6 +34,28 @@
// set debug arch 1 architecture tracing
// maint print registers-remote check on register map
+#define MAXPKT 8192
+
+#define S_IDLE 0
+#define S_RECV 1
+#define S_CHK1 2
+#define S_CHK2 3
+
+#define F_ACK 1
+#define F_TRACE 2
+
+struct gdbcnxn {
+ int fd;
+ unsigned state;
+ unsigned sum;
+ unsigned flags;
+ unsigned char *txptr;
+ unsigned char *rxptr;
+ unsigned char rxbuf[MAXPKT];
+ unsigned char txbuf[MAXPKT];
+ char chk[4];
+};
+
void zprintf(const char *fmt, ...) {
linenoisePause();
va_list ap;
@@ -43,134 +65,146 @@ void zprintf(const char *fmt, ...) {
linenoiseResume();
}
-struct gdbcnxn {
- int tx, rx;
- unsigned chk;
-};
+void gdb_init(struct gdbcnxn *gc, int fd) {
+ gc->fd = fd;
+ gc->state = S_IDLE;
+ gc->sum = 0;
+ gc->flags = F_ACK;
+ gc->txptr = gc->txbuf;
+ gc->rxptr = gc->rxbuf;
+ gc->chk[2] = 0;
+}
-int gdb_getc(struct gdbcnxn *gc) {
- int r;
- unsigned char c;
- for (;;) {
- r = read(gc->rx, &c, 1);
- if (r <= 0) {
- if (errno == EINTR)
- continue;
- return -1;
- }
- return c;
- }
+static inline int rx_full(struct gdbcnxn *gc) {
+ return (gc->rxptr - gc->rxbuf) == (MAXPKT - 1);
+}
+
+static inline int tx_full(struct gdbcnxn *gc) {
+ return (gc->txptr - gc->txbuf) == (MAXPKT - 1);
}
-int gdb_putc(struct gdbcnxn *gc, unsigned n) {
+static inline void gdb_putc(struct gdbcnxn *gc, unsigned n) {
unsigned char c = n;
- int r;
- gc->chk += c;
- for (;;) {
- r = write(gc->tx, &c, 1);
- if (r <= 0) {
- if (errno == EINTR)
- continue;
- return -1;
- }
- return 0;
+ if (!tx_full(gc)) {
+ gc->sum += c;
+ *(gc->txptr++) = c;
}
}
-int gdb_puts(struct gdbcnxn *gc, const char *s) {
- int r;
+
+void gdb_puts(struct gdbcnxn *gc, const char *s) {
while (*s) {
- r = gdb_putc(gc, *s++);
- if (r < 0) return r;
+ gdb_putc(gc, *s++);
}
- return 0;
}
-int gdb_prologue(struct gdbcnxn *gc) {
- int n = gdb_putc(gc, '$');
- gc->chk = 0;
- return n;
+
+void gdb_prologue(struct gdbcnxn *gc) {
+ gc->txptr = gc->txbuf;
+ *(gc->txptr++) = '$';
+ gc->sum = 0;
}
-int gdb_epilogue(struct gdbcnxn *gc) {
+
+void gdb_epilogue(struct gdbcnxn *gc) {
+ unsigned char *ptr;
+ int len, r;
char tmp[4];
- sprintf(tmp,"#%02x", gc->chk & 0xff);
- return gdb_puts(gc, tmp);
+ sprintf(tmp,"#%02x", gc->sum & 0xff);
+ gdb_puts(gc, tmp);
+
+ if (tx_full(gc)) {
+ zprintf("GDB: TX Packet Too Large\n");
+ return;
+ }
+
+ ptr = gc->txbuf;
+ len = gc->txptr - gc->txbuf;
+ while (len > 0) {
+ r = write(gc->fd, ptr, len);
+ if (r <= 0) {
+ if (errno == EINTR) continue;
+ zprintf("GDB: TX Write Error\n");
+ return;
+ }
+ ptr += r;
+ len -= r;
+ }
}
static char HEX[16] = "0123456789abcdef";
-int gdb_puthex(struct gdbcnxn *gc, void *ptr, unsigned len) {
+void gdb_puthex(struct gdbcnxn *gc, void *ptr, unsigned len) {
unsigned char *data = ptr;
- unsigned n;
- char buf[1025];
-
- n = 0;
while (len-- > 0) {
unsigned c = *data++;
- buf[n++] = HEX[c >> 4];
- buf[n++] = HEX[c & 15];
- if (n == 1024) {
- buf[n] = 0;
- if (gdb_puts(gc, buf))
- return -1;
- n = 0;
- }
+ gdb_putc(gc, HEX[c >> 4]);
+ gdb_putc(gc, HEX[c & 15]);
}
- if (n) {
- buf[n] = 0;
- return gdb_puts(gc, buf);
+}
+
+void handle_command(struct gdbcnxn *gc, unsigned char *cmd);
+
+void gdb_recv_cmd(struct gdbcnxn *gc) {
+ if (gc->flags & F_TRACE) {
+ zprintf("PKT: %s\n", gc->rxbuf);
}
- return 0;
+ debugger_lock();
+ handle_command(gc, gc->rxbuf);
+ debugger_unlock();
}
-int gdb_recv(struct gdbcnxn *gc, char *buf, int max) {
- char *start = buf;
- unsigned chk;
- char tmp[3];
- int c;
-
-again:
- do {
- c = gdb_getc(gc);
- if (c < 0) goto fail;
- if (c == 3) {
- buf[0] = 's';
- buf[1] = 0;
- return 0;
- }
- if (c < 0x20)
- zprintf("PKT: ?? %02x\n",c);
- } while (c != '$');
-
- chk = 0;
- while (max > 1) {
- c = gdb_getc(gc);
- if (c == '#') {
- *buf++ = 0;
- c = gdb_getc(gc);
- if (c < 0) goto fail;
- tmp[0] = c;
- c = gdb_getc(gc);
- if (c < 0) goto fail;
- tmp[1] = c;
- c = strtoul(tmp, 0, 16);
- if (c != (chk & 0xff)) {
- gdb_putc(gc,'-');
- zprintf("PKT: BAD CHECKSUM\n");
- goto again;
+int gdb_recv(struct gdbcnxn *gc, unsigned char *ptr, int len) {
+ unsigned char *start = ptr;
+ unsigned char c;
+
+ while (len > 0) {
+ c = *ptr++;
+ len--;
+ switch (gc->state) {
+ case S_IDLE:
+ if (c == 3) {
+ gc->rxbuf[0] = 's';
+ gc->rxbuf[1] = 0;
+ gdb_recv_cmd(gc);
+ } else if (c == '$') {
+ gc->state = S_RECV;
+ gc->sum = 0;
+ gc->rxptr = gc->rxbuf;
+ }
+ break;
+ case S_RECV:
+ if (c == '#') {
+ gc->state = S_CHK1;
} else {
- gdb_putc(gc,'+');
- return 0;
+ if (rx_full(gc)) {
+ zprintf("PKT: Too Large, Discarding.");
+ gc->rxptr = gc->rxbuf;
+ gc->state = S_IDLE;
+ } else {
+ *(gc->rxptr++) = c;
+ gc->sum += c;
+ }
}
- } else {
- chk += c;
- *buf++ = c;
+ break;
+ case S_CHK1:
+ gc->chk[0] = c;
+ gc->state = S_CHK2;
+ break;
+ case S_CHK2:
+ gc->chk[1] = c;
+ gc->state = S_IDLE;
+ *(gc->rxptr++) = 0;
+ if (strtoul(gc->chk, NULL, 16) == (gc->sum & 0xFF)) {
+ if (gc->flags & F_ACK) {
+ if (write(gc->fd, "+", 1)) ;
+ }
+ gdb_recv_cmd(gc);
+ } else {
+ if (gc->flags & F_ACK) {
+ if (write(gc->fd, "-", 1)) ;
+ }
+ }
+ break;
}
}
- gdb_putc(gc,'-');
- zprintf("PKT: OVERFLOW\n");
- goto again;
-
-fail:
- *start = 0;
- return -1;
+ return ptr - start;
}
unsigned unhex(char *x) {
@@ -182,20 +216,6 @@ unsigned unhex(char *x) {
return n;
}
-static struct gdbcnxn *GC;
-
-#if 0
-void xprintf(const char *fmt, ...) {
- char buf[256];
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- buf[sizeof(buf)-1] = 0;
- va_end(ap);
- gdb_puthex(GC, buf, strlen(buf));
-}
-#endif
-
static const char *target_xml =
"<?xml version=\"1.0\"?>"
"<target>"
@@ -224,7 +244,9 @@ static const char *target_xml =
"</target>";
void handle_ext_command(struct gdbcnxn *gc, char *cmd, char *args) {
- zprintf("EXT: <%s> <%s>\n", cmd, args);
+ if (gc->flags & F_TRACE) {
+ zprintf("EXT: <%s> <%s>\n", cmd, args);
+ }
if (!strcmp(cmd,"Rcmd")) {
char *p = args;
cmd = p;
@@ -233,12 +255,11 @@ void handle_ext_command(struct gdbcnxn *gc, char *cmd, char *args) {
p+=2;
}
*cmd = 0;
- GC = gc;
debugger_command(args);
} else if(!strcmp(cmd, "Supported")) {
gdb_puts(gc,
"qXfer:features:read+"
- ";PacketSize=800"
+ ";PacketSize=2000"
);
} else if(!strcmp(cmd, "Xfer")) {
if (!strncmp(args, "features:read:target.xml:", 25)) {
@@ -246,10 +267,12 @@ void handle_ext_command(struct gdbcnxn *gc, char *cmd, char *args) {
// todo: support binary format w/ escaping
gdb_puts(gc, target_xml);
}
+ } else {
+ zprintf("GDB: unknown command: q%s:%s\n", cmd, args);
}
}
-void handle_command(struct gdbcnxn *gc, char *cmd) {
+void handle_command(struct gdbcnxn *gc, unsigned char *cmd) {
union {
u32 w[256+2];
u16 h[512+4];
@@ -274,7 +297,7 @@ void handle_command(struct gdbcnxn *gc, char *cmd) {
gdb_puts(gc, "OK");
break;
case 'm':
- if (sscanf(cmd + 1, "%x,%x", &x, &n) != 2)
+ if (sscanf((char*) cmd + 1, "%x,%x", &x, &n) != 2)
break;
if (n > 1024)
@@ -291,7 +314,7 @@ void handle_command(struct gdbcnxn *gc, char *cmd) {
}
case 'p': {
u32 v;
- swdp_core_read(strtoul(cmd + 1, NULL, 16), &v);
+ swdp_core_read(strtoul((char*) cmd + 1, NULL, 16), &v);
gdb_puthex(gc, &v, sizeof(v));
break;
}
@@ -300,7 +323,7 @@ void handle_command(struct gdbcnxn *gc, char *cmd) {
gdb_puts(gc, "S00");
break;
case 'q': {
- char *args = ++cmd;
+ char *args = (char*) ++cmd;
while (*args) {
if ((*args == ':') || (*args == ',')) {
*args++ = 0;
@@ -308,30 +331,36 @@ void handle_command(struct gdbcnxn *gc, char *cmd) {
}
args++;
}
- handle_ext_command(gc, cmd, args);
+ handle_ext_command(gc, (char*) cmd, args);
break;
}
default:
- zprintf("CMD: %c unknown\n", cmd[0]);
+ zprintf("GDB: unknown command: %c\n", cmd[0]);
}
gdb_epilogue(gc);
}
-void handler(int n) {
-}
-
void gdb_server(int fd) {
struct gdbcnxn gc;
- char cmd[32768];
- gc.tx = fd;
- gc.rx = fd;
- gc.chk = 0;
-
- while (gdb_recv(&gc, cmd, sizeof(cmd)) == 0) {
- zprintf("PKT: %s\n", cmd);
- debugger_lock();
- handle_command(&gc, cmd);
- debugger_unlock();
+ unsigned char iobuf[32768];
+ unsigned char *ptr;
+ int r, len;
+
+ gdb_init(&gc, fd);
+
+ for (;;) {
+ r = read(fd, iobuf, sizeof(iobuf));
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ return;
+ }
+ len = r;
+ ptr = iobuf;
+ while (len > 0) {
+ r = gdb_recv(&gc, ptr, len);
+ ptr += r;
+ len -= r;
+ }
}
}