From f3a8df82f9e823a8695568d0623dabe6ca5b49be Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Mon, 6 Jun 2011 13:50:50 +1200 Subject: [PATCH] Extracted GDB remote protocol implementation. --- Makefile | 3 +- gdb.c | 222 ++------------------------------------------------ gdb_proto.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb_proto.h | 47 +++++++++++ 4 files changed, 289 insertions(+), 214 deletions(-) create mode 100644 gdb_proto.c create mode 100644 gdb_proto.h diff --git a/Makefile b/Makefile index 6e112b3..f27b842 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,8 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \ reader.o vector.o output_util.o expr.o fet_error.o binfile.o \ fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \ cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o simio_tracer.o \ - simio_timer.o simio_wdt.o simio_hwmult.o simio_gpio.o aliasdb.o + simio_timer.o simio_wdt.o simio_hwmult.o simio_gpio.o aliasdb.o \ + gdb_proto.o $(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/gdb.c b/gdb.c index 1f50e99..f063398 100644 --- a/gdb.c +++ b/gdb.c @@ -34,158 +34,7 @@ #include "output.h" #include "reader.h" #include "expr.h" - -#define MAX_MEM_XFER 8192 - -/************************************************************************ - * GDB IO routines - */ - -struct gdb_data { - int sock; - int error; - - char xbuf[1024]; - int head; - int tail; - - char outbuf[MAX_MEM_XFER * 2 + 64]; - int outlen; -}; - -static void gdb_printf(struct gdb_data *data, const char *fmt, ...) -{ - va_list ap; - int len; - - va_start(ap, fmt); - len = vsnprintf(data->outbuf + data->outlen, - sizeof(data->outbuf) - data->outlen, - fmt, ap); - va_end(ap); - - data->outlen += len; -} - -static int gdb_read(struct gdb_data *data, int blocking) -{ - fd_set r; - int len; - struct timeval to = { - .tv_sec = 0, - .tv_usec = 0 - }; - - FD_ZERO(&r); - FD_SET(data->sock, &r); - - if (select(data->sock + 1, &r, NULL, NULL, - blocking ? NULL : &to) < 0) { - pr_error("gdb: select"); - return -1; - } - - if (!FD_ISSET(data->sock, &r)) - return 0; - - len = recv(data->sock, data->xbuf, sizeof(data->xbuf), 0); - - if (len < 0) { - data->error = errno; - pr_error("gdb: recv"); - return -1; - } - - if (!len) { - printc("Connection closed\n"); - return -1; - } - - data->head = 0; - data->tail = len; - return len; -} - -static int gdb_peek(struct gdb_data *data) -{ - if (data->head == data->tail && gdb_read(data, 0) < 0) - return -1; - - return data->head != data->tail; -} - -static int gdb_getc(struct gdb_data *data) -{ - int c; - - /* If the buffer is empty, receive some more data */ - if (data->head == data->tail && gdb_read(data, 1) < 0) - return -1; - - c = data->xbuf[data->head]; - data->head++; - - return c; -} - -static int gdb_flush(struct gdb_data *data) -{ - if (send(data->sock, data->outbuf, data->outlen, 0) < 0) { - data->error = errno; - pr_error("gdb: flush"); - return -1; - } - - data->outlen = 0; - return 0; -} - -static int gdb_flush_ack(struct gdb_data *data) -{ - int c; - - do { - data->outbuf[data->outlen] = 0; -#ifdef DEBUG_GDB - printc("-> %s\n", data->outbuf); -#endif - if (send(data->sock, data->outbuf, data->outlen, 0) < 0) { - data->error = errno; - pr_error("gdb: flush_ack"); - return -1; - } - - c = gdb_getc(data); - if (c < 0) - return -1; - } while (c != '+'); - - data->outlen = 0; - return 0; -} - -static void gdb_packet_start(struct gdb_data *data) -{ - gdb_printf(data, "$"); -} - -static void gdb_packet_end(struct gdb_data *data) -{ - int i; - int c = 0; - - for (i = 1; i < data->outlen; i++) - c = (c + data->outbuf[i]) & 0xff; - gdb_printf(data, "#%02x", c); -} - -static int gdb_send(struct gdb_data *data, const char *msg) -{ - gdb_packet_start(data); - gdb_printf(data, "%s", msg); - gdb_packet_end(data); - return gdb_flush_ack(data); -} +#include "gdb_proto.h" /************************************************************************ * GDB server @@ -210,7 +59,7 @@ static int read_registers(struct gdb_data *data) } struct monitor_buf { - char buf[MAX_MEM_XFER]; + char buf[GDB_MAX_XFER]; int len; int trunc; }; @@ -296,7 +145,7 @@ static int read_memory(struct gdb_data *data, char *text) { char *length_text = strchr(text, ','); address_t length, addr; - uint8_t buf[MAX_MEM_XFER]; + uint8_t buf[GDB_MAX_XFER]; int i; if (!length_text) { @@ -330,7 +179,7 @@ static int write_memory(struct gdb_data *data, char *text) char *data_text = strchr(text, ':'); char *length_text = strchr(text, ','); address_t length, addr; - uint8_t buf[MAX_MEM_XFER]; + uint8_t buf[GDB_MAX_XFER]; int buflen = 0; if (!(data_text && length_text)) { @@ -512,7 +361,7 @@ static int set_breakpoint(struct gdb_data *data, int enable, char *buf) static int gdb_send_supported(struct gdb_data *data) { gdb_packet_start(data); - gdb_printf(data, "PacketSize=%x", MAX_MEM_XFER * 2); + gdb_printf(data, "PacketSize=%x", GDB_MAX_XFER * 2); gdb_packet_end(data); return gdb_flush_ack(data); } @@ -569,61 +418,12 @@ static int process_gdb_command(struct gdb_data *data, char *buf, int len) static void gdb_reader_loop(struct gdb_data *data) { for (;;) { - char buf[MAX_MEM_XFER * 2 + 64]; + char buf[GDB_BUF_SIZE]; int len = 0; - int cksum_calc = 0; - int cksum_recv = 0; - int c; - /* Wait for packet start */ - do { - c = gdb_getc(data); - if (c < 0) - return; - } while (c != '$'); - - /* Read packet payload */ - while (len + 1 < sizeof(buf)) { - c = gdb_getc(data); - if (c < 0) - return; - if (c == '#') - break; - - buf[len++] = c; - cksum_calc = (cksum_calc + c) & 0xff; - } - buf[len] = 0; - - /* Read packet checksum */ - c = gdb_getc(data); - if (c < 0) + len = gdb_read_packet(data, buf); + if (len < 0) return; - cksum_recv = hexval(c); - c = gdb_getc(data); - if (c < 0) - return; - cksum_recv = (cksum_recv << 4) | hexval(c); - -#ifdef DEBUG_GDB - printc("<- $%s#%02x\n", buf, cksum_recv); -#endif - - if (cksum_recv != cksum_calc) { - printc_err("gdb: bad checksum (calc = 0x%02x, " - "recv = 0x%02x)\n", cksum_calc, cksum_recv); - printc_err("gdb: packet data was: %s\n", buf); - gdb_printf(data, "-"); - if (gdb_flush(data) < 0) - return; - continue; - } - - /* Send acknowledgement */ - gdb_printf(data, "+"); - if (gdb_flush(data) < 0) - return; - if (len && process_gdb_command(data, buf, len) < 0) return; } @@ -679,11 +479,7 @@ static int gdb_server(int port) printc("Client connected from %s:%d\n", inet_ntoa(addr.sin_addr), htons(addr.sin_port)); - data.sock = client; - data.error = 0; - data.head = 0; - data.tail = 0; - data.outlen = 0; + gdb_init(&data, client); /* Put the hardware breakpoint setting into a known state. */ printc("Clearing all breakpoints...\n"); diff --git a/gdb_proto.c b/gdb_proto.c new file mode 100644 index 0000000..a16879c --- /dev/null +++ b/gdb_proto.c @@ -0,0 +1,231 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009-2011 Daniel Beer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gdb_proto.h" +#include "output.h" +#include "util.h" + +void gdb_init(struct gdb_data *data, int sock) +{ + data->sock = sock; + data->error = 0; + data->head = 0; + data->tail = 0; + data->outlen = 0; +} + +void gdb_printf(struct gdb_data *data, const char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = vsnprintf(data->outbuf + data->outlen, + sizeof(data->outbuf) - data->outlen, + fmt, ap); + va_end(ap); + + data->outlen += len; +} + +static int gdb_read(struct gdb_data *data, int blocking) +{ + fd_set r; + int len; + struct timeval to = { + .tv_sec = 0, + .tv_usec = 0 + }; + + FD_ZERO(&r); + FD_SET(data->sock, &r); + + if (select(data->sock + 1, &r, NULL, NULL, + blocking ? NULL : &to) < 0) { + pr_error("gdb: select"); + return -1; + } + + if (!FD_ISSET(data->sock, &r)) + return 0; + + len = recv(data->sock, data->xbuf, sizeof(data->xbuf), 0); + + if (len < 0) { + data->error = errno; + pr_error("gdb: recv"); + return -1; + } + + if (!len) { + printc("Connection closed\n"); + return -1; + } + + data->head = 0; + data->tail = len; + return len; +} + +int gdb_peek(struct gdb_data *data) +{ + if (data->head == data->tail && gdb_read(data, 0) < 0) + return -1; + + return data->head != data->tail; +} + +int gdb_getc(struct gdb_data *data) +{ + int c; + + /* If the buffer is empty, receive some more data */ + if (data->head == data->tail && gdb_read(data, 1) < 0) + return -1; + + c = data->xbuf[data->head]; + data->head++; + + return c; +} + +static int gdb_flush(struct gdb_data *data) +{ + if (send(data->sock, data->outbuf, data->outlen, 0) < 0) { + data->error = errno; + pr_error("gdb: flush"); + return -1; + } + + data->outlen = 0; + return 0; +} + +int gdb_flush_ack(struct gdb_data *data) +{ + int c; + + do { + data->outbuf[data->outlen] = 0; +#ifdef DEBUG_GDB + printc("-> %s\n", data->outbuf); +#endif + if (send(data->sock, data->outbuf, data->outlen, 0) < 0) { + data->error = errno; + pr_error("gdb: flush_ack"); + return -1; + } + + c = gdb_getc(data); + if (c < 0) + return -1; + } while (c != '+'); + + data->outlen = 0; + return 0; +} + +void gdb_packet_start(struct gdb_data *data) +{ + gdb_printf(data, "$"); +} + +void gdb_packet_end(struct gdb_data *data) +{ + int i; + int c = 0; + + for (i = 1; i < data->outlen; i++) + c = (c + data->outbuf[i]) & 0xff; + gdb_printf(data, "#%02x", c); +} + +int gdb_send(struct gdb_data *data, const char *msg) +{ + gdb_packet_start(data); + gdb_printf(data, "%s", msg); + gdb_packet_end(data); + return gdb_flush_ack(data); +} + +int gdb_read_packet(struct gdb_data *data, char *buf) +{ + int c; + int len = 0; + int cksum_calc = 0; + int cksum_recv = 0; + + /* Wait for packet start */ + do { + c = gdb_getc(data); + if (c < 0) + return -1; + } while (c != '$'); + + /* Read packet payload */ + while (len + 1 < GDB_BUF_SIZE) { + c = gdb_getc(data); + if (c < 0) + return -1; + if (c == '#') + break; + + buf[len++] = c; + cksum_calc = (cksum_calc + c) & 0xff; + } + buf[len] = 0; + + /* Read packet checksum */ + c = gdb_getc(data); + if (c < 0) + return -1; + cksum_recv = hexval(c); + c = gdb_getc(data); + if (c < 0) + return -1; + cksum_recv = (cksum_recv << 4) | hexval(c); + +#ifdef DEBUG_GDB + printc("<- $%s#%02x\n", buf, cksum_recv); +#endif + + if (cksum_recv != cksum_calc) { + printc_err("gdb: bad checksum (calc = 0x%02x, " + "recv = 0x%02x)\n", cksum_calc, cksum_recv); + printc_err("gdb: packet data was: %s\n", buf); + gdb_printf(data, "-"); + if (gdb_flush(data) < 0) + return -1; + return 0; + } + + /* Send acknowledgement */ + gdb_printf(data, "+"); + if (gdb_flush(data) < 0) + return -1; + + return len; +} diff --git a/gdb_proto.h b/gdb_proto.h new file mode 100644 index 0000000..8f6b5e4 --- /dev/null +++ b/gdb_proto.h @@ -0,0 +1,47 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009-2011 Daniel Beer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GDB_PROTO_H_ +#define GDB_PROTO_H_ + +#define GDB_MAX_XFER 8192 +#define GDB_BUF_SIZE (GDB_MAX_XFER * 2 + 64) + +struct gdb_data { + int sock; + int error; + + char xbuf[1024]; + int head; + int tail; + + char outbuf[GDB_BUF_SIZE]; + int outlen; +}; + +void gdb_init(struct gdb_data *d, int sock); +void gdb_printf(struct gdb_data *data, const char *fmt, ...); +int gdb_send(struct gdb_data *data, const char *msg); +void gdb_packet_start(struct gdb_data *data); +void gdb_packet_end(struct gdb_data *data); +int gdb_peek(struct gdb_data *data); +int gdb_getc(struct gdb_data *data); +int gdb_flush_ack(struct gdb_data *data); +int gdb_read_packet(struct gdb_data *data, char *buf); + +#endif