enum gdb_output_flag {
/* GDB doesn't accept 'O' packets */
GDB_OUTPUT_NO,
+ /* GDB doesn't accept 'O' packets but accepts notifications */
+ GDB_OUTPUT_NOTIF,
/* GDB accepts 'O' packets */
GDB_OUTPUT_ALL,
};
enum target_state frontend_state;
struct image *vflash_image;
bool closed;
+ /* set to prevent re-entrance from log messages during gdb_get_packet()
+ * and gdb_put_packet(). */
bool busy;
int noack_mode;
/* set flag to true if you want the next stepi to return immediately.
gdb_connection->output_flag = GDB_OUTPUT_NO;
gdb_connection->unique_index = next_unique_id++;
- /* send ACK to GDB for debug request */
- gdb_write(connection, "+", 1);
-
/* output goes through gdb connection */
command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
return ERROR_OK;
}
-/* We don't have to worry about the default 2 second timeout for GDB packets,
- * because GDB breaks up large memory reads into smaller reads.
- */
static int gdb_read_memory_packet(struct connection *connection,
char const *packet, int packet_size)
{
}
if (strncmp(packet, "vFlashErase:", 12) == 0) {
- unsigned long addr;
+ target_addr_t addr;
unsigned long length;
char const *parse = packet + 12;
return ERROR_SERVER_REMOTE_CLOSED;
}
- addr = strtoul(parse, (char **)&parse, 16);
+ addr = strtoull(parse, (char **)&parse, 16);
if (*(parse++) != ',' || *parse == '\0') {
LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
if (strncmp(packet, "vFlashWrite:", 12) == 0) {
int retval;
- unsigned long addr;
+ target_addr_t addr;
unsigned long length;
char const *parse = packet + 12;
LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
return ERROR_SERVER_REMOTE_CLOSED;
}
- addr = strtoul(parse, (char **)&parse, 16);
+
+ addr = strtoull(parse, (char **)&parse, 16);
if (*(parse++) != ':') {
LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
return ERROR_SERVER_REMOTE_CLOSED;
if (strncmp(packet, "vFlashDone", 10) == 0) {
uint32_t written;
+ /* GDB command 'flash-erase' does not send a vFlashWrite,
+ * so nothing to write here. */
+ if (!gdb_connection->vflash_image) {
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+ }
+
/* process the flashing buffer. No need to erase as GDB
* always issues a vFlashErase first. */
target_call_event_callbacks(target,
struct connection *connection = priv;
struct gdb_connection *gdb_con = connection->priv;
- if (gdb_con->output_flag == GDB_OUTPUT_NO)
+ if (gdb_con->output_flag != GDB_OUTPUT_ALL)
/* No out allowed */
return;
retval = gdb_set_register_packet(connection, packet, packet_size);
break;
case 'm':
+ gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_read_memory_packet(connection, packet, packet_size);
+ gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'M':
+ gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_write_memory_packet(connection, packet, packet_size);
+ gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'z':
case 'Z':
retval = gdb_detach(connection);
break;
case 'X':
+ gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
- if (retval != ERROR_OK)
- return retval;
+ gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'k':
if (gdb_con->extended_protocol) {
return ERROR_OK;
}
+/*
+ * Send custom notification packet as keep-alive during memory read/write.
+ *
+ * From gdb 7.0 (released 2009-10-06) an unknown notification received during
+ * memory read/write would be silently dropped.
+ * Before gdb 7.0 any character, with exclusion of "+-$", would be considered
+ * as junk and ignored.
+ * In both cases the reception will reset the timeout counter in gdb, thus
+ * working as a keep-alive.
+ * Check putpkt_binary() and getpkt_sane() in gdb commit
+ * 74531fed1f2d662debc2c209b8b3faddceb55960
+ *
+ * Enable remote debug in gdb with 'set debug remote 1' to either dump the junk
+ * characters in gdb pre-7.0 and the notification from gdb 7.0.
+ */
+static void gdb_async_notif(struct connection *connection)
+{
+ static unsigned char count;
+ unsigned char checksum = 0;
+ char buf[22];
+
+ int len = sprintf(buf, "%%oocd_keepalive:%2.2x", count++);
+ for (int i = 1; i < len; i++)
+ checksum += buf[i];
+ len += sprintf(buf + len, "#%2.2x", checksum);
+
+#ifdef _DEBUG_GDB_IO_
+ LOG_DEBUG("sending packet '%s'", buf);
+#endif
+
+ gdb_write(connection, buf, len);
+}
+
static void gdb_keep_client_alive(struct connection *connection)
{
struct gdb_connection *gdb_con = connection->priv;
- if (gdb_con->busy) {
- /* do not send packets, retry asap */
- return;
- }
-
switch (gdb_con->output_flag) {
case GDB_OUTPUT_NO:
/* no need for keep-alive */
break;
+ case GDB_OUTPUT_NOTIF:
+ /* send asynchronous notification */
+ gdb_async_notif(connection);
+ break;
case GDB_OUTPUT_ALL:
/* send an empty O packet */
gdb_output_con(connection, "");