gdb: fix single stepping, memory read reply error

This commit is contained in:
Daniel Beer 2010-03-23 13:38:14 +13:00
parent 484aecd7bc
commit 4d0a23954f
1 changed files with 106 additions and 108 deletions

214
gdb.c
View File

@ -165,13 +165,17 @@ static void gdb_packet_end(void)
for (i = 1; i < gdb_outlen; i++) for (i = 1; i < gdb_outlen; i++)
c = (c + gdb_outbuf[i]) & 0xff; c = (c + gdb_outbuf[i]) & 0xff;
gdb_printf("#%02X", c); gdb_printf("#%02x", c);
} }
static void gdb_hexstring(const char *text) static int gdb_send_hex(const char *text)
{ {
gdb_packet_start();
while (*text) while (*text)
gdb_printf("%02X", *(text++)); gdb_printf("%02x", *(text++));
gdb_packet_end();
return gdb_flush_ack();
} }
static int hexval(int c) static int hexval(int c)
@ -186,26 +190,35 @@ static int hexval(int c)
return 0; return 0;
} }
static int gdb_send(const char *msg)
{
gdb_packet_start();
gdb_printf("%s", msg);
gdb_packet_end();
return gdb_flush_ack();
}
/************************************************************************ /************************************************************************
* GDB server * GDB server
*/ */
static void read_registers(void) static int read_registers(void)
{ {
u_int16_t regs[DEVICE_NUM_REGS]; u_int16_t regs[DEVICE_NUM_REGS];
int i;
printf("Reading registers\n"); printf("Reading registers\n");
if (gdb_device->getregs(regs) < 0) { if (gdb_device->getregs(regs) < 0)
gdb_printf("E00"); return gdb_send("E00");
} else {
int i;
for (i = 0; i < DEVICE_NUM_REGS; i++) gdb_packet_start();
gdb_printf("%02X%02X", regs[i] & 0xff, regs[i] >> 8); for (i = 0; i < DEVICE_NUM_REGS; i++)
} gdb_printf("%02x%02x", regs[i] & 0xff, regs[i] >> 8);
gdb_packet_end();
return gdb_flush_ack();
} }
static void monitor_command(char *buf) static int monitor_command(char *buf)
{ {
char cmd[128]; char cmd[128];
int len = 0; int len = 0;
@ -218,23 +231,24 @@ static void monitor_command(char *buf)
if (!strcasecmp(cmd, "reset")) { if (!strcasecmp(cmd, "reset")) {
printf("Resetting device\n"); printf("Resetting device\n");
if (gdb_device->control(DEVICE_CTL_RESET) < 0) if (gdb_device->control(DEVICE_CTL_RESET) < 0)
gdb_hexstring("Reset failed\n"); return gdb_send_hex("Reset failed\n");
else
gdb_printf("OK");
} else if (!strcasecmp(cmd, "erase")) { } else if (!strcasecmp(cmd, "erase")) {
printf("Erasing device\n"); printf("Erasing device\n");
if (gdb_device->control(DEVICE_CTL_ERASE) < 0) if (gdb_device->control(DEVICE_CTL_ERASE) < 0)
gdb_hexstring("Erase failed\n"); return gdb_send_hex("Erase failed\n");
else
gdb_printf("OK");
} }
return gdb_send("OK");
} }
static void write_registers(char *buf) static int write_registers(char *buf)
{ {
u_int16_t regs[DEVICE_NUM_REGS]; u_int16_t regs[DEVICE_NUM_REGS];
int i; int i;
if (strlen(buf) < DEVICE_NUM_REGS * 4)
return gdb_send("E00");
printf("Writing registers\n"); printf("Writing registers\n");
for (i = 0; i < DEVICE_NUM_REGS; i++) { for (i = 0; i < DEVICE_NUM_REGS; i++) {
regs[i] = (hexval(buf[2]) << 12) | regs[i] = (hexval(buf[2]) << 12) |
@ -245,21 +259,21 @@ static void write_registers(char *buf)
} }
if (gdb_device->setregs(regs) < 0) if (gdb_device->setregs(regs) < 0)
gdb_printf("E00"); return gdb_send("E00");
else
gdb_printf("OK"); return gdb_send("OK");
} }
static void read_memory(char *text) static int read_memory(char *text)
{ {
char *length_text = strchr(text, ','); char *length_text = strchr(text, ',');
int length, addr; int length, addr;
u_int8_t buf[128]; u_int8_t buf[128];
int i;
if (!length_text) { if (!length_text) {
fprintf(stderr, "gdb: malformed memory read request\n"); fprintf(stderr, "gdb: malformed memory read request\n");
gdb_printf("E00"); return gdb_send("E00");
return;
} }
*(length_text++) = 0; *(length_text++) = 0;
@ -272,17 +286,18 @@ static void read_memory(char *text)
printf("Reading %d bytes from 0x%04x\n", length, addr); printf("Reading %d bytes from 0x%04x\n", length, addr);
if (gdb_device->readmem(addr, buf, length) < 0) { if (gdb_device->readmem(addr, buf, length) < 0)
gdb_printf("E00"); return gdb_send("E00");
} else {
int i;
for (i = 0; i < length; i++) gdb_packet_start();
gdb_printf("%02X", buf[i]); for (i = 0; i < length; i++)
} gdb_printf("%02x", buf[i]);
gdb_packet_end();
return gdb_flush_ack();
} }
static void write_memory(char *text) static int write_memory(char *text)
{ {
char *data_text = strchr(text, ':'); char *data_text = strchr(text, ':');
char *length_text = strchr(text, ','); char *length_text = strchr(text, ',');
@ -292,8 +307,7 @@ static void write_memory(char *text)
if (!(data_text && length_text)) { if (!(data_text && length_text)) {
fprintf(stderr, "gdb: malformed memory write request\n"); fprintf(stderr, "gdb: malformed memory write request\n");
gdb_printf("E00"); return gdb_send("E00");
return;
} }
*(data_text++) = 0; *(data_text++) = 0;
@ -310,72 +324,77 @@ static void write_memory(char *text)
if (buflen != length) { if (buflen != length) {
fprintf(stderr, "gdb: length mismatch\n"); fprintf(stderr, "gdb: length mismatch\n");
gdb_printf("E00"); return gdb_send("E00");
return;
} }
printf("Writing %d bytes to 0x%04x\n", buflen, addr); printf("Writing %d bytes to 0x%04x\n", buflen, addr);
if (gdb_device->writemem(addr, buf, buflen) < 0) if (gdb_device->writemem(addr, buf, buflen) < 0)
gdb_printf("E00"); return gdb_send("E00");
else
gdb_printf("OK"); return gdb_send("OK");
} }
static void single_step(char *buf) static int run_set_pc(char *buf)
{
u_int16_t regs[DEVICE_NUM_REGS];
if (!*buf)
return 0;
if (gdb_device->getregs(regs) < 0)
return -1;
regs[0] = strtoul(buf, NULL, 16);
return gdb_device->setregs(regs);
}
static int run_final_status(void)
{ {
u_int16_t regs[DEVICE_NUM_REGS]; u_int16_t regs[DEVICE_NUM_REGS];
int i; int i;
printf("Single stepping\n");
if (*buf) {
if (gdb_device->getregs(regs) < 0)
goto fail;
regs[0] = strtoul(buf, NULL, 16);
if (gdb_device->setregs(regs) < 0)
goto fail;
}
if (gdb_device->control(DEVICE_CTL_STEP) < 0)
goto fail;
if (gdb_device->getregs(regs) < 0) if (gdb_device->getregs(regs) < 0)
goto fail; return gdb_send("E00");
gdb_packet_start();
gdb_printf("T00"); gdb_printf("T00");
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
gdb_printf("%02X:%02X%02X;", i, regs[i] & 0xff, regs[i] >> 8); gdb_printf("%02x:%02x%02x;", i, regs[i] & 0xff, regs[i] >> 8);
gdb_packet_end();
return; return gdb_flush_ack();
fail:
gdb_printf("E00");
} }
static void run(char *buf) static int single_step(char *buf)
{ {
u_int16_t regs[DEVICE_NUM_REGS]; printf("Single stepping\n");
int i;
if (run_set_pc(buf) < 0 ||
gdb_device->control(DEVICE_CTL_STEP) < 0)
gdb_send("E00");
return run_final_status();
}
static int run(char *buf)
{
printf("Running\n"); printf("Running\n");
if (*buf) { if (run_set_pc(buf) < 0 ||
if (gdb_device->getregs(regs) < 0) gdb_device->control(DEVICE_CTL_RUN) < 0) {
goto fail; gdb_send("E00");
return run_final_status();
regs[0] = strtoul(buf, NULL, 16);
if (gdb_device->setregs(regs) < 0)
goto fail;
} }
if (gdb_device->control(DEVICE_CTL_RUN) < 0)
goto fail;
for (;;) { for (;;) {
int status = gdb_device->wait(0); int status = gdb_device->wait(0);
if (status < 0) if (status < 0) {
goto fail; gdb_send("E00");
return run_final_status();
}
if (!status) { if (!status) {
printf("Target halted\n"); printf("Target halted\n");
goto out; goto out;
@ -385,7 +404,7 @@ static void run(char *buf)
int c = gdb_getc(); int c = gdb_getc();
if (c < 0) if (c < 0)
return; return -1;
if (c == 3) { if (c == 3) {
printf("Interrupted by gdb\n"); printf("Interrupted by gdb\n");
@ -396,64 +415,43 @@ static void run(char *buf)
out: out:
if (gdb_device->control(DEVICE_CTL_HALT) < 0) if (gdb_device->control(DEVICE_CTL_HALT) < 0)
goto fail; gdb_send("E00");
if (gdb_device->getregs(regs) < 0)
goto fail;
gdb_printf("T00"); return run_final_status();
for (i = 0; i < 16; i++)
gdb_printf("%02X:%02X%02X;", i, regs[i] & 0xff, regs[i] >> 8);
return;
fail:
gdb_printf("E00");
} }
static int process_command(char *buf, int len) static int process_command(char *buf, int len)
{ {
gdb_packet_start();
switch (buf[0]) { switch (buf[0]) {
case '?': /* Return target halt reason */ case '?': /* Return target halt reason */
gdb_printf("T00"); return gdb_send("T00");
break;
case 'g': /* Read registers */ case 'g': /* Read registers */
read_registers(); return read_registers();
break;
case 'G': /* Write registers */ case 'G': /* Write registers */
if (len >= DEVICE_NUM_REGS * 4) return write_registers(buf + 1);
write_registers(buf + 1);
else
gdb_printf("E00");
break;
case 'q': /* Query */ case 'q': /* Query */
if (!strncmp(buf, "qRcmd,", 6)) if (!strncmp(buf, "qRcmd,", 6))
monitor_command(buf + 6); return monitor_command(buf + 6);
break; break;
case 'm': /* Read memory */ case 'm': /* Read memory */
read_memory(buf + 1); return read_memory(buf + 1);
break;
case 'M': /* Write memory */ case 'M': /* Write memory */
write_memory(buf + 1); return write_memory(buf + 1);
break;
case 'c': /* Continue */ case 'c': /* Continue */
run(buf + 1); return run(buf + 1);
break;
case 's': /* Single step */ case 's': /* Single step */
single_step(buf + 1); return single_step(buf + 1);
break;
} }
/* For unknown/unsupported packets, return an empty reply */ /* For unknown/unsupported packets, return an empty reply */
gdb_packet_end(); return gdb_send("");
return gdb_flush_ack();
} }
static void reader_loop(void) static void reader_loop(void)
@ -496,7 +494,7 @@ static void reader_loop(void)
cksum_recv = (cksum_recv << 4) | hexval(c); cksum_recv = (cksum_recv << 4) | hexval(c);
#ifdef DEBUG_GDB #ifdef DEBUG_GDB
printf("<- $%s#%02X\n", buf, cksum_recv); printf("<- $%s#%02x\n", buf, cksum_recv);
#endif #endif
if (cksum_recv != cksum_calc) { if (cksum_recv != cksum_calc) {