return m_state == state::SET;
}
+ /* Is this object in state::UNSET? */
+ bool is_unset () const
+ {
+ return m_state == state::UNSET;
+ }
+
/* Return the argument string. Only call when is_set returns true. */
const std::string &args () const
{
return rs->last_seen_expedited_registers.count (regnum) > 0;
}
+/* An enum used to track where the per-program-space remote exec-file data
+ came from. This is useful when deciding which warnings to give to the
+ user. */
+
+enum class remote_exec_source
+{
+ /* The remote exec-file has it's default (empty string) value, neither
+ the user, nor the remote target have tried to set the value yet. */
+ DEFAULT_VALUE,
+
+ /* The remote exec-file value was set based on information fetched from
+ the remote target. We warn the user if we are replacing a value they
+ supplied with one fetched from the remote target. */
+ VALUE_FROM_REMOTE,
+
+ /* The remote exec-file value was set either directly by the user, or by
+ GDB after the inferior performed an exec. */
+ VALUE_FROM_GDB,
+
+ /* The remote exec-file has it's default (empty string) value, but this
+ is because the user hasn't supplied a value yet, and the remote target
+ has specifically told GDB that it has no default executable available. */
+ 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.
+
+ 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>;
+
/* Per-program-space data key. */
-static const registry<program_space>::key<std::string> remote_pspace_data;
+static const registry<program_space>::key<remote_exec_file_info>
+ 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. */
+
+static remote_exec_file_info &
+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);
+ gdb_assert (info != nullptr);
+ return *info;
+}
/* The size to align memory write packets, when practical. The protocol
does not guarantee any alignment, and gdb will generate short
/* Fetch the remote exec-file from the current program space. */
static const std::string &
-get_remote_exec_file (void)
+get_remote_exec_file ()
{
- const std::string *remote_exec_file
- = remote_pspace_data.get (current_program_space);
- if (remote_exec_file == nullptr)
- remote_exec_file = remote_pspace_data.emplace (current_program_space);
- return *remote_exec_file;
+ const remote_exec_file_info &info
+ = get_remote_exec_file_info (current_program_space);
+ return info.first;
}
/* Set the remote exec file for PSPACE. */
static void
set_pspace_remote_exec_file (struct program_space *pspace,
- const std::string &filename)
+ const std::string &filename,
+ remote_exec_source source)
{
- remote_pspace_data.clear (pspace);
- remote_pspace_data.emplace (pspace, filename);
+ remote_exec_file_info &info = get_remote_exec_file_info (pspace);
+ info.first = filename;
+ info.second = source;
}
/* The "set remote exec-file" callback. */
static void
set_remote_exec_file_cb (const std::string &filename)
{
- set_pspace_remote_exec_file (current_program_space,
- filename);
+ set_pspace_remote_exec_file (current_program_space, filename,
+ remote_exec_source::VALUE_FROM_GDB);
}
/* Implement the "show remote exec-file" command. */
show_remote_exec_file (struct ui_file *file, int from_tty,
struct cmd_list_element *cmd, const char *value)
{
- const std::string &filename = get_remote_exec_file ();
- if (filename.empty ())
- gdb_printf (file, _("The remote exec-file is unset, the default remote "
- "executable will be used.\n"));
+ const remote_exec_file_info &info
+ = get_remote_exec_file_info (current_program_space);
+
+ if (info.second == 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)
+ 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 \"%s\".\n", filename.c_str ());
+ gdb_printf (file, _("The remote exec-file is \"%ps\".\n"),
+ styled_string (file_name_style.style (),
+ info.first.c_str ()));
}
static int
if (exec_and_args.is_set ())
{
current_inferior ()->set_args (exec_and_args.args ());
-
if (!exec_and_args.exec ().empty ())
{
- const std::string &remote_exec = get_remote_exec_file ();
- if (!remote_exec.empty () && remote_exec != exec_and_args.exec ())
+ 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 ())
warning (_("updating 'remote exec-file' to '%ps' to match "
"remote target"),
styled_string (file_name_style.style (),
exec_and_args.exec ().c_str ()));
- set_pspace_remote_exec_file (current_program_space,
- exec_and_args.exec ());
+ info.first = exec_and_args.exec ();
+ info.second = 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)
+ {
+ info.first.clear ();
+ info.second = remote_exec_source::UNSET_VALUE;
}
}
for (inferior *inf : all_inferiors (target))
{
switch_to_inferior_no_thread (inf);
+
+ /* If this remote told INF specifically, that there was no inferior
+ currently set, then reset this state back to GDB being in the
+ default state.
+
+ If however, the INF was set, either from the GDB side, or even
+ from the remote side, then we retain the current setting. The
+ 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)
+ {
+ gdb_assert (exec_info.first.empty ());
+ exec_info.second = remote_exec_source::DEFAULT_VALUE;
+ }
+
inf->pop_all_targets_at_and_above (process_stratum);
generic_mourn_inferior ();
}
if (is_target_filename (execd_pathname))
execd_pathname += strlen (TARGET_SYSROOT_PREFIX);
- set_pspace_remote_exec_file (follow_inf->pspace, execd_pathname);
+ set_pspace_remote_exec_file (follow_inf->pspace, execd_pathname,
+ remote_exec_source::VALUE_FROM_GDB);
}
/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
# is converted to a regexp by this function.
proc check_remote_exec_file { packet filename } {
if { $filename eq "" } {
- set remote_exec_re \
- "The remote exec-file is unset, the default remote executable will be used\\."
+ if { $packet } {
+ 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\\."
+ }
} else {
set remote_exec_re \
"The remote exec-file is \"[string_to_regexp $filename]\"\\."
cleanup_gdbserver
}
+# Start GDB. When PACKET is 'off' disable the qExecAndArgs packet,
+# otherwise, when PACKET is 'on' enable the packet.
+#
+# Start gdbserver in extended-remote mode, but don't provide a
+# 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 } {
+ clean_restart
+
+ gdb_test "disconnect" ".*"
+
+ gdb_file_cmd $::binfile
+
+ gdb_test "set remote fetch-exec-and-args ${packet}" \
+ "Support for the 'qExecAndArgs' packet on future remote targets is set to \"${packet}\"\\."
+
+ # Start gdbserver.
+ set target_exec [gdbserver_download_current_prog]
+
+ if { $set_remote_exec } {
+ gdb_test_no_output "set remote exec-file $target_exec" \
+ "set remote exec-file"
+ set expected_filename $target_exec
+ } else {
+ set expected_filename ""
+ }
+
+ gdbserver_start_extended
+
+ check_remote_exec_file $packet $expected_filename
+}
+
# This override prevents the remote exec-file from being set when
# using the extended-remote protocol. This is harmless when using
# other boards.
with_override extended_gdbserver_load_last_file do_nothing {
- foreach_with_prefix packet { on off } {
- test_exec_and_args_unset $packet
- test_exec_and_arg_fetch $packet
- }
+ # This override stops GDB connecting to the gdbserver as soon as
+ # GDB is started when testing with the extended-remote protocol.
+ with_override gdbserver_start_multi do_nothing {
+ foreach_with_prefix packet { on off } {
+ test_exec_and_args_unset $packet
+ test_exec_and_arg_fetch $packet
+
+ foreach_with_prefix set_remote_exec { true false } {
+ test_server_with_no_exec $packet $set_remote_exec
+ }
+ }
- test_remote_exec_warning
+ test_remote_exec_warning
+ }
}