Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH] gdb: use current executable for 'remote exec-file' in some cases
@ 2025-10-06 15:07 Andrew Burgess
  2025-10-06 15:43 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-10-06 15:07 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

This commit allows GDB to make use of the file set with the 'file'
command when starting a new inferior on an extended-remote target.
There are however some restrictions.

If the user has used 'set remote exec-file', then this setting is
always used in preference to the file set with the 'file' command.

Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
that the remote target has an executable set, then this will be used
in preference to the file set with the 'file' command; this preserves
GDB's existing behaviour.  In effect, when GDB connects to the remote
target, the remote sets the 'remote exec-file' and this prevents GDB
from using the 'file' filename.

And, GDB can only use the file set with the 'file' command if it
believes that both GDB and the remote target will both be able to
access this file.  This means that one of these is true:

  + the the remote_target::filesystem_is_local function returns
    true (see the implementation of that function for details of when
    this can happen).  This means GDB and the remote target can see
    the same file system, GDB can just use the current executable's
    filename as is, or

  + the user has set the 'file' to something with a 'target:' prefix,
    e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
    the exec filename without the 'target:' prefix, this filename is,
    by definition, something the remote target can see, or

  + the sysroot has been updated by the user and no longer contains a
    'target:' prefix.  In this case, if the 'file' filename is within
    the sysroot, then it is assumed the remote will also be able to
    see a file with the same filename.  For example, if the sysroot is
    '/aa/', and the current executable is '/aa/bb/cc', then GDB will
    tell the remote to run '/bb/cc'.  One common case here is when the
    sysroot is set to the empty string, which is usually done when GDB
    and the remote target can see the same filesystem, in this case
    GDB will use the current executable's filename unmodified.

If one of these conditions is met, then GDB will use the current
executable's filename (with possible modifications as mentioned
above), when starting a new extended-remote inferior, in all other
cases, GDB will use the file name  set with 'set remote exec-file'.

This change could be useful any time a user is running a remote target
on the same machine as GDB, but I am specifically thinking of the case
where GDB is using a tool other than gdbserver, e.g. valgrind, as this
saves one additional step that a user must remember.  The current
steps to start valgrind with GDB, as given on the valgrind
website (https://valgrind.org/docs/manual/manual-core-adv.html) are:

  $ gdb prog
  (gdb) set remote exec-file prog
  (gdb) set sysroot /
  (gdb) target extended-remote | vgdb --multi --vargs -q
  (gdb) start

With this GDB work, and once support for the qExecAndArgs packet is
added to valgrind, then the 'set remote exec-file' line can be dropped
from those instructions.

This commit also extends the 'show remote exec-file' command so that
GDB will display the automatic value that it plans to use.  Here's an
example of the new output:

  $ gdb -q /tmp/hello
  Reading symbols from /tmp/hello...
  (gdb) set sysroot
  (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
  Remote debugging using | ./gdbserver/gdbserver --multi --once -
  Remote debugging using stdio
  (gdb) show remote exec-file
  The remote exec-file is unset, using automatic value "/tmp/hello".

The last line shows the new output.
---
 gdb/NEWS                             |   7 ++
 gdb/doc/gdb.texinfo                  |   4 +-
 gdb/remote.c                         | 153 ++++++++++++++++++++++---
 gdb/testsuite/gdb.server/ext-run.exp | 160 ++++++++++++++++++++++-----
 4 files changed, 282 insertions(+), 42 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 2c73776944f..cfea3cf95c9 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,13 @@
   subsequent runs of the inferior will use the same arguments as the
   first run.
 
+* When connected to an extended-remote target which does not have an
+  executable specified, if the current executable is specified using a
+  'target:' prefix; or if the sysroot does not have a 'target:'
+  prefix, and the current executable is within the sysroot; then GDB
+  can use the current executable name in order to start inferiors on
+  the remote without having to 'set remote exec-file'.
+
 * New targets
 
 GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1b463b167e7..efd9d80de07 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24668,7 +24668,9 @@ Remote Configuration
 Select the file used for @code{run} with @code{target
 extended-remote}.  This should be set to a filename valid on the
 target system.  If it is not set, the target will use a default
-filename (e.g.@: the last program run).
+filename (e.g.@: the last program run, or a filename derived from the
+current executable if @value{GDBN} and the remote can see the same
+file system).
 
 When connecting to a remote system, with @kbd{target extended-remote}
 or @kbd{target remote}, if the remote server supports the
diff --git a/gdb/remote.c b/gdb/remote.c
index ce6cfdc3bfb..edefdee57e2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -46,6 +46,7 @@
 #include "gdbsupport/rsp-low.h"
 #include "disasm.h"
 #include "location.h"
+#include "filenames.h"
 
 #include "gdbsupport/gdb_sys_time.h"
 
@@ -1555,8 +1556,42 @@ class extended_remote_target final : public remote_target
 
   void post_attach (int) override;
   bool supports_disable_randomization () override;
+
+  /* Return the file name for the executable that GDB should ask the remote
+     target to use when starting an inferior.
+
+     EXEC_FILE is the string passed from GDB core, which is the file name
+     of the current executable, which can be NULL.
+
+     If the user has done 'set remote exec-file', or the remote told GDB
+     which executable to use via the 'qExecAndArgs' packet, then this is
+     the value returned by this function, EXEC_FILE is ignored.
+
+     But if there is no remote exec-file set, then we might be able to use
+     EXEC_FILE, or a variation of EXEC_FILE, as the 'remote exec-file'
+     setting.  This will depend on the value of EXEC_FILE and/or the
+     current gdb_sysroot setting.  In this case the file name derived from
+     EXEC_FILE is returned.
+
+     If neither approach comes up with a suitable file name to run then
+     the empty string is returned.  */
+
+  std::string get_exec_file_for_create_inferior (const char *exec_file);
 };
 
+/* Get a pointer to the current remote target.  If not connected to a
+   remote target, return NULL.  The template argument allows users of this
+   function to ask for 'remote_target' or 'extended_remote_target'.  */
+
+template<typename T = remote_target,
+	 std::enable_if_t<std::is_base_of_v<remote_target, T>, bool> = true>
+static T *
+get_current_remote_target ()
+{
+  target_ops *proc_target = current_inferior ()->process_target ();
+  return dynamic_cast<T *> (proc_target);
+}
+
 struct stop_reply : public notif_event
 {
   /* The identifier of the thread about this event  */
@@ -2038,8 +2073,26 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
   else if (info.second == remote_exec_source::UNSET_VALUE)
-    gdb_printf (file, _("The remote exec-file is unset, the remote has "
-			"no default executable set.\n"));
+    {
+      std::string remote_exec_filename;
+      extended_remote_target *remote
+	= get_current_remote_target<extended_remote_target> ();
+      if (remote != nullptr)
+	{
+	  const char *exec_file = current_program_space->exec_filename ();
+	  remote_exec_filename
+	    = remote->get_exec_file_for_create_inferior (exec_file);
+	}
+
+      if (!remote_exec_filename.empty ())
+	gdb_printf (file, _("The remote exec-file is unset, using "
+			    "automatic value \"%ps\".\n"),
+		    styled_string (file_name_style.style (),
+				   remote_exec_filename.c_str ()));
+      else
+	gdb_printf (file, _("The remote exec-file is unset, the remote has "
+			    "no default executable set.\n"));
+    }
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
@@ -2145,16 +2198,6 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch)
     this->remote_packet_size = (this->sizeof_g_packet * 2 + 32);
 }
 
-/* Get a pointer to the current remote target.  If not connected to a
-   remote target, return NULL.  */
-
-static remote_target *
-get_current_remote_target ()
-{
-  target_ops *proc_target = current_inferior ()->process_target ();
-  return dynamic_cast<remote_target *> (proc_target);
-}
-
 /* Return the current allowed size of a remote packet.  This is
    inferred from the current architecture, and should be used to
    limit the length of outgoing packets.  */
@@ -11313,6 +11356,88 @@ directory: %s"),
     }
 }
 
+/* See class declaration above.  */
+
+std::string
+extended_remote_target::get_exec_file_for_create_inferior
+  (const char *exec_file)
+{
+  const remote_exec_file_info &info
+    = get_remote_exec_file_info (current_program_space);
+
+  /* Historically, when the remote target started a new inferior GDB would
+     ignore the filename from GDB core (EXEC_FILE) and would use whatever
+     value the user had set in 'remote exec-file'.  Now we try to be
+     smarter.
+
+     Obviously, if 'remote exec-file' has been set, then this should be
+     considered definitive.  But if 'remote exec-file' has not been set,
+     then, in some cases, we might be able to use EXEC_FILE, or a
+     derivative of EXEC_FILE.
+
+     It can also happen that EXEC_FILE is NULL.  This is mostly a bit of an
+     edge case where GDB has attached to a running process, and couldn't
+     figure out the filename for the executable.  If the user then does
+     'run' we could end up with EXEC_FILE being NULL.  If this happens then
+     the only option is to use the 'remote exec-file' setting.
+
+     If INFO.SECOND is ::VALUE_FROM_REMOTE or ::VALUE_FROM_GDB then there
+     is a value in 'remote exec-file', we should not do anything with
+     EXEC_FILE and just retain the 'remote exec-file' value.
+
+     If INFO.SECOND is ::UNSET_VALUE then the user hasn't 'set remote
+     exec-file' value, and the remote target has specifically told us (via
+     the qExecAndArgs packet) that it has no default executable set.  In
+     this case, if GDB and the remote can see the same filesystem, we can
+     potentially use EXEC_FILE.
+
+     If INFO.SECOND is ::DEFAULT_VALUE then the user hasn't set a 'remote
+     exec-file' value, but the remote target was unable to tell us (maybe
+     the qExecAndArgs packet isn't supported) if it has a default
+     executable set.  We might be tempted to treat this like the
+     ::UNSET_VALUE case, however, this could potentially break backward
+     compatibility in the case where the remote does have a default
+     executable set.  To maintain compatibility, we send over the 'remote
+     exec-file' setting, whatever it might be.  */
+  if (exec_file != nullptr
+      && info.second == remote_exec_source::UNSET_VALUE)
+    {
+      /* If the user has set the core exec file to a file on the target
+	 then we can just strip the target prefix and use that as the
+	 remote exec file name.  */
+      if (is_target_filename (exec_file))
+	return exec_file + strlen (TARGET_SYSROOT_PREFIX);
+
+      /* If the target filesystem is local then the remote can see
+	 everything GDB can see.  In this case the remote should be able to
+	 access EXEC_FILE.  */
+      if (target_filesystem_is_local ())
+	return exec_file;
+
+      /* If the sysroot is not a target path, then GDB can see a copy of
+	 the remote target's filesystem, or if sysroot is empty, then the
+	 remote and GDB could be sharing a filesystem.
+
+	 In either case, by removing the sysroot from the front of
+	 EXEC_FILE, we can build a filename that the remote can see.  */
+      if (!is_target_filename (gdb_sysroot)
+	  && startswith (exec_file, gdb_sysroot.c_str ()))
+	{
+	  /* If the prefix is '/aa/' and EXEC_FILE is '/aa/bb/cc' then we
+	     only want t remove '/aa' from EXEC_FILE to leave '/bb/cc'.  */
+	  size_t len = gdb_sysroot.length ();
+	  while (len > 0 && IS_DIR_SEPARATOR (gdb_sysroot[len - 1]))
+	    --len;
+
+	  return exec_file + len;
+	}
+    }
+
+  /* The user has set the remote exec-file, or GDB doesn't think the remote
+     target and GDB can see the same filesystem.  */
+  return info.first;
+}
+
 /* In the extended protocol we want to be able to do things like
    "run" and have them basically work as expected.  So we need
    a special create_inferior function.  We support changing the
@@ -11327,7 +11452,9 @@ extended_remote_target::create_inferior (const char *exec_file,
   int run_worked;
   char *stop_reply;
   struct remote_state *rs = get_remote_state ();
-  const std::string &remote_exec_file = get_remote_exec_file ();
+
+  std::string remote_exec_file
+    = get_exec_file_for_create_inferior (exec_file);
 
   /* If running asynchronously, register the target file descriptor
      with the event loop.  */
diff --git a/gdb/testsuite/gdb.server/ext-run.exp b/gdb/testsuite/gdb.server/ext-run.exp
index f4ff546c393..18205e11ec8 100644
--- a/gdb/testsuite/gdb.server/ext-run.exp
+++ b/gdb/testsuite/gdb.server/ext-run.exp
@@ -30,43 +30,147 @@ if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
 # allow_xml_test must be called while gdb is not running.
 set do_xml_test [allow_xml_test]
 
