diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d7f071ba98..f734aed9c7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +2008-08-12 Pedro Alves + + Add no-ack mode to the remote protocol --- optionally stop ACKing + packets and responses when we have a reliable communication + medium. + + Based on Apple's GDB, by Jason Molenda + + * remote.c (struct remote_state): Add noack_mode field. + (PACKET_QStartNoAckMode): New. + (remote_start_remote): Don't any outstanding packet here. + (remote_open_1): Clear noack_mode. Ack any outstanding packet + here. Activate noack mode if requested. + (remote_protocol_features): Add QStartNoAckMode. + (remote_open_1): + (putpkt_binary): Don't send ack in noack mode. + (read_frame): Don't recompute the checksum in noack mode. + (getpkt_sane): Skip sending ack if in noack mode. + (_initialize_remote): Add set/show remote noack mode. + * NEWS: Note the new features. + 2008-08-11 Kevin Buettner * rs6000-tdep.c (BL_MASK, BL_INSTRUCTION, BL_DISPLACEMENT_MASK): diff --git a/gdb/NEWS b/gdb/NEWS index eb2e280a05..b7ef61cf23 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -22,6 +22,11 @@ completions will be "f1" and "f2". qSearch:memory: Search memory for a sequence of bytes. +QStartNoAckMode + Turn off `+'/`-' protocol acknowledgments to permit more efficient + operation over reliable transport links. Use of this packet is + controlled by the `set remote noack-packet' command. + * Removed remote protocol undocumented extension An undocumented extension to the remote protocol's `S' stop reply @@ -62,6 +67,9 @@ have also been fixed. gdbserver executable to debug both 32-bit and 64-bit programs. (This requires gdbserver itself to be built as a 64-bit executable.) + - gdbserver uses the new noack protocol mode for TCP connections to + reduce communications latency, if also supported and enabled in GDB. + * Python scripting GDB now has support for scripting using Python. Whether this is diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 872fe60d5b..7a434f30ce 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,13 @@ +2008-08-12 Sandra Loosemore + + * gdb.texinfo (Remote Configuration): Document set remote noack-packet. + (Remote Protocol): Add Packet Acknowledgment to menu. + (Overview): Mention +/- can be disabled, and point to new section + where this is discussed in detail. + (General Query Packets): Document QStartNoAckMode packet, and + corresponding qSupported reply. + (Packet Acknowledgment): New section. + 2008-08-11 Sandra Loosemore Pedro Alves diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 72455f37c6..8cbef2f4bd 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -13949,6 +13949,10 @@ are: @item @code{hostio-unlink-packet} @tab @code{vFile:unlink} @tab @code{remote delete} + +@item @code{noack-packet} +@tab @code{QStartNoAckMode} +@tab Packet acknowledgment @end multitable @node Remote Stub @@ -15631,7 +15635,7 @@ As usual, you can inquire about the @code{mipsfpu} variable with You can control the timeout used while waiting for a packet, in the MIPS remote protocol, with the @code{set timeout @var{seconds}} command. The default is 5 seconds. Similarly, you can control the timeout used while -waiting for an acknowledgement of a packet with the @code{set +waiting for an acknowledgment of a packet with the @code{set retransmit-timeout @var{seconds}} command. The default is 3 seconds. You can inspect both values with @code{show timeout} and @code{show retransmit-timeout}. (These commands are @emph{only} available when @@ -24144,6 +24148,7 @@ Show the current setting of the target wait timeout. * Tracepoint Packets:: * Host I/O Packets:: * Interrupts:: +* Packet Acknowledgment:: * Examples:: * File-I/O Remote Protocol Extension:: * Library List Format:: @@ -24193,7 +24198,6 @@ That @var{sequence-id} was appended to the acknowledgment. @value{GDBN} has never output @var{sequence-id}s. Stubs that handle packets added since @value{GDBN} 5.0 must not accept @var{sequence-id}. -@cindex acknowledgment, for @value{GDBN} remote When either the host or the target machine receives a packet, the first response expected is an acknowledgment: either @samp{+} (to indicate the package was received correctly) or @samp{-} (to request @@ -24205,6 +24209,10 @@ retransmission): @end smallexample @noindent +The @samp{+}/@samp{-} acknowledgments can be disabled +once a connection is established. +@xref{Packet Acknowledgment}, for details. + The host (@value{GDBN}) sends @var{command}s, and the target (the debugging stub incorporated in your program) sends a @var{response}. In the case of step and continue @var{command}s, the response is only sent @@ -25259,6 +25267,23 @@ A badly formed request or an error was encountered while searching memory. An empty reply indicates that @samp{qSearch:memory} is not recognized. @end table +@item QStartNoAckMode +@cindex @samp{QStartNoAckMode} packet +@anchor{QStartNoAckMode} +Request that the remote stub disable the normal @samp{+}/@samp{-} +protocol acknowledgments (@pxref{Packet Acknowledgment}). + +Reply: +@table @samp +@item OK +The stub has switched to no-acknowledgment mode. +@value{GDBN} acknowledges this reponse, +but neither the stub nor @value{GDBN} shall send or expect further +@samp{+}/@samp{-} acknowledgments in the current connection. +@item +An empty reply indicates that the stub does not support no-acknowledgment mode. +@end table + @item qSupported @r{[}:@var{gdbfeature} @r{[};@var{gdbfeature}@r{]}@dots{} @r{]} @cindex supported packets, remote query @cindex features of the remote protocol @@ -25400,6 +25425,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QStartNoAckMode} +@tab No +@tab @samp{-} +@tab Yes + @end multitable These are the currently defined stub features, in more detail: @@ -25444,6 +25474,10 @@ The remote stub understands the @samp{qXfer:spu:write} packet The remote stub understands the @samp{QPassSignals} packet (@pxref{QPassSignals}). +@item QStartNoAckMode +The remote stub understands the @samp{QStartNoAckMode} packet and +prefers to operate in no-acknowledgment mode. @xref{Packet Acknowledgment}. + @end table @item qSymbol:: @@ -25988,6 +26022,50 @@ Reply Packets (@pxref{Stop Reply Packets}) to @value{GDBN} as a result of successfully stopping the program. Interrupts received while the program is stopped will be discarded. +@node Packet Acknowledgment +@section Packet Acknowledgment + +@cindex acknowledgment, for @value{GDBN} remote +@cindex packet acknowledgment, for @value{GDBN} remote +By default, when either the host or the target machine receives a packet, +the first response expected is an acknowledgment: either @samp{+} (to indicate +the package was received correctly) or @samp{-} (to request retransmission). +This mechanism allows the @value{GDBN} remote protocol to operate over +unreliable transport mechanisms, such as a serial line. + +In cases where the transport mechanism is itself reliable (such as a pipe or +TCP connection), the @samp{+}/@samp{-} acknowledgments are redundant. +It may be desirable to disable them in that case to reduce communication +overhead, or for other reasons. This can be accomplished by means of the +@samp{QStartNoAckMode} packet; @pxref{QStartNoAckMode}. + +When in no-acknowledgment mode, neither the stub nor @value{GDBN} shall send or +expect @samp{+}/@samp{-} protocol acknowledgments. The packet +and response format still includes the normal checksum, as described in +@ref{Overview}, but the checksum may be ignored by the receiver. + +If the stub supports @samp{QStartNoAckMode} and prefers to operate in +no-acknowledgment mode, it should report that to @value{GDBN} +by including @samp{QStartNoAckMode+} in its response to @samp{qSupported}; +@pxref{qSupported}. +If @value{GDBN} also supports @samp{QStartNoAckMode} and it has not been +disabled via the @code{set remote noack-packet off} command +(@pxref{Remote Configuration}), +@value{GDBN} may then send a @samp{QStartNoAckMode} packet to the stub. +Only then may the stub actually turn off packet acknowledgments. +@value{GDBN} sends a final @samp{+} acknowledgment of the stub's @samp{OK} +response, which can be safely ignored by the stub. + +Note that @code{set remote noack-packet} command only affects negotiation +between @value{GDBN} and the stub when subsequent connections are made; +it does not affect the protocol acknowledgment state for any current +connection. +Since @samp{+}/@samp{-} acknowledgments are enabled by default when a +new connection is established, +there is also no protocol request to re-enable the acknowledgments +for the current connection, once disabled. + + @node Examples @section Examples diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 8e6198164e..a4ea4bea73 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,15 @@ +2008-08-12 Pedro Alves + + * remote-utils.c (noack_mode, transport_is_reliable): New globals. + (remote_open): Set or clear transport_is_reliable. + (putpkt_binary): Don't expect acks in noack mode. + (getpkt): Don't send ack/nac in noack mode. + * server.c (handle_general_set): Handle QStartNoAckMode. + (handle_query): If connected by tcp pass QStartNoAckMode+ in + qSupported. + (main): Reset noack_mode on every connection. + * server.h (noack_mode): Declare. + 2008-08-07 Ralf Wildenhues * Makefile.in (GDBREPLAY_OBS): New variable. diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index e062be8fc1..b5665f5895 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -99,6 +99,11 @@ static int remote_desc = INVALID_DESCRIPTOR; extern int using_threads; extern int debug_threads; +/* If true, then GDB has requested noack mode. */ +int noack_mode = 0; +/* If true, then we tell GDB to use noack mode by default. */ +int transport_is_reliable = 0; + #ifdef USE_WIN32API # define read(fd, buf, len) recv (fd, (char *) buf, len, 0) # define write(fd, buf, len) send (fd, (char *) buf, len, 0) @@ -181,6 +186,8 @@ remote_open (char *name) fprintf (stderr, "Remote debugging using %s\n", name); #endif /* USE_WIN32API */ + + transport_is_reliable = 0; } else { @@ -267,6 +274,8 @@ remote_open (char *name) /* Convert IP address to string. */ fprintf (stderr, "Remote debugging from host %s\n", inet_ntoa (sockaddr.sin_addr)); + + transport_is_reliable = 1; } #if defined(F_SETFL) && defined (FASYNC) @@ -551,6 +560,17 @@ putpkt_binary (char *buf, int cnt) return -1; } + if (noack_mode) + { + /* Don't expect an ack then. */ + if (remote_debug) + { + fprintf (stderr, "putpkt (\"%s\"); [noack mode]\n", buf2); + fflush (stderr); + } + break; + } + if (remote_debug) { fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2); @@ -774,23 +794,34 @@ getpkt (char *buf) if (csum == (c1 << 4) + c2) break; + if (noack_mode) + { + fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s [no-ack-mode, Bad medium?]\n", + (c1 << 4) + c2, csum, buf); + /* Not much we can do, GDB wasn't expecting an ack/nac. */ + break; + } + fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", (c1 << 4) + c2, csum, buf); write (remote_desc, "-", 1); } - if (remote_debug) + if (!noack_mode) { - fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf); - fflush (stderr); - } + if (remote_debug) + { + fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf); + fflush (stderr); + } - write (remote_desc, "+", 1); + write (remote_desc, "+", 1); - if (remote_debug) - { - fprintf (stderr, "[sent ack]\n"); - fflush (stderr); + if (remote_debug) + { + fprintf (stderr, "[sent ack]\n"); + fflush (stderr); + } } return bp - buf; diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 1fa16942b8..60df3d8de0 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -270,6 +270,19 @@ handle_general_set (char *own_buf) return; } + if (strcmp (own_buf, "QStartNoAckMode") == 0) + { + if (remote_debug) + { + fprintf (stderr, "[noack mode enabled]\n"); + fflush (stderr); + } + + noack_mode = 1; + write_ok (own_buf); + return; + } + /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0; @@ -777,6 +790,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) qXfer:feature:read at all, we will never be re-queried. */ strcat (own_buf, ";qXfer:features:read+"); + if (transport_is_reliable) + strcat (own_buf, ";QStartNoAckMode+"); return; } @@ -1447,6 +1462,7 @@ main (int argc, char *argv[]) while (1) { + noack_mode = 0; remote_open (port); restart: diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index b519696827..817b5c47ef 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -175,6 +175,8 @@ extern void hostio_last_error_from_errno (char *own_buf); extern int remote_debug; extern int all_symbols_looked_up; +extern int noack_mode; +extern int transport_is_reliable; int putpkt (char *buf); int putpkt_binary (char *buf, int len); diff --git a/gdb/remote.c b/gdb/remote.c index 2e626a9ddc..2782d056b3 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -274,6 +274,11 @@ struct remote_state skip calling getpkt. This flag is set when BUF contains a stop reply packet and the target is not waiting. */ int cached_wait_status; + + /* True, if in no ack mode. That is, neither GDB nor the stub will + expect acks from each other. The connection is assumed to be + reliable. */ + int noack_mode; }; /* This data could be associated with a target, but we do not always @@ -960,6 +965,7 @@ enum { PACKET_qSearch_memory, PACKET_vAttach, PACKET_vRun, + PACKET_QStartNoAckMode, PACKET_MAX }; @@ -2297,9 +2303,6 @@ remote_start_remote (struct ui_out *uiout, void *opaque) immediate_quit++; /* Allow user to interrupt it. */ - /* Ack any packet which the remote side has already sent. */ - serial_write (remote_desc, "+", 1); - /* Check whether the target is running now. */ putpkt ("?"); getpkt (&rs->buf, &rs->buf_size, 0); @@ -2557,6 +2560,8 @@ static struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_spu_write }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, + PACKET_QStartNoAckMode }, }; static void @@ -2690,6 +2695,8 @@ static void remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended_p) { struct remote_state *rs = get_remote_state (); + struct packet_config *noack_config; + if (name == 0) error (_("To open a remote debug connection, you need to specify what\n" "serial device is attached to the remote system\n" @@ -2771,6 +2778,7 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended remote_query_supported or as they are needed. */ init_all_packet_configs (); rs->explicit_packet_size = 0; + rs->noack_mode = 0; general_thread = not_sent_ptid; continue_thread = not_sent_ptid; @@ -2779,11 +2787,39 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended use_threadinfo_query = 1; use_threadextra_query = 1; + /* Ack any packet which the remote side has already sent. */ + serial_write (remote_desc, "+", 1); + /* The first packet we send to the target is the optional "supported packets" request. If the target can answer this, it will tell us which later probes to skip. */ remote_query_supported (); + /* Next, we possibly activate noack mode. + + If the QStartNoAckMode packet configuration is set to AUTO, + enable noack mode if the stub reported a wish for it with + qSupported. + + If set to TRUE, then enable noack mode even if the stub didn't + report it in qSupported. If the stub doesn't reply OK, the + session ends with an error. + + If FALSE, then don't activate noack mode, regardless of what the + stub claimed should be the default with qSupported. */ + + noack_config = &remote_protocol_packets[PACKET_QStartNoAckMode]; + + if (noack_config->detect == AUTO_BOOLEAN_TRUE + || (noack_config->detect == AUTO_BOOLEAN_AUTO + && noack_config->support == PACKET_ENABLE)) + { + putpkt ("QStartNoAckMode"); + getpkt (&rs->buf, &rs->buf_size, 0); + if (packet_ok (rs->buf, noack_config) == PACKET_OK) + rs->noack_mode = 1; + } + /* Next, if the target can specify a description, read it. We do this before anything involving memory or registers. */ target_find_description (); @@ -4789,6 +4825,11 @@ putpkt_binary (char *buf, int cnt) if (serial_write (remote_desc, buf2, p - buf2)) perror_with_name (_("putpkt: write failed")); + /* If this is a no acks version of the remote protocol, send the + packet and move on. */ + if (rs->noack_mode) + break; + /* Read until either a timeout occurs (-2) or '+' is read. */ while (1) { @@ -4865,6 +4906,7 @@ putpkt_binary (char *buf, int cnt) } #endif } + return 0; } /* Come here after finding the start of a frame when we expected an @@ -4920,6 +4962,7 @@ read_frame (char **buf_p, long bc; int c; char *buf = *buf_p; + struct remote_state *rs = get_remote_state (); csum = 0; bc = 0; @@ -4965,6 +5008,12 @@ read_frame (char **buf_p, return -1; } + /* Don't recompute the checksum; with no ack packets we + don't have any way to indicate a packet retransmission + is necessary. */ + if (rs->noack_mode) + return bc; + pktcsum = (fromhex (check_0) << 4) | fromhex (check_1); if (csum == pktcsum) return bc; @@ -5123,20 +5172,28 @@ getpkt_sane (char **buf, long *sizeof_buf, int forever) fputstrn_unfiltered (*buf, val, 0, gdb_stdlog); fprintf_unfiltered (gdb_stdlog, "\n"); } - serial_write (remote_desc, "+", 1); + + /* Skip the ack char if we're in no-ack mode. */ + if (!rs->noack_mode) + serial_write (remote_desc, "+", 1); return val; } /* Try the whole thing again. */ retry: - serial_write (remote_desc, "-", 1); + /* Skip the nack char if we're in no-ack mode. */ + if (!rs->noack_mode) + serial_write (remote_desc, "-", 1); } /* We have tried hard enough, and just can't receive the packet. Give up. */ printf_unfiltered (_("Ignoring packet error, continuing...\n")); - serial_write (remote_desc, "+", 1); + + /* Skip the ack char if we're in no-ack mode. */ + if (!rs->noack_mode) + serial_write (remote_desc, "+", 1); return -1; } @@ -7531,6 +7588,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_vRun], "vRun", "run", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartNoAckMode], + "QStartNoAckMode", "noack", 0); + /* Keep the old ``set remote Z-packet ...'' working. Each individual Z sub-packet has its own set and show commands, but users may have sets to this variable in their .gdbinit files (or in their