[PATCH v4 11/11] gdb, gdbserver: add AlwaysNonStop remote protocol extension
Mohamed Bouhaouel <[email protected]>
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
From: "Bouhaouel, Mohamed" <[email protected]> Add a new RSP extension allowing remote stubs to declare that a target prefers to operate in non-stop mode. When a stub advertises "AlwaysNonStop+" in its qSupported response: * The stub automatically initializes to non-stop mode. * GDB will operate the stub in non-stop mode (with default settings). * The stub may reject QNonStop:0 requests with descriptive error messages. * GDB allows connection even if 'maint set target-non-stop off' is set, but lets the stub decide whether to accept mode switches. Additionally, gdbserver now accepts --enable-packet=PACKET to enable specific remote protocol packets or extensions at startup. Currently this supports the 'AlwaysNonStop' extension. Reviewed-By: Eli Zaretskii <[email protected]> --- gdb/NEWS | 13 +++ gdb/doc/gdb.texinfo | 46 ++++++++++- gdb/remote.c | 21 +++++ .../gdb.server/enable-always-non-stop.exp | 56 +++++++++++++ gdbserver/server.cc | 79 +++++++++++++++++-- gdbserver/server.h | 2 + gdbserver/target.cc | 6 ++ gdbserver/target.h | 6 ++ 8 files changed, 223 insertions(+), 6 deletions(-) create mode 100644 gdb/testsuite/gdb.server/enable-always-non-stop.exp diff --git a/gdb/NEWS b/gdb/NEWS index ec9b5a33787..4f75a55af5d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -22,6 +22,10 @@ this flag is used gdbserver will not escape special shell characters within the inferior arguments. +* gdbserver now accepts --enable-packet=PACKET to enable specific remote + protocol packets or extensions at startup. Currently this supports + 'AlwaysNonStop' to force the target to always operate in non-stop mode. + * The add-inferior, clone-inferior, and MI -add-inferior commands will now give a warning, and create the new inferior without a connection, when the current inferior's connection, at the time the @@ -116,6 +120,15 @@ intent to remove it in a future release. The s390 64-bit target (s390x-*) remains supported. +* New remote protocol extension 'AlwaysNonStop' allows gdbserver to + indicate that the target prefers to operate in non-stop mode. When a + remote stub advertises 'AlwaysNonStop+' in its qSupported reply, GDB + will operate the stub in non-stop mode (when 'maint set target-non-stop' + is 'auto', the default). If the user explicitly sets 'maint set + target-non-stop off', GDB will allow the connection but the stub may + reject attempts to switch to all-stop mode with a descriptive error + message. + * Configure changes ** --with-babeltrace has been removed. The babeltrace library was diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a698b2b8451..3019cb915f2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -42922,7 +42922,9 @@ does not indicate support. @item maint set target-non-stop off @value{GDBN} does not control the target in non-stop mode even if the -target supports it. +target supports it. Note: targets that prefer non-stop mode (via +@samp{AlwaysNonStop+}) may reject attempts to switch to all-stop mode +with a descriptive error message. @end table Here is how @code{set non-stop} and @code{maint set target-non-stop} @@ -45094,6 +45096,12 @@ Reply: @table @samp @item OK The request succeeded. + +@item @samp{E.@var{message}} +The request failed. This may occur if the stub prefers non-stop mode +and advertised @samp{AlwaysNonStop+} support, and @value{GDBN} attempted to +switch to all-stop mode with @samp{QNonStop:0}. The stub returns a +textual error message describing why the mode switch was rejected. @end table This packet is not probed by default; the remote stub must request it, @@ -45511,6 +45519,22 @@ multiple-watchpoint-addresses-packet} command (@pxref{Remote Configuration, set remote multiple-watchpoint-addresses-packet}). @end table +@item AlwaysNonStop +This feature indicates that @value{GDBN} supports remote stubs that +prefer non-stop mode operation. If the stub advertises +@samp{AlwaysNonStop+}, it will run in non-stop mode, similar to +the setting @code{maint set target-non-stop on}. If @value{GDBN} +attempts to switch the target to all-stop mode, the stub may reject +the request with a descriptive error message. + +Note: @samp{AlwaysNonStop+} requires @samp{QNonStop+} support. +If a stub advertises @samp{AlwaysNonStop+} without @samp{QNonStop+}, +the @samp{AlwaysNonStop+} extension will be silently ignored by @value{GDBN}. + +Use of this feature is controlled by the @code{set remote +always-non-stop-feature-packet} command (@pxref{Remote +Configuration, set remote always-non-stop-feature-packet}). + Stubs should ignore any unknown values for @var{gdbfeature}. Any @value{GDBN} which sends a @samp{qSupported} packet supports receiving packets of unlimited length (earlier @@ -45907,6 +45931,13 @@ packet (@pxref{qXfer fdpic loadmap read}). The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). +@item AlwaysNonStop +The remote stub prefers non-stop mode operation, may reject +@samp{QNonStop:0} requests with a descriptive error message, and +automatically initializes to non-stop mode. This feature must be +advertised together with @samp{QNonStop+}; if advertised without it, +the feature will be silently ignored by @value{GDBN}. @xref{QNonStop}. + @item QCatchSyscalls The remote stub understands the @samp{QCatchSyscalls} packet (@pxref{QCatchSyscalls}). @@ -52204,6 +52235,19 @@ option special shell characters will not be escaped. When @command{gdbserver} starts a new shell in order to invoke the inferior, this new shell will expand any special shell characters. +@item --enable-packet=@var{packet}@r{[},@var{packet}@dots{}@r{]} +Enable specific remote protocol packets or extensions at startup. +The @var{packet} argument can be one of the following: + +@table @code +@item AlwaysNonStop +Force the target to always operate in non-stop mode. When this +extension is enabled, @command{gdbserver} will reject any attempts +by @value{GDBN} to switch to all-stop mode with a descriptive error +message. This is useful for targets that require non-stop mode +for correct operation. +@end table + @c --disable-packet is not documented for users. @c --disable-randomization and --no-disable-randomization are superseded by diff --git a/gdb/remote.c b/gdb/remote.c index b1bc1283b9a..fc5fb6cd160 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -323,6 +323,9 @@ enum { /* Support for the QNonStop packet. */ PACKET_QNonStop, + /* Support for AlwaysNonStop extension. */ + PACKET_AlwaysNonStop_feature, + /* Support for the QThreadEvents packet. */ PACKET_QThreadEvents, @@ -1442,6 +1445,8 @@ class remote_target : public process_stratum_target void check_binary_download (CORE_ADDR addr); + bool always_non_stop_p () override; + target_xfer_status remote_write_bytes_aux (const char *header, CORE_ADDR memaddr, const gdb_byte *myaddr, @@ -6133,6 +6138,8 @@ static const struct protocol_feature remote_protocol_features[] = { { "multiprocess", PACKET_DISABLE, remote_supported_packet, PACKET_multiprocess_feature }, { "QNonStop", PACKET_DISABLE, remote_supported_packet, PACKET_QNonStop }, + { "AlwaysNonStop", PACKET_DISABLE, remote_supported_packet, + PACKET_AlwaysNonStop_feature }, { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_siginfo_read }, { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet, @@ -9817,6 +9824,18 @@ remote_target::check_binary_download (CORE_ADDR addr) } } +/* Determine whether the remote target operates in non-stop mode. + Returns true if the target advertises AlwaysNonStop, and supports + QNonStop for asynchronous execution and stop notifications. */ + +bool +remote_target::always_non_stop_p () +{ + return ((m_features.packet_support (PACKET_QNonStop) == PACKET_ENABLE) + && (m_features.packet_support (PACKET_AlwaysNonStop_feature) + == PACKET_ENABLE)); +} + /* Helper function to resize the payload in order to try to get a good alignment. We try to write an amount of data such that the next write will start on an address aligned on REMOTE_ALIGN_WRITES. */ @@ -17073,6 +17092,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (PACKET_multi_wp_addr, "multi-wp-addr", "multiple-watchpoint-addresses", 0); + add_packet_config_cmd (PACKET_AlwaysNonStop_feature, + "AlwaysNonStop", "always-non-stop-feature", 0); /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ diff --git a/gdb/testsuite/gdb.server/enable-always-non-stop.exp b/gdb/testsuite/gdb.server/enable-always-non-stop.exp new file mode 100644 index 00000000000..c05f58847bb --- /dev/null +++ b/gdb/testsuite/gdb.server/enable-always-non-stop.exp @@ -0,0 +1,56 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2026 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that the --enable-packet=AlwaysNonStop gdbserver command line option +# causes GDB to operate gdbserver with target-non-stop mode enabled. + +load_lib gdbserver-support.exp + +require allow_gdbserver_tests + +standard_testfile server.c + +if { [build_executable "failed to prepare" $testfile $srcfile] == -1 } { + return +} +set target_binfile [gdb_remote_download target $binfile] + +save_vars { ::GDBFLAGS } { + if { ![is_remote host] && ![is_remote target] } { + set ::GDBFLAGS "$::GDBFLAGS -ex \"set sysroot\"" + } + clean_restart $::testfile +} +gdb_test "disconnect" ".*" + +# Start gdbserver with --enable-packet=AlwaysNonStop +set res [gdbserver_start "--enable-packet=AlwaysNonStop" $::target_binfile] +set protocol [lindex $res 0] +set port [lindex $res 1] + +set res [gdb_target_cmd $protocol $port] +if { ![gdb_assert {$res == 0} "connect"] } { + return +} + +# Check that target-non-stop is on +gdb_test "maint show target-non-stop" \ + "Whether the target is always in non-stop mode is auto \\(currently on\\)\\." \ + "verify target-non-stop is on" + +# continue to end +gdb_continue_to_end diff --git a/gdbserver/server.cc b/gdbserver/server.cc index 4a727c465f0..614e807271f 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -147,6 +147,9 @@ bool disable_packet_qC; bool disable_packet_qfThreadInfo; bool disable_packet_T; +/* Set if you want to enable optional packets or extensions via CLI. */ +bool enable_always_non_stop; + static unsigned char *mem_buf; /* A sub-class of 'struct notif_event' for stop, holding information @@ -838,10 +841,19 @@ handle_general_set (char *own_buf) } req_str = req ? "non-stop" : "all-stop"; - if (the_target->start_non_stop (req == 1) != 0) + + try { - fprintf (stderr, "Setting %s mode failed\n", req_str); - write_enn (own_buf); + if (the_target->start_non_stop (req == 1) != 0) + { + sprintf (own_buf, "E.Setting %s mode failed.", req_str); + return; + } + } + catch (const gdb_exception_error &exception) + { + /* The target rejected the setting, forward the error message. */ + sprintf (own_buf, "E.%s", exception.what ()); return; } @@ -2812,7 +2824,11 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) strcat (own_buf, ";exec-events+"); if (target_supports_non_stop ()) - strcat (own_buf, ";QNonStop+"); + { + strcat (own_buf, ";QNonStop+"); + if (target_always_non_stop ()) + strcat (own_buf, ";AlwaysNonStop+"); + } if (target_supports_disable_randomization ()) strcat (own_buf, ";QDisableRandomization+"); @@ -2876,6 +2892,19 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (cs.single_inferior_argument) strcat (own_buf, ";single-inf-arg+"); + /* If the target requires non-stop mode, initialize it now rather + than waiting for GDB to request it via QNonStop:1. */ + if (target_supports_non_stop () && target_always_non_stop ()) + { + if (the_target->start_non_stop (true) != 0) + error ("Cannot initialize target: requires non-stop mode but " + "non-stop mode initialization failed."); + + non_stop = true; + remote_debug_printf ("Target requires non-stop mode: " + "enabled at startup.\n"); + } + /* Reinitialize components as needed for the new connection. */ hostio_handle_new_gdb_connection (); target_handle_new_gdb_connection (); @@ -3931,6 +3960,10 @@ gdbserver_usage (FILE *stream) " Options:\n" " vCont, vConts, T, Tthread, qC, qfThreadInfo and\n" " threads (disable all threading packets).\n" + " --enable-packet=OPT1[,OPT2,...]\n" + " Enable support for RSP packets or extensions.\n" + " Options:\n" + " AlwaysNonStop.\n" "\n" "For more information, consult the GDB manual (available as on-line \n" "info or a printed manual).\n"); @@ -3951,6 +3984,13 @@ gdbserver_show_disableable (FILE *stream) " T \tAll 'T' packets\n"); } +static void +gdbserver_show_enableable (FILE *stream) +{ + fprintf (stream, "Enableable packets:\n" + " AlwaysNonStop\tForce AlwaysNonStop extension\n"); +} + /* Start up the event loop. This is the entry point to the event loop. */ @@ -4186,7 +4226,7 @@ captured_main (int argc, char *argv[]) enum opts { OPT_VERSION = 1, OPT_HELP, OPT_ATTACH, OPT_MULTI, OPT_WRAPPER, OPT_DEBUG, OPT_DEBUG_FILE, OPT_DEBUG_FORMAT, OPT_DISABLE_PACKET, - OPT_DISABLE_RANDOMIZATION, OPT_NO_DISABLE_RANDOMIZATION, + OPT_ENABLE_PACKET, OPT_DISABLE_RANDOMIZATION, OPT_NO_DISABLE_RANDOMIZATION, OPT_STARTUP_WITH_SHELL, OPT_NO_STARTUP_WITH_SHELL, OPT_ONCE, OPT_SELFTEST, OPT_NO_ESCAPE }; @@ -4204,6 +4244,9 @@ captured_main (int argc, char *argv[]) /* --disable-packet is optional_argument only so that we can print a better help list when the argument is missing. */ {"disable-packet", optional_argument, nullptr, OPT_DISABLE_PACKET}, + /* --enable-packet is optional_argument only so that we can print a + better help list when the argument is missing. */ + {"enable-packet", optional_argument, nullptr, OPT_ENABLE_PACKET}, {"disable-randomization", no_argument, nullptr, OPT_DISABLE_RANDOMIZATION}, {"no-disable-randomization", no_argument, nullptr, @@ -4411,6 +4454,32 @@ captured_main (int argc, char *argv[]) } break; + case OPT_ENABLE_PACKET: + { + char *packets = optarg; + if (packets == nullptr) + { + gdbserver_show_enableable (stdout); + exit (1); + } + char *saveptr; + for (char *tok = strtok_r (packets, ",", &saveptr); + tok != nullptr; + tok = strtok_r (nullptr, ",", &saveptr)) + { + if (streq ("AlwaysNonStop", tok)) + enable_always_non_stop = true; + else + { + fprintf (stderr, "Don't know how to enable \"%s\".\n\n", + tok); + gdbserver_show_enableable (stderr); + exit (1); + } + } + } + break; + case OPT_DISABLE_RANDOMIZATION: cs.disable_randomization = 1; break; diff --git a/gdbserver/server.h b/gdbserver/server.h index bbba3650de7..4238882dfc7 100644 --- a/gdbserver/server.h +++ b/gdbserver/server.h @@ -74,6 +74,8 @@ extern bool disable_packet_qC; extern bool disable_packet_qfThreadInfo; extern bool disable_packet_T; +extern bool enable_always_non_stop; + extern bool run_once; extern bool non_stop; diff --git a/gdbserver/target.cc b/gdbserver/target.cc index 43ef421df74..6ce584c8aba 100644 --- a/gdbserver/target.cc +++ b/gdbserver/target.cc @@ -498,6 +498,12 @@ process_stratum_target::supports_non_stop () return false; } +bool +process_stratum_target::always_non_stop () +{ + return enable_always_non_stop; +} + bool process_stratum_target::async (bool enable) { diff --git a/gdbserver/target.h b/gdbserver/target.h index 82eab9d1243..cdd1e26f2d6 100644 --- a/gdbserver/target.h +++ b/gdbserver/target.h @@ -260,6 +260,9 @@ class process_stratum_target /* Return true if non-stop mode is supported. */ virtual bool supports_non_stop (); + /* Return true if target must run in non-stop mode. */ + virtual bool always_non_stop (); + /* Enables async target events. Returns the previous enable state. */ virtual bool async (bool enable); @@ -583,6 +586,9 @@ int kill_inferior (process_info *proc); #define target_supports_non_stop() \ the_target->supports_non_stop () +#define target_always_non_stop() \ + the_target->always_non_stop () + #define target_async(enable) \ the_target->async (enable) -- 2.43.0 Intel Deutschland GmbH Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany Tel: +49 89 991 430, www.intel.de Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell Chairperson of the Supervisory Board: Nicole Lau Registered Seat: Munich Commercial Register: Amtsgericht Muenchen HRB 186928