-save_vars { GDBFLAGS } {
-    # If GDB and GDBserver are both running locally, set the sysroot to avoid
-    # reading files via the remote protocol.
-    if { ![is_remote host] && ![is_remote target] } {
-	set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\""
+# This is used as an override function.
+proc do_nothing {} { return 0 }
+
+# Start an exetended-remote gdbserver, connect to it, and then use
+# 'run' to start an inferior.
+#
+# If CLEAR_SYSROOT is true then the 'set sysroot' command is issued,
+# clearing the sysroot, otherwise the sysroot is left unchanged.
+#
+# If SET_REMOTE_EXEC is true then the 'set remote-exec ...' command is
+# issued to point GDB at the executable on the target (after copying
+# the executable over).  Otherwise, we rely on GDB and gdbserver being
+# able to see the same filesystem, remote exec-file is not set, and
+# GDB will just use the path to the executable.
+proc do_test { clear_sysroot set_remote_exec fetch_exec_and_args } {
+
+    # If we don't clear the sysroot, then the sysroot will remain as
+    # 'target:'.  In this case, if we don't 'set remote exec-file'
+    # then GDB will not be able to start a remote inferior.
+    if { !$clear_sysroot && !$set_remote_exec } {
+	return
     }
 
     clean_restart $::testfile
-}
 
-# Make sure we're disconnected, in case we're testing with an
-# extended-remote board, therefore already connected.
-gdb_test "disconnect" ".*"
+    # Disable, or enable, use of the qExecAndArgs packet.
+    gdb_test "set remote fetch-exec-and-args-packet ${fetch_exec_and_args}" \
+	".*"
 
-set target_exec [gdbserver_download_current_prog]
-gdbserver_start_extended
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
 
-gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+    if { $clear_sysroot } {
+	gdb_test_no_output "set sysroot" \
+	    "clear sysroot"
+    } else {
+	set sysroot "UNKNOWN"
+	gdb_test_multiple "show sysroot" "" {
+	    -re -wrap "^The current system root is \"(\[^\r\n\]*)\"\\." {
+		set sysroot $expect_out(1,string)
+		pass $gdb_test_name
+	    }
+	}
 
-gdb_breakpoint main
-gdb_test "run" "Breakpoint.* main .*" "continue to main"
-
-if { [istarget *-*-linux*] } {
-    # On Linux, gdbserver can also report the list of processes.
-    # But only if xml support is compiled in.
-    if { $do_xml_test } {
-	# This is done in a way to avoid the timeout that can occur from
-	# applying .* regexp to large output.
-	gdb_test_lines "info os processes" "get process list" \
-	    "^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	if { $sysroot eq "" } {
+	    gdb_test_no_output "set sysroot target:"
+	} elseif { $sysroot ne "target:" } {
+	    unsupported "unexpected sysroot value"
+	    return
+	}
     }
-}
 
-gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+    gdbserver_start_extended
 
-gdb_load $binfile
-gdb_test "monitor help" "The following monitor commands.*" \
+    # Check the 'remote exec-file' setting before we (possibly) set it
+    # ourselves.
+    if { !$fetch_exec_and_args } {
+	set suffix "the default remote executable will be used"
+    } elseif { !$clear_sysroot} {
+	set suffix "the remote has no default executable set"
+    } else {
+	set file_re [string_to_regexp $::binfile]
+	set suffix "using automatic value \"$file_re\""
+    }
+    gdb_test "show remote exec-file" \
+	"The remote exec-file is unset, ${suffix}\\." \
+	"check remote exec-file is unset"
+
+    if { $set_remote_exec } {
+	set target_exec [gdbserver_download_current_prog]
+	gdb_test_no_output "set remote exec-file $target_exec" \
+	    "set remote exec-file"
+
+	# Check GDB reflect the value we just set.
+	set file_re [string_to_regexp $target_exec]
+	gdb_test "show remote exec-file" \
+	    "The remote exec-file is \"$file_re\"\\." \
+	    "check remote exec-file after set"
+    }
+
+    gdb_breakpoint main
+    gdb_test_multiple "run" "continue to main" {
+	-re -wrap "Breakpoint.* main .*" {
+	    pass $gdb_test_name
+	}
+	-re -wrap "Running the default executable on the remote target failed; try \"set remote exec-file\"." {
+
+	    # If 'set remote exec-file' has been used then we should
+	    # not get here.
+	    gdb_assert {!$set_remote_exec} \
+		"confirm remote exec-file is not set"
+
+	    if {!$fetch_exec_and_args} {
+		# We deliberately disabled GDB's ability to know that
+		# the remote doesn't have a default executable set (by
+		# disabling the qDefaultExecAndArgs packet).  We got
+		# the result we expected, but the inferior is not
+		# running, so we're done with this phase of testing.
+		pass $gdb_test_name
+		return
+	    }
+	}
+    }
+
+    if { [istarget *-*-linux*] } {
+	# On Linux, gdbserver can also report the list of processes.
+	# But only if xml support is compiled in.
+	if { $::do_xml_test } {
+	    # This is done in a way to avoid the timeout that can occur from
+	    # applying .* regexp to large output.
+	    gdb_test_lines "info os processes" "get process list" \
+		"^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	}
+    }
+
+    gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+
+    gdb_load $::binfile
+    gdb_test "monitor help" "The following monitor commands.*" \
         "load new file without any gdbserver inferior"
 
-gdb_test_no_output "monitor exit"
+    gdb_test_no_output "monitor exit"
+}
+
+set clear_sysroot_modes { false }
+set set_remote_exec_modes { true }
+if {![is_remote target] && ![is_remote host]} {
+    lappend set_remote_exec_modes false
+    lappend clear_sysroot_modes true
+}
+
+# This override prevents GDB from automatically setting the 'remote
+# exec-file' when using the extended-remote protocol.  If we want the
+# exec-file set, then this test takes care of it.
+with_override extended_gdbserver_load_last_file do_nothing {
+    foreach_with_prefix clear_sysroot $clear_sysroot_modes {
+	foreach_with_prefix set_remote_exec $set_remote_exec_modes {
+	    foreach_with_prefix fetch_exec_and_args { on off } {
+		do_test $clear_sysroot $set_remote_exec $fetch_exec_and_args
+	    }
+	}
+    }
+}

base-commit: 3c724596812882cc0c3b653330551fae132d6475
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-06 15:07 [PATCH] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
@ 2025-10-06 15:43 ` Eli Zaretskii
  2025-10-09 16:17 ` Simon Marchi
  2025-10-11 13:34 ` [PATCH 0/2] Auto setting of 'remote exec-file' Andrew Burgess
  2 siblings, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2025-10-06 15:43 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <aburgess@redhat.com>
> Cc: Andrew Burgess <aburgess@redhat.com>
> Date: Mon,  6 Oct 2025 16:07:50 +0100
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 2c73776944f..cfea3cf95c9 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -31,6 +31,13 @@
>    subsequent runs of the inferior will use the same arguments as the
>    first run.
>  
> +* When connected to an extended-remote target which does not have an
> +  executable specified, if the current executable is specified using a
> +  'target:' prefix; or if the sysroot does not have a 'target:'
> +  prefix, and the current executable is within the sysroot; then GDB
> +  can use the current executable name in order to start inferiors on
> +  the remote without having to 'set remote exec-file'.

This single sentence is quite a mouth-full.  Could you perhaps split
it into two or more simpler sentences, e.g., the first one describing
the capability and the rest describing the limitations/restrictions?

> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -24668,7 +24668,9 @@ Remote Configuration
>  Select the file used for @code{run} with @code{target
>  extended-remote}.  This should be set to a filename valid on the
>  target system.  If it is not set, the target will use a default
> -filename (e.g.@: the last program run).
> +filename (e.g.@: the last program run, or a filename derived from the
> +current executable if @value{GDBN} and the remote can see the same
> +file system).

This part is okay.

Thanks.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-06 15:07 [PATCH] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2025-10-06 15:43 ` Eli Zaretskii
@ 2025-10-09 16:17 ` Simon Marchi
  2025-10-11 13:34 ` [PATCH 0/2] Auto setting of 'remote exec-file' Andrew Burgess
  2 siblings, 0 replies; 20+ messages in thread
From: Simon Marchi @ 2025-10-09 16:17 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 10/6/25 11:07 AM, Andrew Burgess wrote:
> This commit allows GDB to make use of the file set with the 'file'
> command when starting a new inferior on an extended-remote target.
> There are however some restrictions.
> 
> If the user has used 'set remote exec-file', then this setting is
> always used in preference to the file set with the 'file' command.
> 
> Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
> that the remote target has an executable set, then this will be used
> in preference to the file set with the 'file' command; this preserves
> GDB's existing behaviour.  In effect, when GDB connects to the remote
> target, the remote sets the 'remote exec-file' and this prevents GDB
> from using the 'file' filename.
> 
> And, GDB can only use the file set with the 'file' command if it
> believes that both GDB and the remote target will both be able to
> access this file.  This means that one of these is true:
> 
>   + the the remote_target::filesystem_is_local function returns
>     true (see the implementation of that function for details of when
>     this can happen).  This means GDB and the remote target can see
>     the same file system, GDB can just use the current executable's
>     filename as is, or
> 
>   + the user has set the 'file' to something with a 'target:' prefix,
>     e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
>     the exec filename without the 'target:' prefix, this filename is,
>     by definition, something the remote target can see, or
> 
>   + the sysroot has been updated by the user and no longer contains a
>     'target:' prefix.  In this case, if the 'file' filename is within
>     the sysroot, then it is assumed the remote will also be able to
>     see a file with the same filename.  For example, if the sysroot is
>     '/aa/', and the current executable is '/aa/bb/cc', then GDB will
>     tell the remote to run '/bb/cc'.  One common case here is when the
>     sysroot is set to the empty string, which is usually done when GDB
>     and the remote target can see the same filesystem, in this case
>     GDB will use the current executable's filename unmodified.
> 
> If one of these conditions is met, then GDB will use the current
> executable's filename (with possible modifications as mentioned
> above), when starting a new extended-remote inferior, in all other
> cases, GDB will use the file name  set with 'set remote exec-file'.
> 
> This change could be useful any time a user is running a remote target
> on the same machine as GDB, but I am specifically thinking of the case
> where GDB is using a tool other than gdbserver, e.g. valgrind, as this
> saves one additional step that a user must remember.  The current
> steps to start valgrind with GDB, as given on the valgrind
> website (https://valgrind.org/docs/manual/manual-core-adv.html) are:
> 
>   $ gdb prog
>   (gdb) set remote exec-file prog
>   (gdb) set sysroot /
>   (gdb) target extended-remote | vgdb --multi --vargs -q
>   (gdb) start
> 
> With this GDB work, and once support for the qExecAndArgs packet is
> added to valgrind, then the 'set remote exec-file' line can be dropped
> from those instructions.
> 
> This commit also extends the 'show remote exec-file' command so that
> GDB will display the automatic value that it plans to use.  Here's an
> example of the new output:
> 
>   $ gdb -q /tmp/hello
>   Reading symbols from /tmp/hello...
>   (gdb) set sysroot
>   (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using stdio
>   (gdb) show remote exec-file
>   The remote exec-file is unset, using automatic value "/tmp/hello".
> 
> The last line shows the new output.

Thanks for this patch, I silently wished for this feature when debugging
problems related to extended-remote runs.  I didn't think about your
logic very hard, but on the surface it seems good.  Some minor comments:

> +/* Get a pointer to the current remote target.  If not connected to a
> +   remote target, return NULL.  The template argument allows users of this
> +   function to ask for 'remote_target' or 'extended_remote_target'.  */
> +
> +template<typename T = remote_target,
> +	 std::enable_if_t<std::is_base_of_v<remote_target, T>, bool> = true>
> +static T *
> +get_current_remote_target ()
> +{
> +  target_ops *proc_target = current_inferior ()->process_target ();
> +  return dynamic_cast<T *> (proc_target);
> +}

Since there are just two options, and it's pretty unlikely that there
will be many more, I think it would be clearer to just spell out the two
functions:

  - get_current_remote_target
  - get_current_extended_remote_target.

get_current_extended_remote_target is also shorter to use than
get_current_remote_target<extended_remote_target>.

> @@ -11313,6 +11356,88 @@ directory: %s"),
>      }
>  }
>  
> +/* See class declaration above.  */
> +
> +std::string
> +extended_remote_target::get_exec_file_for_create_inferior
> +  (const char *exec_file)
> +{
> +  const remote_exec_file_info &info
> +    = get_remote_exec_file_info (current_program_space);
> +
> +  /* Historically, when the remote target started a new inferior GDB would
> +     ignore the filename from GDB core (EXEC_FILE) and would use whatever
> +     value the user had set in 'remote exec-file'.  Now we try to be
> +     smarter.
> +
> +     Obviously, if 'remote exec-file' has been set, then this should be
> +     considered definitive.  But if 'remote exec-file' has not been set,
> +     then, in some cases, we might be able to use EXEC_FILE, or a
> +     derivative of EXEC_FILE.
> +
> +     It can also happen that EXEC_FILE is NULL.  This is mostly a bit of an
> +     edge case where GDB has attached to a running process, and couldn't
> +     figure out the filename for the executable.  If the user then does
> +     'run' we could end up with EXEC_FILE being NULL.  If this happens then
> +     the only option is to use the 'remote exec-file' setting.
> +
> +     If INFO.SECOND is ::VALUE_FROM_REMOTE or ::VALUE_FROM_GDB then there
> +     is a value in 'remote exec-file', we should not do anything with
> +     EXEC_FILE and just retain the 'remote exec-file' value.

std::pair is pretty bad for documentation (and code clarity).  If you
want to switch the std::pair for:

struct remote_exec_file_info
{
  remote_exec_source source;
  std::string value;
};

... I wouldn't be against it.

> +
> +     If INFO.SECOND is ::UNSET_VALUE then the user hasn't 'set remote
> +     exec-file' value, and the remote target has specifically told us (via
> +     the qExecAndArgs packet) that it has no default executable set.  In
> +     this case, if GDB and the remote can see the same filesystem, we can
> +     potentially use EXEC_FILE.
> +
> +     If INFO.SECOND is ::DEFAULT_VALUE then the user hasn't set a 'remote
> +     exec-file' value, but the remote target was unable to tell us (maybe
> +     the qExecAndArgs packet isn't supported) if it has a default
> +     executable set.  We might be tempted to treat this like the
> +     ::UNSET_VALUE case, however, this could potentially break backward
> +     compatibility in the case where the remote does have a default
> +     executable set.  To maintain compatibility, we send over the 'remote
> +     exec-file' setting, whatever it might be.  */
> +  if (exec_file != nullptr
> +      && info.second == remote_exec_source::UNSET_VALUE)
> +    {
> +      /* If the user has set the core exec file to a file on the target
> +	 then we can just strip the target prefix and use that as the
> +	 remote exec file name.  */
> +      if (is_target_filename (exec_file))
> +	return exec_file + strlen (TARGET_SYSROOT_PREFIX);
> +
> +      /* If the target filesystem is local then the remote can see
> +	 everything GDB can see.  In this case the remote should be able to
> +	 access EXEC_FILE.  */
> +      if (target_filesystem_is_local ())
> +	return exec_file;
> +
> +      /* If the sysroot is not a target path, then GDB can see a copy of
> +	 the remote target's filesystem, or if sysroot is empty, then the
> +	 remote and GDB could be sharing a filesystem.
> +
> +	 In either case, by removing the sysroot from the front of
> +	 EXEC_FILE, we can build a filename that the remote can see.  */
> +      if (!is_target_filename (gdb_sysroot)
> +	  && startswith (exec_file, gdb_sysroot.c_str ()))
> +	{
> +	  /* If the prefix is '/aa/' and EXEC_FILE is '/aa/bb/cc' then we
> +	     only want t remove '/aa' from EXEC_FILE to leave '/bb/cc'.  */
> +	  size_t len = gdb_sysroot.length ();
> +	  while (len > 0 && IS_DIR_SEPARATOR (gdb_sysroot[len - 1]))
> +	    --len;
> +
> +	  return exec_file + len;
> +	}

Edge case:

execfile: /aaaaa/foo.exe
sysroot: /aa

I guess that would be handled incorrectly, given the use of startswith?

Handling paths correctly is hard. Do we have a "is prefix of" file path
util already?

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 0/2] Auto setting of 'remote exec-file'
  2025-10-06 15:07 [PATCH] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2025-10-06 15:43 ` Eli Zaretskii
  2025-10-09 16:17 ` Simon Marchi
@ 2025-10-11 13:34 ` Andrew Burgess
  2025-10-11 13:34   ` [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct Andrew Burgess
  2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2 siblings, 2 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-10-11 13:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Patch #1 is some refactoring requested during review of V1.

Patch #2 is the updated version of the V1 patch.  This includes:

  - Rewrite of the NEWS entry to try and make it more readable.

  - Use of child_path function rather than startswith to detect when a
    file is inside the sysroot.

  - Add get_current_extended_remote_target rather than templating
    get_current_remote_target.

  - Updates to take account of the refactoring in patch #1, that is
    replacing a std::pair with a struct with named fields.


---

Andrew Burgess (2):
  gdb/remote: replace use of std::pair with an actual struct
  gdb: use current executable for 'remote exec-file' in some cases

 gdb/NEWS                             |   8 +
 gdb/doc/gdb.texinfo                  |   4 +-
 gdb/remote.c                         | 216 ++++++++++++++++++++++-----
 gdb/testsuite/gdb.server/ext-run.exp | 160 ++++++++++++++++----
 4 files changed, 319 insertions(+), 69 deletions(-)


base-commit: c1950dcc04c07e713b708efcf1c6cc88eda60843
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-11 13:34 ` [PATCH 0/2] Auto setting of 'remote exec-file' Andrew Burgess
@ 2025-10-11 13:34   ` Andrew Burgess
  2025-10-11 13:46     ` Simon Marchi
  2025-11-19 10:32     ` Andrew Burgess
  2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  1 sibling, 2 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-10-11 13:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Commit:

  commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
  Date:   Mon Jul 24 17:35:54 2023 +0100

      gdb: detect when gdbserver has no default executable set

Introduced a use of std::pair as a data structure to hold some per
program space information within the program space registry.

It was pointed out during review of a later patch that the code would
be easier to understand if the std::pair was replaced with a struct
with named fields.

That is what this commit does.  Replace the std::pair with a struct,
and update all accesses to use the named fields.

There should be no user visible changes after this commit.
---
 gdb/remote.c | 60 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 27 deletions(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index 2e706e2d45b..143835ad503 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1640,15 +1640,22 @@ enum class remote_exec_source
   UNSET_VALUE,
 };
 
-/* Data held per program-space to represent the remote exec-file path.  The
-   first item in the pair is the exec-file path, this is set either by the
-   user with 'set remote exec-file', or automatically by GDB when
-   connecting to a remote target.
+/* Data held per program-space to represent the remote exec-file path.
+   This holds the 'remote exec-file' value and an enum to indicate where
+   the exec-file value came from, or what an empty exec-file value means.
+   See show_remote_exec_file for details.  */
 
-   The second item in the pair is an enum flag that indicates where the
-   path value came from, or, when the path is the empty string, what this
-   actually means.  See show_remote_exec_file for details.  */
-using remote_exec_file_info = std::pair<std::string, remote_exec_source>;
+struct remote_exec_file_info
+{
+  /* The 'remote exec-file' value.  This will be empty before being set.
+     This is set either with the 'set remote exec-file' command, or
+     automatically by GDB when connecting to a remote target.  */
+  std::string filename;
+
+  /* An enum that indicates where VALUE came from, or what an empty VALUE
+     means.  */
+  remote_exec_source source = remote_exec_source::DEFAULT_VALUE;
+};
 
 /* Per-program-space data key.  */
 static const registry<program_space>::key<remote_exec_file_info>
@@ -1662,8 +1669,7 @@ get_remote_exec_file_info (program_space *pspace)
 {
   remote_exec_file_info *info = remote_pspace_data.get (pspace);
   if (info == nullptr)
-    info = remote_pspace_data.emplace (pspace, "",
-				       remote_exec_source::DEFAULT_VALUE);
+    info = remote_pspace_data.emplace (pspace);
   gdb_assert (info != nullptr);
   return *info;
 }
@@ -2001,7 +2007,7 @@ get_remote_exec_file ()
 {
   const remote_exec_file_info &info
     = get_remote_exec_file_info (current_program_space);
-  return info.first;
+  return info.filename;
 }
 
 /* Set the remote exec file for PSPACE.  */
@@ -2012,8 +2018,8 @@ set_pspace_remote_exec_file (struct program_space *pspace,
 			     remote_exec_source source)
 {
   remote_exec_file_info &info = get_remote_exec_file_info (pspace);
-  info.first = filename;
-  info.second = source;
+  info.filename = filename;
+  info.source = source;
 }
 
 /* The "set remote exec-file" callback.  */
@@ -2034,16 +2040,16 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
   const remote_exec_file_info &info
     = get_remote_exec_file_info (current_program_space);
 
-  if (info.second == remote_exec_source::DEFAULT_VALUE)
+  if (info.source == remote_exec_source::DEFAULT_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
-  else if (info.second == remote_exec_source::UNSET_VALUE)
+  else if (info.source == remote_exec_source::UNSET_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the remote has "
 			"no default executable set.\n"));
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
-			       info.first.c_str ()));
+			       info.filename.c_str ()));
 }
 
 static int
