This is an automated email from Gerrit. Antonio Borneo (borneo.anto...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4828
-- gerrit commit 1fde262047cc0df36218bef9fe8f9fe84e959e2d Author: Antonio Borneo <borneo.anto...@gmail.com> Date: Thu Jun 7 19:13:09 2018 +0200 gdb_server: add keep-alive during memory read/write To avoid gdb to timeout, OpenOCD implements a keep-alive mechanism that consists in sending periodically to gdb empty strings embedded in the "O" remote reply packet. The main purpose of "O" packets is to forward in the gdb console the output of the remote execution; the gdb-remote puts in the "O" packet the string that gdb will print. It's use is restricted to few "running/execution" contexts listed in http://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html and this currently limits the keep-alive capabilities of OpenOCD. Long data transfer (memory R/W) can also cause gdb to timeout if the interface is too slow. In this case the usual keep-alive based on "O" packet cannot be used and, if used, would trigger a protocol error that causes the transfer to be dropped. The slow transfer rate can be simulated by adding some delay in the main loop of mem_ap_write() and mem_ap_read(), then using the gdb commands "dump" and "restore". In the wait loop during a memory R/W, gdb drops any extra character received from the gdb-remote that is not recognized as a valid reply to the memory command. Every dropped character re-initializes the timeout counter and could be used as keep-alive. From gdb 7.0 (released 2009-10-06), an asynchronous notification can also be received from gdb-remote during a memory R/W and has the effect to reset the timeout counter, thus can be used as keep-alive. The notification would be treated as "junk" extra characters by any gdb older than 7.0, being still valid as keep-alive. Check putpkt_binary() and getpkt_sane() in gdb commit 74531fed1f2d662debc2c209b8b3faddceb55960 Currently, only one notification packet ("Stop") is recognized by gdb, and gdb documentation reports that notification packets that are not recognized should be silently dropped. Use 'set debug remote 1' in gdb to dump the received notifications and the junk extra characters. Implement a new log callback that sends a custom "oocd_keepalive" notification packet when keep_alive() prints an empty string. Activate this new callback only during memory transfers. After this commit, the proper calls to keep_alive() have to be added in the loops that code the memory transfers. Change-Id: I7681bdd80e86c79130f62ed85c8f6a5ee1478232 Signed-off-by: Antonio Borneo <borneo.anto...@gmail.com> diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 13e5aca..0ceb032 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1403,11 +1403,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. - * - * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192????? - */ static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { @@ -3106,6 +3101,50 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, gdb_output_con(connection, string); } +/* + * 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_keepalive_callback(void *priv, const char *file, unsigned line, + const char *function, const char *string) +{ + static unsigned int count; + struct connection *connection = priv; + struct gdb_connection *gdb_con = connection->priv; + int i, len; + unsigned int my_checksum = 0; + char buf[22]; + + /* keep_alive() sends empty strings */ + if (gdb_con->busy || string[0]) + return; + + len = sprintf(buf, "%%oocd_keepalive:%2.2x", count); + count = (count + 1) & 255; + for (i = 1; i < len; i++) + my_checksum += buf[i]; + len += sprintf(buf + len, "#%2.2x", my_checksum & 255); + +#ifdef _DEBUG_GDB_IO_ + LOG_DEBUG("sending packet '%s'", buf); +#endif + + gdb_con->busy = true; + gdb_write(connection, buf, len); + gdb_con->busy = false; +} + static void gdb_sig_halted(struct connection *connection) { char sig_reply[4]; @@ -3189,10 +3228,14 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': + log_add_callback(gdb_keepalive_callback, connection); retval = gdb_read_memory_packet(connection, packet, packet_size); + log_remove_callback(gdb_keepalive_callback, connection); break; case 'M': + log_add_callback(gdb_keepalive_callback, connection); retval = gdb_write_memory_packet(connection, packet, packet_size); + log_remove_callback(gdb_keepalive_callback, connection); break; case 'z': case 'Z': @@ -3278,9 +3321,9 @@ static int gdb_input_inner(struct connection *connection) extended_protocol = 0; break; case 'X': + log_add_callback(gdb_keepalive_callback, connection); retval = gdb_write_memory_binary_packet(connection, packet, packet_size); - if (retval != ERROR_OK) - return retval; + log_remove_callback(gdb_keepalive_callback, connection); break; case 'k': if (extended_protocol != 0) { -- _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel