X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=c8f0e523ce63805f93d1fea07aacdfee2fd1e2cf;hb=HEAD;hp=d1bcfb5406b8c3ca5b04e421b9c42b49cca85541;hpb=14b1b35e4247091f1e90311f9b61805ae1f6f34d;p=openocd.git diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d1bcfb5406..5052bf43b2 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -53,6 +53,8 @@ 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, }; @@ -71,6 +73,8 @@ struct gdb_connection { 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. @@ -124,9 +128,9 @@ static int gdb_actual_connections; /* set if we are sending a memory map to gdb * via qXfer:memory-map:read packet */ /* enabled by default*/ -static int gdb_use_memory_map = 1; +static bool gdb_use_memory_map = true; /* enabled by default*/ -static int gdb_flash_program = 1; +static bool gdb_flash_program = true; /* if set, data aborts cause an error to be reported in memory read packets * see the code in gdb_read_memory_packet() for further explanations. @@ -140,7 +144,7 @@ static int gdb_report_register_access_error; /* set if we are sending target descriptions to gdb * via qXfer:features:read packet */ /* enabled by default */ -static int gdb_use_target_description = 1; +static bool gdb_use_target_description = true; /* current processing free-run type, used by file-I/O */ static char gdb_running_type; @@ -1001,9 +1005,6 @@ static int gdb_new_connection(struct connection *connection) 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); @@ -1489,9 +1490,6 @@ static int gdb_error(struct connection *connection, int retval) 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) { @@ -2601,7 +2599,7 @@ static int gdb_get_target_description_chunk(struct target *target, struct target return ERROR_OK; } -static int gdb_target_description_supported(struct target *target, int *supported) +static int gdb_target_description_supported(struct target *target, bool *supported) { int retval = ERROR_OK; struct reg **reg_list = NULL; @@ -2633,9 +2631,9 @@ static int gdb_target_description_supported(struct target *target, int *supporte if (supported) { if (architecture || feature_list_size) - *supported = 1; + *supported = true; else - *supported = 0; + *supported = false; } error: @@ -2847,7 +2845,9 @@ static int gdb_query_packet(struct connection *connection, len = strtoul(separator + 1, NULL, 16); + gdb_connection->output_flag = GDB_OUTPUT_NOTIF; retval = target_checksum_memory(target, addr, len, &checksum); + gdb_connection->output_flag = GDB_OUTPUT_NO; if (retval == ERROR_OK) { snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum); @@ -2867,20 +2867,20 @@ static int gdb_query_packet(struct connection *connection, char *buffer = NULL; int pos = 0; int size = 0; - int gdb_target_desc_supported = 0; + bool gdb_target_desc_supported = false; /* we need to test that the target supports target descriptions */ retval = gdb_target_description_supported(target, &gdb_target_desc_supported); if (retval != ERROR_OK) { LOG_INFO("Failed detecting Target Description Support, disabling"); - gdb_target_desc_supported = 0; + gdb_target_desc_supported = false; } /* support may be disabled globally */ - if (gdb_use_target_description == 0) { + if (!gdb_use_target_description) { if (gdb_target_desc_supported) LOG_WARNING("Target Descriptions Supported, but disabled"); - gdb_target_desc_supported = 0; + gdb_target_desc_supported = false; } xml_printf(&retval, @@ -2889,8 +2889,8 @@ static int gdb_query_packet(struct connection *connection, &size, "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", GDB_BUFFER_SIZE, - ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', - (gdb_target_desc_supported == 1) ? '+' : '-'); + (gdb_use_memory_map && (flash_get_bank_count() > 0)) ? '+' : '-', + gdb_target_desc_supported ? '+' : '-'); if (retval != ERROR_OK) { gdb_send_error(connection, 01); @@ -3280,13 +3280,13 @@ static int gdb_v_packet(struct connection *connection, /* if flash programming disabled - send a empty reply */ - if (gdb_flash_program == 0) { + if (!gdb_flash_program) { gdb_put_packet(connection, "", 0); return ERROR_OK; } if (strncmp(packet, "vFlashErase:", 12) == 0) { - unsigned long addr; + target_addr_t addr; unsigned long length; char const *parse = packet + 12; @@ -3295,7 +3295,7 @@ static int gdb_v_packet(struct connection *connection, 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"); @@ -3343,7 +3343,7 @@ static int gdb_v_packet(struct connection *connection, if (strncmp(packet, "vFlashWrite:", 12) == 0) { int retval; - unsigned long addr; + target_addr_t addr; unsigned long length; char const *parse = packet + 12; @@ -3351,7 +3351,8 @@ static int gdb_v_packet(struct connection *connection, 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; @@ -3378,6 +3379,13 @@ static int gdb_v_packet(struct connection *connection, 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, @@ -3472,7 +3480,7 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, 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; @@ -3557,10 +3565,14 @@ static int gdb_input_inner(struct connection *connection) 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': @@ -3651,9 +3663,9 @@ static int gdb_input_inner(struct connection *connection) 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) { @@ -3749,19 +3761,51 @@ static int gdb_input(struct connection *connection) 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, "");