X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fcorelow.c;h=10942e6af01fe2859ec175922fd52dfed70ef226;hb=7c80aab93666727965c2d5d6e17b1338d88293e0;hp=bdbfae372d74f187d1ebde7f03ab823e7c741b7d;hpb=aa2d5a4229eb541406d3b91a384ad6a62caf7760;p=binutils-gdb.git diff --git a/gdb/corelow.c b/gdb/corelow.c index bdbfae372d7..10942e6af01 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -1,6 +1,6 @@ /* Core dump and executable file functions below target vector, for GDB. - Copyright (C) 1986-2019 Free Software Foundation, Inc. + Copyright (C) 1986-2021 Free Software Foundation, Inc. This file is part of GDB. @@ -37,6 +37,7 @@ #include "exec.h" #include "readline/tilde.h" #include "solib.h" +#include "solist.h" #include "filenames.h" #include "progspace.h" #include "objfiles.h" @@ -44,14 +45,16 @@ #include "completer.h" #include "gdbsupport/filestuff.h" #include "build-id.h" +#include "gdbsupport/pathstuff.h" +#include +#include +#include "gdbcmd.h" +#include "xml-tdesc.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif -static core_fns *sniff_core_bfd (gdbarch *core_gdbarch, - bfd *abfd); - /* The core file target. */ static const target_info core_target_info = { @@ -65,7 +68,6 @@ class core_target final : public process_stratum_target { public: core_target (); - ~core_target () override; const target_info &info () const override { return core_target_info; } @@ -89,11 +91,11 @@ public: const char *thread_name (struct thread_info *) override; - bool has_all_memory () override { return false; } + bool has_all_memory () override { return true; } bool has_memory () override; bool has_stack () override; bool has_registers () override; - bool has_execution (ptid_t) override { return false; } + bool has_execution (inferior *inf) override { return false; } bool info_proc (const char *, enum info_proc_what) override; @@ -110,10 +112,12 @@ public: const struct regset *regset, const char *name, int section_min_size, - int which, 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 @@ -122,11 +126,26 @@ private: /* per-core data */ 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 {}; + 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; - /* The core_fns for a core file handler that is prepared to read the - core file currently open on core_bfd. */ - core_fns *m_core_vec = NULL; + /* 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 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. */ @@ -135,124 +154,141 @@ private: /* per-core data */ 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); - /* Find a suitable core file handler to munch on core_bfd */ - m_core_vec = sniff_core_bfd (m_core_gdbarch, core_bfd); - - /* Find the data section */ - if (build_section_table (core_bfd, - &m_core_section_table.sections, - &m_core_section_table.sections_end)) - error (_("\"%s\": Can't find sections: %s"), - bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ())); -} - -core_target::~core_target () -{ - xfree (m_core_section_table.sections); -} - -/* List of all available core_fns. On gdb startup, each core file - register reader calls deprecated_add_core_fns() to register - information on each core format it is prepared to read. */ - -static struct core_fns *core_file_fns = NULL; + /* 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 (); -static int gdb_check_format (bfd *); - -static void add_to_thread_list (bfd *, asection *, void *); - -/* An arbitrary identifier for the core inferior. */ -#define CORELOW_PID 1 - -/* Link a new core_fns into the global core_file_fns list. Called on - gdb startup by the _initialize routine in each core file register - reader, to register information about each format the reader is - prepared to handle. */ - -void -deprecated_add_core_fns (struct core_fns *cf) -{ - cf->next = core_file_fns; - core_file_fns = cf; -} + if (tdesc != nullptr) + { + struct gdbarch_info info; + info.abfd = core_bfd; + info.target_desc = tdesc; + m_core_gdbarch = gdbarch_find_by_info (info); + } -/* The default function that core file handlers can use to examine a - core file BFD and decide whether or not to accept the job of - reading the core file. */ + 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)); -int -default_core_sniffer (struct core_fns *our_fns, bfd *abfd) -{ - int result; + /* Find the data section */ + m_core_section_table = build_section_table (core_bfd); - result = (bfd_get_flavour (abfd) == our_fns -> core_flavour); - return (result); + build_file_mappings (); } -/* Walk through the list of core functions to find a set that can - handle the core file open on ABFD. Returns pointer to set that is - selected. */ - -static struct core_fns * -sniff_core_bfd (struct gdbarch *core_gdbarch, bfd *abfd) -{ - struct core_fns *cf; - struct core_fns *yummy = NULL; - int matches = 0; - - /* Don't sniff if we have support for register sets in - CORE_GDBARCH. */ - if (core_gdbarch && gdbarch_iterate_over_regset_sections_p (core_gdbarch)) - return NULL; - - for (cf = core_file_fns; cf != NULL; cf = cf->next) - { - if (cf->core_sniffer (cf, abfd)) - { - yummy = cf; - matches++; - } - } - if (matches > 1) - { - warning (_("\"%s\": ambiguous core format, %d handlers match"), - bfd_get_filename (abfd), matches); - } - else if (matches == 0) - error (_("\"%s\": no core file handler recognizes format"), - bfd_get_filename (abfd)); +/* Construct the target_section_table for file-backed mappings if + they exist. - return (yummy); -} + 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. -/* The default is to reject every core file format we see. Either - BFD has to recognize it, or we have to provide a function in the - core file handler that recognizes it. */ + 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. */ -int -default_check_format (bfd *abfd) +void +core_target::build_file_mappings () { - return (0); + std::unordered_map bfd_map; + std::unordered_set 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 expanded_fname + = exec_file_find (filename, NULL); + 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); + }); + + normalize_mem_ranges (&m_core_unavailable_mappings); } -/* Attempt to recognize core file formats that BFD rejects. */ - -static int -gdb_check_format (bfd *abfd) -{ - struct core_fns *cf; - - for (cf = core_file_fns; cf != NULL; cf = cf->next) - { - if (cf->check_format (abfd)) - { - return (1); - } - } - return (0); -} +/* An arbitrary identifier for the core inferior. */ +#define CORELOW_PID 1 /* Close the core target. */ @@ -261,12 +297,12 @@ core_target::close () { if (core_bfd) { - inferior_ptid = null_ptid; /* Avoid confusion from thread - stuff. */ + 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. */ + comments in clear_solib in solib.c. */ clear_solib (); current_program_space->cbfd.reset (nullptr); @@ -281,12 +317,10 @@ core_target::close () extract the list of threads in a core file. */ static void -add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg) +add_to_thread_list (asection *asect, asection *reg_sect) { - ptid_t ptid; int core_tid; int pid, lwpid; - asection *reg_sect = (asection *) reg_sect_arg; bool fake_pid_p = false; struct inferior *inf; @@ -311,15 +345,15 @@ add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg) inf->fake_pid_p = fake_pid_p; } - ptid = ptid_t (pid, lwpid, 0); + ptid_t ptid (pid, lwpid); - add_thread (ptid); + 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? */ - inferior_ptid = ptid; /* Yes, make it current. */ + switch_to_thread (thr); /* Yes, make it current. */ } /* Issue a message saying we have no core to debug, if FROM_TTY. */ @@ -394,16 +428,16 @@ core_target_open (const char *arg, int from_tty) } gdb::unique_xmalloc_ptr filename (tilde_expand (arg)); - if (!IS_ABSOLUTE_PATH (filename.get ())) - filename.reset (concat (current_directory, "/", - filename.get (), (char *) NULL)); + 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); + scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release (); if (scratch_chan < 0) perror_with_name (filename.get ()); @@ -413,13 +447,12 @@ core_target_open (const char *arg, int from_tty) if (temp_bfd == NULL) perror_with_name (filename.get ()); - if (!bfd_check_format (temp_bfd.get (), bfd_core) - && !gdb_check_format (temp_bfd.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). */ + 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 ())); } @@ -437,12 +470,12 @@ core_target_open (const char *arg, int from_tty) 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 (!exec_bfd) + if (!current_program_space->exec_bfd ()) set_gdbarch_from_file (core_bfd); - push_target (std::move (target_holder)); + current_inferior ()->push_target (std::move (target_holder)); - inferior_ptid = null_ptid; + 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 @@ -455,8 +488,9 @@ core_target_open (const char *arg, int from_tty) /* Build up thread list from BFD sections, and possibly set the current thread to the .reg/NN section matching the .reg section. */ - bfd_map_over_sections (core_bfd, add_to_thread_list, - bfd_get_section_by_name (core_bfd, ".reg")); + 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) { @@ -471,17 +505,16 @@ core_target_open (const char *arg, int from_tty) if (thread == NULL) { inferior_appeared (current_inferior (), CORELOW_PID); - inferior_ptid = ptid_t (CORELOW_PID); - add_thread_silent (inferior_ptid); + thread = add_thread_silent (target, ptid_t (CORELOW_PID)); } - else - switch_to_thread (thread); + + switch_to_thread (thread); } - if (exec_bfd == nullptr) + if (current_program_space->exec_bfd () == nullptr) locate_exec_from_corefile_build_id (core_bfd, from_tty); - post_create_inferior (target, 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 @@ -521,8 +554,11 @@ core_target_open (const char *arg, int from_tty) siggy) : gdb_signal_from_host (siggy)); - printf_filtered (_("Program terminated with signal %s, %s.\n"), + printf_filtered (_("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); + printf_filtered (_(".\n")); /* Set the value of the internal variable $_exitsignal, which holds the signal uncaught by the inferior. */ @@ -540,7 +576,7 @@ core_target_open (const char *arg, int from_tty) /* 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 () >= 2) + if (thread_count (target) >= 2) { try { @@ -559,7 +595,7 @@ 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'. */ - unpush_target (this); + inf->unpush_target (this); /* Clear the register cache and the frame cache. */ registers_changed (); @@ -568,8 +604,7 @@ core_target::detach (inferior *inf, int from_tty) } /* Try to retrieve registers from a section in core_bfd, and supply - them to m_core_vec->core_read_registers, as the register set - numbered WHICH. + 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 @@ -588,15 +623,14 @@ core_target::get_core_register_section (struct regcache *regcache, const struct regset *regset, const char *name, int section_min_size, - int which, const char *human_name, bool required) { + gdb_assert (regset != nullptr); + struct bfd_section *section; bfd_size_type size; - char *contents; - bool variable_size_section = (regset != NULL - && regset->flags & REGSET_VARIABLE_SIZE); + bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE); thread_section_name section_name (name, regcache->ptid ()); @@ -622,24 +656,16 @@ core_target::get_core_register_section (struct regcache *regcache, section_name.c_str ()); } - contents = (char *) alloca (size); - if (! bfd_get_section_contents (core_bfd, section, contents, - (file_ptr) 0, size)) + 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; } - if (regset != NULL) - { - regset->supply_regset (regset, regcache, -1, contents, size); - return; - } - - gdb_assert (m_core_vec != nullptr); - m_core_vec->core_read_registers (regcache, contents, size, which, - (CORE_ADDR) bfd_section_vma (section)); + regset->supply_regset (regset, regcache, -1, contents.data (), size); } /* Data passed to gdbarch_iterate_over_regset_sections's callback. */ @@ -657,10 +683,11 @@ 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 != NULL - && regset->flags & REGSET_VARIABLE_SIZE); + bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE); if (!variable_size_section) gdb_assert (supply_size == collect_size); @@ -677,11 +704,8 @@ get_core_registers_cb (const char *sect_name, int supply_size, int collect_size, human_name = "floating-point"; } - /* The 'which' parameter is only used when no regset is provided. - Thus we just set it to -1. */ data->target->get_core_register_section (data->regcache, regset, sect_name, - supply_size, -1, human_name, - required); + supply_size, human_name, required); } /* Get the registers out of a core file. This is the machine- @@ -694,36 +718,22 @@ get_core_registers_cb (const char *sect_name, int supply_size, int collect_size, void core_target::fetch_registers (struct regcache *regcache, int regno) { - int i; - struct gdbarch *gdbarch; - if (!(m_core_gdbarch != nullptr - && gdbarch_iterate_over_regset_sections_p (m_core_gdbarch)) - && (m_core_vec == NULL || m_core_vec->core_read_registers == NULL)) + && gdbarch_iterate_over_regset_sections_p (m_core_gdbarch))) { fprintf_filtered (gdb_stderr, "Can't fetch registers from this type of core file\n"); return; } - gdbarch = regcache->arch (); - if (gdbarch_iterate_over_regset_sections_p (gdbarch)) - { - get_core_registers_cb_data data = { this, regcache }; - gdbarch_iterate_over_regset_sections (gdbarch, - get_core_registers_cb, - (void *) &data, NULL); - } - else - { - get_core_register_section (regcache, NULL, - ".reg", 0, 0, "general-purpose", 1); - get_core_register_section (regcache, NULL, - ".reg2", 0, 2, "floating-point", 0); - } + 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 (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++) + for (int i = 0; i < gdbarch_num_regs (regcache->arch ()); i++) if (regcache->get_register_status (i) == REG_UNKNOWN) regcache->raw_supply (i, NULL); } @@ -734,6 +744,56 @@ 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, @@ -742,13 +802,59 @@ core_target::xfer_partial (enum target_object object, const char *annex, switch (object) { case TARGET_OBJECT_MEMORY: - return (section_table_xfer_memory_partial - (readbuf, writebuf, - offset, len, xfered_len, - m_core_section_table.sections, - m_core_section_table.sections_end, - NULL)); + { + 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) { @@ -910,6 +1016,29 @@ core_target::thread_alive (ptid_t ptid) 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; @@ -944,7 +1073,7 @@ core_target::pid_to_str (ptid_t ptid) /* Otherwise, this isn't a "threaded" core -- use the PID field, but only if it isn't a fake PID. */ - inf = find_inferior_ptid (ptid); + inf = find_inferior_ptid (this, ptid); if (inf != NULL && !inf->fake_pid_p) return normal_pid_to_str (ptid); @@ -994,8 +1123,90 @@ core_target::info_proc (const char *args, enum info_proc_what 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 (proc_target); +} + +/* Display file backed mappings from core file. */ + +void +core_target::info_proc_mappings (struct gdbarch *gdbarch) +{ + if (!m_core_file_mappings.empty ()) + { + printf_filtered (_("Mapped address spaces:\n\n")); + if (gdbarch_addr_bit (gdbarch) == 32) + { + printf_filtered ("\t%10s %10s %10s %10s %s\n", + "Start Addr", + " End Addr", + " Size", " Offset", "objfile"); + } + else + { + printf_filtered (" %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) + printf_filtered ("\t%10s %10s %10s %10s %s\n", + paddress (gdbarch, start), + paddress (gdbarch, end), + hex_string (end - start), + hex_string (file_ofs), + filename); + else + printf_filtered (" %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 (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); }