@@ -5483,25 +5489,25 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
 	{
 	  remote_exec_file_info &info
 	    = get_remote_exec_file_info (current_program_space);
-	  if (info.second == remote_exec_source::VALUE_FROM_GDB
-	      && info.first != exec_and_args.exec ())
+	  if (info.source == remote_exec_source::VALUE_FROM_GDB
+	      && info.filename != exec_and_args.exec ())
 	    warning (_("updating 'remote exec-file' to '%ps' to match "
 		       "remote target"),
 		     styled_string (file_name_style.style (),
 				    exec_and_args.exec ().c_str ()));
-	  info.first = exec_and_args.exec ();
-	  info.second = remote_exec_source::VALUE_FROM_REMOTE;
+	  info.filename = exec_and_args.exec ();
+	  info.source = remote_exec_source::VALUE_FROM_REMOTE;
 	}
     }
   else if (exec_and_args.is_unset ())
     {
       remote_exec_file_info &info
 	= get_remote_exec_file_info (current_program_space);
-      if (info.second == remote_exec_source::DEFAULT_VALUE
-	  || info.second == remote_exec_source::VALUE_FROM_REMOTE)
+      if (info.source == remote_exec_source::DEFAULT_VALUE
+	  || info.source == remote_exec_source::VALUE_FROM_REMOTE)
 	{
-	  info.first.clear ();
-	  info.second = remote_exec_source::UNSET_VALUE;
+	  info.filename.clear ();
+	  info.source = remote_exec_source::UNSET_VALUE;
 	}
     }
 
@@ -6492,10 +6498,10 @@ remote_unpush_target (remote_target *target)
 	 would be unhelpful.  */
       remote_exec_file_info &exec_info
 	= get_remote_exec_file_info (inf->pspace);
