/* Work with executable files, for GDB.
- Copyright (C) 1988-2016 Free Software Foundation, Inc.
+ Copyright (C) 1988-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "completer.h"
#include "value.h"
#include "exec.h"
-#include "observer.h"
+#include "observable.h"
#include "arch-utils.h"
#include "gdbthread.h"
#include "progspace.h"
+#include "progspace-and-thread.h"
#include "gdb_bfd.h"
#include "gcore.h"
+#include "source.h"
+#include "build-id.h"
#include <fcntl.h>
-#include "readline/readline.h"
+#include "readline/tilde.h"
#include "gdbcore.h"
#include <ctype.h>
#include <sys/stat.h>
#include "solist.h"
+#include <algorithm>
+#include "gdbsupport/pathstuff.h"
+#include "cli/cli-style.h"
-void (*deprecated_file_changed_hook) (char *);
+void (*deprecated_file_changed_hook) (const char *);
-/* Prototypes for local functions */
+static const target_info exec_target_info = {
+ "exec",
+ N_("Local exec file"),
+ N_("Use an executable file as a target.\n\
+Specify the filename of the executable file.")
+};
-static void file_command (char *, int);
+/* The target vector for executable files. */
-static void set_section_command (char *, int);
+struct exec_target final : public target_ops
+{
+ const target_info &info () const override
+ { return exec_target_info; }
-static void exec_files_info (struct target_ops *);
+ strata stratum () const override { return file_stratum; }
-static void init_exec_ops (void);
+ void close () override;
+ enum target_xfer_status xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len) override;
+ void files_info () override;
-void _initialize_exec (void);
+ bool has_memory () override;
+ gdb::unique_xmalloc_ptr<char> make_corefile_notes (bfd *, int *) override;
+ int find_memory_regions (find_memory_region_ftype func, void *data) override;
+};
-/* The target vector for executable files. */
+static exec_target exec_ops;
-static struct target_ops exec_ops;
+/* How to handle a mismatch between the current exec file and the exec
+ file determined from target. */
+
+static const char *const exec_file_mismatch_names[]
+ = {"ask", "warn", "off", NULL };
+enum exec_file_mismatch_mode
+ {
+ exec_file_mismatch_ask, exec_file_mismatch_warn, exec_file_mismatch_off
+ };
+static const char *exec_file_mismatch = exec_file_mismatch_names[0];
+static enum exec_file_mismatch_mode exec_file_mismatch_mode
+ = exec_file_mismatch_ask;
+
+/* Show command. */
+static void
+show_exec_file_mismatch_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (gdb_stdout,
+ _("exec-file-mismatch handling is currently \"%s\".\n"),
+ exec_file_mismatch_names[exec_file_mismatch_mode]);
+}
+
+/* Set command. Change the setting for range checking. */
+static void
+set_exec_file_mismatch_command (const char *ignore,
+ int from_tty, struct cmd_list_element *c)
+{
+ for (enum exec_file_mismatch_mode mode = exec_file_mismatch_ask;
+ ;
+ mode = static_cast<enum exec_file_mismatch_mode>(1 + (int) mode))
+ {
+ if (strcmp (exec_file_mismatch, exec_file_mismatch_names[mode]) == 0)
+ {
+ exec_file_mismatch_mode = mode;
+ return;
+ }
+ if (mode == exec_file_mismatch_off)
+ internal_error (__FILE__, __LINE__,
+ _("Unrecognized exec-file-mismatch setting: \"%s\""),
+ exec_file_mismatch);
+ }
+}
/* Whether to open exec and core files read-only or read-write. */
-int write_files = 0;
+bool write_files = false;
static void
show_write_files (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
static void
-exec_open (const char *args, int from_tty)
+exec_target_open (const char *args, int from_tty)
{
target_preopen (from_tty);
exec_file_attach (args, from_tty);
}
-/* Close and clear exec_bfd. If we end up with no target sections to
- read memory from, this unpushes the exec_ops target. */
+/* This is the target_close implementation. Clears all target
+ sections and closes all executable bfds from all program spaces. */
void
-exec_close (void)
+exec_target::close ()
{
- if (exec_bfd)
+ for (struct program_space *ss : program_spaces)
{
- bfd *abfd = exec_bfd;
+ ss->clear_target_sections ();
+ ss->exec_close ();
+ }
+}
+
+/* See gdbcore.h. */
- gdb_bfd_unref (abfd);
+void
+try_open_exec_file (const char *exec_file_host, struct inferior *inf,
+ symfile_add_flags add_flags)
+{
+ struct gdb_exception prev_err;
- /* Removing target sections may close the exec_ops target.
- Clear exec_bfd before doing so to prevent recursion. */
- exec_bfd = NULL;
- exec_bfd_mtime = 0;
+ /* exec_file_attach and symbol_file_add_main may throw an error if the file
+ cannot be opened either locally or remotely.
- remove_target_sections (&exec_bfd);
+ This happens for example, when the file is first found in the local
+ sysroot (above), and then disappears (a TOCTOU race), or when it doesn't
+ exist in the target filesystem, or when the file does exist, but
+ is not readable.
- xfree (exec_filename);
- exec_filename = NULL;
+ Even without a symbol file, the remote-based debugging session should
+ continue normally instead of ending abruptly. Hence we catch thrown
+ errors/exceptions in the following code. */
+ try
+ {
+ /* We must do this step even if exec_file_host is NULL, so that
+ exec_file_attach will clear state. */
+ exec_file_attach (exec_file_host, add_flags & SYMFILE_VERBOSE);
+ }
+ catch (gdb_exception_error &err)
+ {
+ if (err.message != NULL)
+ warning ("%s", err.what ());
+
+ prev_err = std::move (err);
+ }
+
+ if (exec_file_host != NULL)
+ {
+ try
+ {
+ symbol_file_add_main (exec_file_host, add_flags);
+ }
+ catch (const gdb_exception_error &err)
+ {
+ if (!exception_print_same (prev_err, err))
+ warning ("%s", err.what ());
+ }
}
}
-/* This is the target_close implementation. Clears all target
- sections and closes all executable bfds from all program spaces. */
+/* See gdbcore.h. */
-static void
-exec_close_1 (struct target_ops *self)
+void
+validate_exec_file (int from_tty)
{
- struct program_space *ss;
- struct cleanup *old_chain;
+ /* If user asked to ignore the mismatch, do nothing. */
+ if (exec_file_mismatch_mode == exec_file_mismatch_off)
+ return;
- old_chain = save_current_program_space ();
- ALL_PSPACES (ss)
- {
- set_current_program_space (ss);
- clear_section_table (current_target_sections);
- exec_close ();
- }
+ const char *current_exec_file = get_exec_file (0);
+ struct inferior *inf = current_inferior ();
+ /* Try to determine a filename from the process itself. */
+ const char *pid_exec_file = target_pid_to_exec_file (inf->pid);
+ bool build_id_mismatch = false;
- do_cleanups (old_chain);
-}
+ /* If we cannot validate the exec file, return. */
+ if (current_exec_file == NULL || pid_exec_file == NULL)
+ return;
-void
-exec_file_clear (int from_tty)
-{
- /* Remove exec file. */
- exec_close ();
+ /* Try validating via build-id, if available. This is the most
+ reliable check. */
- if (from_tty)
- printf_unfiltered (_("No executable file now.\n"));
+ /* In case current_exec_file was changed, reopen_exec_file ensures
+ an up to date build_id (will do nothing if the file timestamp
+ did not change). If exec file changed, reopen_exec_file has
+ allocated another file name, so get_exec_file again. */
+ reopen_exec_file ();
+ current_exec_file = get_exec_file (0);
+
+ const bfd_build_id *exec_file_build_id
+ = build_id_bfd_get (current_program_space->exec_bfd ());
+ if (exec_file_build_id != nullptr)
+ {
+ /* Prepend the target prefix, to force gdb_bfd_open to open the
+ file on the remote file system (if indeed remote). */
+ std::string target_pid_exec_file
+ = std::string (TARGET_SYSROOT_PREFIX) + pid_exec_file;
+
+ gdb_bfd_ref_ptr abfd (gdb_bfd_open (target_pid_exec_file.c_str (),
+ gnutarget, -1, false));
+ if (abfd != nullptr)
+ {
+ const bfd_build_id *target_exec_file_build_id
+ = build_id_bfd_get (abfd.get ());
+
+ if (target_exec_file_build_id != nullptr)
+ {
+ if (exec_file_build_id->size == target_exec_file_build_id->size
+ && memcmp (exec_file_build_id->data,
+ target_exec_file_build_id->data,
+ exec_file_build_id->size) == 0)
+ {
+ /* Match. */
+ return;
+ }
+ else
+ build_id_mismatch = true;
+ }
+ }
+ }
+
+ if (build_id_mismatch)
+ {
+ std::string exec_file_target (pid_exec_file);
+
+ /* In case the exec file is not local, exec_file_target has to point at
+ the target file system. */
+ if (is_target_filename (current_exec_file) && !target_filesystem_is_local ())
+ exec_file_target = TARGET_SYSROOT_PREFIX + exec_file_target;
+
+ warning
+ (_("Build ID mismatch between current exec-file %ps\n"
+ "and automatically determined exec-file %ps\n"
+ "exec-file-mismatch handling is currently \"%s\""),
+ styled_string (file_name_style.style (), current_exec_file),
+ styled_string (file_name_style.style (), exec_file_target.c_str ()),
+ exec_file_mismatch_names[exec_file_mismatch_mode]);
+ if (exec_file_mismatch_mode == exec_file_mismatch_ask)
+ {
+ symfile_add_flags add_flags = SYMFILE_MAINLINE;
+ if (from_tty)
+ {
+ add_flags |= SYMFILE_VERBOSE;
+ add_flags |= SYMFILE_ALWAYS_CONFIRM;
+ }
+ try
+ {
+ symbol_file_add_main (exec_file_target.c_str (), add_flags);
+ exec_file_attach (exec_file_target.c_str (), from_tty);
+ }
+ catch (gdb_exception_error &err)
+ {
+ warning (_("loading %ps %s"),
+ styled_string (file_name_style.style (),
+ exec_file_target.c_str ()),
+ err.message != NULL ? err.what () : "error");
+ }
+ }
+ }
}
/* See gdbcore.h. */
void
-exec_file_locate_attach (int pid, int from_tty)
+exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty)
{
- char *exec_file, *full_exec_path = NULL;
- struct cleanup *old_chain;
+ char *exec_file_target;
+ symfile_add_flags add_flags = 0;
/* Do nothing if we already have an executable filename. */
- exec_file = (char *) get_exec_file (0);
- if (exec_file != NULL)
+ if (get_exec_file (0) != NULL)
return;
/* Try to determine a filename from the process itself. */
- exec_file = target_pid_to_exec_file (pid);
- if (exec_file == NULL)
- return;
-
- /* If gdb_sysroot is not empty and the discovered filename
- is absolute then prefix the filename with gdb_sysroot. */
- if (*gdb_sysroot != '\0' && IS_ABSOLUTE_PATH (exec_file))
- full_exec_path = exec_file_find (exec_file, NULL);
-
- if (full_exec_path == NULL)
+ exec_file_target = target_pid_to_exec_file (pid);
+ if (exec_file_target == NULL)
{
- /* It's possible we don't have a full path, but rather just a
- filename. Some targets, such as HP-UX, don't provide the
- full path, sigh.
-
- Attempt to qualify the filename against the source path.
- (If that fails, we'll just fall back on the original
- filename. Not much more we can do...) */
- if (!source_full_path_of (exec_file, &full_exec_path))
- full_exec_path = xstrdup (exec_file);
+ warning (_("No executable has been specified and target does not "
+ "support\n"
+ "determining executable automatically. "
+ "Try using the \"file\" command."));
+ return;
}
- old_chain = make_cleanup (xfree, full_exec_path);
+ gdb::unique_xmalloc_ptr<char> exec_file_host
+ = exec_file_find (exec_file_target, NULL);
- exec_file_attach (full_exec_path, from_tty);
- symbol_file_add_main (full_exec_path, from_tty);
+ if (defer_bp_reset)
+ add_flags |= SYMFILE_DEFER_BP_RESET;
+
+ if (from_tty)
+ add_flags |= SYMFILE_VERBOSE;
- do_cleanups (old_chain);
+ /* Attempt to open the exec file. */
+ try_open_exec_file (exec_file_host.get (), current_inferior (), add_flags);
}
/* Set FILENAME as the new exec file.
void
exec_file_attach (const char *filename, int from_tty)
{
- struct cleanup *cleanups;
-
- /* First, acquire a reference to the current exec_bfd. We release
+ /* First, acquire a reference to the exec_bfd. We release
this at the end of the function; but acquiring it now lets the
BFD cache return it if this call refers to the same file. */
- gdb_bfd_ref (exec_bfd);
- cleanups = make_cleanup_bfd_unref (exec_bfd);
+ gdb_bfd_ref_ptr exec_bfd_holder
+ = gdb_bfd_ref_ptr::new_reference (current_program_space->exec_bfd ());
/* Remove any previous exec file. */
- exec_close ();
+ current_program_space->exec_close ();
/* Now open and digest the file the user requested, if any. */
if (!filename)
{
if (from_tty)
- printf_unfiltered (_("No executable file now.\n"));
+ printf_unfiltered (_("No executable file now.\n"));
set_gdbarch_from_file (NULL);
}
else
{
int load_via_target = 0;
- char *scratch_pathname, *canonical_pathname;
+ const char *scratch_pathname, *canonical_pathname;
int scratch_chan;
- struct target_section *sections = NULL, *sections_end = NULL;
char **matching;
if (is_target_filename (filename))
load_via_target = 1;
}
+ gdb::unique_xmalloc_ptr<char> canonical_storage, scratch_storage;
if (load_via_target)
{
/* gdb_bfd_fopen does not support "target:" filenames. */
"not supported for %s sysroots"),
TARGET_SYSROOT_PREFIX);
- scratch_pathname = xstrdup (filename);
- make_cleanup (xfree, scratch_pathname);
-
+ scratch_pathname = filename;
scratch_chan = -1;
-
canonical_pathname = scratch_pathname;
}
else
scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST,
filename, write_files ?
O_RDWR | O_BINARY : O_RDONLY | O_BINARY,
- &scratch_pathname);
+ &scratch_storage);
#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
if (scratch_chan < 0)
{
+ int first_errno = errno;
char *exename = (char *) alloca (strlen (filename) + 5);
strcat (strcpy (exename, filename), ".exe");
exename, write_files ?
O_RDWR | O_BINARY
: O_RDONLY | O_BINARY,
- &scratch_pathname);
+ &scratch_storage);
+ if (scratch_chan < 0)
+ errno = first_errno;
}
#endif
if (scratch_chan < 0)
perror_with_name (filename);
- make_cleanup (xfree, scratch_pathname);
+ scratch_pathname = scratch_storage.get ();
/* gdb_bfd_open (and its variants) prefers canonicalized
pathname for better BFD caching. */
- canonical_pathname = gdb_realpath (scratch_pathname);
- make_cleanup (xfree, canonical_pathname);
+ canonical_storage = gdb_realpath (scratch_pathname);
+ canonical_pathname = canonical_storage.get ();
}
+ gdb_bfd_ref_ptr temp;
if (write_files && !load_via_target)
- exec_bfd = gdb_bfd_fopen (canonical_pathname, gnutarget,
- FOPEN_RUB, scratch_chan);
+ temp = gdb_bfd_fopen (canonical_pathname, gnutarget,
+ FOPEN_RUB, scratch_chan);
else
- exec_bfd = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan);
+ temp = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan);
+ current_program_space->set_exec_bfd (std::move (temp));
- if (!exec_bfd)
+ if (!current_program_space->exec_bfd ())
{
- error (_("\"%s\": could not open as an executable file: %s."),
- scratch_pathname, bfd_errmsg (bfd_get_error ()));
+ error (_("\"%ps\": could not open as an executable file: %s."),
+ styled_string (file_name_style.style (), scratch_pathname),
+ bfd_errmsg (bfd_get_error ()));
}
/* gdb_realpath_keepfile resolves symlinks on the local
filesystem and so cannot be used for "target:" files. */
- gdb_assert (exec_filename == NULL);
+ gdb_assert (current_program_space->exec_filename == nullptr);
if (load_via_target)
- exec_filename = xstrdup (bfd_get_filename (exec_bfd));
+ current_program_space->exec_filename
+ = (make_unique_xstrdup
+ (bfd_get_filename (current_program_space->exec_bfd ())));
else
- exec_filename = gdb_realpath_keepfile (scratch_pathname);
+ current_program_space->exec_filename
+ = gdb_realpath_keepfile (scratch_pathname);
- if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching))
+ if (!bfd_check_format_matches (current_program_space->exec_bfd (),
+ bfd_object, &matching))
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
- exec_close ();
- error (_("\"%s\": not in executable format: %s"),
- scratch_pathname,
- gdb_bfd_errmsg (bfd_get_error (), matching));
+ current_program_space->exec_close ();
+ error (_("\"%ps\": not in executable format: %s"),
+ styled_string (file_name_style.style (), scratch_pathname),
+ gdb_bfd_errmsg (bfd_get_error (), matching).c_str ());
}
- if (build_section_table (exec_bfd, §ions, §ions_end))
- {
- /* Make sure to close exec_bfd, or else "run" might try to use
- it. */
- exec_close ();
- error (_("\"%s\": can't find the file sections: %s"),
- scratch_pathname, bfd_errmsg (bfd_get_error ()));
- }
+ target_section_table sections
+ = build_section_table (current_program_space->exec_bfd ());
- exec_bfd_mtime = bfd_get_mtime (exec_bfd);
+ current_program_space->ebfd_mtime
+ = bfd_get_mtime (current_program_space->exec_bfd ());
validate_files ();
- set_gdbarch_from_file (exec_bfd);
+ set_gdbarch_from_file (current_program_space->exec_bfd ());
/* Add the executable's sections to the current address spaces'
list of sections. This possibly pushes the exec_ops
target. */
- add_target_sections (&exec_bfd, sections, sections_end);
- xfree (sections);
+ current_program_space->add_target_sections (¤t_program_space->ebfd,
+ sections);
/* Tell display code (if any) about the changed file name. */
if (deprecated_exec_file_display_hook)
(*deprecated_exec_file_display_hook) (filename);
}
- do_cleanups (cleanups);
-
bfd_cache_close_all ();
- observer_notify_executable_changed ();
+ gdb::observers::executable_changed.notify ();
}
/* Process the first arg in ARGS as the new exec file.
If ARGS is NULL, we just want to close the exec file. */
static void
-exec_file_command (char *args, int from_tty)
+exec_file_command (const char *args, int from_tty)
{
- char **argv;
- char *filename;
-
- if (from_tty && target_has_execution
+ if (from_tty && target_has_execution ()
&& !query (_("A program is being debugged already.\n"
"Are you sure you want to change the file? ")))
error (_("File not changed."));
if (args)
{
- struct cleanup *cleanups;
-
/* Scan through the args and pick up the first non option arg
- as the filename. */
+ as the filename. */
- argv = gdb_buildargv (args);
- cleanups = make_cleanup_freeargv (argv);
+ gdb_argv built_argv (args);
+ char **argv = built_argv.get ();
for (; (*argv != NULL) && (**argv == '-'); argv++)
- {;
- }
+ {;
+ }
if (*argv == NULL)
- error (_("No executable file name was specified"));
+ error (_("No executable file name was specified"));
- filename = tilde_expand (*argv);
- make_cleanup (xfree, filename);
- exec_file_attach (filename, from_tty);
-
- do_cleanups (cleanups);
+ gdb::unique_xmalloc_ptr<char> filename (tilde_expand (*argv));
+ exec_file_attach (filename.get (), from_tty);
}
else
exec_file_attach (NULL, from_tty);
command was added? */
static void
-file_command (char *arg, int from_tty)
+file_command (const char *arg, int from_tty)
{
/* FIXME, if we lose on reading the symbol file, we should revert
the exec file, but that's rough. */
}
\f
-/* Locate all mappable sections of a BFD file.
- table_pp_char is a char * to get it through bfd_map_over_sections;
- we cast it back to its proper type. */
+/* Builds a section table, given args BFD, TABLE. */
-static void
-add_to_section_table (bfd *abfd, struct bfd_section *asect,
- void *table_pp_char)
+target_section_table
+build_section_table (struct bfd *some_bfd)
{
- struct target_section **table_pp = (struct target_section **) table_pp_char;
- flagword aflag;
-
- gdb_assert (abfd == asect->owner);
-
- /* Check the section flags, but do not discard zero-length sections, since
- some symbols may still be attached to this section. For instance, we
- encountered on sparc-solaris 2.10 a shared library with an empty .bss
- section to which a symbol named "_end" was attached. The address
- of this symbol still needs to be relocated. */
- aflag = bfd_get_section_flags (abfd, asect);
- if (!(aflag & SEC_ALLOC))
- return;
-
- (*table_pp)->owner = NULL;
- (*table_pp)->the_bfd_section = asect;
- (*table_pp)->addr = bfd_section_vma (abfd, asect);
- (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
- (*table_pp)++;
-}
-
-/* See exec.h. */
-
-void
-clear_section_table (struct target_section_table *table)
-{
- xfree (table->sections);
- table->sections = table->sections_end = NULL;
-}
-
-/* Resize section table TABLE by ADJUSTMENT.
- ADJUSTMENT may be negative, in which case the caller must have already
- removed the sections being deleted.
- Returns the old size. */
-
-static int
-resize_section_table (struct target_section_table *table, int adjustment)
-{
- int old_count;
- int new_count;
-
- old_count = table->sections_end - table->sections;
+ target_section_table table;
- new_count = adjustment + old_count;
-
- if (new_count)
+ for (asection *asect : gdb_bfd_sections (some_bfd))
{
- table->sections = XRESIZEVEC (struct target_section, table->sections,
- new_count);
- table->sections_end = table->sections + new_count;
- }
- else
- clear_section_table (table);
-
- return old_count;
-}
+ flagword aflag;
+
+ /* Check the section flags, but do not discard zero-length
+ sections, since some symbols may still be attached to this
+ section. For instance, we encountered on sparc-solaris 2.10
+ a shared library with an empty .bss section to which a symbol
+ named "_end" was attached. The address of this symbol still
+ needs to be relocated. */
+ aflag = bfd_section_flags (asect);
+ if (!(aflag & SEC_ALLOC))
+ continue;
-/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
- Returns 0 if OK, 1 on error. */
+ table.emplace_back (bfd_section_vma (asect),
+ bfd_section_vma (asect) + bfd_section_size (asect),
+ asect);
+ }
-int
-build_section_table (struct bfd *some_bfd, struct target_section **start,
- struct target_section **end)
-{
- unsigned count;
-
- count = bfd_count_sections (some_bfd);
- if (*start)
- xfree (* start);
- *start = XNEWVEC (struct target_section, count);
- *end = *start;
- bfd_map_over_sections (some_bfd, add_to_section_table, (char *) end);
- if (*end > *start + count)
- internal_error (__FILE__, __LINE__,
- _("failed internal consistency check"));
- /* We could realloc the table, but it probably loses for most files. */
- return 0;
+ return table;
}
/* Add the sections array defined by [SECTIONS..SECTIONS_END[ to the
current set of target sections. */
void
-add_target_sections (void *owner,
- struct target_section *sections,
- struct target_section *sections_end)
+program_space::add_target_sections (void *owner,
+ const target_section_table §ions)
{
- int count;
- struct target_section_table *table = current_target_sections;
-
- count = sections_end - sections;
-
- if (count > 0)
+ if (!sections.empty ())
{
- int space = resize_section_table (table, count);
- int i;
-
- for (i = 0; i < count; ++i)
+ for (const target_section &s : sections)
{
- table->sections[space + i] = sections[i];
- table->sections[space + i].owner = owner;
+ m_target_sections.push_back (s);
+ m_target_sections.back ().owner = owner;
}
+ scoped_restore_current_pspace_and_thread restore_pspace_thread;
+
/* If these are the first file sections we can provide memory
- from, push the file_stratum target. */
- if (!target_is_pushed (&exec_ops))
- push_target (&exec_ops);
+ from, push the file_stratum target. Must do this in all
+ inferiors sharing the program space. */
+ for (inferior *inf : all_inferiors ())
+ {
+ if (inf->pspace != this)
+ continue;
+
+ if (inf->target_is_pushed (&exec_ops))
+ continue;
+
+ switch_to_inferior_no_thread (inf);
+ inf->push_target (&exec_ops);
+ }
}
}
/* Add the sections of OBJFILE to the current set of target sections. */
void
-add_target_sections_of_objfile (struct objfile *objfile)
+program_space::add_target_sections (struct objfile *objfile)
{
- struct target_section_table *table = current_target_sections;
struct obj_section *osect;
- int space;
- unsigned count = 0;
- struct target_section *ts;
- if (objfile == NULL)
- return;
+ gdb_assert (objfile != nullptr);
/* Compute the number of sections to add. */
ALL_OBJFILE_OSECTIONS (objfile, osect)
{
- if (bfd_get_section_size (osect->the_bfd_section) == 0)
+ if (bfd_section_size (osect->the_bfd_section) == 0)
continue;
- count++;
- }
- if (count == 0)
- return;
-
- space = resize_section_table (table, count);
-
- ts = table->sections + space;
-
- ALL_OBJFILE_OSECTIONS (objfile, osect)
- {
- if (bfd_get_section_size (osect->the_bfd_section) == 0)
- continue;
-
- gdb_assert (ts < table->sections + space + count);
-
- ts->addr = obj_section_addr (osect);
- ts->endaddr = obj_section_endaddr (osect);
- ts->the_bfd_section = osect->the_bfd_section;
- ts->owner = (void *) objfile;
-
- ts++;
+ m_target_sections.emplace_back (obj_section_addr (osect),
+ obj_section_endaddr (osect),
+ osect->the_bfd_section, (void *) objfile);
}
}
OWNER must be the same value passed to add_target_sections. */
void
-remove_target_sections (void *owner)
+program_space::remove_target_sections (void *owner)
{
- struct target_section *src, *dest;
- struct target_section_table *table = current_target_sections;
-
gdb_assert (owner != NULL);
- dest = table->sections;
- for (src = table->sections; src < table->sections_end; src++)
- if (src->owner != owner)
- {
- /* Keep this section. */
- if (dest < src)
- *dest = *src;
- dest++;
- }
-
- /* If we've dropped any sections, resize the section table. */
- if (dest < src)
+ auto it = std::remove_if (m_target_sections.begin (),
+ m_target_sections.end (),
+ [&] (target_section §)
+ {
+ return sect.owner == owner;
+ });
+ m_target_sections.erase (it, m_target_sections.end ());
+
+ /* If we don't have any more sections to read memory from,
+ remove the file_stratum target from the stack of each
+ inferior sharing the program space. */
+ if (m_target_sections.empty ())
{
- int old_count;
+ scoped_restore_current_pspace_and_thread restore_pspace_thread;
- old_count = resize_section_table (table, dest - src);
-
- /* If we don't have any more sections to read memory from,
- remove the file_stratum target from the stack. */
- if (old_count + (dest - src) == 0)
+ for (inferior *inf : all_inferiors ())
{
- struct program_space *pspace;
-
- ALL_PSPACES (pspace)
- if (pspace->target_sections.sections
- != pspace->target_sections.sections_end)
- return;
+ if (inf->pspace != this)
+ continue;
- unpush_target (&exec_ops);
+ switch_to_inferior_no_thread (inf);
+ inf->unpush_target (&exec_ops);
}
}
}
+/* See exec.h. */
+
+void
+exec_on_vfork ()
+{
+ if (!current_program_space->target_sections ().empty ())
+ current_inferior ()->push_target (&exec_ops);
+}
+
\f
enum target_xfer_status
/* It's unduly pedantic to refuse to look at the executable for
read-only pieces; so do the equivalent of readonly regions aka
QTro packet. */
- if (exec_bfd != NULL)
+ if (current_program_space->exec_bfd () != NULL)
{
asection *s;
bfd_size_type size;
bfd_vma vma;
- for (s = exec_bfd->sections; s; s = s->next)
+ for (s = current_program_space->exec_bfd ()->sections; s; s = s->next)
{
if ((s->flags & SEC_LOAD) == 0
|| (s->flags & SEC_READONLY) == 0)
continue;
vma = s->vma;
- size = bfd_get_section_size (s);
+ size = bfd_section_size (s);
if (vma <= offset && offset < (vma + size))
{
ULONGEST amt;
if (amt > len)
amt = len;
- amt = bfd_get_section_contents (exec_bfd, s,
+ amt = bfd_get_section_contents (current_program_space->exec_bfd (), s,
readbuf, offset - vma, amt);
if (amt == 0)
return TARGET_XFER_E_IO;
}
-/* Appends all read-only memory ranges found in the target section
+/* Return all read-only memory ranges found in the target section
table defined by SECTIONS and SECTIONS_END, starting at (and
- intersected with) MEMADDR for LEN bytes. Returns the augmented
- VEC. */
-
-static VEC(mem_range_s) *
-section_table_available_memory (VEC(mem_range_s) *memory,
- CORE_ADDR memaddr, ULONGEST len,
- struct target_section *sections,
- struct target_section *sections_end)
+ intersected with) MEMADDR for LEN bytes. */
+
+static std::vector<mem_range>
+section_table_available_memory (CORE_ADDR memaddr, ULONGEST len,
+ const target_section_table §ions)
{
- struct target_section *p;
+ std::vector<mem_range> memory;
- for (p = sections; p < sections_end; p++)
+ for (const target_section &p : sections)
{
- if ((bfd_get_section_flags (p->the_bfd_section->owner,
- p->the_bfd_section)
- & SEC_READONLY) == 0)
+ if ((bfd_section_flags (p.the_bfd_section) & SEC_READONLY) == 0)
continue;
/* Copy the meta-data, adjusted. */
- if (mem_ranges_overlap (p->addr, p->endaddr - p->addr, memaddr, len))
+ if (mem_ranges_overlap (p.addr, p.endaddr - p.addr, memaddr, len))
{
ULONGEST lo1, hi1, lo2, hi2;
- struct mem_range *r;
lo1 = memaddr;
hi1 = memaddr + len;
- lo2 = p->addr;
- hi2 = p->endaddr;
+ lo2 = p.addr;
+ hi2 = p.endaddr;
- r = VEC_safe_push (mem_range_s, memory, NULL);
+ CORE_ADDR start = std::max (lo1, lo2);
+ int length = std::min (hi1, hi2) - start;
- r->start = max (lo1, lo2);
- r->length = min (hi1, hi2) - r->start;
+ memory.emplace_back (start, length);
}
}
section_table_read_available_memory (gdb_byte *readbuf, ULONGEST offset,
ULONGEST len, ULONGEST *xfered_len)
{
- VEC(mem_range_s) *available_memory = NULL;
- struct target_section_table *table;
- struct cleanup *old_chain;
- mem_range_s *r;
- int i;
-
- table = target_get_section_table (&exec_ops);
- available_memory = section_table_available_memory (available_memory,
- offset, len,
- table->sections,
- table->sections_end);
-
- old_chain = make_cleanup (VEC_cleanup(mem_range_s),
- &available_memory);
-
- normalize_mem_ranges (available_memory);
-
- for (i = 0;
- VEC_iterate (mem_range_s, available_memory, i, r);
- i++)
+ const target_section_table *table
+ = target_get_section_table (current_inferior ()->top_target ());
+ std::vector<mem_range> available_memory
+ = section_table_available_memory (offset, len, *table);
+
+ normalize_mem_ranges (&available_memory);
+
+ for (const mem_range &r : available_memory)
{
- if (mem_ranges_overlap (r->start, r->length, offset, len))
+ if (mem_ranges_overlap (r.start, r.length, offset, len))
{
CORE_ADDR end;
enum target_xfer_status status;
/* Get the intersection window. */
- end = min (offset + len, r->start + r->length);
+ end = std::min<CORE_ADDR> (offset + len, r.start + r.length);
gdb_assert (end - offset <= len);
- if (offset >= r->start)
+ if (offset >= r.start)
status = exec_read_partial_read_only (readbuf, offset,
end - offset,
xfered_len);
else
{
- *xfered_len = r->start - offset;
+ *xfered_len = r.start - offset;
status = TARGET_XFER_UNAVAILABLE;
}
- do_cleanups (old_chain);
return status;
}
}
- do_cleanups (old_chain);
*xfered_len = len;
return TARGET_XFER_UNAVAILABLE;
section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, ULONGEST len,
ULONGEST *xfered_len,
- struct target_section *sections,
- struct target_section *sections_end,
- const char *section_name)
+ const target_section_table §ions,
+ gdb::function_view<bool
+ (const struct target_section *)> match_cb)
{
int res;
- struct target_section *p;
ULONGEST memaddr = offset;
ULONGEST memend = memaddr + len;
- if (len == 0)
- internal_error (__FILE__, __LINE__,
- _("failed internal consistency check"));
+ gdb_assert (len != 0);
- for (p = sections; p < sections_end; p++)
+ for (const target_section &p : sections)
{
- struct bfd_section *asect = p->the_bfd_section;
+ struct bfd_section *asect = p.the_bfd_section;
bfd *abfd = asect->owner;
- if (section_name && strcmp (section_name, asect->name) != 0)
+ if (match_cb != nullptr && !match_cb (&p))
continue; /* not the section we need. */
- if (memaddr >= p->addr)
- {
- if (memend <= p->endaddr)
+ if (memaddr >= p.addr)
+ {
+ if (memend <= p.endaddr)
{
/* Entire transfer is within this section. */
if (writebuf)
res = bfd_set_section_contents (abfd, asect,
- writebuf, memaddr - p->addr,
+ writebuf, memaddr - p.addr,
len);
else
res = bfd_get_section_contents (abfd, asect,
- readbuf, memaddr - p->addr,
+ readbuf, memaddr - p.addr,
len);
if (res != 0)
else
return TARGET_XFER_EOF;
}
- else if (memaddr >= p->endaddr)
+ else if (memaddr >= p.endaddr)
{
/* This section ends before the transfer starts. */
continue;
else
{
/* This section overlaps the transfer. Just do half. */
- len = p->endaddr - memaddr;
+ len = p.endaddr - memaddr;
if (writebuf)
res = bfd_set_section_contents (abfd, asect,
- writebuf, memaddr - p->addr,
+ writebuf, memaddr - p.addr,
len);
else
res = bfd_get_section_contents (abfd, asect,
- readbuf, memaddr - p->addr,
+ readbuf, memaddr - p.addr,
len);
if (res != 0)
{
else
return TARGET_XFER_EOF;
}
- }
+ }
}
return TARGET_XFER_EOF; /* We can't help. */
}
-static struct target_section_table *
-exec_get_section_table (struct target_ops *ops)
-{
- return current_target_sections;
-}
-
-static enum target_xfer_status
-exec_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
+enum target_xfer_status
+exec_target::xfer_partial (enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
{
- struct target_section_table *table = target_get_section_table (ops);
+ const target_section_table *table = target_get_section_table (this);
if (object == TARGET_OBJECT_MEMORY)
return section_table_xfer_memory_partial (readbuf, writebuf,
offset, len, xfered_len,
- table->sections,
- table->sections_end,
- NULL);
+ *table);
else
return TARGET_XFER_E_IO;
}
\f
void
-print_section_info (struct target_section_table *t, bfd *abfd)
+print_section_info (const target_section_table *t, bfd *abfd)
{
struct gdbarch *gdbarch = gdbarch_from_bfd (abfd);
- struct target_section *p;
/* FIXME: 16 is not wide enough when gdbarch_addr_bit > 64. */
int wid = gdbarch_addr_bit (gdbarch) <= 32 ? 8 : 16;
- printf_filtered ("\t`%s', ", bfd_get_filename (abfd));
+ printf_filtered ("\t`%ps', ",
+ styled_string (file_name_style.style (),
+ bfd_get_filename (abfd)));
wrap_here (" ");
printf_filtered (_("file type %s.\n"), bfd_get_target (abfd));
- if (abfd == exec_bfd)
+ if (abfd == current_program_space->exec_bfd ())
{
/* gcc-3.4 does not like the initialization in
<p == t->sections_end>. */
bfd_vma displacement = 0;
bfd_vma entry_point;
+ bool found = false;
- for (p = t->sections; p < t->sections_end; p++)
+ for (const target_section &p : *t)
{
- struct bfd_section *psect = p->the_bfd_section;
- bfd *pbfd = psect->owner;
+ struct bfd_section *psect = p.the_bfd_section;
- if ((bfd_get_section_flags (pbfd, psect) & (SEC_ALLOC | SEC_LOAD))
+ if ((bfd_section_flags (psect) & (SEC_ALLOC | SEC_LOAD))
!= (SEC_ALLOC | SEC_LOAD))
continue;
- if (bfd_get_section_vma (pbfd, psect) <= abfd->start_address
- && abfd->start_address < (bfd_get_section_vma (pbfd, psect)
- + bfd_get_section_size (psect)))
+ if (bfd_section_vma (psect) <= abfd->start_address
+ && abfd->start_address < (bfd_section_vma (psect)
+ + bfd_section_size (psect)))
{
- displacement = p->addr - bfd_get_section_vma (pbfd, psect);
+ displacement = p.addr - bfd_section_vma (psect);
+ found = true;
break;
}
}
- if (p == t->sections_end)
- warning (_("Cannot find section for the entry point of %s."),
- bfd_get_filename (abfd));
+ if (!found)
+ warning (_("Cannot find section for the entry point of %ps."),
+ styled_string (file_name_style.style (),
+ bfd_get_filename (abfd)));
entry_point = gdbarch_addr_bits_remove (gdbarch,
bfd_get_start_address (abfd)
printf_filtered (_("\tEntry point: %s\n"),
paddress (gdbarch, entry_point));
}
- for (p = t->sections; p < t->sections_end; p++)
+ for (const target_section &p : *t)
{
- struct bfd_section *psect = p->the_bfd_section;
+ struct bfd_section *psect = p.the_bfd_section;
bfd *pbfd = psect->owner;
- printf_filtered ("\t%s", hex_string_custom (p->addr, wid));
- printf_filtered (" - %s", hex_string_custom (p->endaddr, wid));
+ printf_filtered ("\t%s", hex_string_custom (p.addr, wid));
+ printf_filtered (" - %s", hex_string_custom (p.endaddr, wid));
/* FIXME: A format of "08l" is not wide enough for file offsets
larger than 4GB. OTOH, making it "016l" isn't desirable either
if (info_verbose)
printf_filtered (" @ %s",
hex_string_custom (psect->filepos, 8));
- printf_filtered (" is %s", bfd_section_name (pbfd, psect));
+ printf_filtered (" is %s", bfd_section_name (psect));
if (pbfd != abfd)
- printf_filtered (" in %s", bfd_get_filename (pbfd));
+ printf_filtered (" in %ps",
+ styled_string (file_name_style.style (),
+ bfd_get_filename (pbfd)));
printf_filtered ("\n");
}
}
-static void
-exec_files_info (struct target_ops *t)
+void
+exec_target::files_info ()
{
- if (exec_bfd)
- print_section_info (current_target_sections, exec_bfd);
+ if (current_program_space->exec_bfd ())
+ print_section_info (¤t_program_space->target_sections (),
+ current_program_space->exec_bfd ());
else
puts_filtered (_("\t<no file loaded>\n"));
}
static void
-set_section_command (char *args, int from_tty)
+set_section_command (const char *args, int from_tty)
{
- struct target_section *p;
- char *secname;
- unsigned seclen;
- unsigned long secaddr;
- char secprint[100];
- long offset;
- struct target_section_table *table;
+ const char *secname;
if (args == 0)
error (_("Must specify section name and its virtual address"));
/* Parse out section name. */
for (secname = args; !isspace (*args); args++);
- seclen = args - secname;
+ unsigned seclen = args - secname;
/* Parse out new virtual address. */
- secaddr = parse_and_eval_address (args);
+ CORE_ADDR secaddr = parse_and_eval_address (args);
- table = current_target_sections;
- for (p = table->sections; p < table->sections_end; p++)
+ for (target_section &p : current_program_space->target_sections ())
{
- if (!strncmp (secname, bfd_section_name (p->bfd,
- p->the_bfd_section), seclen)
- && bfd_section_name (p->bfd, p->the_bfd_section)[seclen] == '\0')
+ if (!strncmp (secname, bfd_section_name (p.the_bfd_section), seclen)
+ && bfd_section_name (p.the_bfd_section)[seclen] == '\0')
{
- offset = secaddr - p->addr;
- p->addr += offset;
- p->endaddr += offset;
+ long offset = secaddr - p.addr;
+ p.addr += offset;
+ p.endaddr += offset;
if (from_tty)
- exec_files_info (&exec_ops);
+ exec_ops.files_info ();
return;
}
}
- if (seclen >= sizeof (secprint))
- seclen = sizeof (secprint) - 1;
- strncpy (secprint, secname, seclen);
- secprint[seclen] = '\0';
- error (_("Section %s not found"), secprint);
+
+ std::string secprint (secname, seclen);
+ error (_("Section %s not found"), secprint.c_str ());
}
/* If we can find a section in FILENAME with BFD index INDEX, adjust
void
exec_set_section_address (const char *filename, int index, CORE_ADDR address)
{
- struct target_section *p;
- struct target_section_table *table;
-
- table = current_target_sections;
- for (p = table->sections; p < table->sections_end; p++)
+ for (target_section &p : current_program_space->target_sections ())
{
- if (filename_cmp (filename, p->the_bfd_section->owner->filename) == 0
- && index == p->the_bfd_section->index)
+ if (filename_cmp (filename,
+ bfd_get_filename (p.the_bfd_section->owner)) == 0
+ && index == p.the_bfd_section->index)
{
- p->endaddr += address - p->addr;
- p->addr = address;
+ p.endaddr += address - p.addr;
+ p.addr = address;
}
}
}
-/* If mourn is being called in all the right places, this could be say
- `gdb internal error' (since generic_mourn calls
- breakpoint_init_inferior). */
-
-static int
-ignore (struct target_ops *ops, struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
-{
- return 0;
-}
-
-static int
-exec_has_memory (struct target_ops *ops)
+bool
+exec_target::has_memory ()
{
/* We can provide memory if we have any file/target sections to read
from. */
- return (current_target_sections->sections
- != current_target_sections->sections_end);
+ return !current_program_space->target_sections ().empty ();
}
-static char *
-exec_make_note_section (struct target_ops *self, bfd *obfd, int *note_size)
+gdb::unique_xmalloc_ptr<char>
+exec_target::make_corefile_notes (bfd *obfd, int *note_size)
{
error (_("Can't create a corefile"));
}
-/* Fill in the exec file target vector. Very few entries need to be
- defined. */
-
-static void
-init_exec_ops (void)
+int
+exec_target::find_memory_regions (find_memory_region_ftype func, void *data)
{
- exec_ops.to_shortname = "exec";
- exec_ops.to_longname = "Local exec file";
- exec_ops.to_doc = "Use an executable file as a target.\n\
-Specify the filename of the executable file.";
- exec_ops.to_open = exec_open;
- exec_ops.to_close = exec_close_1;
- exec_ops.to_xfer_partial = exec_xfer_partial;
- exec_ops.to_get_section_table = exec_get_section_table;
- exec_ops.to_files_info = exec_files_info;
- exec_ops.to_insert_breakpoint = ignore;
- exec_ops.to_remove_breakpoint = ignore;
- exec_ops.to_stratum = file_stratum;
- exec_ops.to_has_memory = exec_has_memory;
- exec_ops.to_make_corefile_notes = exec_make_note_section;
- exec_ops.to_find_memory_regions = objfile_find_memory_regions;
- exec_ops.to_magic = OPS_MAGIC;
+ return objfile_find_memory_regions (this, func, data);
}
+void _initialize_exec ();
void
-_initialize_exec (void)
+_initialize_exec ()
{
struct cmd_list_element *c;
- init_exec_ops ();
-
if (!dbx_commands)
{
c = add_cmd ("file", class_files, file_command, _("\
show_write_files,
&setlist, &showlist);
- add_target_with_completer (&exec_ops, filename_completer);
+ add_setshow_enum_cmd ("exec-file-mismatch", class_support,
+ exec_file_mismatch_names,
+ &exec_file_mismatch,
+ _("\
+Set exec-file-mismatch handling (ask|warn|off)."),
+ _("\
+Show exec-file-mismatch handling (ask|warn|off)."),
+ _("\
+Specifies how to handle a mismatch between the current exec-file\n\
+loaded by GDB and the exec-file automatically determined when attaching\n\
+to a process:\n\n\
+ ask - warn the user and ask whether to load the determined exec-file.\n\
+ warn - warn the user, but do not change the exec-file.\n\
+ off - do not check for mismatch.\n\
+\n\
+GDB detects a mismatch by comparing the build IDs of the files.\n\
+If the user confirms loading the determined exec-file, then its symbols\n\
+will be loaded as well."),
+ set_exec_file_mismatch_command,
+ show_exec_file_mismatch_command,
+ &setlist, &showlist);
+
+ add_target (exec_target_info, exec_target_open, filename_completer);
}