static unsigned short gdb_port;
+static void gdb_log_callback(void *privData, const char *file, int line,
+ const char *function, const char *format, va_list args);
+
+
enum gdb_detach_mode
{
GDB_DETACH_RESUME,
return ERROR_OK;
}
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
+int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
{
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);
return ERROR_OK;
}
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
+int gdb_put_packet(connection_t *connection, char *buffer, int len)
+{
+ gdb_connection_t *gdb_connection = connection->priv;
+ gdb_connection->output_disable=1;
+ int retval=gdb_put_packet_inner(connection, buffer, len);
+ gdb_connection->output_disable=0;
+ return retval;
+}
+
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
{
int character;
int count = 0;
} while (character != '$');
my_checksum = 0;
-
- do
+
+ count=0;
+ gdb_connection_t *gdb_con = connection->priv;
+ 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;
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;
}
-int gdb_output(struct command_context_s *context, char* line)
+int gdb_get_packet(connection_t *connection, char *buffer, int *len)
{
- connection_t *connection = context->output_handler_priv;
gdb_connection_t *gdb_connection = connection->priv;
+ gdb_connection->output_disable=1;
+ int retval=gdb_get_packet_inner(connection, buffer, len);
+ gdb_connection->output_disable=0;
+ return retval;
+}
+int gdb_output_con(connection_t *connection, char* line)
+{
+ gdb_connection_t *gdb_connection = connection->priv;
char *hex_buffer;
int i, bin_size;
return ERROR_OK;
}
+int gdb_output(struct command_context_s *context, char* line)
+{
+ connection_t *connection = context->output_handler_priv;
+ return gdb_output_con(connection, line);
+}
+
int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
{
FILE *script;
case TARGET_EVENT_HALTED:
if (gdb_connection->frontend_state == TARGET_RUNNING)
{
+ // stop forwarding log packets!
+ log_setCallback(NULL, NULL);
+
if (gdb_connection->ctrl_c)
{
signal = 0x2;
case ERROR_TARGET_NOT_HALTED:
ERROR("gdb tried to read memory but we're not halted, dropping connection");
return ERROR_SERVER_REMOTE_CLOSED;
- break;
case ERROR_TARGET_DATA_ABORT:
gdb_send_error(connection, EIO);
break;
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);
return 0;
}
+int gdb_calc_blocksize(flash_bank_t *bank)
+{
+ int i;
+ int block_size = 0xffffffff;
+
+ /* loop through all sectors and return smallest sector size */
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ if (bank->sectors[i].size < block_size)
+ block_size = bank->sectors[i].size;
+ }
+
+ return block_size;
+}
+
int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
{
command_context_t *cmd_ctx = connection->cmd_ctx;
cmd[i] = tmp;
}
cmd[(packet_size - 6)/2] = 0x0;
+
+ /* We want to print all debug output to GDB connection */
+ log_setCallback(gdb_log_callback, connection);
target_call_timer_callbacks();
command_run_line(cmd_ctx, cmd);
free(cmd);
int offset;
int length;
char *separator;
+ int blocksize;
/* skip command character */
packet += 23;
if (p == NULL)
break;
+ /* if device has uneven sector sizes, eg. str7, lpc
+ * we pass the smallest sector size to gdb memory map */
+ blocksize = gdb_calc_blocksize(p);
+
xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
"<property name=\"blocksize\">0x%x</property>\n" \
"</memory>\n", \
- p->base, p->size, p->size/p->num_sectors);
+ p->base, p->size, blocksize);
i++;
}
return ERROR_OK;
}
+
+
+static void gdb_log_callback(void *privData, const char *file, int line,
+ const char *function, const char *format, va_list args)
+{
+ connection_t *connection=(connection_t *)privData;
+
+ char *t=allocPrintf(format, args);
+ if (t==NULL)
+ return;
+
+ gdb_output_con(connection, t);
+
+ free(t);
+}
+
int gdb_input(connection_t *connection)
{
gdb_service_t *gdb_service = connection->service->priv;
break;
case 'c':
case 's':
+ /* We're running/stepping, in which case we can
+ * forward log output until the target is halted */
+ log_setCallback(gdb_log_callback, connection);
gdb_step_continue_packet(connection, target, packet, packet_size);
break;
case 'v':