-      if (exec_info.second == remote_exec_source::UNSET_VALUE)
+      if (exec_info.source == remote_exec_source::UNSET_VALUE)
 	{
-	  gdb_assert (exec_info.first.empty ());
-	  exec_info.second = remote_exec_source::DEFAULT_VALUE;
+	  gdb_assert (exec_info.filename.empty ());
+	  exec_info.source = remote_exec_source::DEFAULT_VALUE;
 	}
 
       inf->pop_all_targets_at_and_above (process_stratum);
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-11 13:34 ` [PATCH 0/2] Auto setting of 'remote exec-file' Andrew Burgess
  2025-10-11 13:34   ` [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct Andrew Burgess
@ 2025-10-11 13:34   ` Andrew Burgess
  2025-10-11 14:45     ` Eli Zaretskii
                       ` (2 more replies)
  1 sibling, 3 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-10-11 13:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Eli Zaretskii

This commit allows GDB to make use of the file set with the 'file'
command when starting a new inferior on an extended-remote target.
There are however some restrictions.

If the user has used 'set remote exec-file', then this setting is
always used in preference to the file set with the 'file' command.

Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
that the remote target has an executable set, then this will be used
in preference to the file set with the 'file' command; this preserves
GDB's existing behaviour.  In effect, when GDB connects to the remote
target, the remote sets the 'remote exec-file' and this prevents GDB
from using the 'file' filename.

And, GDB can only use the file set with the 'file' command if it
believes that both GDB and the remote target will both be able to
access this file.  This means that one of these is true:

  + the the remote_target::filesystem_is_local function returns
    true (see the implementation of that function for details of when
    this can happen).  This means GDB and the remote target can see
    the same file system, GDB can just use the current executable's
    filename as is, or

  + the user has set the 'file' to something with a 'target:' prefix,
    e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
    the exec filename without the 'target:' prefix, this filename is,
    by definition, something the remote target can see, or

  + the sysroot has been updated by the user and no longer contains a
    'target:' prefix.  In this case, if the 'file' filename is within
    the sysroot, then it is assumed the remote will also be able to
    see a file with the same filename.  For example, if the sysroot is
    '/aa/', and the current executable is '/aa/bb/cc', then GDB will
    tell the remote to run '/bb/cc'.  One common case here is when the
    sysroot is set to the empty string, which is usually done when GDB
    and the remote target can see the same filesystem, in this case
    GDB will use the current executable's filename unmodified.

If one of these conditions is met, then GDB will use the current
executable's filename (with possible modifications as mentioned
above), when starting a new extended-remote inferior, in all other
cases, GDB will use the file name  set with 'set remote exec-file'.

This change could be useful any time a user is running a remote target
on the same machine as GDB, but I am specifically thinking of the case
where GDB is using a tool other than gdbserver, e.g. valgrind, as this
saves one additional step that a user must remember.  The current
steps to start valgrind with GDB, as given on the valgrind
website (https://valgrind.org/docs/manual/manual-core-adv.html) are:

  $ gdb prog
  (gdb) set remote exec-file prog
  (gdb) set sysroot /
  (gdb) target extended-remote | vgdb --multi --vargs -q
  (gdb) start

With this GDB work, and once support for the qExecAndArgs packet is
added to valgrind, then the 'set remote exec-file' line can be dropped
from those instructions.

This commit also extends the 'show remote exec-file' command so that
GDB will display the automatic value that it plans to use.  Here's an
example of the new output:

  $ gdb -q /tmp/hello
  Reading symbols from /tmp/hello...
  (gdb) set sysroot
  (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
  Remote debugging using | ./gdbserver/gdbserver --multi --once -
  Remote debugging using stdio
  (gdb) show remote exec-file
  The remote exec-file is unset, using automatic value "/tmp/hello".

The last line shows the new output.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                             |   8 ++
 gdb/doc/gdb.texinfo                  |   4 +-
 gdb/remote.c                         | 156 +++++++++++++++++++++++---
 gdb/testsuite/gdb.server/ext-run.exp | 160 ++++++++++++++++++++++-----
 4 files changed, 286 insertions(+), 42 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index b0146852c5c..58a5b3c2496 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,14 @@
   subsequent runs of the inferior will use the same arguments as the
   first run.
 
+* When connected to an extended-remote target GDB can now
+  automatically set the 'remote exec-file' in some cases.  GDB will
+  auto set the remote exec-file only if the remote wasn't started with
+  an executable, and the user hasn't used 'set remote exec-file' to
+  set an executable.  GDB will auto set the remote exec-file using the
+  current executable if the current executable has a 'target:' prefix,
+  or if the current executable is within the sysroot.
+
 * New targets
 
 GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1b463b167e7..efd9d80de07 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24668,7 +24668,9 @@ Remote Configuration
 Select the file used for @code{run} with @code{target
 extended-remote}.  This should be set to a filename valid on the
 target system.  If it is not set, the target will use a default
-filename (e.g.@: the last program run).
+filename (e.g.@: the last program run, or a filename derived from the
+current executable if @value{GDBN} and the remote can see the same
+file system).
 
 When connecting to a remote system, with @kbd{target extended-remote}
 or @kbd{target remote}, if the remote server supports the
diff --git a/gdb/remote.c b/gdb/remote.c
index 143835ad503..2c77405305e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -43,9 +43,11 @@
 #include "target-descriptions.h"
 #include "gdb_bfd.h"
 #include "gdbsupport/filestuff.h"
+#include "gdbsupport/pathstuff.h"
 #include "gdbsupport/rsp-low.h"
 #include "disasm.h"
 #include "location.h"
+#include "filenames.h"
 
 #include "gdbsupport/gdb_sys_time.h"
 
@@ -1555,8 +1557,49 @@ class extended_remote_target final : public remote_target
 
   void post_attach (int) override;
   bool supports_disable_randomization () override;
+
+  /* Return the file name for the executable that GDB should ask the remote
+     target to use when starting an inferior.
+
+     EXEC_FILE is the string passed from GDB core, which is the file name
+     of the current executable, which can be NULL.
+
+     If the user has done 'set remote exec-file', or the remote told GDB
+     which executable to use via the 'qExecAndArgs' packet, then this is
+     the value returned by this function, EXEC_FILE is ignored.
+
+     But if there is no remote exec-file set, then we might be able to use
+     EXEC_FILE, or a variation of EXEC_FILE, as the 'remote exec-file'
+     setting.  This will depend on the value of EXEC_FILE and/or the
+     current gdb_sysroot setting.  In this case the file name derived from
+     EXEC_FILE is returned.
+
+     If neither approach comes up with a suitable file name to run then
+     the empty string is returned.  */
+
+  std::string get_exec_file_for_create_inferior (const char *exec_file);
 };
 
+/* Get a pointer to the current remote target.  If not connected to a
+   remote target, return NULL.  */
+
+static remote_target *
+get_current_remote_target ()
+{
+  target_ops *proc_target = current_inferior ()->process_target ();
+  return dynamic_cast<remote_target *> (proc_target);
+}
+
+/* Get a pointer to the current remote target.  If not connected to a
+   remote target, return NULL.  */
+
+static extended_remote_target *
+get_current_extended_remote_target ()
+{
+  target_ops *proc_target = current_inferior ()->process_target ();
+  return dynamic_cast<extended_remote_target *> (proc_target);
+}
+
 struct stop_reply : public notif_event
 {
   /* The identifier of the thread about this event  */
@@ -2044,8 +2087,25 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
   else if (info.source == remote_exec_source::UNSET_VALUE)
-    gdb_printf (file, _("The remote exec-file is unset, the remote has "
-			"no default executable set.\n"));
+    {
+      std::string remote_exec_filename;
+      extended_remote_target *remote = get_current_extended_remote_target ();
+      if (remote != nullptr)
+	{
+	  const char *exec_file = current_program_space->exec_filename ();
+	  remote_exec_filename
+	    = remote->get_exec_file_for_create_inferior (exec_file);
+	}
+
+      if (!remote_exec_filename.empty ())
+	gdb_printf (file, _("The remote exec-file is unset, using "
+			    "automatic value \"%ps\".\n"),
+		    styled_string (file_name_style.style (),
+				   remote_exec_filename.c_str ()));
+      else
+	gdb_printf (file, _("The remote exec-file is unset, the remote has "
+			    "no default executable set.\n"));
+    }
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
@@ -2151,16 +2211,6 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch)
     this->remote_packet_size = (this->sizeof_g_packet * 2 + 32);
 }
 
-/* Get a pointer to the current remote target.  If not connected to a
-   remote target, return NULL.  */
-
-static remote_target *
-get_current_remote_target ()
-{
-  target_ops *proc_target = current_inferior ()->process_target ();
-  return dynamic_cast<remote_target *> (proc_target);
-}
-
 /* Return the current allowed size of a remote packet.  This is
    inferred from the current architecture, and should be used to
    limit the length of outgoing packets.  */
@@ -11319,6 +11369,84 @@ directory: %s"),
     }
 }
 
+/* See class declaration above.  */
+
+std::string
+extended_remote_target::get_exec_file_for_create_inferior
+  (const char *exec_file)
+{
+  const remote_exec_file_info &info
+    = get_remote_exec_file_info (current_program_space);
+
+  /* Historically, when the remote target started a new inferior GDB would
+     ignore the filename from GDB core (EXEC_FILE) and would use whatever
+     value the user had set in 'remote exec-file'.  Now we try to be
+     smarter.
+
+     Obviously, if 'remote exec-file' has been set, then this should be
+     considered definitive.  But if 'remote exec-file' has not been set,
+     then, in some cases, we might be able to use EXEC_FILE, or a
+     derivative of EXEC_FILE.
+
+     It can also happen that EXEC_FILE is NULL.  This is mostly a bit of an
+     edge case where GDB has attached to a running process, and couldn't
+     figure out the filename for the executable.  If the user then does
+     'run' we could end up with EXEC_FILE being NULL.  If this happens then
+     the only option is to use the 'remote exec-file' setting.
+
+     If INFO.SOURCE is ::VALUE_FROM_REMOTE or ::VALUE_FROM_GDB then there
+     is a value in 'remote exec-file', we should not do anything with
+     EXEC_FILE and just retain the 'remote exec-file' value.
+
+     If INFO.SOURCE is ::UNSET_VALUE then the user hasn't 'set remote
+     exec-file' value, and the remote target has specifically told us (via
+     the qExecAndArgs packet) that it has no default executable set.  In
+     this case, if GDB and the remote can see the same filesystem, we can
+     potentially use EXEC_FILE.
+
+     If INFO.SOURCE is ::DEFAULT_VALUE then the user hasn't set a 'remote
+     exec-file' value, but the remote target was unable to tell us (maybe
+     the qExecAndArgs packet isn't supported) if it has a default
+     executable set.  We might be tempted to treat this like the
+     ::UNSET_VALUE case, however, this could potentially break backward
+     compatibility in the case where the remote does have a default
+     executable set.  To maintain compatibility, we send over the 'remote
+     exec-file' setting, whatever it might be.  */
+  if (exec_file != nullptr
+      && info.source == remote_exec_source::UNSET_VALUE)
+    {
+      /* If the user has set the core exec file to a file on the target
+	 then we can just strip the target prefix and use that as the
+	 remote exec file name.  */
+      if (is_target_filename (exec_file))
+	return exec_file + strlen (TARGET_SYSROOT_PREFIX);
+
+      /* If the target filesystem is local then the remote can see
+	 everything GDB can see.  In this case the remote should be able to
+	 access EXEC_FILE.  */
+      if (target_filesystem_is_local ())
+	return exec_file;
+
+      /* If the sysroot is not a target path, then GDB can see a copy of
+	 the remote target's filesystem, or if sysroot is empty, then the
+	 remote and GDB could be sharing a filesystem.
+
+	 In either case, by removing the sysroot from the front of
+	 EXEC_FILE, we can build a filename that the remote can see.  */
+      if (!is_target_filename (gdb_sysroot))
+	{
+	  const char *in_sysroot_path = child_path (gdb_sysroot.c_str (),
+						    exec_file);
+	  if (in_sysroot_path != nullptr)
+	    return path_join ("/", in_sysroot_path);
+	}
+    }
+
+  /* The user has set the remote exec-file, or GDB doesn't think the remote
+     target and GDB can see the same filesystem.  */
+  return info.filename;
+}
+
 /* In the extended protocol we want to be able to do things like
    "run" and have them basically work as expected.  So we need
    a special create_inferior function.  We support changing the
@@ -11333,7 +11461,9 @@ extended_remote_target::create_inferior (const char *exec_file,
   int run_worked;
   char *stop_reply;
   struct remote_state *rs = get_remote_state ();
-  const std::string &remote_exec_file = get_remote_exec_file ();
+
+  std::string remote_exec_file
+    = get_exec_file_for_create_inferior (exec_file);
 
   /* If running asynchronously, register the target file descriptor
      with the event loop.  */
diff --git a/gdb/testsuite/gdb.server/ext-run.exp b/gdb/testsuite/gdb.server/ext-run.exp
index f4ff546c393..18205e11ec8 100644
--- a/gdb/testsuite/gdb.server/ext-run.exp
+++ b/gdb/testsuite/gdb.server/ext-run.exp
@@ -30,43 +30,147 @@ if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
 # allow_xml_test must be called while gdb is not running.
 set do_xml_test [allow_xml_test]
 
-save_vars { GDBFLAGS } {
-    # If GDB and GDBserver are both running locally, set the sysroot to avoid
-    # reading files via the remote protocol.
-    if { ![is_remote host] && ![is_remote target] } {
-	set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\""
+# This is used as an override function.
+proc do_nothing {} { return 0 }
+
+# Start an exetended-remote gdbserver, connect to it, and then use
+# 'run' to start an inferior.
+#
+# If CLEAR_SYSROOT is true then the 'set sysroot' command is issued,
+# clearing the sysroot, otherwise the sysroot is left unchanged.
+#
+# If SET_REMOTE_EXEC is true then the 'set remote-exec ...' command is
+# issued to point GDB at the executable on the target (after copying
+# the executable over).  Otherwise, we rely on GDB and gdbserver being
+# able to see the same filesystem, remote exec-file is not set, and
+# GDB will just use the path to the executable.
+proc do_test { clear_sysroot set_remote_exec fetch_exec_and_args } {
+
+    # If we don't clear the sysroot, then the sysroot will remain as
+    # 'target:'.  In this case, if we don't 'set remote exec-file'
+    # then GDB will not be able to start a remote inferior.
+    if { !$clear_sysroot && !$set_remote_exec } {
+	return
     }
 
     clean_restart $::testfile
-}
 
-# Make sure we're disconnected, in case we're testing with an
-# extended-remote board, therefore already connected.
-gdb_test "disconnect" ".*"
+    # Disable, or enable, use of the qExecAndArgs packet.
+    gdb_test "set remote fetch-exec-and-args-packet ${fetch_exec_and_args}" \
+	".*"
 
-set target_exec [gdbserver_download_current_prog]
-gdbserver_start_extended
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
 
-gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+    if { $clear_sysroot } {
+	gdb_test_no_output "set sysroot" \
+	    "clear sysroot"
+    } else {
+	set sysroot "UNKNOWN"
+	gdb_test_multiple "show sysroot" "" {
+	    -re -wrap "^The current system root is \"(\[^\r\n\]*)\"\\." {
+		set sysroot $expect_out(1,string)
+		pass $gdb_test_name
+	    }
+	}
 
-gdb_breakpoint main
-gdb_test "run" "Breakpoint.* main .*" "continue to main"
-
-if { [istarget *-*-linux*] } {
-    # On Linux, gdbserver can also report the list of processes.
-    # But only if xml support is compiled in.
-    if { $do_xml_test } {
-	# This is done in a way to avoid the timeout that can occur from
-	# applying .* regexp to large output.
-	gdb_test_lines "info os processes" "get process list" \
-	    "^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	if { $sysroot eq "" } {
+	    gdb_test_no_output "set sysroot target:"
+	} elseif { $sysroot ne "target:" } {
+	    unsupported "unexpected sysroot value"
+	    return
+	}
     }
-}
 
-gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+    gdbserver_start_extended
 
-gdb_load $binfile
-gdb_test "monitor help" "The following monitor commands.*" \
+    # Check the 'remote exec-file' setting before we (possibly) set it
+    # ourselves.
+    if { !$fetch_exec_and_args } {
+	set suffix "the default remote executable will be used"
+    } elseif { !$clear_sysroot} {
+	set suffix "the remote has no default executable set"
+    } else {
+	set file_re [string_to_regexp $::binfile]
+	set suffix "using automatic value \"$file_re\""
+    }
+    gdb_test "show remote exec-file" \
+	"The remote exec-file is unset, ${suffix}\\." \
+	"check remote exec-file is unset"
+
+    if { $set_remote_exec } {
+	set target_exec [gdbserver_download_current_prog]
+	gdb_test_no_output "set remote exec-file $target_exec" \
+	    "set remote exec-file"
+
+	# Check GDB reflect the value we just set.
+	set file_re [string_to_regexp $target_exec]
+	gdb_test "show remote exec-file" \
+	    "The remote exec-file is \"$file_re\"\\." \
+	    "check remote exec-file after set"
+    }
+
+    gdb_breakpoint main
+    gdb_test_multiple "run" "continue to main" {
+	-re -wrap "Breakpoint.* main .*" {
+	    pass $gdb_test_name
+	}
+	-re -wrap "Running the default executable on the remote target failed; try \"set remote exec-file\"." {
+
+	    # If 'set remote exec-file' has been used then we should
+	    # not get here.
+	    gdb_assert {!$set_remote_exec} \
+		"confirm remote exec-file is not set"
+
+	    if {!$fetch_exec_and_args} {
+		# We deliberately disabled GDB's ability to know that
+		# the remote doesn't have a default executable set (by
+		# disabling the qDefaultExecAndArgs packet).  We got
+		# the result we expected, but the inferior is not
+		# running, so we're done with this phase of testing.
+		pass $gdb_test_name
+		return
+	    }
+	}
+    }
+
+    if { [istarget *-*-linux*] } {
+	# On Linux, gdbserver can also report the list of processes.
+	# But only if xml support is compiled in.
+	if { $::do_xml_test } {
+	    # This is done in a way to avoid the timeout that can occur from
+	    # applying .* regexp to large output.
+	    gdb_test_lines "info os processes" "get process list" \
+		"^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	}
+    }
+
+    gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+
+    gdb_load $::binfile
+    gdb_test "monitor help" "The following monitor commands.*" \
         "load new file without any gdbserver inferior"
 
-gdb_test_no_output "monitor exit"
+    gdb_test_no_output "monitor exit"
+}
+
+set clear_sysroot_modes { false }
+set set_remote_exec_modes { true }
+if {![is_remote target] && ![is_remote host]} {
+    lappend set_remote_exec_modes false
+    lappend clear_sysroot_modes true
+}
+
+# This override prevents GDB from automatically setting the 'remote
+# exec-file' when using the extended-remote protocol.  If we want the
+# exec-file set, then this test takes care of it.
+with_override extended_gdbserver_load_last_file do_nothing {
+    foreach_with_prefix clear_sysroot $clear_sysroot_modes {
+	foreach_with_prefix set_remote_exec $set_remote_exec_modes {
+	    foreach_with_prefix fetch_exec_and_args { on off } {
+		do_test $clear_sysroot $set_remote_exec $fetch_exec_and_args
+	    }
+	}
+    }
+}
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-11 13:34   ` [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct Andrew Burgess
@ 2025-10-11 13:46     ` Simon Marchi
  2025-10-12  8:57       ` Andrew Burgess
  2025-11-19 10:32     ` Andrew Burgess
  1 sibling, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2025-10-11 13:46 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches



On 2025-10-11 09:34, Andrew Burgess wrote:
> Commit:
> 
>   commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
>   Date:   Mon Jul 24 17:35:54 2023 +0100
> 
>       gdb: detect when gdbserver has no default executable set
> 
> Introduced a use of std::pair as a data structure to hold some per
> program space information within the program space registry.
> 
> It was pointed out during review of a later patch that the code would
> be easier to understand if the std::pair was replaced with a struct
> with named fields.
> 
> That is what this commit does.  Replace the std::pair with a struct,
> and update all accesses to use the named fields.
> 
> There should be no user visible changes after this commit.

Thanks, this LGTM.

Approved-By: Simon Marchi <simon.marchi@efficios.com>

I would just like to point out that if we ever add more fields to this
structure (this the remote target needs to record per-pspace), then it
would probably make sense to rename to to "remote_per_pspace" or
something like that, since it would no longer be only used to hold
remote exec information.  But as of now, it's correct.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
@ 2025-10-11 14:45     ` Eli Zaretskii
  2025-11-07 20:46     ` Simon Marchi
  2025-11-19 10:32     ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2 siblings, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2025-10-11 14:45 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <aburgess@redhat.com>
> Cc: Andrew Burgess <aburgess@redhat.com>,
> 	Eli Zaretskii <eliz@gnu.org>
> Date: Sat, 11 Oct 2025 14:34:04 +0100
> 
> This commit allows GDB to make use of the file set with the 'file'
> command when starting a new inferior on an extended-remote target.
> There are however some restrictions.
> 
> If the user has used 'set remote exec-file', then this setting is
> always used in preference to the file set with the 'file' command.
> 
> Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
> that the remote target has an executable set, then this will be used
> in preference to the file set with the 'file' command; this preserves
> GDB's existing behaviour.  In effect, when GDB connects to the remote
> target, the remote sets the 'remote exec-file' and this prevents GDB
> from using the 'file' filename.
> 
> And, GDB can only use the file set with the 'file' command if it
> believes that both GDB and the remote target will both be able to
> access this file.  This means that one of these is true:
> 
>   + the the remote_target::filesystem_is_local function returns
>     true (see the implementation of that function for details of when
>     this can happen).  This means GDB and the remote target can see
>     the same file system, GDB can just use the current executable's
>     filename as is, or
> 
>   + the user has set the 'file' to something with a 'target:' prefix,
>     e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
>     the exec filename without the 'target:' prefix, this filename is,
>     by definition, something the remote target can see, or
> 
>   + the sysroot has been updated by the user and no longer contains a
>     'target:' prefix.  In this case, if the 'file' filename is within
>     the sysroot, then it is assumed the remote will also be able to
>     see a file with the same filename.  For example, if the sysroot is
>     '/aa/', and the current executable is '/aa/bb/cc', then GDB will
>     tell the remote to run '/bb/cc'.  One common case here is when the
>     sysroot is set to the empty string, which is usually done when GDB
>     and the remote target can see the same filesystem, in this case
>     GDB will use the current executable's filename unmodified.
> 
> If one of these conditions is met, then GDB will use the current
> executable's filename (with possible modifications as mentioned
> above), when starting a new extended-remote inferior, in all other
> cases, GDB will use the file name  set with 'set remote exec-file'.
> 
> This change could be useful any time a user is running a remote target
> on the same machine as GDB, but I am specifically thinking of the case
> where GDB is using a tool other than gdbserver, e.g. valgrind, as this
> saves one additional step that a user must remember.  The current
> steps to start valgrind with GDB, as given on the valgrind
> website (https://valgrind.org/docs/manual/manual-core-adv.html) are:
> 
>   $ gdb prog
>   (gdb) set remote exec-file prog
>   (gdb) set sysroot /
>   (gdb) target extended-remote | vgdb --multi --vargs -q
>   (gdb) start
> 
> With this GDB work, and once support for the qExecAndArgs packet is
> added to valgrind, then the 'set remote exec-file' line can be dropped
> from those instructions.
> 
> This commit also extends the 'show remote exec-file' command so that
> GDB will display the automatic value that it plans to use.  Here's an
> example of the new output:
> 
>   $ gdb -q /tmp/hello
>   Reading symbols from /tmp/hello...
>   (gdb) set sysroot
>   (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using stdio
>   (gdb) show remote exec-file
>   The remote exec-file is unset, using automatic value "/tmp/hello".
> 
> The last line shows the new output.
> 
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
> ---
>  gdb/NEWS                             |   8 ++
>  gdb/doc/gdb.texinfo                  |   4 +-
>  gdb/remote.c                         | 156 +++++++++++++++++++++++---
>  gdb/testsuite/gdb.server/ext-run.exp | 160 ++++++++++++++++++++++-----
>  4 files changed, 286 insertions(+), 42 deletions(-)

Thanks, the documentation parts are okay.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-11 13:46     ` Simon Marchi
@ 2025-10-12  8:57       ` Andrew Burgess
  2025-10-12 12:05         ` Simon Marchi
  0 siblings, 1 reply; 20+ messages in thread
From: Andrew Burgess @ 2025-10-12  8:57 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

Simon Marchi <simark@simark.ca> writes:

> On 2025-10-11 09:34, Andrew Burgess wrote:
>> Commit:
>> 
>>   commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
>>   Date:   Mon Jul 24 17:35:54 2023 +0100
>> 
>>       gdb: detect when gdbserver has no default executable set
>> 
>> Introduced a use of std::pair as a data structure to hold some per
>> program space information within the program space registry.
>> 
>> It was pointed out during review of a later patch that the code would
>> be easier to understand if the std::pair was replaced with a struct
>> with named fields.
>> 
>> That is what this commit does.  Replace the std::pair with a struct,
>> and update all accesses to use the named fields.
>> 
>> There should be no user visible changes after this commit.
>
> Thanks, this LGTM.
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
>
> I would just like to point out that if we ever add more fields to this
> structure (this the remote target needs to record per-pspace), then it
> would probably make sense to rename to to "remote_per_pspace" or
> something like that, since it would no longer be only used to hold
> remote exec information.  But as of now, it's correct.

Ask and you shall receive!

The update below names the struct remote_per_progspace, and moves the
exec file information into a nested struct.

Is this better?

Thanks,
Andrew

---

commit ce25366de1752c28513aa5e78adfca2c558218e4
Author: Andrew Burgess <aburgess@redhat.com>
Date:   Sat Oct 11 14:03:39 2025 +0100

    gdb/remote: replace use of std::pair with an actual struct
    
    Commit:
    
      commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
      Date:   Mon Jul 24 17:35:54 2023 +0100
    
          gdb: detect when gdbserver has no default executable set
    
    Introduced a use of std::pair as a data structure to hold some per
    program space information within the program space registry.
    
    It was pointed out during review of a later patch[1][2] that the code
    would be easier to understand if the std::pair was replaced with a
    struct with named fields.
    
    That is what this commit does.  Replace the std::pair with a struct,
    and update all accesses to use the named fields.
    
    There should be no user visible changes after this commit.
    
    [1] https://inbox.sourceware.org/gdb-patches/69681489-d556-4496-9e3b-8273cab3d8f5@simark.ca
    [2] https://inbox.sourceware.org/gdb-patches/469655a7-2bcc-4f27-b2d7-3fa8808ca5b5@simark.ca

diff --git a/gdb/remote.c b/gdb/remote.c
index 2e706e2d45b..858076bfa42 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1640,30 +1640,44 @@ enum class remote_exec_source
   UNSET_VALUE,
 };
 
-/* Data held per program-space to represent the remote exec-file path.  The
-   first item in the pair is the exec-file path, this is set either by the
-   user with 'set remote exec-file', or automatically by GDB when
-   connecting to a remote target.
+/* Data held per program space for each remote target.  */
 
-   The second item in the pair is an enum flag that indicates where the
-   path value came from, or, when the path is the empty string, what this
-   actually means.  See show_remote_exec_file for details.  */
-using remote_exec_file_info = std::pair<std::string, remote_exec_source>;
+struct remote_per_progspace
+{
+  /* The following represents the remote exec-file filename.  This value
+     can be set directly by the user with 'set remote exec-file', but can
+     also be set automatically when connecting to a remote target.  We
+     track both the filename value, and also the source of this value, as
+     where the value came from determines when the filename value can be
+     auto-generated from other sources, or when a remote target can
+     override the current value.  See show_remote_exec_file for details.  */
+  struct exec_info
+  {
+    /* The 'remote exec-file' filename value.  This will start empty.  This
+       is set either with the 'set remote exec-file' command, or
+       automatically by GDB when connecting to a remote target.  */
+    std::string filename;
+
+    /* An enum that indicates where FILENAME came from, or what an empty
+       VALUE means.  */
+    remote_exec_source source = remote_exec_source::DEFAULT_VALUE;
+  } exec_info;
+};
 
 /* Per-program-space data key.  */
-static const registry<program_space>::key<remote_exec_file_info>
+static const registry<program_space>::key<remote_per_progspace>
   remote_pspace_data;
 
-/* Retrieve the remote_exec_file_info object for PSPACE.  If no such object
-   yet exists then create a new one using the default constructor.  */
+/* Retrieve the remote_per_progspace object for PSPACE.  If no such object
+   yet exists then create a new one using the default constructor and
+   return that.  */
 
-static remote_exec_file_info &
-get_remote_exec_file_info (program_space *pspace)
+static remote_per_progspace &
+get_remote_progspace_info (program_space *pspace)
 {
-  remote_exec_file_info *info = remote_pspace_data.get (pspace);
+  remote_per_progspace *info = remote_pspace_data.get (pspace);
   if (info == nullptr)
-    info = remote_pspace_data.emplace (pspace, "",
-				       remote_exec_source::DEFAULT_VALUE);
+    info = remote_pspace_data.emplace (pspace);
   gdb_assert (info != nullptr);
   return *info;
 }
@@ -1999,21 +2013,22 @@ remote_target::get_remote_state ()
 static const std::string &
 get_remote_exec_file ()
 {
-  const remote_exec_file_info &info
-    = get_remote_exec_file_info (current_program_space);
-  return info.first;
+  const remote_per_progspace &info
+    = get_remote_progspace_info (current_program_space);
+  return info.exec_info.filename;
 }
 
-/* Set the remote exec file for PSPACE.  */
+/* Set the remote exec file for PSPACE.  FILENAME is the new exec file
+   value, and SOURCE describes where FILENAME came from.  */
 
 static void
 set_pspace_remote_exec_file (struct program_space *pspace,
 			     const std::string &filename,
 			     remote_exec_source source)
 {
-  remote_exec_file_info &info = get_remote_exec_file_info (pspace);
-  info.first = filename;
-  info.second = source;
+  remote_per_progspace &info = get_remote_progspace_info (pspace);
+  info.exec_info.filename = filename;
+  info.exec_info.source = source;
 }
 
 /* The "set remote exec-file" callback.  */
@@ -2031,19 +2046,19 @@ static void
 show_remote_exec_file (struct ui_file *file, int from_tty,
 		       struct cmd_list_element *cmd, const char *value)
 {
-  const remote_exec_file_info &info
-    = get_remote_exec_file_info (current_program_space);
+  const struct remote_per_progspace::exec_info &info
+    = get_remote_progspace_info (current_program_space).exec_info;
 
-  if (info.second == remote_exec_source::DEFAULT_VALUE)
+  if (info.source == remote_exec_source::DEFAULT_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
-  else if (info.second == remote_exec_source::UNSET_VALUE)
+  else if (info.source == remote_exec_source::UNSET_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the remote has "
 			"no default executable set.\n"));
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
-			       info.first.c_str ()));
+			       info.filename.c_str ()));
 }
 
 static int
