elf/x86: Issue an error on discarded output .plt section
[binutils-gdb.git] / gdb / corelow.c
index deabf84def9cd26c65fc04f62a4aec4b54346861..10942e6af01fe2859ec175922fd52dfed70ef226 100644 (file)
@@ -1,6 +1,6 @@
 /* Core dump and executable file functions below target vector, for GDB.
 
-   Copyright (C) 1986-2018 Free Software Foundation, Inc.
+   Copyright (C) 1986-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -21,9 +21,6 @@
 #include "arch-utils.h"
 #include <signal.h>
 #include <fcntl.h>
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>          /* needed for F_OK and friends */
-#endif
 #include "frame.h"             /* required by inferior.h */
 #include "inferior.h"
 #include "infrun.h"
 #include "regset.h"
 #include "symfile.h"
 #include "exec.h"
-#include "readline/readline.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 "filestuff.h"
+#include "gdbsupport/filestuff.h"
+#include "build-id.h"
+#include "gdbsupport/pathstuff.h"
+#include <unordered_map>
+#include <unordered_set>
+#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 = {
   "core",
   N_("Local core dump file"),
-  N_("Use a core file as a target.  Specify the filename of the core 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 ();
-  ~core_target () override;
 
   const target_info &info () const override
   { return core_target_info; }
@@ -86,13 +87,16 @@ public:
   bool thread_alive (ptid_t ptid) override;
   const struct target_desc *read_description () override;
 
-  const char *pid_to_str (ptid_t) 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.  */
@@ -108,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
@@ -120,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;
 
-  /* 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;
+  /* 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.  */
@@ -133,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;
-
-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.  */
+  /* 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 ();
 
-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<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)
+             {
+               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.  */
 
@@ -259,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);
@@ -279,24 +317,22 @@ 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;
-  int fake_pid_p = 0;
+  bool fake_pid_p = false;
   struct inferior *inf;
 
-  if (!startswith (bfd_section_name (abfd, asect), ".reg/"))
+  if (!startswith (bfd_section_name (asect), ".reg/"))
     return;
 
-  core_tid = atoi (bfd_section_name (abfd, asect) + 5);
+  core_tid = atoi (bfd_section_name (asect) + 5);
 
   pid = bfd_core_file_pid (core_bfd);
   if (pid == 0)
     {
-      fake_pid_p = 1;
+      fake_pid_p = true;
       pid = CORELOW_PID;
     }
 
@@ -309,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.  */
@@ -329,7 +365,7 @@ maybe_say_no_core_file_now (int from_tty)
     printf_filtered (_("No core file now.\n"));
 }
 
-/* Backward compatability with old way of specifying core files.  */
+/* Backward compatibility with old way of specifying core files.  */
 
 void
 core_file_command (const char *filename, int from_tty)
@@ -350,6 +386,27 @@ core_file_command (const char *filename, int from_tty)
     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)
+    {
+      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
@@ -371,16 +428,16 @@ core_target_open (const char *arg, int from_tty)
     }
 
   gdb::unique_xmalloc_ptr<char> 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 ());
 
@@ -390,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 ()));
     }
@@ -414,13 +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 (target);
-  target_holder.release ();
+  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
@@ -433,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)
     {
@@ -449,29 +505,30 @@ 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);
     }
 
-  post_create_inferior (target, from_tty);
+  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
+  try
     {
       target_update_thread_list ();
     }
 
-  CATCH (except, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &except)
     {
       exception_print (gdb_stderr, except);
     }
-  END_CATCH
 
   p = bfd_core_file_failing_command (core_bfd);
   if (p)
@@ -497,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.  */
@@ -516,17 +576,16 @@ 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
+      try
        {
          thread_command (NULL, from_tty);
        }
-      CATCH (except, RETURN_MASK_ERROR)
+      catch (const gdb_exception_error &except)
        {
          exception_print (gdb_stderr, except);
        }
-      END_CATCH
     }
 }
 
@@ -536,15 +595,16 @@ 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 ();
   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 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
@@ -563,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 ());
 
@@ -584,7 +643,7 @@ core_target::get_core_register_section (struct regcache *regcache,
       return;
     }
 
-  size = bfd_section_size (core_bfd, section);
+  size = bfd_section_size (section);
   if (size < section_min_size)
     {
       warning (_("Section `%s' in core file too small."),
@@ -597,25 +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 (core_bfd, section)));
+  regset->supply_regset (regset, regcache, -1, contents.data (), size);
 }
 
 /* Data passed to gdbarch_iterate_over_regset_sections's callback.  */
@@ -633,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);
@@ -653,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-
@@ -670,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);
 }
