123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251 |
- /* Core dump and executable file functions below target vector, for GDB.
- Copyright (C) 1986-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 "arch-utils.h"
- #include <signal.h>
- #include <fcntl.h>
- #include "frame.h" /* required by inferior.h */
- #include "inferior.h"
- #include "infrun.h"
- #include "symtab.h"
- #include "command.h"
- #include "bfd.h"
- #include "target.h"
- #include "process-stratum-target.h"
- #include "gdbcore.h"
- #include "gdbthread.h"
- #include "regcache.h"
- #include "regset.h"
- #include "symfile.h"
- #include "exec.h"
- #include "readline/tilde.h"
- #include "solib.h"
- #include "solist.h"
- #include "filenames.h"
- #include "progspace.h"
- #include "objfiles.h"
- #include "gdb_bfd.h"
- #include "completer.h"
- #include "gdbsupport/filestuff.h"
- #include "build-id.h"
- #include "gdbsupport/pathstuff.h"
- #include "gdbsupport/scoped_fd.h"
- #include "debuginfod-support.h"
- #include <unordered_map>
- #include <unordered_set>
- #include "gdbcmd.h"
- #include "xml-tdesc.h"
- #ifndef O_LARGEFILE
- #define O_LARGEFILE 0
- #endif
- /* The core file target. */
- static const target_info core_target_info = {
- "core",
- N_("Local core dump file"),
- N_("Use a core file as a target.\n\
- Specify the filename of the core file.")
- };
- class core_target final : public process_stratum_target
- {
- public:
- core_target ();
- const target_info &info () const override
- { return core_target_info; }
- void close () override;
- void detach (inferior *, int) override;
- void fetch_registers (struct regcache *, int) 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 thread_alive (ptid_t ptid) override;
- const struct target_desc *read_description () override;
- std::string pid_to_str (ptid_t) override;
- const char *thread_name (struct thread_info *) override;
- bool has_all_memory () override { return true; }
- bool has_memory () override;
- bool has_stack () override;
- bool has_registers () override;
- bool has_execution (inferior *inf) override { return false; }
- bool info_proc (const char *, enum info_proc_what) override;
- /* A few helpers. */
- /* Getter, see variable definition. */
- struct gdbarch *core_gdbarch ()
- {
- return m_core_gdbarch;
- }
- /* See definition. */
- void get_core_register_section (struct regcache *regcache,
- const struct regset *regset,
- const char *name,
- int section_min_size,
- const char *human_name,
- bool required);
- /* See definition. */
- void info_proc_mappings (struct gdbarch *gdbarch);
- private: /* per-core data */
- /* The core's section table. Note that these target sections are
- *not* mapped in the current address spaces' set of target
- sections --- those should come only from pure executable or
- shared library bfds. The core bfd sections are an implementation
- detail of the core target, just like ptrace is for unix child
- targets. */
- target_section_table m_core_section_table;
- /* File-backed address space mappings: some core files include
- information about memory mapped files. */
- target_section_table m_core_file_mappings;
- /* Unavailable mappings. These correspond to pathnames which either
- weren't found or could not be opened. Knowing these addresses can
- still be useful. */
- std::vector<mem_range> m_core_unavailable_mappings;
- /* Build m_core_file_mappings. Called from the constructor. */
- void build_file_mappings ();
- /* Helper method for xfer_partial. */
- enum target_xfer_status xfer_memory_via_mappings (gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- ULONGEST len,
- ULONGEST *xfered_len);
- /* FIXME: kettenis/20031023: Eventually this field should
- disappear. */
- struct gdbarch *m_core_gdbarch = NULL;
- };
- core_target::core_target ()
- {
- /* Find a first arch based on the BFD. We need the initial gdbarch so
- we can setup the hooks to find a target description. */
- m_core_gdbarch = gdbarch_from_bfd (core_bfd);
- /* If the arch is able to read a target description from the core, it
- could yield a more specific gdbarch. */
- const struct target_desc *tdesc = read_description ();
- if (tdesc != nullptr)
- {
- struct gdbarch_info info;
- info.abfd = core_bfd;
- info.target_desc = tdesc;
- m_core_gdbarch = gdbarch_find_by_info (info);
- }
- if (!m_core_gdbarch
- || !gdbarch_iterate_over_regset_sections_p (m_core_gdbarch))
- error (_("\"%s\": Core file format not supported"),
- bfd_get_filename (core_bfd));
- /* Find the data section */
- m_core_section_table = build_section_table (core_bfd);
- build_file_mappings ();
- }
- /* Construct the target_section_table for file-backed mappings if
- they exist.
- For each unique path in the note, we'll open a BFD with a bfd
- target of "binary". This is an unstructured bfd target upon which
- we'll impose a structure from the mappings in the architecture-specific
- mappings note. A BFD section is allocated and initialized for each
- file-backed mapping.
- We take care to not share already open bfds with other parts of
- GDB; in particular, we don't want to add new sections to existing
- BFDs. We do, however, ensure that the BFDs that we allocate here
- will go away (be deallocated) when the core target is detached. */
- void
- core_target::build_file_mappings ()
- {
- std::unordered_map<std::string, struct bfd *> bfd_map;
- std::unordered_set<std::string> unavailable_paths;
- /* See linux_read_core_file_mappings() in linux-tdep.c for an example
- read_core_file_mappings method. */
- gdbarch_read_core_file_mappings (m_core_gdbarch, core_bfd,
- /* After determining the number of mappings, read_core_file_mappings
- will invoke this lambda. */
- [&] (ULONGEST)
- {
- },
- /* read_core_file_mappings will invoke this lambda for each mapping
- that it finds. */
- [&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
- const char *filename, const bfd_build_id *build_id)
- {
- /* Architecture-specific read_core_mapping methods are expected to
- weed out non-file-backed mappings. */
- gdb_assert (filename != nullptr);
- struct bfd *bfd = bfd_map[filename];
- if (bfd == nullptr)
- {
- /* Use exec_file_find() to do sysroot expansion. It'll
- also strip the potential sysroot "target:" prefix. If
- there is no sysroot, an equivalent (possibly more
- canonical) pathname will be provided. */
- gdb::unique_xmalloc_ptr<char> expanded_fname
- = exec_file_find (filename, NULL);
- if (expanded_fname == nullptr && build_id != nullptr)
- debuginfod_exec_query (build_id->data, build_id->size,
- filename, &expanded_fname);
- if (expanded_fname == nullptr)
- {
- m_core_unavailable_mappings.emplace_back (start, end - start);
- /* Print just one warning per path. */
- if (unavailable_paths.insert (filename).second)
- warning (_("Can't open file %s during file-backed mapping "
- "note processing"),
- filename);
- return;
- }
- bfd = bfd_map[filename] = bfd_openr (expanded_fname.get (),
- "binary");
- if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
- {
- m_core_unavailable_mappings.emplace_back (start, end - start);
- /* If we get here, there's a good chance that it's due to
- an internal error. We issue a warning instead of an
- internal error because of the possibility that the
- file was removed in between checking for its
- existence during the expansion in exec_file_find()
- and the calls to bfd_openr() / bfd_check_format().
- Output both the path from the core file note along
- with its expansion to make debugging this problem
- easier. */
- warning (_("Can't open file %s which was expanded to %s "
- "during file-backed mapping note processing"),
- filename, expanded_fname.get ());
- if (bfd != nullptr)
- bfd_close (bfd);
- return;
- }
- /* Ensure that the bfd will be closed when core_bfd is closed.
- This can be checked before/after a core file detach via
- "maint info bfds". */
- gdb_bfd_record_inclusion (core_bfd, bfd);
- }
- /* Make new BFD section. All sections have the same name,
- which is permitted by bfd_make_section_anyway(). */
- asection *sec = bfd_make_section_anyway (bfd, "load");
- if (sec == nullptr)
- error (_("Can't make section"));
- sec->filepos = file_ofs;
- bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
- bfd_set_section_size (sec, end - start);
- bfd_set_section_vma (sec, start);
- bfd_set_section_lma (sec, start);
- bfd_set_section_alignment (sec, 2);
- /* Set target_section fields. */
- m_core_file_mappings.emplace_back (start, end, sec);
- /* If this is a bfd of a shared library, record its soname
- and build id. */
- if (build_id != nullptr)
- {
- gdb::unique_xmalloc_ptr<char> soname
- = gdb_bfd_read_elf_soname (bfd->filename);
- if (soname != nullptr)
- set_cbfd_soname_build_id (current_program_space->cbfd,
- soname.get (), build_id);
- }
- });
- normalize_mem_ranges (&m_core_unavailable_mappings);
- }
- /* An arbitrary identifier for the core inferior. */
- #define CORELOW_PID 1
- /* Close the core target. */
- void
- core_target::close ()
- {
- if (core_bfd)
- {
- switch_to_no_thread (); /* Avoid confusion from thread
- stuff. */
- exit_inferior_silent (current_inferior ());
- /* Clear out solib state while the bfd is still open. See
- comments in clear_solib in solib.c. */
- clear_solib ();
- current_program_space->cbfd.reset (nullptr);
- }
- /* Core targets are heap-allocated (see core_target_open), so here
- we delete ourselves. */
- delete this;
- }
- /* Look for sections whose names start with `.reg/' so that we can
- extract the list of threads in a core file. */
- static void
- add_to_thread_list (asection *asect, asection *reg_sect)
- {
- int core_tid;
- int pid, lwpid;
- bool fake_pid_p = false;
- struct inferior *inf;
- if (!startswith (bfd_section_name (asect), ".reg/"))
- return;
- core_tid = atoi (bfd_section_name (asect) + 5);
- pid = bfd_core_file_pid (core_bfd);
- if (pid == 0)
- {
- fake_pid_p = true;
- pid = CORELOW_PID;
- }
- lwpid = core_tid;
- inf = current_inferior ();
- if (inf->pid == 0)
- {
- inferior_appeared (inf, pid);
- inf->fake_pid_p = fake_pid_p;
- }
- ptid_t ptid (pid, lwpid);
- thread_info *thr = add_thread (inf->process_target (), ptid);
- /* Warning, Will Robinson, looking at BFD private data! */
- if (reg_sect != NULL
- && asect->filepos == reg_sect->filepos) /* Did we find .reg? */
- switch_to_thread (thr); /* Yes, make it current. */
- }
- /* Issue a message saying we have no core to debug, if FROM_TTY. */
- static void
- maybe_say_no_core_file_now (int from_tty)
- {
- if (from_tty)
- gdb_printf (_("No core file now.\n"));
- }
- /* Backward compatibility with old way of specifying core files. */
- void
- core_file_command (const char *filename, int from_tty)
- {
- dont_repeat (); /* Either way, seems bogus. */
- if (filename == NULL)
- {
- if (core_bfd != NULL)
- {
- target_detach (current_inferior (), from_tty);
- gdb_assert (core_bfd == NULL);
- }
- else
- maybe_say_no_core_file_now (from_tty);
- }
- else
- core_target_open (filename, from_tty);
- }
- /* Locate (and load) an executable file (and symbols) given the core file
- BFD ABFD. */
- static void
- locate_exec_from_corefile_build_id (bfd *abfd, int from_tty)
- {
- const bfd_build_id *build_id = build_id_bfd_get (abfd);
- if (build_id == nullptr)
- return;
- gdb_bfd_ref_ptr execbfd
- = build_id_to_exec_bfd (build_id->size, build_id->data);
- if (execbfd == nullptr)
- {
- /* Attempt to query debuginfod for the executable. */
- gdb::unique_xmalloc_ptr<char> execpath;
- scoped_fd fd = debuginfod_exec_query (build_id->data, build_id->size,
- abfd->filename, &execpath);
- if (fd.get () >= 0)
- {
- execbfd = gdb_bfd_open (execpath.get (), gnutarget);
- if (execbfd == nullptr)
- warning (_("\"%s\" from debuginfod cannot be opened as bfd: %s"),
- execpath.get (),
- gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
- else if (!build_id_verify (execbfd.get (), build_id->size,
- build_id->data))
- execbfd.reset (nullptr);
- }
- }
- if (execbfd != nullptr)
- {
- exec_file_attach (bfd_get_filename (execbfd.get ()), from_tty);
- symbol_file_add_main (bfd_get_filename (execbfd.get ()),
- symfile_add_flag (from_tty ? SYMFILE_VERBOSE : 0));
- }
- }
- /* See gdbcore.h. */
- void
- core_target_open (const char *arg, int from_tty)
- {
- const char *p;
- int siggy;
- int scratch_chan;
- int flags;
- target_preopen (from_tty);
- if (!arg)
- {
- if (core_bfd)
- error (_("No core file specified. (Use `detach' "
- "to stop debugging a core file.)"));
- else
- error (_("No core file specified."));
- }
- gdb::unique_xmalloc_ptr<char> filename (tilde_expand (arg));
- if (strlen (filename.get ()) != 0
- && !IS_ABSOLUTE_PATH (filename.get ()))
- filename = gdb_abspath (filename.get ());
- flags = O_BINARY | O_LARGEFILE;
- if (write_files)
- flags |= O_RDWR;
- else
- flags |= O_RDONLY;
- scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release ();
- if (scratch_chan < 0)
- perror_with_name (filename.get ());
- gdb_bfd_ref_ptr temp_bfd (gdb_bfd_fopen (filename.get (), gnutarget,
- write_files ? FOPEN_RUB : FOPEN_RB,
- scratch_chan));
- if (temp_bfd == NULL)
- perror_with_name (filename.get ());
- if (!bfd_check_format (temp_bfd.get (), bfd_core))
- {
- /* Do it after the err msg */
- /* FIXME: should be checking for errors from bfd_close (for one
- thing, on error it does not free all the storage associated
- with the bfd). */
- error (_("\"%s\" is not a core dump: %s"),
- filename.get (), bfd_errmsg (bfd_get_error ()));
- }
- current_program_space->cbfd = std::move (temp_bfd);
- core_target *target = new core_target ();
- /* Own the target until it is successfully pushed. */
- target_ops_up target_holder (target);
- validate_files ();
- /* If we have no exec file, try to set the architecture from the
- core file. We don't do this unconditionally since an exec file
- typically contains more information that helps us determine the
- architecture than a core file. */
- if (!current_program_space->exec_bfd ())
- set_gdbarch_from_file (core_bfd);
- current_inferior ()->push_target (std::move (target_holder));
- switch_to_no_thread ();
- /* Need to flush the register cache (and the frame cache) from a
- previous debug session. If inferior_ptid ends up the same as the
- last debug session --- e.g., b foo; run; gcore core1; step; gcore
- core2; core core1; core core2 --- then there's potential for
- get_current_regcache to return the cached regcache of the
- previous session, and the frame cache being stale. */
- registers_changed ();
- /* Build up thread list from BFD sections, and possibly set the
- current thread to the .reg/NN section matching the .reg
- section. */
- asection *reg_sect = bfd_get_section_by_name (core_bfd, ".reg");
- for (asection *sect : gdb_bfd_sections (core_bfd))
- add_to_thread_list (sect, reg_sect);
- if (inferior_ptid == null_ptid)
- {
- /* Either we found no .reg/NN section, and hence we have a
- non-threaded core (single-threaded, from gdb's perspective),
- or for some reason add_to_thread_list couldn't determine
- which was the "main" thread. The latter case shouldn't
- usually happen, but we're dealing with input here, which can
- always be broken in different ways. */
- thread_info *thread = first_thread_of_inferior (current_inferior ());
- if (thread == NULL)
- {
- inferior_appeared (current_inferior (), CORELOW_PID);
- thread = add_thread_silent (target, ptid_t (CORELOW_PID));
- }
- switch_to_thread (thread);
- }
- if (current_program_space->exec_bfd () == nullptr)
- locate_exec_from_corefile_build_id (core_bfd, from_tty);
- post_create_inferior (from_tty);
- /* Now go through the target stack looking for threads since there
- may be a thread_stratum target loaded on top of target core by
- now. The layer above should claim threads found in the BFD
- sections. */
- try
- {
- target_update_thread_list ();
- }
- catch (const gdb_exception_error &except)
- {
- exception_print (gdb_stderr, except);
- }
- p = bfd_core_file_failing_command (core_bfd);
- if (p)
- gdb_printf (_("Core was generated by `%s'.\n"), p);
- /* Clearing any previous state of convenience variables. */
- clear_exit_convenience_vars ();
- siggy = bfd_core_file_failing_signal (core_bfd);
- if (siggy > 0)
- {
- gdbarch *core_gdbarch = target->core_gdbarch ();
- /* If we don't have a CORE_GDBARCH to work with, assume a native
- core (map gdb_signal from host signals). If we do have
- CORE_GDBARCH to work with, but no gdb_signal_from_target
- implementation for that gdbarch, as a fallback measure,
- assume the host signal mapping. It'll be correct for native
- cores, but most likely incorrect for cross-cores. */
- enum gdb_signal sig = (core_gdbarch != NULL
- && gdbarch_gdb_signal_from_target_p (core_gdbarch)
- ? gdbarch_gdb_signal_from_target (core_gdbarch,
- siggy)
- : gdb_signal_from_host (siggy));
- gdb_printf (_("Program terminated with signal %s, %s"),
- gdb_signal_to_name (sig), gdb_signal_to_string (sig));
- if (gdbarch_report_signal_info_p (core_gdbarch))
- gdbarch_report_signal_info (core_gdbarch, current_uiout, sig);
- gdb_printf (_(".\n"));
- /* Set the value of the internal variable $_exitsignal,
- which holds the signal uncaught by the inferior. */
- set_internalvar_integer (lookup_internalvar ("_exitsignal"),
- siggy);
- }
- /* Fetch all registers from core file. */
- target_fetch_registers (get_current_regcache (), -1);
- /* Now, set up the frame cache, and print the top of stack. */
- reinit_frame_cache ();
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
- /* Current thread should be NUM 1 but the user does not know that.
- If a program is single threaded gdb in general does not mention
- anything about threads. That is why the test is >= 2. */
- if (thread_count (target) >= 2)
- {
- try
- {
- thread_command (NULL, from_tty);
- }
- catch (const gdb_exception_error &except)
- {
- exception_print (gdb_stderr, except);
- }
- }
- }
- void
- core_target::detach (inferior *inf, int from_tty)
- {
- /* Note that 'this' is dangling after this call. unpush_target
- closes the target, and our close implementation deletes
- 'this'. */
- inf->unpush_target (this);
- /* Clear the register cache and the frame cache. */
- registers_changed ();
- reinit_frame_cache ();
- maybe_say_no_core_file_now (from_tty);
- }
- /* Try to retrieve registers from a section in core_bfd, and supply
- them to REGSET.
- If ptid's lwp member is zero, do the single-threaded
- thing: look for a section named NAME. If ptid's lwp
- member is non-zero, do the multi-threaded thing: look for a section
- named "NAME/LWP", where LWP is the shortest ASCII decimal
- representation of ptid's lwp member.
- HUMAN_NAME is a human-readable name for the kind of registers the
- NAME section contains, for use in error messages.
- If REQUIRED is true, print an error if the core file doesn't have a
- section by the appropriate name. Otherwise, just do nothing. */
- void
- core_target::get_core_register_section (struct regcache *regcache,
- const struct regset *regset,
- const char *name,
- int section_min_size,
- const char *human_name,
- bool required)
- {
- gdb_assert (regset != nullptr);
- struct bfd_section *section;
- bfd_size_type size;
- bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE);
- thread_section_name section_name (name, regcache->ptid ());
- section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
- if (! section)
- {
- if (required)
- warning (_("Couldn't find %s registers in core file."),
- human_name);
- return;
- }
- size = bfd_section_size (section);
- if (size < section_min_size)
- {
- warning (_("Section `%s' in core file too small."),
- section_name.c_str ());
- return;
- }
- if (size != section_min_size && !variable_size_section)
- {
- warning (_("Unexpected size of section `%s' in core file."),
- section_name.c_str ());
- }
- gdb::byte_vector contents (size);
- if (!bfd_get_section_contents (core_bfd, section, contents.data (),
- (file_ptr) 0, size))
- {
- warning (_("Couldn't read %s registers from `%s' section in core file."),
- human_name, section_name.c_str ());
- return;
- }
- regset->supply_regset (regset, regcache, -1, contents.data (), size);
- }
- /* Data passed to gdbarch_iterate_over_regset_sections's callback. */
- struct get_core_registers_cb_data
- {
- core_target *target;
- struct regcache *regcache;
- };
- /* Callback for get_core_registers that handles a single core file
- register note section. */
- static void
- get_core_registers_cb (const char *sect_name, int supply_size, int collect_size,
- const struct regset *regset,
- const char *human_name, void *cb_data)
- {
- gdb_assert (regset != nullptr);
- auto *data = (get_core_registers_cb_data *) cb_data;
- bool required = false;
- bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE);
- if (!variable_size_section)
- gdb_assert (supply_size == collect_size);
- if (strcmp (sect_name, ".reg") == 0)
- {
- required = true;
- if (human_name == NULL)
- human_name = "general-purpose";
- }
- else if (strcmp (sect_name, ".reg2") == 0)
- {
- if (human_name == NULL)
- human_name = "floating-point";
- }
- data->target->get_core_register_section (data->regcache, regset, sect_name,
- supply_size, human_name, required);
- }
- /* Get the registers out of a core file. This is the machine-
- independent part. Fetch_core_registers is the machine-dependent
- part, typically implemented in the xm-file for each
- architecture. */
- /* We just get all the registers, so we don't use regno. */
- void
- core_target::fetch_registers (struct regcache *regcache, int regno)
- {
- if (!(m_core_gdbarch != nullptr
- && gdbarch_iterate_over_regset_sections_p (m_core_gdbarch)))
- {
- gdb_printf (gdb_stderr,
- "Can't fetch registers from this type of core file\n");
- return;
- }
- struct gdbarch *gdbarch = regcache->arch ();
- get_core_registers_cb_data data = { this, regcache };
- gdbarch_iterate_over_regset_sections (gdbarch,
- get_core_registers_cb,
- (void *) &data, NULL);
- /* Mark all registers not found in the core as unavailable. */
- for (int i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
- if (regcache->get_register_status (i) == REG_UNKNOWN)
- regcache->raw_supply (i, NULL);
- }
- void
- core_target::files_info ()
- {
- print_section_info (&m_core_section_table, core_bfd);
- }
- /* Helper method for core_target::xfer_partial. */
- enum target_xfer_status
- core_target::xfer_memory_via_mappings (gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len)
- {
- enum target_xfer_status xfer_status;
- xfer_status = (section_table_xfer_memory_partial
- (readbuf, writebuf,
- offset, len, xfered_len,
- m_core_file_mappings));
- if (xfer_status == TARGET_XFER_OK || m_core_unavailable_mappings.empty ())
- return xfer_status;
- /* There are instances - e.g. when debugging within a docker
- container using the AUFS storage driver - where the pathnames
- obtained from the note section are incorrect. Despite the path
- being wrong, just knowing the start and end addresses of the
- mappings is still useful; we can attempt an access of the file
- stratum constrained to the address ranges corresponding to the
- unavailable mappings. */
- ULONGEST memaddr = offset;
- ULONGEST memend = offset + len;
- for (const auto &mr : m_core_unavailable_mappings)
- {
- if (address_in_mem_range (memaddr, &mr))
- {
- if (!address_in_mem_range (memend, &mr))
- len = mr.start + mr.length - memaddr;
- xfer_status = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY,
- NULL,
- readbuf,
- writebuf,
- offset,
- len,
- xfered_len);
- break;
- }
- }
- return xfer_status;
- }
- enum target_xfer_status
- core_target::xfer_partial (enum target_object object, const char *annex,
- gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
- {
- switch (object)
- {
- case TARGET_OBJECT_MEMORY:
- {
- enum target_xfer_status xfer_status;
- /* Try accessing memory contents from core file data,
- restricting consideration to those sections for which
- the BFD section flag SEC_HAS_CONTENTS is set. */
- auto has_contents_cb = [] (const struct target_section *s)
- {
- return ((s->the_bfd_section->flags & SEC_HAS_CONTENTS) != 0);
- };
- xfer_status = section_table_xfer_memory_partial
- (readbuf, writebuf,
- offset, len, xfered_len,
- m_core_section_table,
- has_contents_cb);
- if (xfer_status == TARGET_XFER_OK)
- return TARGET_XFER_OK;
- /* Check file backed mappings. If they're available, use
- core file provided mappings (e.g. from .note.linuxcore.file
- or the like) as this should provide a more accurate
- result. If not, check the stratum beneath us, which should
- be the file stratum.
- We also check unavailable mappings due to Docker/AUFS driver
- issues. */
- if (!m_core_file_mappings.empty ()
- || !m_core_unavailable_mappings.empty ())
- {
- xfer_status = xfer_memory_via_mappings (readbuf, writebuf, offset,
- len, xfered_len);
- }
- else
- xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
- writebuf, offset, len,
- xfered_len);
- if (xfer_status == TARGET_XFER_OK)
- return TARGET_XFER_OK;
- /* Finally, attempt to access data in core file sections with
- no contents. These will typically read as all zero. */
- auto no_contents_cb = [&] (const struct target_section *s)
- {
- return !has_contents_cb (s);
- };
- xfer_status = section_table_xfer_memory_partial
- (readbuf, writebuf,
- offset, len, xfered_len,
- m_core_section_table,
- no_contents_cb);
- return xfer_status;
- }
- case TARGET_OBJECT_AUXV:
- if (readbuf)
- {
- /* When the aux vector is stored in core file, BFD
- represents this with a fake section called ".auxv". */
- struct bfd_section *section;
- bfd_size_type size;
- section = bfd_get_section_by_name (core_bfd, ".auxv");
- if (section == NULL)
- return TARGET_XFER_E_IO;
- size = bfd_section_size (section);
- if (offset >= size)
- return TARGET_XFER_EOF;
- size -= offset;
- if (size > len)
- size = len;
- if (size == 0)
- return TARGET_XFER_EOF;
- if (!bfd_get_section_contents (core_bfd, section, readbuf,
- (file_ptr) offset, size))
- {
- warning (_("Couldn't read NT_AUXV note in core file."));
- return TARGET_XFER_E_IO;
- }
- *xfered_len = (ULONGEST) size;
- return TARGET_XFER_OK;
- }
- return TARGET_XFER_E_IO;
- case TARGET_OBJECT_WCOOKIE:
- if (readbuf)
- {
- /* When the StackGhost cookie is stored in core file, BFD
- represents this with a fake section called
- ".wcookie". */
- struct bfd_section *section;
- bfd_size_type size;
- section = bfd_get_section_by_name (core_bfd, ".wcookie");
- if (section == NULL)
- return TARGET_XFER_E_IO;
- size = bfd_section_size (section);
- if (offset >= size)
- return TARGET_XFER_EOF;
- size -= offset;
- if (size > len)
- size = len;
- if (size == 0)
- return TARGET_XFER_EOF;
- if (!bfd_get_section_contents (core_bfd, section, readbuf,
- (file_ptr) offset, size))
- {
- warning (_("Couldn't read StackGhost cookie in core file."));
- return TARGET_XFER_E_IO;
- }
- *xfered_len = (ULONGEST) size;
- return TARGET_XFER_OK;
- }
- return TARGET_XFER_E_IO;
- case TARGET_OBJECT_LIBRARIES:
- if (m_core_gdbarch != nullptr
- && gdbarch_core_xfer_shared_libraries_p (m_core_gdbarch))
- {
- if (writebuf)
- return TARGET_XFER_E_IO;
- else
- {
- *xfered_len = gdbarch_core_xfer_shared_libraries (m_core_gdbarch,
- readbuf,
- offset, len);
- if (*xfered_len == 0)
- return TARGET_XFER_EOF;
- else
- return TARGET_XFER_OK;
- }
- }
- return TARGET_XFER_E_IO;
- case TARGET_OBJECT_LIBRARIES_AIX:
- if (m_core_gdbarch != nullptr
- && gdbarch_core_xfer_shared_libraries_aix_p (m_core_gdbarch))
- {
- if (writebuf)
- return TARGET_XFER_E_IO;
- else
- {
- *xfered_len
- = gdbarch_core_xfer_shared_libraries_aix (m_core_gdbarch,
- readbuf, offset,
- len);
- if (*xfered_len == 0)
- return TARGET_XFER_EOF;
- else
- return TARGET_XFER_OK;
- }
- }
- return TARGET_XFER_E_IO;
- case TARGET_OBJECT_SIGNAL_INFO:
- if (readbuf)
- {
- if (m_core_gdbarch != nullptr
- && gdbarch_core_xfer_siginfo_p (m_core_gdbarch))
- {
- LONGEST l = gdbarch_core_xfer_siginfo (m_core_gdbarch, readbuf,
- offset, len);
- if (l >= 0)
- {
- *xfered_len = l;
- if (l == 0)
- return TARGET_XFER_EOF;
- else
- return TARGET_XFER_OK;
- }
- }
- }
- return TARGET_XFER_E_IO;
- default:
- return this->beneath ()->xfer_partial (object, annex, readbuf,
- writebuf, offset, len,
- xfered_len);
- }
- }
- /* Okay, let's be honest: threads gleaned from a core file aren't
- exactly lively, are they? On the other hand, if we don't claim
- that each & every one is alive, then we don't get any of them
- to appear in an "info thread" command, which is quite a useful
- behaviour.
- */
- bool
- core_target::thread_alive (ptid_t ptid)
- {
- return true;
- }
- /* Ask the current architecture what it knows about this core file.
- That will be used, in turn, to pick a better architecture. This
- wrapper could be avoided if targets got a chance to specialize
- core_target. */
- const struct target_desc *
- core_target::read_description ()
- {
- /* If the core file contains a target description note then we will use
- that in preference to anything else. */
- bfd_size_type tdesc_note_size = 0;
- struct bfd_section *tdesc_note_section
- = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
- if (tdesc_note_section != nullptr)
- tdesc_note_size = bfd_section_size (tdesc_note_section);
- if (tdesc_note_size > 0)
- {
- gdb::char_vector contents (tdesc_note_size + 1);
- if (bfd_get_section_contents (core_bfd, tdesc_note_section,
- contents.data (), (file_ptr) 0,
- tdesc_note_size))
- {
- /* Ensure we have a null terminator. */
- contents[tdesc_note_size] = '\0';
- const struct target_desc *result
- = string_read_description_xml (contents.data ());
- if (result != nullptr)
- return result;
- }
- }
- if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
- {
- const struct target_desc *result;
- result = gdbarch_core_read_description (m_core_gdbarch, this, core_bfd);
- if (result != NULL)
- return result;
- }
- return this->beneath ()->read_description ();
- }
- std::string
- core_target::pid_to_str (ptid_t ptid)
- {
- struct inferior *inf;
- int pid;
- /* The preferred way is to have a gdbarch/OS specific
- implementation. */
- if (m_core_gdbarch != nullptr
- && gdbarch_core_pid_to_str_p (m_core_gdbarch))
- return gdbarch_core_pid_to_str (m_core_gdbarch, ptid);
- /* Otherwise, if we don't have one, we'll just fallback to
- "process", with normal_pid_to_str. */
- /* Try the LWPID field first. */
- pid = ptid.lwp ();
- if (pid != 0)
- return normal_pid_to_str (ptid_t (pid));
- /* Otherwise, this isn't a "threaded" core -- use the PID field, but
- only if it isn't a fake PID. */
- inf = find_inferior_ptid (this, ptid);
- if (inf != NULL && !inf->fake_pid_p)
- return normal_pid_to_str (ptid);
- /* No luck. We simply don't have a valid PID to print. */
- return "<main task>";
- }
- const char *
- core_target::thread_name (struct thread_info *thr)
- {
- if (m_core_gdbarch != nullptr
- && gdbarch_core_thread_name_p (m_core_gdbarch))
- return gdbarch_core_thread_name (m_core_gdbarch, thr);
- return NULL;
- }
- bool
- core_target::has_memory ()
- {
- return (core_bfd != NULL);
- }
- bool
- core_target::has_stack ()
- {
- return (core_bfd != NULL);
- }
- bool
- core_target::has_registers ()
- {
- return (core_bfd != NULL);
- }
- /* Implement the to_info_proc method. */
- bool
- core_target::info_proc (const char *args, enum info_proc_what request)
- {
- struct gdbarch *gdbarch = get_current_arch ();
- /* Since this is the core file target, call the 'core_info_proc'
- method on gdbarch, not 'info_proc'. */
- if (gdbarch_core_info_proc_p (gdbarch))
- gdbarch_core_info_proc (gdbarch, args, request);
- return true;
- }
- /* Get a pointer to the current core target. If not connected to a
- core target, return NULL. */
- static core_target *
- get_current_core_target ()
- {
- target_ops *proc_target = current_inferior ()->process_target ();
- return dynamic_cast<core_target *> (proc_target);
- }
- /* Display file backed mappings from core file. */
- void
- core_target::info_proc_mappings (struct gdbarch *gdbarch)
- {
- if (!m_core_file_mappings.empty ())
- {
- gdb_printf (_("Mapped address spaces:\n\n"));
- if (gdbarch_addr_bit (gdbarch) == 32)
- {
- gdb_printf ("\t%10s %10s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
- }
- else
- {
- gdb_printf (" %18s %18s %10s %10s %s\n",
- "Start Addr",
- " End Addr",
- " Size", " Offset", "objfile");
- }
- }
- for (const target_section &tsp : m_core_file_mappings)
- {
- ULONGEST start = tsp.addr;
- ULONGEST end = tsp.endaddr;
- ULONGEST file_ofs = tsp.the_bfd_section->filepos;
- const char *filename = bfd_get_filename (tsp.the_bfd_section->owner);
- if (gdbarch_addr_bit (gdbarch) == 32)
- gdb_printf ("\t%10s %10s %10s %10s %s\n",
- paddress (gdbarch, start),
- paddress (gdbarch, end),
- hex_string (end - start),
- hex_string (file_ofs),
- filename);
- else
- gdb_printf (" %18s %18s %10s %10s %s\n",
- paddress (gdbarch, start),
- paddress (gdbarch, end),
- hex_string (end - start),
- hex_string (file_ofs),
- filename);
- }
- }
- /* Implement "maintenance print core-file-backed-mappings" command.
- If mappings are loaded, the results should be similar to the
- mappings shown by "info proc mappings". This command is mainly a
- debugging tool for GDB developers to make sure that the expected
- mappings are present after loading a core file. For Linux, the
- output provided by this command will be very similar (if not
- identical) to that provided by "info proc mappings". This is not
- necessarily the case for other OSes which might provide
- more/different information in the "info proc mappings" output. */
- static void
- maintenance_print_core_file_backed_mappings (const char *args, int from_tty)
- {
- core_target *targ = get_current_core_target ();
- if (targ != nullptr)
- targ->info_proc_mappings (targ->core_gdbarch ());
- }
- void _initialize_corelow ();
- void
- _initialize_corelow ()
- {
- add_target (core_target_info, core_target_open, filename_completer);
- add_cmd ("core-file-backed-mappings", class_maintenance,
- maintenance_print_core_file_backed_mappings,
- _("Print core file's file-backed mappings."),
- &maintenanceprintlist);
- }
|