@@ -5481,27 +5496,27 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
       current_inferior ()->set_args (exec_and_args.args ());
       if (!exec_and_args.exec ().empty ())
 	{
-	  remote_exec_file_info &info
-	    = get_remote_exec_file_info (current_program_space);
-	  if (info.second == remote_exec_source::VALUE_FROM_GDB
-	      && info.first != exec_and_args.exec ())
+	  struct remote_per_progspace::exec_info &info
+	    = get_remote_progspace_info (current_program_space).exec_info;
+	  if (info.source == remote_exec_source::VALUE_FROM_GDB
+	      && info.filename != exec_and_args.exec ())
 	    warning (_("updating 'remote exec-file' to '%ps' to match "
 		       "remote target"),
 		     styled_string (file_name_style.style (),
 				    exec_and_args.exec ().c_str ()));
-	  info.first = exec_and_args.exec ();
-	  info.second = remote_exec_source::VALUE_FROM_REMOTE;
+	  info.filename = exec_and_args.exec ();
+	  info.source = remote_exec_source::VALUE_FROM_REMOTE;
 	}
     }
   else if (exec_and_args.is_unset ())
     {
-      remote_exec_file_info &info
-	= get_remote_exec_file_info (current_program_space);
-      if (info.second == remote_exec_source::DEFAULT_VALUE
-	  || info.second == remote_exec_source::VALUE_FROM_REMOTE)
+      struct remote_per_progspace::exec_info &info
+	= get_remote_progspace_info (current_program_space).exec_info;
+      if (info.source == remote_exec_source::DEFAULT_VALUE
+	  || info.source == remote_exec_source::VALUE_FROM_REMOTE)
 	{
-	  info.first.clear ();
-	  info.second = remote_exec_source::UNSET_VALUE;
+	  info.filename.clear ();
+	  info.source = remote_exec_source::UNSET_VALUE;
 	}
     }
 
@@ -6490,12 +6505,12 @@ remote_unpush_target (remote_target *target)
 	 assumption is that the user is, or will, be debugging the same
 	 executable again in the future, so clearing an existing value
 	 would be unhelpful.  */
-      remote_exec_file_info &exec_info
-	= get_remote_exec_file_info (inf->pspace);
-      if (exec_info.second == remote_exec_source::UNSET_VALUE)
+      struct remote_per_progspace::exec_info &exec_info
+	= get_remote_progspace_info (inf->pspace).exec_info;
+      if (exec_info.source == remote_exec_source::UNSET_VALUE)
 	{
-	  gdb_assert (exec_info.first.empty ());
-	  exec_info.second = remote_exec_source::DEFAULT_VALUE;
+	  gdb_assert (exec_info.filename.empty ());
+	  exec_info.source = remote_exec_source::DEFAULT_VALUE;
 	}
 
       inf->pop_all_targets_at_and_above (process_stratum);


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-12  8:57       ` Andrew Burgess
@ 2025-10-12 12:05         ` Simon Marchi
  2025-10-12 13:13           ` Andrew Burgess
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2025-10-12 12:05 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches



On 2025-10-12 04:57, Andrew Burgess wrote:
> Simon Marchi <simark@simark.ca> writes:
> 
>> On 2025-10-11 09:34, Andrew Burgess wrote:
>>> Commit:
>>>
>>>   commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
>>>   Date:   Mon Jul 24 17:35:54 2023 +0100
>>>
>>>       gdb: detect when gdbserver has no default executable set
>>>
>>> Introduced a use of std::pair as a data structure to hold some per
>>> program space information within the program space registry.
>>>
>>> It was pointed out during review of a later patch that the code would
>>> be easier to understand if the std::pair was replaced with a struct
>>> with named fields.
>>>
>>> That is what this commit does.  Replace the std::pair with a struct,
>>> and update all accesses to use the named fields.
>>>
>>> There should be no user visible changes after this commit.
>>
>> Thanks, this LGTM.
>>
>> Approved-By: Simon Marchi <simon.marchi@efficios.com>
>>
>> I would just like to point out that if we ever add more fields to this
>> structure (this the remote target needs to record per-pspace), then it
>> would probably make sense to rename to to "remote_per_pspace" or
>> something like that, since it would no longer be only used to hold
>> remote exec information.  But as of now, it's correct.
> 
> Ask and you shall receive!
> 
> The update below names the struct remote_per_progspace, and moves the
> exec file information into a nested struct.
> 
> Is this better?

This looks clean to me, thanks.

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-12 12:05         ` Simon Marchi
@ 2025-10-12 13:13           ` Andrew Burgess
  0 siblings, 0 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-10-12 13:13 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

Simon Marchi <simark@simark.ca> writes:

> On 2025-10-12 04:57, Andrew Burgess wrote:
>> Simon Marchi <simark@simark.ca> writes:
>> 
>>> On 2025-10-11 09:34, Andrew Burgess wrote:
>>>> Commit:
>>>>
>>>>   commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
>>>>   Date:   Mon Jul 24 17:35:54 2023 +0100
>>>>
>>>>       gdb: detect when gdbserver has no default executable set
>>>>
>>>> Introduced a use of std::pair as a data structure to hold some per
>>>> program space information within the program space registry.
>>>>
>>>> It was pointed out during review of a later patch that the code would
>>>> be easier to understand if the std::pair was replaced with a struct
>>>> with named fields.
>>>>
>>>> That is what this commit does.  Replace the std::pair with a struct,
>>>> and update all accesses to use the named fields.
>>>>
>>>> There should be no user visible changes after this commit.
>>>
>>> Thanks, this LGTM.
>>>
>>> Approved-By: Simon Marchi <simon.marchi@efficios.com>
>>>
>>> I would just like to point out that if we ever add more fields to this
>>> structure (this the remote target needs to record per-pspace), then it
>>> would probably make sense to rename to to "remote_per_pspace" or
>>> something like that, since it would no longer be only used to hold
>>> remote exec information.  But as of now, it's correct.
>> 
>> Ask and you shall receive!
>> 
>> The update below names the struct remote_per_progspace, and moves the
>> exec file information into a nested struct.
>> 
>> Is this better?
>
> This looks clean to me, thanks.
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>

I pushed just this patch for now.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2025-10-11 14:45     ` Eli Zaretskii
@ 2025-11-07 20:46     ` Simon Marchi
  2025-11-11 15:59       ` Andrew Burgess
  2025-11-19 10:32     ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2025-11-07 20:46 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Eli Zaretskii

On 10/11/25 9:34 AM, Andrew Burgess wrote:
> This commit allows GDB to make use of the file set with the 'file'
> command when starting a new inferior on an extended-remote target.
> There are however some restrictions.
> 
> If the user has used 'set remote exec-file', then this setting is
> always used in preference to the file set with the 'file' command.
> 
> Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
> that the remote target has an executable set, then this will be used
> in preference to the file set with the 'file' command; this preserves
> GDB's existing behaviour.  In effect, when GDB connects to the remote
> target, the remote sets the 'remote exec-file' and this prevents GDB
> from using the 'file' filename.
> 
> And, GDB can only use the file set with the 'file' command if it
> believes that both GDB and the remote target will both be able to
> access this file.  This means that one of these is true:
> 
>   + the the remote_target::filesystem_is_local function returns
>     true (see the implementation of that function for details of when
>     this can happen).  This means GDB and the remote target can see
>     the same file system, GDB can just use the current executable's
>     filename as is, or
> 
>   + the user has set the 'file' to something with a 'target:' prefix,
>     e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
>     the exec filename without the 'target:' prefix, this filename is,
>     by definition, something the remote target can see, or
> 
>   + the sysroot has been updated by the user and no longer contains a
>     'target:' prefix.  In this case, if the 'file' filename is within
>     the sysroot, then it is assumed the remote will also be able to
>     see a file with the same filename.  For example, if the sysroot is
>     '/aa/', and the current executable is '/aa/bb/cc', then GDB will
>     tell the remote to run '/bb/cc'.  One common case here is when the
>     sysroot is set to the empty string, which is usually done when GDB
>     and the remote target can see the same filesystem, in this case
>     GDB will use the current executable's filename unmodified.
> 
> If one of these conditions is met, then GDB will use the current
> executable's filename (with possible modifications as mentioned
> above), when starting a new extended-remote inferior, in all other
> cases, GDB will use the file name  set with 'set remote exec-file'.
> 
> This change could be useful any time a user is running a remote target
> on the same machine as GDB, but I am specifically thinking of the case
> where GDB is using a tool other than gdbserver, e.g. valgrind, as this
> saves one additional step that a user must remember.  The current
> steps to start valgrind with GDB, as given on the valgrind
> website (https://valgrind.org/docs/manual/manual-core-adv.html) are:
> 
>   $ gdb prog
>   (gdb) set remote exec-file prog
>   (gdb) set sysroot /
>   (gdb) target extended-remote | vgdb --multi --vargs -q
>   (gdb) start
> 
> With this GDB work, and once support for the qExecAndArgs packet is
> added to valgrind, then the 'set remote exec-file' line can be dropped
> from those instructions.
> 
> This commit also extends the 'show remote exec-file' command so that
> GDB will display the automatic value that it plans to use.  Here's an
> example of the new output:
> 
>   $ gdb -q /tmp/hello
>   Reading symbols from /tmp/hello...
>   (gdb) set sysroot
>   (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using | ./gdbserver/gdbserver --multi --once -
>   Remote debugging using stdio
>   (gdb) show remote exec-file
>   The remote exec-file is unset, using automatic value "/tmp/hello".
> 
> The last line shows the new output.
> 
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

I am investigating a regression when running gdb.gdb/selftest.exp with
the native-extended-gdbserver board, caused by my commit d6340aa42e25
("gdb/testsuite: use libtool to launch selftests").  A side-effect of my
change is that the test no longer does a "set remote exec-file", which
is currently required in order to run a new process with an
extended-remote board.  I started writing a patch to add a manual "set
remote exec-file", but then remembered about this patch.  I gave it a
try, and indeed it fixes those regressions.  I would therefore be very
happy to see this patch merged (I had forgotten about it before just now
to be honest).

I'm fine with what you have see below for small comments.

Approved-By: Simon Marchi <simon.marchi@efficios.com>

> @@ -43,9 +43,11 @@
>  #include "target-descriptions.h"
>  #include "gdb_bfd.h"
>  #include "gdbsupport/filestuff.h"
> +#include "gdbsupport/pathstuff.h"
>  #include "gdbsupport/rsp-low.h"
>  #include "disasm.h"
>  #include "location.h"
> +#include "filenames.h"
>  
>  #include "gdbsupport/gdb_sys_time.h"
>  
> @@ -1555,8 +1557,49 @@ class extended_remote_target final : public remote_target
>  
>    void post_attach (int) override;
>    bool supports_disable_randomization () override;
> +
> +  /* Return the file name for the executable that GDB should ask the remote
> +     target to use when starting an inferior.
> +
> +     EXEC_FILE is the string passed from GDB core, which is the file name
> +     of the current executable, which can be NULL.
> +
> +     If the user has done 'set remote exec-file', or the remote told GDB
> +     which executable to use via the 'qExecAndArgs' packet, then this is
> +     the value returned by this function, EXEC_FILE is ignored.
> +
> +     But if there is no remote exec-file set, then we might be able to use
> +     EXEC_FILE, or a variation of EXEC_FILE, as the 'remote exec-file'
> +     setting.  This will depend on the value of EXEC_FILE and/or the
> +     current gdb_sysroot setting.  In this case the file name derived from
> +     EXEC_FILE is returned.
> +
> +     If neither approach comes up with a suitable file name to run then
> +     the empty string is returned.  */
> +
> +  std::string get_exec_file_for_create_inferior (const char *exec_file);
>  };
>  
> +/* Get a pointer to the current remote target.  If not connected to a
> +   remote target, return NULL.  */
> +
> +static remote_target *
> +get_current_remote_target ()
> +{
> +  target_ops *proc_target = current_inferior ()->process_target ();
> +  return dynamic_cast<remote_target *> (proc_target);
> +}
> +
> +/* Get a pointer to the current remote target.  If not connected to a
> +   remote target, return NULL.  */

Here, I'd say:

/* Get a pointer to the current extended-remote target.  If not connected to an
   extended-remote target, return NULL.  */

> @@ -11319,6 +11369,84 @@ directory: %s"),
>      }
>  }
>  
> +/* See class declaration above.  */
> +
> +std::string
> +extended_remote_target::get_exec_file_for_create_inferior
> +  (const char *exec_file)
> +{
> +  const remote_exec_file_info &info
> +    = get_remote_exec_file_info (current_program_space);
> +
> +  /* Historically, when the remote target started a new inferior GDB would
> +     ignore the filename from GDB core (EXEC_FILE) and would use whatever
> +     value the user had set in 'remote exec-file'.  Now we try to be
> +     smarter.
> +
> +     Obviously, if 'remote exec-file' has been set, then this should be
> +     considered definitive.  But if 'remote exec-file' has not been set,
> +     then, in some cases, we might be able to use EXEC_FILE, or a
> +     derivative of EXEC_FILE.
> +
> +     It can also happen that EXEC_FILE is NULL.  This is mostly a bit of an
> +     edge case where GDB has attached to a running process, and couldn't
> +     figure out the filename for the executable.  If the user then does
> +     'run' we could end up with EXEC_FILE being NULL.  If this happens then
> +     the only option is to use the 'remote exec-file' setting.
> +
> +     If INFO.SOURCE is ::VALUE_FROM_REMOTE or ::VALUE_FROM_GDB then there
> +     is a value in 'remote exec-file', we should not do anything with
> +     EXEC_FILE and just retain the 'remote exec-file' value.
> +
> +     If INFO.SOURCE is ::UNSET_VALUE then the user hasn't 'set remote

The apostrophe is at the wrong place... it seems.  Not sure if it's
intentional.

> +     exec-file' value, and the remote target has specifically told us (via
> +     the qExecAndArgs packet) that it has no default executable set.  In
> +     this case, if GDB and the remote can see the same filesystem, we can
> +     potentially use EXEC_FILE.
> +
> +     If INFO.SOURCE is ::DEFAULT_VALUE then the user hasn't set a 'remote
> +     exec-file' value, but the remote target was unable to tell us (maybe
> +     the qExecAndArgs packet isn't supported) if it has a default
> +     executable set.  We might be tempted to treat this like the
> +     ::UNSET_VALUE case, however, this could potentially break backward
> +     compatibility in the case where the remote does have a default
> +     executable set.  To maintain compatibility, we send over the 'remote
> +     exec-file' setting, whatever it might be.  */
> +  if (exec_file != nullptr
> +      && info.source == remote_exec_source::UNSET_VALUE)
> +    {
> +      /* If the user has set the core exec file to a file on the target
> +	 then we can just strip the target prefix and use that as the
> +	 remote exec file name.  */
> +      if (is_target_filename (exec_file))
> +	return exec_file + strlen (TARGET_SYSROOT_PREFIX);
> +
> +      /* If the target filesystem is local then the remote can see
> +	 everything GDB can see.  In this case the remote should be able to
> +	 access EXEC_FILE.  */
> +      if (target_filesystem_is_local ())
> +	return exec_file;
> +
> +      /* If the sysroot is not a target path, then GDB can see a copy of
> +	 the remote target's filesystem, or if sysroot is empty, then the
> +	 remote and GDB could be sharing a filesystem.
> +
> +	 In either case, by removing the sysroot from the front of
> +	 EXEC_FILE, we can build a filename that the remote can see.  */
> +      if (!is_target_filename (gdb_sysroot))
> +	{
> +	  const char *in_sysroot_path = child_path (gdb_sysroot.c_str (),
> +						    exec_file);
> +	  if (in_sysroot_path != nullptr)
> +	    return path_join ("/", in_sysroot_path);
> +	}
> +    }
> +
> +  /* The user has set the remote exec-file, or GDB doesn't think the remote
> +     target and GDB can see the same filesystem.  */
> +  return info.filename;
> +}

