Implemented GDB client driver.
This commit is contained in:
parent
f3a8df82f9
commit
57d5ea34d5
2
Makefile
2
Makefile
|
@ -65,7 +65,7 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
|
||||||
fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.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 \
|
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
|
gdb_proto.o gdbc.o
|
||||||
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
2
gdb.c
2
gdb.c
|
@ -288,7 +288,7 @@ static int run(struct gdb_data *data, char *buf)
|
||||||
if (status == DEVICE_STATUS_INTR)
|
if (status == DEVICE_STATUS_INTR)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while (gdb_peek(data)) {
|
while (gdb_peek(data, 0)) {
|
||||||
int c = gdb_getc(data);
|
int c = gdb_getc(data);
|
||||||
|
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
|
|
23
gdb_proto.c
23
gdb_proto.c
|
@ -51,20 +51,20 @@ void gdb_printf(struct gdb_data *data, const char *fmt, ...)
|
||||||
data->outlen += len;
|
data->outlen += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdb_read(struct gdb_data *data, int blocking)
|
static int gdb_read(struct gdb_data *data, int timeout_ms)
|
||||||
{
|
{
|
||||||
fd_set r;
|
fd_set r;
|
||||||
int len;
|
int len;
|
||||||
struct timeval to = {
|
struct timeval to = {
|
||||||
.tv_sec = 0,
|
.tv_sec = timeout_ms / 1000,
|
||||||
.tv_usec = 0
|
.tv_usec = timeout_ms % 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
FD_ZERO(&r);
|
FD_ZERO(&r);
|
||||||
FD_SET(data->sock, &r);
|
FD_SET(data->sock, &r);
|
||||||
|
|
||||||
if (select(data->sock + 1, &r, NULL, NULL,
|
if (select(data->sock + 1, &r, NULL, NULL,
|
||||||
blocking ? NULL : &to) < 0) {
|
timeout_ms < 0 ? NULL : &to) < 0) {
|
||||||
pr_error("gdb: select");
|
pr_error("gdb: select");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -90,9 +90,9 @@ static int gdb_read(struct gdb_data *data, int blocking)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gdb_peek(struct gdb_data *data)
|
int gdb_peek(struct gdb_data *data, int timeout_ms)
|
||||||
{
|
{
|
||||||
if (data->head == data->tail && gdb_read(data, 0) < 0)
|
if (data->head == data->tail && gdb_read(data, timeout_ms) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return data->head != data->tail;
|
return data->head != data->tail;
|
||||||
|
@ -103,7 +103,7 @@ int gdb_getc(struct gdb_data *data)
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
/* If the buffer is empty, receive some more data */
|
/* If the buffer is empty, receive some more data */
|
||||||
if (data->head == data->tail && gdb_read(data, 1) < 0)
|
if (data->head == data->tail && gdb_read(data, -1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
c = data->xbuf[data->head];
|
c = data->xbuf[data->head];
|
||||||
|
@ -128,20 +128,21 @@ int gdb_flush_ack(struct gdb_data *data)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
do {
|
|
||||||
data->outbuf[data->outlen] = 0;
|
|
||||||
#ifdef DEBUG_GDB
|
#ifdef DEBUG_GDB
|
||||||
printc("-> %s\n", data->outbuf);
|
printc("-> %s\n", data->outbuf);
|
||||||
#endif
|
#endif
|
||||||
|
data->outbuf[data->outlen] = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
if (send(data->sock, data->outbuf, data->outlen, 0) < 0) {
|
if (send(data->sock, data->outbuf, data->outlen, 0) < 0) {
|
||||||
data->error = errno;
|
data->error = errno;
|
||||||
pr_error("gdb: flush_ack");
|
pr_error("gdb: flush_ack");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
c = gdb_getc(data);
|
c = gdb_getc(data);
|
||||||
if (c < 0)
|
} while (c != '+' && c != '-');
|
||||||
return -1;
|
|
||||||
} while (c != '+');
|
} while (c != '+');
|
||||||
|
|
||||||
data->outlen = 0;
|
data->outlen = 0;
|
||||||
|
|
|
@ -39,7 +39,7 @@ void gdb_printf(struct gdb_data *data, const char *fmt, ...);
|
||||||
int gdb_send(struct gdb_data *data, const char *msg);
|
int gdb_send(struct gdb_data *data, const char *msg);
|
||||||
void gdb_packet_start(struct gdb_data *data);
|
void gdb_packet_start(struct gdb_data *data);
|
||||||
void gdb_packet_end(struct gdb_data *data);
|
void gdb_packet_end(struct gdb_data *data);
|
||||||
int gdb_peek(struct gdb_data *data);
|
int gdb_peek(struct gdb_data *data, int timeout_ms);
|
||||||
int gdb_getc(struct gdb_data *data);
|
int gdb_getc(struct gdb_data *data);
|
||||||
int gdb_flush_ack(struct gdb_data *data);
|
int gdb_flush_ack(struct gdb_data *data);
|
||||||
int gdb_read_packet(struct gdb_data *data, char *buf);
|
int gdb_read_packet(struct gdb_data *data, char *buf);
|
||||||
|
|
|
@ -0,0 +1,446 @@
|
||||||
|
/* 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 <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "output.h"
|
||||||
|
#include "gdbc.h"
|
||||||
|
#include "gdb_proto.h"
|
||||||
|
#include "opdb.h"
|
||||||
|
|
||||||
|
struct gdb_client {
|
||||||
|
struct device base;
|
||||||
|
struct gdb_data gdb;
|
||||||
|
int is_running;
|
||||||
|
|
||||||
|
struct device_breakpoint last_bps[DEVICE_MAX_BREAKPOINTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_xfer_size(void)
|
||||||
|
{
|
||||||
|
int x = opdb_get_numeric("gdbc_xfer_size");
|
||||||
|
|
||||||
|
if (x < 2)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (x > GDB_MAX_XFER)
|
||||||
|
return GDB_MAX_XFER;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_ok(struct gdb_data *gdb)
|
||||||
|
{
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = gdb_read_packet(gdb, buf);
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len < 1 || buf[0] == 'E') {
|
||||||
|
printc_err("gdbc: bad response: %s\n", buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gdbc_destroy(device_t dev_base)
|
||||||
|
{
|
||||||
|
struct gdb_client *c = (struct gdb_client *)dev_base;
|
||||||
|
|
||||||
|
shutdown(c->gdb.sock, 2);
|
||||||
|
close(c->gdb.sock);
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_readmem(device_t dev_base, address_t addr,
|
||||||
|
uint8_t *mem, address_t len)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
int xfer_size = get_xfer_size();
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
int plen = len > xfer_size ? xfer_size : len;
|
||||||
|
int r;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gdb_packet_start(&dev->gdb);
|
||||||
|
gdb_printf(&dev->gdb, "m%04x,%x", addr, plen);
|
||||||
|
gdb_packet_end(&dev->gdb);
|
||||||
|
if (gdb_flush_ack(&dev->gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
r = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
if (r < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (r < plen * 2) {
|
||||||
|
printc_err("gdbc: short read at 0x%04x: expected %d "
|
||||||
|
"bytes, got %d\n", addr, plen, r / 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i * 2 < r; i++)
|
||||||
|
mem[i] = (hexval(buf[i * 2]) << 4) |
|
||||||
|
hexval(buf[i * 2 + 1]);
|
||||||
|
|
||||||
|
mem += plen;
|
||||||
|
len -= plen;
|
||||||
|
addr += plen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_writemem(device_t dev_base, address_t addr,
|
||||||
|
const uint8_t *mem, address_t len)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
int xfer_size = get_xfer_size();
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
int plen = len > xfer_size ? xfer_size : len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gdb_packet_start(&dev->gdb);
|
||||||
|
gdb_printf(&dev->gdb, "M%04x,%x:", addr, plen);
|
||||||
|
for (i = 0; i < plen; i++)
|
||||||
|
gdb_printf(&dev->gdb, "%02x", mem[i]);
|
||||||
|
gdb_packet_end(&dev->gdb);
|
||||||
|
if (gdb_flush_ack(&dev->gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_ok(&dev->gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mem += plen;
|
||||||
|
len -= plen;
|
||||||
|
addr += plen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_getregs(device_t dev_base, address_t *regs)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (gdb_send(&dev->gdb, "g") < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len < DEVICE_NUM_REGS * 4) {
|
||||||
|
printc_err("gdbc: short read: expected %d chars, got %d\n",
|
||||||
|
DEVICE_NUM_REGS * 4, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||||
|
char *text = buf + i * 4;
|
||||||
|
|
||||||
|
regs[i] = (hexval(text[0]) << 4) | (hexval(text[1])) |
|
||||||
|
(hexval(text[2]) << 12) | (hexval(text[3]) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_setregs(device_t dev_base, const address_t *regs)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gdb_packet_start(&dev->gdb);
|
||||||
|
gdb_printf(&dev->gdb, "G");
|
||||||
|
for (i = 0; i < DEVICE_NUM_REGS; i++)
|
||||||
|
gdb_printf(&dev->gdb, "%02x%02x",
|
||||||
|
regs[i] & 0xff, (regs[i] >> 8) & 0xff);
|
||||||
|
gdb_packet_end(&dev->gdb);
|
||||||
|
if (gdb_flush_ack(&dev->gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return check_ok(&dev->gdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_reset(struct gdb_client *dev)
|
||||||
|
{
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (gdb_send(&dev->gdb, "R00") < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
if (!len) {
|
||||||
|
if (gdb_send(&dev->gdb, "r") < 0)
|
||||||
|
return -1;
|
||||||
|
len = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len < 2 || buf[0] != 'O' || buf[1] != 'K') {
|
||||||
|
printc_err("gdbc: reset: bad response: %s\n", buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bp_send(struct gdb_data *gdb, int c, address_t addr)
|
||||||
|
{
|
||||||
|
gdb_packet_start(gdb);
|
||||||
|
gdb_printf(gdb, "%c1,%04x,2", c, addr);
|
||||||
|
gdb_packet_end(gdb);
|
||||||
|
if (gdb_flush_ack(gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return check_ok(gdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int refresh_bps(struct gdb_client *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->base.max_breakpoints; i++) {
|
||||||
|
struct device_breakpoint *bp = &dev->base.breakpoints[i];
|
||||||
|
struct device_breakpoint *old = &dev->last_bps[i];
|
||||||
|
|
||||||
|
if (!(bp->flags & DEVICE_BP_DIRTY))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((old->flags & DEVICE_BP_ENABLED) &&
|
||||||
|
(bp_send(&dev->gdb, 'z', old->addr) < 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((bp->flags & DEVICE_BP_ENABLED) &&
|
||||||
|
(bp_send(&dev->gdb, 'Z', bp->addr) < 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
bp->flags &= ~DEVICE_BP_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dev->last_bps, dev->base.breakpoints, sizeof(dev->last_bps));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_ctl(device_t dev_base, device_ctl_t op)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case DEVICE_CTL_STEP:
|
||||||
|
if (gdb_send(&dev->gdb, "s") < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return check_ok(&dev->gdb);
|
||||||
|
|
||||||
|
case DEVICE_CTL_RUN:
|
||||||
|
if (refresh_bps(dev) < 0)
|
||||||
|
return -1;
|
||||||
|
if (gdb_send(&dev->gdb, "c") < 0)
|
||||||
|
return -1;
|
||||||
|
dev->is_running = 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DEVICE_CTL_HALT:
|
||||||
|
if (dev->is_running) {
|
||||||
|
if (write_all(dev->gdb.sock,
|
||||||
|
(const uint8_t *)"\003", 1) < 0) {
|
||||||
|
pr_error("gdbc: write");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->is_running = 0;
|
||||||
|
return check_ok(&dev->gdb);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DEVICE_CTL_RESET:
|
||||||
|
return do_reset(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gdbc_erase(device_t dev_base, device_erase_type_t type,
|
||||||
|
address_t addr)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
const char *cmd = "erase";
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
gdb_packet_start(&dev->gdb);
|
||||||
|
gdb_printf(&dev->gdb, "qRcmd,");
|
||||||
|
while (*cmd)
|
||||||
|
gdb_printf(&dev->gdb, "%02x", *(cmd++));
|
||||||
|
gdb_packet_end(&dev->gdb);
|
||||||
|
|
||||||
|
if (gdb_flush_ack(&dev->gdb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_status_t gdbc_poll(device_t dev_base)
|
||||||
|
{
|
||||||
|
struct gdb_client *dev = (struct gdb_client *)dev_base;
|
||||||
|
char buf[GDB_BUF_SIZE];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!dev->is_running)
|
||||||
|
return DEVICE_STATUS_HALTED;
|
||||||
|
|
||||||
|
len = gdb_peek(&dev->gdb, 50);
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
return DEVICE_STATUS_INTR;
|
||||||
|
|
||||||
|
dev->is_running = 0;
|
||||||
|
return DEVICE_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return DEVICE_STATUS_RUNNING;
|
||||||
|
|
||||||
|
len = gdb_read_packet(&dev->gdb, buf);
|
||||||
|
if (len < 0) {
|
||||||
|
dev->is_running = 0;
|
||||||
|
return DEVICE_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->is_running = 0;
|
||||||
|
return DEVICE_STATUS_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int connect_to(const char *spec)
|
||||||
|
{
|
||||||
|
const char *port_text;
|
||||||
|
int hn_len;
|
||||||
|
int port = 2000;
|
||||||
|
char hostname[128];
|
||||||
|
struct hostent *ent;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int sock;
|
||||||
|
|
||||||
|
if (!spec) {
|
||||||
|
printc_err("gdbc: no remote target specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
port_text = strchr(spec, ':');
|
||||||
|
if (port_text) {
|
||||||
|
port = atoi(port_text + 1);
|
||||||
|
hn_len = port_text - spec;
|
||||||
|
} else {
|
||||||
|
hn_len = strlen(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hn_len + 1 > sizeof(hostname))
|
||||||
|
hn_len = sizeof(hostname) - 1;
|
||||||
|
memcpy(hostname, spec, hn_len);
|
||||||
|
hostname[hn_len] = 0;
|
||||||
|
|
||||||
|
printc_dbg("Looking up %s...\n", hostname);
|
||||||
|
ent = gethostbyname(hostname);
|
||||||
|
if (!ent) {
|
||||||
|
printc_err("No such host: %s: %s\n", hostname,
|
||||||
|
hstrerror(h_errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (!sock) {
|
||||||
|
printc_err("socket: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr = *(struct in_addr *)ent->h_addr;
|
||||||
|
printc_dbg("Connecting to %s:%d...\n",
|
||||||
|
inet_ntoa(addr.sin_addr), port);
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
printc_err("connect: %s\n", strerror(errno));
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_t gdbc_open(const struct device_args *args)
|
||||||
|
{
|
||||||
|
int sock = connect_to(args->path);
|
||||||
|
struct gdb_client *dev;
|
||||||
|
|
||||||
|
if (sock < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dev = malloc(sizeof(struct gdb_client));
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("gdbc: can't allocate memory: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dev, 0, sizeof(*dev));
|
||||||
|
dev->base.type = &device_gdbc;
|
||||||
|
dev->base.max_breakpoints = DEVICE_MAX_BREAKPOINTS;
|
||||||
|
|
||||||
|
gdb_init(&dev->gdb, sock);
|
||||||
|
return (device_t)dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct device_class device_gdbc = {
|
||||||
|
.name = "gdbc",
|
||||||
|
.help = "GDB client mode",
|
||||||
|
.open = gdbc_open,
|
||||||
|
.destroy = gdbc_destroy,
|
||||||
|
.readmem = gdbc_readmem,
|
||||||
|
.writemem = gdbc_writemem,
|
||||||
|
.erase = gdbc_erase,
|
||||||
|
.getregs = gdbc_getregs,
|
||||||
|
.setregs = gdbc_setregs,
|
||||||
|
.ctl = gdbc_ctl,
|
||||||
|
.poll = gdbc_poll
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* 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 GDBC_H_
|
||||||
|
#define GDBC_H_
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
/* GDB client implementation */
|
||||||
|
extern const struct device_class device_gdbc;
|
||||||
|
|
||||||
|
#endif
|
4
main.c
4
main.c
|
@ -46,6 +46,7 @@
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "fet_db.h"
|
#include "fet_db.h"
|
||||||
#include "flash_bsl.h"
|
#include "flash_bsl.h"
|
||||||
|
#include "gdbc.h"
|
||||||
|
|
||||||
#include "uif.h"
|
#include "uif.h"
|
||||||
#include "olimex.h"
|
#include "olimex.h"
|
||||||
|
@ -64,7 +65,8 @@ static const struct device_class *const driver_table[] = {
|
||||||
&device_sim,
|
&device_sim,
|
||||||
&device_uif,
|
&device_uif,
|
||||||
&device_bsl,
|
&device_bsl,
|
||||||
&device_flash_bsl
|
&device_flash_bsl,
|
||||||
|
&device_gdbc
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *version_text =
|
static const char *version_text =
|
||||||
|
|
|
@ -117,6 +117,11 @@ Connect RTS to the device's TEST pin and DTR to the device's RST pin.
|
||||||
Use an appropriate serial level-shifter to make the connection, if necessary.
|
Use an appropriate serial level-shifter to make the connection, if necessary.
|
||||||
If connecting to a device with non-multiplexed JTAG pins, connect RTS to
|
If connecting to a device with non-multiplexed JTAG pins, connect RTS to
|
||||||
the device's TCK pin via an inverter.
|
the device's TCK pin via an inverter.
|
||||||
|
.IP "\fBgdbc\fR"
|
||||||
|
GDB client mode. Connect to a server which implements the GDB remote
|
||||||
|
protocol and provide an interface to it. To use this driver, specify
|
||||||
|
the remote address in \fIhostname:port\fR format using the \fB-d\fR
|
||||||
|
option.
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
MSPDebug can accept commands either through an interactive prompt, or
|
MSPDebug can accept commands either through an interactive prompt, or
|
||||||
non-interactively when specified on the command line. The supported
|
non-interactively when specified on the command line. The supported
|
||||||
|
@ -608,6 +613,10 @@ speed, but may cause problems with some chips.
|
||||||
Automatically restart the GDB server after disconnection. If this
|
Automatically restart the GDB server after disconnection. If this
|
||||||
option is set, then the GDB server keeps running until an error occurs,
|
option is set, then the GDB server keeps running until an error occurs,
|
||||||
or the user interrupts with Ctrl+C.
|
or the user interrupts with Ctrl+C.
|
||||||
|
.IP "\fBgdbc_xfer_size\fR (numeric)"
|
||||||
|
Maximum size of memory transfers for the GDB client. Increasing this
|
||||||
|
value will result in faster transfers, but may cause problems with some
|
||||||
|
servers.
|
||||||
.IP "\fBiradix\fR (numeric)"
|
.IP "\fBiradix\fR (numeric)"
|
||||||
Default input radix for address expressions. For address values with
|
Default input radix for address expressions. For address values with
|
||||||
no radix specifier, this value gives the input radix, which is
|
no radix specifier, this value gives the input radix, which is
|
||||||
|
|
11
opdb.c
11
opdb.c
|
@ -66,6 +66,17 @@ const static struct opdb_key keys[] = {
|
||||||
.defval = {
|
.defval = {
|
||||||
.numeric = 64
|
.numeric = 64
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gdbc_xfer_size",
|
||||||
|
.type = OPDB_TYPE_NUMERIC,
|
||||||
|
.help =
|
||||||
|
"Maximum size of memory transfers for the GDB client. Increasing this\n"
|
||||||
|
"value will result in faster transfers, but may cause problems with some\n"
|
||||||
|
"servers.\n",
|
||||||
|
.defval = {
|
||||||
|
.numeric = 64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue