123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- /* Work with executable files, for GDB.
- Copyright (C) 1988-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "frame.h"
- #include "inferior.h"
- #include "target.h"
- #include "gdbcmd.h"
- #include "language.h"
- #include "filenames.h"
- #include "symfile.h"
- #include "objfiles.h"
- #include "completer.h"
- #include "value.h"
- #include "exec.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/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"
- #include "gdbsupport/buildargv.h"
- void (*deprecated_file_changed_hook) (const char *);
- 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.")
- };
- /* The target vector for executable files. */
- struct exec_target final : public target_ops
- {
- const target_info &info () const override
- { return exec_target_info; }
- strata stratum () const override { return file_stratum; }
- 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;
- 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;
- };
- static exec_target 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)
- {
- gdb_printf (file,
- _("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. */
- bool write_files = false;
- static void
- show_write_files (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Writing into executable and core files is %s.\n"),
- value);
- }
- static void
- exec_target_open (const char *args, int from_tty)
- {
- target_preopen (from_tty);
- exec_file_attach (args, from_tty);
- }
- /* This is the target_close implementation. Clears all target
- sections and closes all executable bfds from all program spaces. */
- void
- exec_target::close ()
- {
- for (struct program_space *ss : program_spaces)
- {
- ss->clear_target_sections ();
- ss->exec_close ();
- }
- }
- /* See gdbcore.h. */
- void
- try_open_exec_file (const char *exec_file_host, struct inferior *inf,
- symfile_add_flags add_flags)
- {
- struct gdb_exception prev_err;
- /* exec_file_attach and symbol_file_add_main may throw an error if the file
- cannot be opened either locally or remotely.
- 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.
- 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 (prev_err != err)
- warning ("%s", err.what ());
- }
- }
- }
- /* See gdbcore.h. */
- void
- validate_exec_file (int from_tty)
- {
- /* If user asked to ignore the mismatch, do nothing. */
- if (exec_file_mismatch_mode == exec_file_mismatch_off)
- return;
- 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;
- /* If we cannot validate the exec file, return. */
- if (current_exec_file == NULL || pid_exec_file == NULL)
- return;
- /* Try validating via build-id, if available. This is the most
- reliable check. */
- /* 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 defer_bp_reset, int from_tty)
- {
- char *exec_file_target;
- symfile_add_flags add_flags = 0;
- /* Do nothing if we already have an executable filename. */
- if (get_exec_file (0) != NULL)
- return;
- /* Try to determine a filename from the process itself. */
- exec_file_target = target_pid_to_exec_file (pid);
- if (exec_file_target == NULL)
- {
- warning (_("No executable has been specified and target does not "
- "support\n"
- "determining executable automatically. "
- "Try using the \"file\" command."));
- return;
- }
- gdb::unique_xmalloc_ptr<char> exec_file_host
- = exec_file_find (exec_file_target, NULL);
- if (defer_bp_reset)
- add_flags |= SYMFILE_DEFER_BP_RESET;
- if (from_tty)
- add_flags |= SYMFILE_VERBOSE;
- /* 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.
- This function is intended to be behave essentially the same
- as exec_file_command, except that the latter will detect when
- a target is being debugged, and will ask the user whether it
- should be shut down first. (If the answer is "no", then the
- new file is ignored.)
- This file is used by exec_file_command, to do the work of opening
- and processing the exec file after any prompting has happened.
- And, it is used by child_attach, when the attach command was
- given a pid but not a exec pathname, and the attach command could
- figure out the pathname from the pid. (In this case, we shouldn't
- ask the user whether the current target should be shut down --
- we're supplying the exec pathname late for good reason.) */
- void
- exec_file_attach (const char *filename, int from_tty)
- {
- /* 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_ptr exec_bfd_holder
- = gdb_bfd_ref_ptr::new_reference (current_program_space->exec_bfd ());
- /* Remove any previous exec file. */
- current_program_space->exec_close ();
- /* Now open and digest the file the user requested, if any. */
- if (!filename)
- {
- if (from_tty)
- gdb_printf (_("No executable file now.\n"));
- set_gdbarch_from_file (NULL);
- }
- else
- {
- int load_via_target = 0;
- const char *scratch_pathname, *canonical_pathname;
- int scratch_chan;
- char **matching;
- if (is_target_filename (filename))
- {
- if (target_filesystem_is_local ())
- filename += strlen (TARGET_SYSROOT_PREFIX);
- else
- 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. */
- if (write_files)
- warning (_("writing into executable files is "
- "not supported for %s sysroots"),
- TARGET_SYSROOT_PREFIX);
- 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_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");
- scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST,
- exename, write_files ?
- O_RDWR | O_BINARY
- : O_RDONLY | O_BINARY,
- &scratch_storage);
- if (scratch_chan < 0)
- errno = first_errno;
- }
- #endif
- if (scratch_chan < 0)
- perror_with_name (filename);
- scratch_pathname = scratch_storage.get ();
- /* gdb_bfd_open (and its variants) prefers canonicalized
- pathname for better BFD caching. */
- canonical_storage = gdb_realpath (scratch_pathname);
- canonical_pathname = canonical_storage.get ();
- }
- gdb_bfd_ref_ptr temp;
- if (write_files && !load_via_target)
- temp = gdb_bfd_fopen (canonical_pathname, gnutarget,
- FOPEN_RUB, scratch_chan);
- else
- temp = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan);
- current_program_space->set_exec_bfd (std::move (temp));
- if (!current_program_space->exec_bfd ())
- {
- error (_("\"%s\": could not open as an executable file: %s."),
- 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 (current_program_space->exec_filename == nullptr);
- if (load_via_target)
- current_program_space->exec_filename
- = (make_unique_xstrdup
- (bfd_get_filename (current_program_space->exec_bfd ())));
- else
- current_program_space->exec_filename
- = gdb_realpath_keepfile (scratch_pathname);
- 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. */
- current_program_space->exec_close ();
- error (_("\"%s\": not in executable format: %s"), scratch_pathname,
- gdb_bfd_errmsg (bfd_get_error (), matching).c_str ());
- }
- target_section_table sections
- = build_section_table (current_program_space->exec_bfd ());
- current_program_space->ebfd_mtime
- = bfd_get_mtime (current_program_space->exec_bfd ());
- validate_files ();
- 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. */
- 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);
- }
- bfd_cache_close_all ();
- gdb::observers::executable_changed.notify ();
- }
- /* Process the first arg in ARGS as the new exec file.
- Note that we have to explicitly ignore additional args, since we can
- be called from file_command(), which also calls symbol_file_command()
- which can take multiple args.
-
- If ARGS is NULL, we just want to close the exec file. */
- static void
- exec_file_command (const char *args, int from_tty)
- {
- 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)
- {
- /* Scan through the args and pick up the first non option arg
- as the filename. */
- 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"));
- gdb::unique_xmalloc_ptr<char> filename (tilde_expand (*argv));
- exec_file_attach (filename.get (), from_tty);
- }
- else
- exec_file_attach (NULL, from_tty);
- }
- /* Set both the exec file and the symbol file, in one command.
- What a novelty. Why did GDB go through four major releases before this
- command was added? */
- static void
- 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. */
- exec_file_command (arg, from_tty);
- symbol_file_command (arg, from_tty);
- if (deprecated_file_changed_hook)
- deprecated_file_changed_hook (arg);
- }
- /* Builds a section table, given args BFD, TABLE. */
- target_section_table
- build_section_table (struct bfd *some_bfd)
- {
- target_section_table table;
- for (asection *asect : gdb_bfd_sections (some_bfd))
- {
- 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;
- table.emplace_back (bfd_section_vma (asect),
- bfd_section_vma (asect) + bfd_section_size (asect),
- asect);
- }
- return table;
- }
- /* Add the sections array defined by [SECTIONS..SECTIONS_END[ to the
- current set of target sections. */
- void
- program_space::add_target_sections (void *owner,
- const target_section_table §ions)
- {
- if (!sections.empty ())
- {
- for (const target_section &s : sections)
- {
- 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. 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
- program_space::add_target_sections (struct objfile *objfile)
- {
- struct obj_section *osect;
- gdb_assert (objfile != nullptr);
- /* Compute the number of sections to add. */
- ALL_OBJFILE_OSECTIONS (objfile, osect)
- {
- if (bfd_section_size (osect->the_bfd_section) == 0)
- continue;
- m_target_sections.emplace_back (osect->addr (), osect->endaddr (),
- osect->the_bfd_section, (void *) objfile);
- }
- }
- /* Remove all target sections owned by OWNER.
- OWNER must be the same value passed to add_target_sections. */
- void
- program_space::remove_target_sections (void *owner)
- {
- gdb_assert (owner != NULL);
- 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 ())
- {
- scoped_restore_current_pspace_and_thread restore_pspace_thread;
- for (inferior *inf : all_inferiors ())
- {
- if (inf->pspace != this)
- continue;
- switch_to_inferior_no_thread (inf);
- inf->unpush_target (&exec_ops);
- }
- }
- }
- /* See exec.h. */
- void
- exec_on_vfork (inferior *vfork_child)
- {
- if (!vfork_child->pspace->target_sections ().empty ())
- vfork_child->push_target (&exec_ops);
- }
- enum target_xfer_status
- exec_read_partial_read_only (gdb_byte *readbuf, ULONGEST offset,
- ULONGEST len, ULONGEST *xfered_len)
- {
- /* 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 (current_program_space->exec_bfd () != NULL)
- {
- asection *s;
- bfd_size_type size;
- bfd_vma vma;
- 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_section_size (s);
- if (vma <= offset && offset < (vma + size))
- {
- ULONGEST amt;
- amt = (vma + size) - offset;
- if (amt > len)
- amt = len;
- amt = bfd_get_section_contents (current_program_space->exec_bfd (), s,
- readbuf, offset - vma, amt);
- if (amt == 0)
- return TARGET_XFER_EOF;
- else
- {
- *xfered_len = amt;
- return TARGET_XFER_OK;
- }
- }
- }
- }
- /* Indicate failure to find the requested memory block. */
- return TARGET_XFER_E_IO;
- }
- /* 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. */
- static std::vector<mem_range>
- section_table_available_memory (CORE_ADDR memaddr, ULONGEST len,
- const target_section_table §ions)
- {
- std::vector<mem_range> memory;
- for (const target_section &p : sections)
- {
- 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))
- {
- ULONGEST lo1, hi1, lo2, hi2;
- lo1 = memaddr;
- hi1 = memaddr + len;
- lo2 = p.addr;
- hi2 = p.endaddr;
- CORE_ADDR start = std::max (lo1, lo2);
- int length = std::min (hi1, hi2) - start;
- memory.emplace_back (start, length);
- }
- }
- return memory;
- }
- enum target_xfer_status
- section_table_read_available_memory (gdb_byte *readbuf, ULONGEST offset,
- ULONGEST len, ULONGEST *xfered_len)
- {
- 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))
- {
- CORE_ADDR end;
- enum target_xfer_status status;
- /* Get the intersection window. */
- end = std::min<CORE_ADDR> (offset + len, r.start + r.length);
- gdb_assert (end - offset <= len);
- if (offset >= r.start)
- status = exec_read_partial_read_only (readbuf, offset,
- end - offset,
- xfered_len);
- else
- {
- *xfered_len = r.start - offset;
- status = TARGET_XFER_UNAVAILABLE;
- }
- return status;
- }
- }
- *xfered_len = len;
- return TARGET_XFER_UNAVAILABLE;
- }
- enum target_xfer_status
- section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len,
- const target_section_table §ions,
- gdb::function_view<bool
- (const struct target_section *)> match_cb)
- {
- int res;
- ULONGEST memaddr = offset;
- ULONGEST memend = memaddr + len;
- gdb_assert (len != 0);
- for (const target_section &p : sections)
- {
- struct bfd_section *asect = p.the_bfd_section;
- bfd *abfd = asect->owner;
- if (match_cb != nullptr && !match_cb (&p))
- continue; /* not the section we need. */
- 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,
- len);
- else
- res = bfd_get_section_contents (abfd, asect,
- readbuf, memaddr - p.addr,
- len);
- if (res != 0)
- {
- *xfered_len = len;
- return TARGET_XFER_OK;
- }
- else
- return TARGET_XFER_EOF;
- }
- 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;
- if (writebuf)
- res = bfd_set_section_contents (abfd, asect,
- writebuf, memaddr - p.addr,
- len);
- else
- res = bfd_get_section_contents (abfd, asect,
- readbuf, memaddr - p.addr,
- len);
- if (res != 0)
- {
- *xfered_len = len;
- return TARGET_XFER_OK;
- }
- else
- return TARGET_XFER_EOF;
- }
- }
- }
- return TARGET_XFER_EOF; /* We can't help. */
- }
- 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)
- {
- 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);
- else
- return TARGET_XFER_E_IO;
- }
- void
- print_section_info (const target_section_table *t, bfd *abfd)
- {
- struct gdbarch *gdbarch = gdbarch_from_bfd (abfd);
- /* FIXME: 16 is not wide enough when gdbarch_addr_bit > 64. */
- int wid = gdbarch_addr_bit (gdbarch) <= 32 ? 8 : 16;
- gdb_printf ("\t`%ps', ",
- styled_string (file_name_style.style (),
- bfd_get_filename (abfd)));
- gdb_stdout->wrap_here (8);
- gdb_printf (_("file type %s.\n"), bfd_get_target (abfd));
- 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 (const target_section &p : *t)
- {
- struct bfd_section *psect = p.the_bfd_section;
- if ((bfd_section_flags (psect) & (SEC_ALLOC | SEC_LOAD))
- != (SEC_ALLOC | SEC_LOAD))
- continue;
- if (bfd_section_vma (psect) <= abfd->start_address
- && abfd->start_address < (bfd_section_vma (psect)
- + bfd_section_size (psect)))
- {
- displacement = p.addr - bfd_section_vma (psect);
- found = true;
- break;
- }
- }
- 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)
- + displacement);
- gdb_printf (_("\tEntry point: %s\n"),
- paddress (gdbarch, entry_point));
- }
- for (const target_section &p : *t)
- {
- struct bfd_section *psect = p.the_bfd_section;
- bfd *pbfd = psect->owner;
- gdb_printf ("\t%s", hex_string_custom (p.addr, wid));
- gdb_printf (" - %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
- since most output will then be much wider than necessary. It
- may make sense to test the size of the file and choose the
- format string accordingly. */
- /* FIXME: i18n: Need to rewrite this sentence. */
- if (info_verbose)
- gdb_printf (" @ %s",
- hex_string_custom (psect->filepos, 8));
- gdb_printf (" is %s", bfd_section_name (psect));
- if (pbfd != abfd)
- gdb_printf (" in %ps",
- styled_string (file_name_style.style (),
- bfd_get_filename (pbfd)));
- gdb_printf ("\n");
- }
- }
- void
- exec_target::files_info ()
- {
- if (current_program_space->exec_bfd ())
- print_section_info (¤t_program_space->target_sections (),
- current_program_space->exec_bfd ());
- else
- gdb_puts (_("\t<no file loaded>\n"));
- }
- static void
- set_section_command (const char *args, int from_tty)
- {
- 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++);
- unsigned seclen = args - secname;
- /* Parse out new virtual address. */
- CORE_ADDR secaddr = parse_and_eval_address (args);
- for (target_section &p : current_program_space->target_sections ())
- {
- if (!strncmp (secname, bfd_section_name (p.the_bfd_section), seclen)
- && bfd_section_name (p.the_bfd_section)[seclen] == '\0')
- {
- long offset = secaddr - p.addr;
- p.addr += offset;
- p.endaddr += offset;
- if (from_tty)
- exec_ops.files_info ();
- return;
- }
- }
- 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
- it to ADDRESS. */
- void
- exec_set_section_address (const char *filename, int index, CORE_ADDR address)
- {
- for (target_section &p : current_program_space->target_sections ())
- {
- 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;
- }
- }
- }
- bool
- exec_target::has_memory ()
- {
- /* We can provide memory if we have any file/target sections to read
- from. */
- return !current_program_space->target_sections ().empty ();
- }
- gdb::unique_xmalloc_ptr<char>
- exec_target::make_corefile_notes (bfd *obfd, int *note_size)
- {
- error (_("Can't create a corefile"));
- }
- int
- exec_target::find_memory_regions (find_memory_region_ftype func, void *data)
- {
- return objfile_find_memory_regions (this, func, data);
- }
- void _initialize_exec ();
- void
- _initialize_exec ()
- {
- struct cmd_list_element *c;
- c = add_cmd ("file", class_files, file_command, _("\
- Use FILE as program to be debugged.\n\
- It is read for its symbols, for getting the contents of pure memory,\n\
- and it is the program executed when you use the `run' command.\n\
- If FILE cannot be found as specified, your execution directory path\n\
- ($PATH) is searched for a command of that name.\n\
- No arg means to have no executable file and no symbols."), &cmdlist);
- set_cmd_completer (c, filename_completer);
- c = add_cmd ("exec-file", class_files, exec_file_command, _("\
- Use FILE as program for getting contents of pure memory.\n\
- If FILE cannot be found as specified, your execution directory path\n\
- is searched for a command of that name.\n\
- No arg means have no executable file."), &cmdlist);
- set_cmd_completer (c, filename_completer);
- add_com ("section", class_files, set_section_command, _("\
- Change the base address of section SECTION of the exec file to ADDR.\n\
- This can be used if the exec file does not contain section addresses,\n\
- (such as in the a.out format), or when the addresses specified in the\n\
- file itself are wrong. Each section must be changed separately. The\n\
- ``info files'' command lists all the sections and their addresses."));
- add_setshow_boolean_cmd ("write", class_support, &write_files, _("\
- Set writing into executable and core files."), _("\
- Show writing into executable and core files."), NULL,
- NULL,
- show_write_files,
- &setlist, &showlist);
- 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);
- }
|