Is it possible to organize the code in an early return style, where you
check the cases in order of precedence first?  I think that would be a
bit clearer, and it would probably match the order you explain things in
your comment.  I haven't actually tried it, if it doesn't work out,
you can ignore this.

> diff --git a/gdb/testsuite/gdb.server/ext-run.exp b/gdb/testsuite/gdb.server/ext-run.exp
> index f4ff546c393..18205e11ec8 100644
> --- a/gdb/testsuite/gdb.server/ext-run.exp
> +++ b/gdb/testsuite/gdb.server/ext-run.exp
> @@ -30,43 +30,147 @@ if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
>  # allow_xml_test must be called while gdb is not running.
>  set do_xml_test [allow_xml_test]
>  
> -save_vars { GDBFLAGS } {
> -    # If GDB and GDBserver are both running locally, set the sysroot to avoid
> -    # reading files via the remote protocol.
> -    if { ![is_remote host] && ![is_remote target] } {
> -	set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\""
> +# This is used as an override function.
> +proc do_nothing {} { return 0 }
> +
> +# Start an exetended-remote gdbserver, connect to it, and then use

"exetended"

> +# 'run' to start an inferior.
> +#
> +# If CLEAR_SYSROOT is true then the 'set sysroot' command is issued,
> +# clearing the sysroot, otherwise the sysroot is left unchanged.
> +#
> +# If SET_REMOTE_EXEC is true then the 'set remote-exec ...' command is

I guess you mean 'set remote exec-file', since 'set remote-exec' doesn't
exist.

> +# issued to point GDB at the executable on the target (after copying
> +# the executable over).  Otherwise, we rely on GDB and gdbserver being
> +# able to see the same filesystem, remote exec-file is not set, and
> +# GDB will just use the path to the executable.
> +proc do_test { clear_sysroot set_remote_exec fetch_exec_and_args } {
> +
> +    # If we don't clear the sysroot, then the sysroot will remain as
> +    # 'target:'.  In this case, if we don't 'set remote exec-file'
> +    # then GDB will not be able to start a remote inferior.
> +    if { !$clear_sysroot && !$set_remote_exec } {
> +	return
>      }
>  
>      clean_restart $::testfile
> -}
>  
> -# Make sure we're disconnected, in case we're testing with an
> -# extended-remote board, therefore already connected.
> -gdb_test "disconnect" ".*"
> +    # Disable, or enable, use of the qExecAndArgs packet.
> +    gdb_test "set remote fetch-exec-and-args-packet ${fetch_exec_and_args}" \
> +	".*"

You can just omit the ".*".

>  
> -set target_exec [gdbserver_download_current_prog]
> -gdbserver_start_extended
> +    # Make sure we're disconnected, in case we're testing with an
> +    # extended-remote board, therefore already connected.
> +    gdb_test "disconnect" ".*"

Likewise.

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-11-07 20:46     ` Simon Marchi
@ 2025-11-11 15:59       ` Andrew Burgess
  2026-01-14  1:17         ` Simon Marchi
  0 siblings, 1 reply; 20+ messages in thread
From: Andrew Burgess @ 2025-11-11 15:59 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: Eli Zaretskii

Simon Marchi <simark@simark.ca> writes:

> On 10/11/25 9:34 AM, Andrew Burgess wrote:
>> This commit allows GDB to make use of the file set with the 'file'
>> command when starting a new inferior on an extended-remote target.
>> There are however some restrictions.
>> 
>> If the user has used 'set remote exec-file', then this setting is
>> always used in preference to the file set with the 'file' command.
>> 
>> Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
>> that the remote target has an executable set, then this will be used
>> in preference to the file set with the 'file' command; this preserves
>> GDB's existing behaviour.  In effect, when GDB connects to the remote
>> target, the remote sets the 'remote exec-file' and this prevents GDB
>> from using the 'file' filename.
>> 
>> And, GDB can only use the file set with the 'file' command if it
>> believes that both GDB and the remote target will both be able to
>> access this file.  This means that one of these is true:
>> 
>>   + the the remote_target::filesystem_is_local function returns
>>     true (see the implementation of that function for details of when
>>     this can happen).  This means GDB and the remote target can see
>>     the same file system, GDB can just use the current executable's
>>     filename as is, or
>> 
>>   + the user has set the 'file' to something with a 'target:' prefix,
>>     e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
>>     the exec filename without the 'target:' prefix, this filename is,
>>     by definition, something the remote target can see, or
>> 
>>   + the sysroot has been updated by the user and no longer contains a
>>     'target:' prefix.  In this case, if the 'file' filename is within
>>     the sysroot, then it is assumed the remote will also be able to
>>     see a file with the same filename.  For example, if the sysroot is
>>     '/aa/', and the current executable is '/aa/bb/cc', then GDB will
>>     tell the remote to run '/bb/cc'.  One common case here is when the
>>     sysroot is set to the empty string, which is usually done when GDB
>>     and the remote target can see the same filesystem, in this case
>>     GDB will use the current executable's filename unmodified.
>> 
>> If one of these conditions is met, then GDB will use the current
>> executable's filename (with possible modifications as mentioned
>> above), when starting a new extended-remote inferior, in all other
>> cases, GDB will use the file name  set with 'set remote exec-file'.
>> 
>> This change could be useful any time a user is running a remote target
>> on the same machine as GDB, but I am specifically thinking of the case
>> where GDB is using a tool other than gdbserver, e.g. valgrind, as this
>> saves one additional step that a user must remember.  The current
>> steps to start valgrind with GDB, as given on the valgrind
>> website (https://valgrind.org/docs/manual/manual-core-adv.html) are:
>> 
>>   $ gdb prog
>>   (gdb) set remote exec-file prog
>>   (gdb) set sysroot /
>>   (gdb) target extended-remote | vgdb --multi --vargs -q
>>   (gdb) start
>> 
>> With this GDB work, and once support for the qExecAndArgs packet is
>> added to valgrind, then the 'set remote exec-file' line can be dropped
>> from those instructions.
>> 
>> This commit also extends the 'show remote exec-file' command so that
>> GDB will display the automatic value that it plans to use.  Here's an
>> example of the new output:
>> 
>>   $ gdb -q /tmp/hello
>>   Reading symbols from /tmp/hello...
>>   (gdb) set sysroot
>>   (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
>>   Remote debugging using | ./gdbserver/gdbserver --multi --once -
>>   Remote debugging using stdio
>>   (gdb) show remote exec-file
>>   The remote exec-file is unset, using automatic value "/tmp/hello".
>> 
>> The last line shows the new output.
>> 
>> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>
> I am investigating a regression when running gdb.gdb/selftest.exp with
> the native-extended-gdbserver board, caused by my commit d6340aa42e25
> ("gdb/testsuite: use libtool to launch selftests").  A side-effect of my
> change is that the test no longer does a "set remote exec-file", which
> is currently required in order to run a new process with an
> extended-remote board.  I started writing a patch to add a manual "set
> remote exec-file", but then remembered about this patch.  I gave it a
> try, and indeed it fixes those regressions.  I would therefore be very
> happy to see this patch merged (I had forgotten about it before just now
> to be honest).
>
> I'm fine with what you have see below for small comments.
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
>

I addressed the nits you pointed out, and pushed this patch.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct
  2025-10-11 13:34   ` [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct Andrew Burgess
  2025-10-11 13:46     ` Simon Marchi
@ 2025-11-19 10:32     ` Andrew Burgess
  1 sibling, 0 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-11-19 10:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Commit:

  commit 5edcbe2277db05b77ebf53f9c30b6c889a8729bc
  Date:   Mon Jul 24 17:35:54 2023 +0100

      gdb: detect when gdbserver has no default executable set

Introduced a use of std::pair as a data structure to hold some per
program space information within the program space registry.

It was pointed out during review of a later patch that the code would
be easier to understand if the std::pair was replaced with a struct
with named fields.

That is what this commit does.  Replace the std::pair with a struct,
and update all accesses to use the named fields.

There should be no user visible changes after this commit.
---
 gdb/remote.c | 60 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 27 deletions(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index 2e706e2d45b..143835ad503 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1640,15 +1640,22 @@ enum class remote_exec_source
   UNSET_VALUE,
 };
 
-/* Data held per program-space to represent the remote exec-file path.  The
-   first item in the pair is the exec-file path, this is set either by the
-   user with 'set remote exec-file', or automatically by GDB when
-   connecting to a remote target.
+/* Data held per program-space to represent the remote exec-file path.
+   This holds the 'remote exec-file' value and an enum to indicate where
+   the exec-file value came from, or what an empty exec-file value means.
+   See show_remote_exec_file for details.  */
 
-   The second item in the pair is an enum flag that indicates where the
-   path value came from, or, when the path is the empty string, what this
-   actually means.  See show_remote_exec_file for details.  */
-using remote_exec_file_info = std::pair<std::string, remote_exec_source>;
+struct remote_exec_file_info
+{
+  /* The 'remote exec-file' value.  This will be empty before being set.
+     This is set either with the 'set remote exec-file' command, or
+     automatically by GDB when connecting to a remote target.  */
+  std::string filename;
+
+  /* An enum that indicates where VALUE came from, or what an empty VALUE
+     means.  */
+  remote_exec_source source = remote_exec_source::DEFAULT_VALUE;
+};
 
 /* Per-program-space data key.  */
 static const registry<program_space>::key<remote_exec_file_info>
@@ -1662,8 +1669,7 @@ get_remote_exec_file_info (program_space *pspace)
 {
   remote_exec_file_info *info = remote_pspace_data.get (pspace);
   if (info == nullptr)
-    info = remote_pspace_data.emplace (pspace, "",
-				       remote_exec_source::DEFAULT_VALUE);
+    info = remote_pspace_data.emplace (pspace);
   gdb_assert (info != nullptr);
   return *info;
 }
@@ -2001,7 +2007,7 @@ get_remote_exec_file ()
 {
   const remote_exec_file_info &info
     = get_remote_exec_file_info (current_program_space);
-  return info.first;
+  return info.filename;
 }
 
 /* Set the remote exec file for PSPACE.  */
@@ -2012,8 +2018,8 @@ set_pspace_remote_exec_file (struct program_space *pspace,
 			     remote_exec_source source)
 {
   remote_exec_file_info &info = get_remote_exec_file_info (pspace);
-  info.first = filename;
-  info.second = source;
+  info.filename = filename;
+  info.source = source;
 }
 
 /* The "set remote exec-file" callback.  */
@@ -2034,16 +2040,16 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
   const remote_exec_file_info &info
     = get_remote_exec_file_info (current_program_space);
 
-  if (info.second == remote_exec_source::DEFAULT_VALUE)
+  if (info.source == remote_exec_source::DEFAULT_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
-  else if (info.second == remote_exec_source::UNSET_VALUE)
+  else if (info.source == remote_exec_source::UNSET_VALUE)
     gdb_printf (file, _("The remote exec-file is unset, the remote has "
 			"no default executable set.\n"));
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
-			       info.first.c_str ()));
+			       info.filename.c_str ()));
 }
 
 static int
@@ -5483,25 +5489,25 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
 	{
 	  remote_exec_file_info &info
 	    = get_remote_exec_file_info (current_program_space);
-	  if (info.second == remote_exec_source::VALUE_FROM_GDB
-	      && info.first != exec_and_args.exec ())
+	  if (info.source == remote_exec_source::VALUE_FROM_GDB
+	      && info.filename != exec_and_args.exec ())
 	    warning (_("updating 'remote exec-file' to '%ps' to match "
 		       "remote target"),
 		     styled_string (file_name_style.style (),
 				    exec_and_args.exec ().c_str ()));
-	  info.first = exec_and_args.exec ();
-	  info.second = remote_exec_source::VALUE_FROM_REMOTE;
+	  info.filename = exec_and_args.exec ();
+	  info.source = remote_exec_source::VALUE_FROM_REMOTE;
 	}
     }
   else if (exec_and_args.is_unset ())
     {
       remote_exec_file_info &info
 	= get_remote_exec_file_info (current_program_space);
-      if (info.second == remote_exec_source::DEFAULT_VALUE
-	  || info.second == remote_exec_source::VALUE_FROM_REMOTE)
+      if (info.source == remote_exec_source::DEFAULT_VALUE
+	  || info.source == remote_exec_source::VALUE_FROM_REMOTE)
 	{
-	  info.first.clear ();
-	  info.second = remote_exec_source::UNSET_VALUE;
+	  info.filename.clear ();
+	  info.source = remote_exec_source::UNSET_VALUE;
 	}
     }
 
@@ -6492,10 +6498,10 @@ remote_unpush_target (remote_target *target)
 	 would be unhelpful.  */
       remote_exec_file_info &exec_info
 	= get_remote_exec_file_info (inf->pspace);
-      if (exec_info.second == remote_exec_source::UNSET_VALUE)
+      if (exec_info.source == remote_exec_source::UNSET_VALUE)
 	{
-	  gdb_assert (exec_info.first.empty ());
-	  exec_info.second = remote_exec_source::DEFAULT_VALUE;
+	  gdb_assert (exec_info.filename.empty ());
+	  exec_info.source = remote_exec_source::DEFAULT_VALUE;
 	}
 
       inf->pop_all_targets_at_and_above (process_stratum);
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
  2025-10-11 14:45     ` Eli Zaretskii
  2025-11-07 20:46     ` Simon Marchi