@@ -710,34 +744,54 @@ core_target::files_info ()
   print_section_info (&m_core_section_table, core_bfd);
 }
 \f
-struct spuid_list
-{
-  gdb_byte *buf;
-  ULONGEST offset;
-  LONGEST len;
-  ULONGEST pos;
-  ULONGEST written;
-};
+/* Helper method for core_target::xfer_partial.  */
 
-static void
-add_to_spuid_list (bfd *abfd, asection *asect, void *list_p)
+enum target_xfer_status
+core_target::xfer_memory_via_mappings (gdb_byte *readbuf,
+                                      const gdb_byte *writebuf,
+                                      ULONGEST offset, ULONGEST len,
+                                      ULONGEST *xfered_len)
 {
-  struct spuid_list *list = (struct spuid_list *) list_p;
-  enum bfd_endian byte_order
-    = bfd_big_endian (abfd) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
-  int fd, pos = 0;
+  enum target_xfer_status xfer_status;
 
-  sscanf (bfd_section_name (abfd, asect), "SPU/%d/regs%n", &fd, &pos);
-  if (pos == 0)
-    return;
+  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;
 
-  if (list->pos >= list->offset && list->pos + 4 <= list->offset + list->len)
+  for (const auto &mr : m_core_unavailable_mappings)
     {
-      store_unsigned_integer (list->buf + list->pos - list->offset,
-                             4, byte_order, fd);
-      list->written += 4;
+      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;
+       }
     }
-  list->pos += 4;
+
+  return xfer_status;
 }
 
 enum target_xfer_status
@@ -748,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)
        {
@@ -768,7 +868,7 @@ core_target::xfer_partial (enum target_object object, const char *annex,
          if (section == NULL)
            return TARGET_XFER_E_IO;
 
-         size = bfd_section_size (core_bfd, section);
+         size = bfd_section_size (section);
          if (offset >= size)
            return TARGET_XFER_EOF;
          size -= offset;
@@ -803,7 +903,7 @@ core_target::xfer_partial (enum target_object object, const char *annex,
          if (section == NULL)
            return TARGET_XFER_E_IO;
 
-         size = bfd_section_size (core_bfd, section);
+         size = bfd_section_size (section);
          if (offset >= size)
            return TARGET_XFER_EOF;
          size -= offset;
@@ -866,64 +966,6 @@ core_target::xfer_partial (enum target_object object, const char *annex,
        }
       /* FALL THROUGH */
 
-    case TARGET_OBJECT_SPU:
-      if (readbuf && annex)
-       {
-         /* When the SPU contexts are stored in a core file, BFD
-            represents this with a fake section called
-            "SPU/<annex>".  */
-
-         struct bfd_section *section;
-         bfd_size_type size;
-         char sectionstr[100];
-
-         xsnprintf (sectionstr, sizeof sectionstr, "SPU/%s", annex);
-
-         section = bfd_get_section_by_name (core_bfd, sectionstr);
-         if (section == NULL)
-           return TARGET_XFER_E_IO;
-
-         size = bfd_section_size (core_bfd, 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 SPU section in core file."));
-             return TARGET_XFER_E_IO;
-           }
-
-         *xfered_len = (ULONGEST) size;
-         return TARGET_XFER_OK;
-       }
-      else if (readbuf)
-       {
-         /* NULL annex requests list of all present spuids.  */
-         struct spuid_list list;
-
-         list.buf = readbuf;
-         list.offset = offset;
-         list.len = len;
-         list.pos = 0;
-         list.written = 0;
-         bfd_map_over_sections (core_bfd, add_to_spuid_list, &list);
-
-         if (list.written == 0)
-           return TARGET_XFER_EOF;
-         else
-           {
-             *xfered_len = (ULONGEST) list.written;
-             return TARGET_XFER_OK;
-           }
-       }
-      return TARGET_XFER_E_IO;
-
     case TARGET_OBJECT_SIGNAL_INFO:
       if (readbuf)
        {
@@ -974,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;
@@ -986,10 +1051,9 @@ core_target::read_description ()
   return this->beneath ()->read_description ();
 }
 
-const char *
+std::string
 core_target::pid_to_str (ptid_t ptid)
 {
-  static char buf[64];
   struct inferior *inf;
   int pid;
 
@@ -1009,13 +1073,12 @@ 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);
 
   /* No luck.  We simply don't have a valid PID to print.  */
-  xsnprintf (buf, sizeof buf, "<main task>");
-  return buf;
+  return "<main task>";
 }
 
 const char *
@@ -1060,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<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 ())
+    {
+      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);
 }