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