@ 2025-11-19 10:32     ` Andrew Burgess
  2 siblings, 0 replies; 20+ messages in thread
From: Andrew Burgess @ 2025-11-19 10:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Eli Zaretskii

This commit allows GDB to make use of the file set with the 'file'
command when starting a new inferior on an extended-remote target.
There are however some restrictions.

If the user has used 'set remote exec-file', then this setting is
always used in preference to the file set with the 'file' command.

Similarly, if the qExecAndArgs packet has succeeded, and GDB knows
that the remote target has an executable set, then this will be used
in preference to the file set with the 'file' command; this preserves
GDB's existing behaviour.  In effect, when GDB connects to the remote
target, the remote sets the 'remote exec-file' and this prevents GDB
from using the 'file' filename.

And, GDB can only use the file set with the 'file' command if it
believes that both GDB and the remote target will both be able to
access this file.  This means that one of these is true:

  + the the remote_target::filesystem_is_local function returns
    true (see the implementation of that function for details of when
    this can happen).  This means GDB and the remote target can see
    the same file system, GDB can just use the current executable's
    filename as is, or

  + the user has set the 'file' to something with a 'target:' prefix,
    e.g. 'file target:/path/to/exec'.  In this last case, GDB will use
    the exec filename without the 'target:' prefix, this filename is,
    by definition, something the remote target can see, or

  + the sysroot has been updated by the user and no longer contains a
    'target:' prefix.  In this case, if the 'file' filename is within
    the sysroot, then it is assumed the remote will also be able to
    see a file with the same filename.  For example, if the sysroot is
    '/aa/', and the current executable is '/aa/bb/cc', then GDB will
    tell the remote to run '/bb/cc'.  One common case here is when the
    sysroot is set to the empty string, which is usually done when GDB
    and the remote target can see the same filesystem, in this case
    GDB will use the current executable's filename unmodified.

If one of these conditions is met, then GDB will use the current
executable's filename (with possible modifications as mentioned
above), when starting a new extended-remote inferior, in all other
cases, GDB will use the file name  set with 'set remote exec-file'.

This change could be useful any time a user is running a remote target
on the same machine as GDB, but I am specifically thinking of the case
where GDB is using a tool other than gdbserver, e.g. valgrind, as this
saves one additional step that a user must remember.  The current
steps to start valgrind with GDB, as given on the valgrind
website (https://valgrind.org/docs/manual/manual-core-adv.html) are:

  $ gdb prog
  (gdb) set remote exec-file prog
  (gdb) set sysroot /
  (gdb) target extended-remote | vgdb --multi --vargs -q
  (gdb) start

With this GDB work, and once support for the qExecAndArgs packet is
added to valgrind, then the 'set remote exec-file' line can be dropped
from those instructions.

This commit also extends the 'show remote exec-file' command so that
GDB will display the automatic value that it plans to use.  Here's an
example of the new output:

  $ gdb -q /tmp/hello
  Reading symbols from /tmp/hello...
  (gdb) set sysroot
  (gdb) target extended-remote | ./gdbserver/gdbserver --multi --once -
  Remote debugging using | ./gdbserver/gdbserver --multi --once -
  Remote debugging using stdio
  (gdb) show remote exec-file
  The remote exec-file is unset, using automatic value "/tmp/hello".

The last line shows the new output.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                             |   8 ++
 gdb/doc/gdb.texinfo                  |   4 +-
 gdb/remote.c                         | 156 +++++++++++++++++++++++---
 gdb/testsuite/gdb.server/ext-run.exp | 160 ++++++++++++++++++++++-----
 4 files changed, 286 insertions(+), 42 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index b0146852c5c..58a5b3c2496 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,14 @@
   subsequent runs of the inferior will use the same arguments as the
   first run.
 
+* When connected to an extended-remote target GDB can now
+  automatically set the 'remote exec-file' in some cases.  GDB will
+  auto set the remote exec-file only if the remote wasn't started with
+  an executable, and the user hasn't used 'set remote exec-file' to
+  set an executable.  GDB will auto set the remote exec-file using the
+  current executable if the current executable has a 'target:' prefix,
+  or if the current executable is within the sysroot.
+
 * New targets
 
 GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1b463b167e7..efd9d80de07 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24668,7 +24668,9 @@ Remote Configuration
 Select the file used for @code{run} with @code{target
 extended-remote}.  This should be set to a filename valid on the
 target system.  If it is not set, the target will use a default
-filename (e.g.@: the last program run).
+filename (e.g.@: the last program run, or a filename derived from the
+current executable if @value{GDBN} and the remote can see the same
+file system).
 
 When connecting to a remote system, with @kbd{target extended-remote}
 or @kbd{target remote}, if the remote server supports the
diff --git a/gdb/remote.c b/gdb/remote.c
index 143835ad503..2c77405305e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -43,9 +43,11 @@
 #include "target-descriptions.h"
 #include "gdb_bfd.h"
 #include "gdbsupport/filestuff.h"
+#include "gdbsupport/pathstuff.h"
 #include "gdbsupport/rsp-low.h"
 #include "disasm.h"
 #include "location.h"
+#include "filenames.h"
 
 #include "gdbsupport/gdb_sys_time.h"
 
@@ -1555,8 +1557,49 @@ class extended_remote_target final : public remote_target
 
   void post_attach (int) override;
   bool supports_disable_randomization () override;
+
+  /* Return the file name for the executable that GDB should ask the remote
+     target to use when starting an inferior.
+
+     EXEC_FILE is the string passed from GDB core, which is the file name
+     of the current executable, which can be NULL.
+
+     If the user has done 'set remote exec-file', or the remote told GDB
+     which executable to use via the 'qExecAndArgs' packet, then this is
+     the value returned by this function, EXEC_FILE is ignored.
+
+     But if there is no remote exec-file set, then we might be able to use
+     EXEC_FILE, or a variation of EXEC_FILE, as the 'remote exec-file'
+     setting.  This will depend on the value of EXEC_FILE and/or the
+     current gdb_sysroot setting.  In this case the file name derived from
+     EXEC_FILE is returned.
+
+     If neither approach comes up with a suitable file name to run then
+     the empty string is returned.  */
+
+  std::string get_exec_file_for_create_inferior (const char *exec_file);
 };
 
+/* Get a pointer to the current remote target.  If not connected to a
+   remote target, return NULL.  */
+
+static remote_target *
+get_current_remote_target ()
+{
+  target_ops *proc_target = current_inferior ()->process_target ();
+  return dynamic_cast<remote_target *> (proc_target);
+}
+
+/* Get a pointer to the current remote target.  If not connected to a
+   remote target, return NULL.  */
+
+static extended_remote_target *
+get_current_extended_remote_target ()
+{
+  target_ops *proc_target = current_inferior ()->process_target ();
+  return dynamic_cast<extended_remote_target *> (proc_target);
+}
+
 struct stop_reply : public notif_event
 {
   /* The identifier of the thread about this event  */
@@ -2044,8 +2087,25 @@ show_remote_exec_file (struct ui_file *file, int from_tty,
     gdb_printf (file, _("The remote exec-file is unset, the default "
 			"remote executable will be used.\n"));
   else if (info.source == remote_exec_source::UNSET_VALUE)
-    gdb_printf (file, _("The remote exec-file is unset, the remote has "
-			"no default executable set.\n"));
+    {
+      std::string remote_exec_filename;
+      extended_remote_target *remote = get_current_extended_remote_target ();
+      if (remote != nullptr)
+	{
+	  const char *exec_file = current_program_space->exec_filename ();
+	  remote_exec_filename
+	    = remote->get_exec_file_for_create_inferior (exec_file);
+	}
+
+      if (!remote_exec_filename.empty ())
+	gdb_printf (file, _("The remote exec-file is unset, using "
+			    "automatic value \"%ps\".\n"),
+		    styled_string (file_name_style.style (),
+				   remote_exec_filename.c_str ()));
+      else
+	gdb_printf (file, _("The remote exec-file is unset, the remote has "
+			    "no default executable set.\n"));
+    }
   else
     gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
 		styled_string (file_name_style.style (),
@@ -2151,16 +2211,6 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch)
     this->remote_packet_size = (this->sizeof_g_packet * 2 + 32);
 }
 
-/* Get a pointer to the current remote target.  If not connected to a
-   remote target, return NULL.  */
-
-static remote_target *
-get_current_remote_target ()
-{
-  target_ops *proc_target = current_inferior ()->process_target ();
-  return dynamic_cast<remote_target *> (proc_target);
-}
-
 /* Return the current allowed size of a remote packet.  This is
    inferred from the current architecture, and should be used to
    limit the length of outgoing packets.  */
@@ -11319,6 +11369,84 @@ directory: %s"),
     }
 }
 
+/* See class declaration above.  */
+
+std::string
+extended_remote_target::get_exec_file_for_create_inferior
+  (const char *exec_file)
+{
+  const remote_exec_file_info &info
+    = get_remote_exec_file_info (current_program_space);
+
+  /* Historically, when the remote target started a new inferior GDB would
+     ignore the filename from GDB core (EXEC_FILE) and would use whatever
+     value the user had set in 'remote exec-file'.  Now we try to be
+     smarter.
+
+     Obviously, if 'remote exec-file' has been set, then this should be
+     considered definitive.  But if 'remote exec-file' has not been set,
+     then, in some cases, we might be able to use EXEC_FILE, or a
+     derivative of EXEC_FILE.
+
+     It can also happen that EXEC_FILE is NULL.  This is mostly a bit of an
+     edge case where GDB has attached to a running process, and couldn't
+     figure out the filename for the executable.  If the user then does
+     'run' we could end up with EXEC_FILE being NULL.  If this happens then
+     the only option is to use the 'remote exec-file' setting.
+
+     If INFO.SOURCE is ::VALUE_FROM_REMOTE or ::VALUE_FROM_GDB then there
+     is a value in 'remote exec-file', we should not do anything with
+     EXEC_FILE and just retain the 'remote exec-file' value.
+
+     If INFO.SOURCE is ::UNSET_VALUE then the user hasn't 'set remote
+     exec-file' value, and the remote target has specifically told us (via
+     the qExecAndArgs packet) that it has no default executable set.  In
+     this case, if GDB and the remote can see the same filesystem, we can
+     potentially use EXEC_FILE.
+
+     If INFO.SOURCE is ::DEFAULT_VALUE then the user hasn't set a 'remote
+     exec-file' value, but the remote target was unable to tell us (maybe
+     the qExecAndArgs packet isn't supported) if it has a default
+     executable set.  We might be tempted to treat this like the
+     ::UNSET_VALUE case, however, this could potentially break backward
+     compatibility in the case where the remote does have a default
+     executable set.  To maintain compatibility, we send over the 'remote
+     exec-file' setting, whatever it might be.  */
+  if (exec_file != nullptr
+      && info.source == remote_exec_source::UNSET_VALUE)
+    {
+      /* If the user has set the core exec file to a file on the target
+	 then we can just strip the target prefix and use that as the
+	 remote exec file name.  */
+      if (is_target_filename (exec_file))
+	return exec_file + strlen (TARGET_SYSROOT_PREFIX);
+
+      /* If the target filesystem is local then the remote can see
+	 everything GDB can see.  In this case the remote should be able to
+	 access EXEC_FILE.  */
+      if (target_filesystem_is_local ())
+	return exec_file;
+
+      /* If the sysroot is not a target path, then GDB can see a copy of
+	 the remote target's filesystem, or if sysroot is empty, then the
+	 remote and GDB could be sharing a filesystem.
+
+	 In either case, by removing the sysroot from the front of
+	 EXEC_FILE, we can build a filename that the remote can see.  */
+      if (!is_target_filename (gdb_sysroot))
+	{
+	  const char *in_sysroot_path = child_path (gdb_sysroot.c_str (),
+						    exec_file);
+	  if (in_sysroot_path != nullptr)
+	    return path_join ("/", in_sysroot_path);
+	}
+    }
+
+  /* The user has set the remote exec-file, or GDB doesn't think the remote
+     target and GDB can see the same filesystem.  */
+  return info.filename;
+}
+
 /* In the extended protocol we want to be able to do things like
    "run" and have them basically work as expected.  So we need
    a special create_inferior function.  We support changing the
@@ -11333,7 +11461,9 @@ extended_remote_target::create_inferior (const char *exec_file,
   int run_worked;
   char *stop_reply;
   struct remote_state *rs = get_remote_state ();
-  const std::string &remote_exec_file = get_remote_exec_file ();
+
+  std::string remote_exec_file
+    = get_exec_file_for_create_inferior (exec_file);
 
   /* If running asynchronously, register the target file descriptor
      with the event loop.  */
diff --git a/gdb/testsuite/gdb.server/ext-run.exp b/gdb/testsuite/gdb.server/ext-run.exp
index f4ff546c393..18205e11ec8 100644
--- a/gdb/testsuite/gdb.server/ext-run.exp
+++ b/gdb/testsuite/gdb.server/ext-run.exp
@@ -30,43 +30,147 @@ if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
 # allow_xml_test must be called while gdb is not running.
 set do_xml_test [allow_xml_test]
 
-save_vars { GDBFLAGS } {
-    # If GDB and GDBserver are both running locally, set the sysroot to avoid
-    # reading files via the remote protocol.
-    if { ![is_remote host] && ![is_remote target] } {
-	set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\""
+# This is used as an override function.
+proc do_nothing {} { return 0 }
+
+# Start an exetended-remote gdbserver, connect to it, and then use
+# 'run' to start an inferior.
+#
+# If CLEAR_SYSROOT is true then the 'set sysroot' command is issued,
+# clearing the sysroot, otherwise the sysroot is left unchanged.
+#
+# If SET_REMOTE_EXEC is true then the 'set remote-exec ...' command is
+# issued to point GDB at the executable on the target (after copying
+# the executable over).  Otherwise, we rely on GDB and gdbserver being
+# able to see the same filesystem, remote exec-file is not set, and
+# GDB will just use the path to the executable.
+proc do_test { clear_sysroot set_remote_exec fetch_exec_and_args } {
+
+    # If we don't clear the sysroot, then the sysroot will remain as
+    # 'target:'.  In this case, if we don't 'set remote exec-file'
+    # then GDB will not be able to start a remote inferior.
+    if { !$clear_sysroot && !$set_remote_exec } {
+	return
     }
 
     clean_restart $::testfile
-}
 
-# Make sure we're disconnected, in case we're testing with an
-# extended-remote board, therefore already connected.
-gdb_test "disconnect" ".*"
+    # Disable, or enable, use of the qExecAndArgs packet.
+    gdb_test "set remote fetch-exec-and-args-packet ${fetch_exec_and_args}" \
+	".*"
 
-set target_exec [gdbserver_download_current_prog]
-gdbserver_start_extended
+    # Make sure we're disconnected, in case we're testing with an
+    # extended-remote board, therefore already connected.
+    gdb_test "disconnect" ".*"
 
-gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"
+    if { $clear_sysroot } {
+	gdb_test_no_output "set sysroot" \
+	    "clear sysroot"
+    } else {
+	set sysroot "UNKNOWN"
+	gdb_test_multiple "show sysroot" "" {
+	    -re -wrap "^The current system root is \"(\[^\r\n\]*)\"\\." {
+		set sysroot $expect_out(1,string)
+		pass $gdb_test_name
+	    }
+	}
 
-gdb_breakpoint main
-gdb_test "run" "Breakpoint.* main .*" "continue to main"
-
-if { [istarget *-*-linux*] } {
-    # On Linux, gdbserver can also report the list of processes.
-    # But only if xml support is compiled in.
-    if { $do_xml_test } {
-	# This is done in a way to avoid the timeout that can occur from
-	# applying .* regexp to large output.
-	gdb_test_lines "info os processes" "get process list" \
-	    "^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	if { $sysroot eq "" } {
+	    gdb_test_no_output "set sysroot target:"
+	} elseif { $sysroot ne "target:" } {
+	    unsupported "unexpected sysroot value"
+	    return
+	}
     }
-}
 
-gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+    gdbserver_start_extended
 
-gdb_load $binfile
-gdb_test "monitor help" "The following monitor commands.*" \
+    # Check the 'remote exec-file' setting before we (possibly) set it
+    # ourselves.
+    if { !$fetch_exec_and_args } {
+	set suffix "the default remote executable will be used"
+    } elseif { !$clear_sysroot} {
+	set suffix "the remote has no default executable set"
+    } else {
+	set file_re [string_to_regexp $::binfile]
+	set suffix "using automatic value \"$file_re\""
+    }
+    gdb_test "show remote exec-file" \
+	"The remote exec-file is unset, ${suffix}\\." \
+	"check remote exec-file is unset"
+
+    if { $set_remote_exec } {
+	set target_exec [gdbserver_download_current_prog]
+	gdb_test_no_output "set remote exec-file $target_exec" \
+	    "set remote exec-file"
+
+	# Check GDB reflect the value we just set.
+	set file_re [string_to_regexp $target_exec]
+	gdb_test "show remote exec-file" \
+	    "The remote exec-file is \"$file_re\"\\." \
+	    "check remote exec-file after set"
+    }
+
+    gdb_breakpoint main
+    gdb_test_multiple "run" "continue to main" {
+	-re -wrap "Breakpoint.* main .*" {
+	    pass $gdb_test_name
+	}
+	-re -wrap "Running the default executable on the remote target failed; try \"set remote exec-file\"." {
+
+	    # If 'set remote exec-file' has been used then we should
+	    # not get here.
+	    gdb_assert {!$set_remote_exec} \
+		"confirm remote exec-file is not set"
+
+	    if {!$fetch_exec_and_args} {
+		# We deliberately disabled GDB's ability to know that
+		# the remote doesn't have a default executable set (by
+		# disabling the qDefaultExecAndArgs packet).  We got
+		# the result we expected, but the inferior is not
+		# running, so we're done with this phase of testing.
+		pass $gdb_test_name
+		return
+	    }
+	}
+    }
+
+    if { [istarget *-*-linux*] } {
+	# On Linux, gdbserver can also report the list of processes.
+	# But only if xml support is compiled in.
+	if { $::do_xml_test } {
+	    # This is done in a way to avoid the timeout that can occur from
+	    # applying .* regexp to large output.
+	    gdb_test_lines "info os processes" "get process list" \
+		"^pid +user +command.*\r\n1 +root +\[/a-z\]*(init|systemd|bash)"
+	}
+    }
+
+    gdb_test "kill" "" "kill" "Kill the program being debugged. .y or n. " "y"
+
+    gdb_load $::binfile
+    gdb_test "monitor help" "The following monitor commands.*" \
         "load new file without any gdbserver inferior"
 
-gdb_test_no_output "monitor exit"
+    gdb_test_no_output "monitor exit"
+}
+
+set clear_sysroot_modes { false }
+set set_remote_exec_modes { true }
+if {![is_remote target] && ![is_remote host]} {
+    lappend set_remote_exec_modes false
+    lappend clear_sysroot_modes true
+}
+
+# This override prevents GDB from automatically setting the 'remote
+# exec-file' when using the extended-remote protocol.  If we want the
+# exec-file set, then this test takes care of it.
+with_override extended_gdbserver_load_last_file do_nothing {
+    foreach_with_prefix clear_sysroot $clear_sysroot_modes {
+	foreach_with_prefix set_remote_exec $set_remote_exec_modes {
+	    foreach_with_prefix fetch_exec_and_args { on off } {
+		do_test $clear_sysroot $set_remote_exec $fetch_exec_and_args
+	    }
+	}
+    }
+}
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2025-11-11 15:59       ` Andrew Burgess
@ 2026-01-14  1:17         ` Simon Marchi
  2026-01-14 16:48           ` Andrew Burgess
  2026-01-14 20:01           ` [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp Andrew Burgess
  0 siblings, 2 replies; 20+ messages in thread
From: Simon Marchi @ 2026-01-14  1:17 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Eli Zaretskii



On 2025-11-11 10:59, Andrew Burgess wrote:
> I addressed the nits you pointed out, and pushed this patch.
> 
> Thanks,
> Andrew
> 

FYI, I think this patch caused this regression:

https://sourceware.org/bugzilla/show_bug.cgi?id=33792

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases
  2026-01-14  1:17         ` Simon Marchi
