#include <unistd.h>
#include <stdlib.h>
-#if 0
+#if 1
#define _DEBUG_GDB_IO_
#endif
int i;
unsigned char my_checksum = 0;
char checksum[3];
+#ifdef _DEBUG_GDB_IO_
char *debug_buffer;
+#endif
int reply;
int retval;
gdb_connection_t *gdb_con = connection->priv;
while (1)
{
+#ifdef _DEBUG_GDB_IO_
debug_buffer = malloc(len + 1);
memcpy(debug_buffer, buffer, len);
debug_buffer[len] = 0;
DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
free(debug_buffer);
-
+#endif
write_socket(connection->fd, "$", 1);
if (len > 0)
write_socket(connection->fd, buffer, len);
} while (character != '$');
my_checksum = 0;
-
- do
+
+ for (;;)
{
+ /* The common case is that we have an entire packet with no escape chars.
+ * We need to leave at least 2 bytes in the buffer to have
+ * gdb_get_char() update various bits and bobs correctly.
+ */
+ if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
+ {
+ /* The compiler will struggle a bit with constant propagation and
+ * aliasing, so we help it by showing that these values do not
+ * change inside the loop
+ */
+ int i;
+ char *buf = gdb_con->buf_p;
+ int run = gdb_con->buf_cnt - 2;
+ i = 0;
+ int done = 0;
+ while (i < run)
+ {
+ character = *buf++;
+ i++;
+ if (character == '#')
+ {
+ /* Danger! character can be '#' when esc is
+ * used so we need an explicit boolean for done here.
+ */
+ done = 1;
+ break;
+ }
+
+ if (character == '}')
+ {
+ /* data transmitted in binary mode (X packet)
+ * uses 0x7d as escape character */
+ my_checksum += character & 0xff;
+ character = *buf++;
+ i++;
+ my_checksum += character & 0xff;
+ buffer[count++] = (character ^ 0x20) & 0xff;
+ } else
+ {
+ my_checksum += character & 0xff;
+ buffer[count++] = character & 0xff;
+ }
+ }
+ gdb_con->buf_p += i;
+ gdb_con->buf_cnt -= i;
+ if (done)
+ break;
+ }
+ if (count > *len)
+ {
+ ERROR("packet buffer too small");
+ return ERROR_GDB_BUFFER_TOO_SMALL;
+ }
+
if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
return retval;
- if (character == '#') break;
+ if (character == '#')
+ break;
if (character == '}')
{
buffer[count++] = character & 0xff;
}
- if (count > *len)
- {
- ERROR("packet buffer too small");
- return ERROR_GDB_BUFFER_TOO_SMALL;
- }
- } while (1);
+ }
*len = count;
return ERROR_OK;
}
-void gdb_str_to_target(target_t *target, char *str, char *tstr)
+/* Convert register to string of bits. NB! The # of bits in the
+ * register might be non-divisible by 8(a byte), in which
+ * case an entire byte is shown. */
+void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
{
- int str_len = strlen(str);
+ static const char *DIGITS = "0123456789abcdef";
int i;
- if (str_len % 2)
- {
- ERROR("BUG: gdb value with uneven number of characters encountered: %s", str);
- exit(-1);
- }
+ u8 *buf;
+ int buf_len;
+ buf = reg->value;
+ buf_len = CEIL(reg->size, 8);
if (target->endianness == TARGET_LITTLE_ENDIAN)
{
- for (i = 0; i < str_len; i+=2)
+ for (i = 0; i < buf_len; i++)
{
- tstr[str_len - i - 1] = str[i + 1];
- tstr[str_len - i - 2] = str[i];
+ tstr[i*2] = DIGITS[(buf[i]>>4) & 0xf];
+ tstr[i*2+1] = DIGITS[buf[i]&0xf];
}
}
else
{
- for (i = 0; i < str_len; i++)
+ for (i = 0; i < buf_len; i++)
{
- tstr[i] = str[i];
+ tstr[(buf_len-1-i)*2] = DIGITS[(buf[i]>>4)&0xf];
+ tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];
}
}
}
char *reg_packet_p;
int i;
+#ifdef _DEBUG_GDB_IO_
DEBUG("-");
+#endif
if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
{
for (i = 0; i < reg_list_size; i++)
{
- char *hex_buf = buf_to_str(reg_list[i]->value, reg_list[i]->size, 16);
- DEBUG("hex_buf: %s", hex_buf);
- gdb_str_to_target(target, hex_buf, reg_packet_p);
+ gdb_str_to_target(target, reg_packet_p, reg_list[i]);
reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
- free(hex_buf);
}
- reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
- DEBUG("reg_packet: %s", reg_packet_p);
- free(reg_packet_p);
+#ifdef _DEBUG_GDB_IO_
+ {
+ char *reg_packet_p;
+ reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
+ DEBUG("reg_packet: %s", reg_packet_p);
+ free(reg_packet_p);
+ }
+#endif
gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
free(reg_packet);
int retval;
char *packet_p;
+#ifdef _DEBUG_GDB_IO_
DEBUG("-");
+#endif
/* skip command character */
packet++;
reg_t **reg_list;
int reg_list_size;
int retval;
- char *hex_buf;
+#ifdef _DEBUG_GDB_IO_
DEBUG("-");
+#endif
if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
{
reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
- hex_buf = buf_to_str(reg_list[reg_num]->value, reg_list[reg_num]->size, 16);
-
- gdb_str_to_target(target, hex_buf, reg_packet);
+ gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
free(reg_list);
free(reg_packet);
- free(hex_buf);
return ERROR_OK;
}
retval = target->type->read_memory(target, addr, 1, len, buffer);
}
+#if 0
+ if (retval == ERROR_TARGET_DATA_ABORT)
+ {
+ /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
+ * At some point this might be fixed in GDB, in which case this code can be removed.
+ * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395
+ */
+ memset(buffer, 0, len);
+ retval = ERROR_OK;
+ }
+#endif
+
if (retval == ERROR_OK)
{
hex_buffer = malloc(len * 2 + 1);
* Need minimum 2 bytes to fit 1 char and 0 terminator. */
*size = *size * 2 + 2;
- char *t=*xml;
+ char *t = *xml;
*xml = realloc(*xml, *size);
if (*xml == NULL)
{
if (t)
free(t);
- *retval=ERROR_SERVER_REMOTE_CLOSED;
+ *retval = ERROR_SERVER_REMOTE_CLOSED;
return;
}
}
cmd[i] = tmp;
}
cmd[(packet_size - 6)/2] = 0x0;
+ target_call_timer_callbacks();
command_run_line(cmd_ctx, cmd);
free(cmd);
}
char *buffer = NULL;
int pos = 0;
int size = 0;
+
xml_printf(&retval, &buffer, &pos, &size,
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
(GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');
- if (buffer!=NULL)
+
+ if (retval != ERROR_OK)
{
- gdb_put_packet(connection, buffer, strlen(buffer));
- free(buffer);
+ gdb_send_error(connection, 01);
+ return ERROR_OK;
}
- return retval;
+
+ gdb_put_packet(connection, buffer, strlen(buffer));
+ free(buffer);
+
+ return ERROR_OK;
}
else if (strstr(packet, "qXfer:memory-map:read::"))
{
target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
/* perform erase */
- if ((result = flash_erase(gdb_service->target, addr, length)) != ERROR_OK)
+ if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
{
/* GDB doesn't evaluate the actual error number returned,
* treat a failed erase as an I/O error
/* disable gdb output while programming */
gdb_connection->output_disable = 1;
- /* process the flashing buffer */
+ /* process the flashing buffer. No need to erase as GDB
+ * always issues a vFlashErase first. */
if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, &error_str, NULL, 0)) != ERROR_OK)
{
if (result == ERROR_FLASH_DST_OUT_OF_BANK)