@ 2026-01-14 16:48           ` Andrew Burgess
  2026-01-14 20:01           ` [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp Andrew Burgess
  1 sibling, 0 replies; 20+ messages in thread
From: Andrew Burgess @ 2026-01-14 16:48 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches; +Cc: Eli Zaretskii

Simon Marchi <simark@simark.ca> writes:

> On 2025-11-11 10:59, Andrew Burgess wrote:
>> I addressed the nits you pointed out, and pushed this patch.
>> 
>> Thanks,
>> Andrew
>> 
>
> FYI, I think this patch caused this regression:
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=33792
>
> Simon

I'll take a look at this tomorrow.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp
  2026-01-14  1:17         ` Simon Marchi
  2026-01-14 16:48           ` Andrew Burgess
@ 2026-01-14 20:01           ` Andrew Burgess
  2026-01-15 21:13             ` Simon Marchi
  1 sibling, 1 reply; 20+ messages in thread
From: Andrew Burgess @ 2026-01-14 20:01 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Bug PR gdb/33792 reported a gdb.server/fetch-exec-and-args.exp FAIL
when using the native-gdbserver board:

  FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file

The actual test output looks like this:

  (gdb) show remote exec-file
  The remote exec-file is unset, using automatic value "/tmp/build/gdb/testsuite/outputs/gdb.server/fetch-exec-and-args/fetch-exec-and-args".
  (gdb) FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file

This test actually fails with native-gdbsever and
native-extended-gdbserver boards.  The problem is that these boards
clear the sysroot.

This exact test has the following conditions:

  + The qExecAndArgs is in use (see 'packet=on').

  + We're not explicitly doing 'set remote exec-file ...' (see
    'set_remote_exec=false').

  + The test starts gdbserver without an executable (see
    'test_server_with_no_exec').

  + And because of the native-gdbsever board, the sysroot is "".

What this means is that GDB knows that gdbserver doesn't have an
executable thanks to qExecAndArgs, the user hasn't set an executable
for GDB to use when starting a new inferior, but GDB does know that
GDB and gdbserver can see the same filesystem due to the sysroot
setting.  GDB will then automatically use the current executable as
the remote executable name.  The test script doesn't expect this case,
and so the test fails.

Fix this by adjusting the script to expect the 'using automatic value
...' text when appropriate.

I also extended the test_server_with_no_exec proc to take a new flag
'clear_sysroot', we now run the test with the sysroot set to 'target:'
and with the sysroot set to "", even when using the 'unix' board.

Additionally, I ran the test through check-all-boards and found one
additional failure, when using --host_board=local-remote-host-native
and --target_board=local-remote-host-native.  In this case GDB copies
the executable to the remote host, which changes its filename.  When
the filename appears in the 'using automatic value ...' text, I was
expecting the filename assuming a local host.

I could fix this, but it doesn't seem worth the extra complexity for
this one test, so I've just set the test to be skipped for that one
configuration.

Now, when using check-all-boards, I'm seeing no failures.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33792
---
 .../gdb.server/fetch-exec-and-args.exp        | 57 +++++++++++++++++--
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/gdb/testsuite/gdb.server/fetch-exec-and-args.exp b/gdb/testsuite/gdb.server/fetch-exec-and-args.exp
index d85cd94fb1d..36189dec602 100644
--- a/gdb/testsuite/gdb.server/fetch-exec-and-args.exp
+++ b/gdb/testsuite/gdb.server/fetch-exec-and-args.exp
@@ -54,11 +54,22 @@ proc check_show_args { packet } {
 # 'off' and reflects whether the qExecAndArgs packet is turned on or
 # off.  FILENAME is what we expect to see included in the output, and
 # is converted to a regexp by this function.
-proc check_remote_exec_file { packet filename } {
+#
+# The AUTO_FILENAME should only be set when PACKET is on and FILENAME
+# is the empty sting.  If AUTO_FILENAME is set, then this is the
+# filename that GDB is using for the remote executable based on the
+# current executable's filename.  For example, if the sysroot is empty
+# then GDB can use the current executable as the remote executable.
+proc check_remote_exec_file { packet filename { auto_filename "" } } {
     if { $filename eq "" } {
 	if { $packet } {
-	    set remote_exec_re \
-		"The remote exec-file is unset, the remote has no default executable set\\."
+	    if { $auto_filename ne "" } {
+		set remote_exec_re \
+		    "The remote exec-file is unset, using automatic value \"[string_to_regexp $auto_filename]\"\\."
+	    } else {
+		set remote_exec_re \
+		    "The remote exec-file is unset, the remote has no default executable set\\."
+	    }
 	} else {
 	    set remote_exec_re \
 		"The remote exec-file is unset, the default remote executable will be used\\."
@@ -260,9 +271,35 @@ proc_with_prefix test_remote_exec_warning {} {
 # filename when starting gdbserver.
 #
 # Connect to the remote server, and check 'show remote exec-file'.
-proc_with_prefix test_server_with_no_exec { packet set_remote_exec } {
+proc_with_prefix test_server_with_no_exec { packet set_remote_exec clear_sysroot } {
+    # For remote hosts GDB copies the executable to the host, changing
+    # its filename.  We can figure out the new exec filename, but it's
+    # additional work, so just don't bother.  We only need to bail out
+    # though in the precise case that the executable filename will be
+    # used in the output.
+    if {!$set_remote_exec && $clear_sysroot && [is_remote host]} {
+	return
+    }
+
     clean_restart
 
+    set sysroot "*UNKNOWN*"
+    gdb_test_multiple "show sysroot" "" {
+	-re -wrap "^The current system root is \"(\[^\r\n\]*)\"\\." {
+	    set sysroot $expect_out(1,string)
+	    pass $gdb_test_name
+	}
+    }
+    if { $sysroot ne "target:" && $sysroot ne "" } {
+	return
+    }
+
+    if { $clear_sysroot } {
+	gdb_test_no_output "set sysroot"
+    } else {
+	gdb_test_no_output "set sysroot target:"
+    }
+
     gdb_test "disconnect" ".*"
 
     gdb_file_cmd $::binfile
@@ -277,13 +314,18 @@ proc_with_prefix test_server_with_no_exec { packet set_remote_exec } {
 	gdb_test_no_output "set remote exec-file $target_exec" \
 	    "set remote exec-file"
 	set expected_filename $target_exec
+	set auto_filename ""
+    } elseif { $clear_sysroot } {
+	set expected_filename ""
+	set auto_filename $::binfile
     } else {
 	set expected_filename ""
+	set auto_filename ""
     }
 
     gdbserver_start_extended
 
-    check_remote_exec_file $packet $expected_filename
+    check_remote_exec_file $packet $expected_filename $auto_filename
 }
 
 # This override prevents the remote exec-file from being set when
@@ -298,7 +340,10 @@ with_override extended_gdbserver_load_last_file do_nothing {
 	    test_exec_and_arg_fetch $packet
 
 	    foreach_with_prefix set_remote_exec { true false } {
-		test_server_with_no_exec $packet $set_remote_exec
+		foreach_with_prefix clear_sysroot { true false } {
+		    test_server_with_no_exec $packet $set_remote_exec \
+			$clear_sysroot
+		}
 	    }
 	}
 

base-commit: 141f3b0ce1a4141ec0bbd19f1c5713999113a7de
-- 
2.47.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp
  2026-01-14 20:01           ` [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp Andrew Burgess
@ 2026-01-15 21:13             ` Simon Marchi
  2026-01-22 15:31               ` Andrew Burgess
  0 siblings, 1 reply; 20+ messages in thread
From: Simon Marchi @ 2026-01-15 21:13 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 1/14/26 3:01 PM, Andrew Burgess wrote:
> Bug PR gdb/33792 reported a gdb.server/fetch-exec-and-args.exp FAIL
> when using the native-gdbserver board:
> 
>   FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file
> 
> The actual test output looks like this:
> 
>   (gdb) show remote exec-file
>   The remote exec-file is unset, using automatic value "/tmp/build/gdb/testsuite/outputs/gdb.server/fetch-exec-and-args/fetch-exec-and-args".
>   (gdb) FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file
> 
> This test actually fails with native-gdbsever and
> native-extended-gdbserver boards.  The problem is that these boards
> clear the sysroot.
> 
> This exact test has the following conditions:
> 
>   + The qExecAndArgs is in use (see 'packet=on').
> 
>   + We're not explicitly doing 'set remote exec-file ...' (see
>     'set_remote_exec=false').
> 
>   + The test starts gdbserver without an executable (see
>     'test_server_with_no_exec').
> 
>   + And because of the native-gdbsever board, the sysroot is "".
> 
> What this means is that GDB knows that gdbserver doesn't have an
> executable thanks to qExecAndArgs, the user hasn't set an executable
> for GDB to use when starting a new inferior, but GDB does know that
> GDB and gdbserver can see the same filesystem due to the sysroot
> setting.  GDB will then automatically use the current executable as
> the remote executable name.  The test script doesn't expect this case,
> and so the test fails.
> 
> Fix this by adjusting the script to expect the 'using automatic value
> ...' text when appropriate.
> 
> I also extended the test_server_with_no_exec proc to take a new flag
> 'clear_sysroot', we now run the test with the sysroot set to 'target:'
> and with the sysroot set to "", even when using the 'unix' board.
> 
> Additionally, I ran the test through check-all-boards and found one
> additional failure, when using --host_board=local-remote-host-native
> and --target_board=local-remote-host-native.  In this case GDB copies
> the executable to the remote host, which changes its filename.  When
> the filename appears in the 'using automatic value ...' text, I was
> expecting the filename assuming a local host.
> 
> I could fix this, but it doesn't seem worth the extra complexity for
> this one test, so I've just set the test to be skipped for that one
> configuration.
> 
> Now, when using check-all-boards, I'm seeing no failures.
> 
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33792

It appears to fix the failure on my side.  Thanks for the quick fix and
for improving the test.

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp
  2026-01-15 21:13             ` Simon Marchi
@ 2026-01-22 15:31               ` Andrew Burgess
  0 siblings, 0 replies; 20+ messages in thread
From: Andrew Burgess @ 2026-01-22 15:31 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

Simon Marchi <simark@simark.ca> writes:

> On 1/14/26 3:01 PM, Andrew Burgess wrote:
>> Bug PR gdb/33792 reported a gdb.server/fetch-exec-and-args.exp FAIL
>> when using the native-gdbserver board:
>> 
>>   FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file
>> 
>> The actual test output looks like this:
>> 
>>   (gdb) show remote exec-file
>>   The remote exec-file is unset, using automatic value "/tmp/build/gdb/testsuite/outputs/gdb.server/fetch-exec-and-args/fetch-exec-and-args".
>>   (gdb) FAIL: gdb.server/fetch-exec-and-args.exp: packet=on: set_remote_exec=false: test_server_with_no_exec: show remote exec-file
>> 
>> This test actually fails with native-gdbsever and
>> native-extended-gdbserver boards.  The problem is that these boards
>> clear the sysroot.
>> 
>> This exact test has the following conditions:
>> 
>>   + The qExecAndArgs is in use (see 'packet=on').
>> 
>>   + We're not explicitly doing 'set remote exec-file ...' (see
>>     'set_remote_exec=false').
>> 
>>   + The test starts gdbserver without an executable (see
>>     'test_server_with_no_exec').
>> 
>>   + And because of the native-gdbsever board, the sysroot is "".
>> 
>> What this means is that GDB knows that gdbserver doesn't have an
>> executable thanks to qExecAndArgs, the user hasn't set an executable
>> for GDB to use when starting a new inferior, but GDB does know that
>> GDB and gdbserver can see the same filesystem due to the sysroot
>> setting.  GDB will then automatically use the current executable as
>> the remote executable name.  The test script doesn't expect this case,
>> and so the test fails.
>> 
>> Fix this by adjusting the script to expect the 'using automatic value
>> ...' text when appropriate.
>> 
>> I also extended the test_server_with_no_exec proc to take a new flag
>> 'clear_sysroot', we now run the test with the sysroot set to 'target:'
>> and with the sysroot set to "", even when using the 'unix' board.
>> 
>> Additionally, I ran the test through check-all-boards and found one
>> additional failure, when using --host_board=local-remote-host-native
>> and --target_board=local-remote-host-native.  In this case GDB copies
>> the executable to the remote host, which changes its filename.  When
>> the filename appears in the 'using automatic value ...' text, I was
>> expecting the filename assuming a local host.
>> 
>> I could fix this, but it doesn't seem worth the extra complexity for
>> this one test, so I've just set the test to be skipped for that one
>> configuration.
>> 
>> Now, when using check-all-boards, I'm seeing no failures.
>> 
>> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33792
>
> It appears to fix the failure on my side.  Thanks for the quick fix and
> for improving the test.
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>

I forgot about this one.  Now pushed.

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-01-22 15:32 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-06 15:07 [PATCH] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
2025-10-06 15:43 ` Eli Zaretskii
2025-10-09 16:17 ` Simon Marchi
2025-10-11 13:34 ` [PATCH 0/2] Auto setting of 'remote exec-file' Andrew Burgess
2025-10-11 13:34   ` [PATCH 1/2] gdb/remote: replace use of std::pair with an actual struct Andrew Burgess
2025-10-11 13:46     ` Simon Marchi
2025-10-12  8:57       ` Andrew Burgess
2025-10-12 12:05         ` Simon Marchi
2025-10-12 13:13           ` Andrew Burgess
2025-11-19 10:32     ` Andrew Burgess
2025-10-11 13:34   ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess
2025-10-11 14:45     ` Eli Zaretskii
2025-11-07 20:46     ` Simon Marchi
2025-11-11 15:59       ` Andrew Burgess
2026-01-14  1:17         ` Simon Marchi
2026-01-14 16:48           ` Andrew Burgess
2026-01-14 20:01           ` [PATCH] gdb/testsuite: fix failure in gdb.server/fetch-exec-and-args.exp Andrew Burgess
2026-01-15 21:13             ` Simon Marchi
2026-01-22 15:31               ` Andrew Burgess
2025-11-19 10:32     ` [PATCH 2/2] gdb: use current executable for 'remote exec-file' in some cases Andrew Burgess

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox