Blame SOURCES/gdb-rhbz1842691-corefile-mem-access-8of15.patch

0efd7d
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
0efd7d
From: Keith Seitz <keiths@redhat.com>
0efd7d
Date: Mon, 27 Jul 2020 18:51:07 -0400
0efd7d
Subject: gdb-rhbz1842691-corefile-mem-access-8of15.patch
0efd7d
0efd7d
;; Use NT_FILE note section for reading core target memory
0efd7d
;; Kevin Buettner, RH BZ 1842961
0efd7d
0efd7d
   Author: Kevin Buettner <kevinb@redhat.com>
0efd7d
   Date:   Thu Jun 11 19:20:03 2020 -0700
0efd7d
0efd7d
    Use NT_FILE note section for reading core target memory
0efd7d
0efd7d
    In his reviews of my v1 and v2 corefile related patches, Pedro
0efd7d
    identified two cases which weren't handled by those patches.
0efd7d
0efd7d
    In https://sourceware.org/pipermail/gdb-patches/2020-May/168826.html,
0efd7d
    Pedro showed that debugging a core file in which mmap() is used to
0efd7d
    create a new mapping over an existing file-backed mapping will
0efd7d
    produce incorrect results.  I.e, for his example, GDB would
0efd7d
    show:
0efd7d
0efd7d
    (gdb) disassemble main
0efd7d
    Dump of assembler code for function main:
0efd7d
       0x00000000004004e6 <+0>:	push   %rbp
0efd7d
       0x00000000004004e7 <+1>:	mov    %rsp,%rbp
0efd7d
    => 0x00000000004004ea <+4>:	callq  0x4003f0 <abort@plt>
0efd7d
    End of assembler dump.
0efd7d
0efd7d
    This sort of looks like it might be correct, but is not due to the
0efd7d
    fact that mmap(...MAP_FIXED...) was used to create a mapping (of all
0efd7d
    zeros) on top of the .text section.  So, the correct result should be:
0efd7d
0efd7d
    (gdb) disassemble main
0efd7d
    Dump of assembler code for function main:
0efd7d
       0x00000000004004e6 <+0>:	add    %al,(%rax)
0efd7d
       0x00000000004004e8 <+2>:	add    %al,(%rax)
0efd7d
    => 0x00000000004004ea <+4>:	add    %al,(%rax)
0efd7d
       0x00000000004004ec <+6>:	add    %al,(%rax)
0efd7d
       0x00000000004004ee <+8>:	add    %al,(%rax)
0efd7d
    End of assembler dump.
0efd7d
0efd7d
    The other case that Pedro found involved an attempted examination of a
0efd7d
    particular section in the test case from gdb.base/corefile.exp.  On
0efd7d
    Fedora 27 or 28, the following behavior may be observed:
0efd7d
0efd7d
    (gdb) info proc mappings
0efd7d
    Mapped address spaces:
0efd7d
0efd7d
              Start Addr           End Addr       Size     Offset objfile
0efd7d
    ...
0efd7d
          0x7ffff7839000     0x7ffff7a38000   0x1ff000   0x1b5000 /usr/lib64/libc-2.27.so
0efd7d
    ...
0efd7d
    (gdb) x/4x 0x7ffff7839000
0efd7d
    0x7ffff7839000:	Cannot access memory at address 0x7ffff7839000
0efd7d
0efd7d
    FYI, this section appears to be unrelocated vtable data.  See
0efd7d
    https://sourceware.org/pipermail/gdb-patches/2020-May/168331.html for
0efd7d
    a detailed analysis.
0efd7d
0efd7d
    The important thing here is that GDB should be able to access this
0efd7d
    address since it should be backed by the shared library.  I.e. it
0efd7d
    should do this:
0efd7d
0efd7d
    (gdb) x/4x 0x7ffff7839000
0efd7d
    0x7ffff7839000:	0x0007ddf0	0x00000000	0x0007dba0	0x00000000
0efd7d
0efd7d
    Both of these cases are fixed with this commit.
0efd7d
0efd7d
    In a nutshell, this commit opens a "binary" target BFD for each of the
0efd7d
    files that are mentioned in an NT_FILE / .note.linuxcore.file note
0efd7d
    section.  It then uses these mappings instead of the file stratum
0efd7d
    mappings that GDB has used in the past.
0efd7d
0efd7d
    If this note section doesn't exist or is mangled for some reason, then
0efd7d
    GDB will use the file stratum as before.  Should this happen, then
0efd7d
    we can expect both of the above problems to again be present.
0efd7d
0efd7d
    See the code comments in the commit for other details.
0efd7d
0efd7d
    gdb/ChangeLog:
0efd7d
0efd7d
    	* corelow.c (solist.h, unordered_map): Include.
0efd7d
    	(class core_target): Add field m_core_file_mappings and
0efd7d
    	method build_file_mappings.
0efd7d
    	(core_target::core_target): Call build_file_mappings.
0efd7d
    	(core_target::~core_target): Free memory associated with
0efd7d
    	m_core_file_mappings.
0efd7d
    	(core_target::build_file_mappings): New method.
0efd7d
    	(core_target::xfer_partial): Use m_core_file_mappings
0efd7d
    	for memory transfers.
0efd7d
    	* linux-tdep.c (linux_read_core_file_mappings): New
0efd7d
    	function.
0efd7d
    	(linux_core_info_proc_mappings): Rewrite to use
0efd7d
    	linux_read_core_file_mappings.
0efd7d
    	(linux_init_abi): Register linux_read_core_file_mappings.
0efd7d
0efd7d
diff --git a/gdb/corelow.c b/gdb/corelow.c
0efd7d
--- a/gdb/corelow.c
0efd7d
+++ b/gdb/corelow.c
0efd7d
@@ -41,6 +41,7 @@
0efd7d
 #include "exec.h"
0efd7d
 #include "readline/tilde.h"
0efd7d
 #include "solib.h"
0efd7d
+#include "solist.h"
0efd7d
 #include "filenames.h"
0efd7d
 #include "progspace.h"
0efd7d
 #include "objfiles.h"
0efd7d
@@ -48,6 +49,8 @@
0efd7d
 #include "completer.h"
0efd7d
 #include "gdbsupport/filestuff.h"
0efd7d
 #include "build-id.h"
0efd7d
+#include "gdbsupport/pathstuff.h"
0efd7d
+#include <unordered_map>
0efd7d
 
0efd7d
 #ifndef O_LARGEFILE
0efd7d
 #define O_LARGEFILE 0
0efd7d
@@ -132,6 +135,13 @@ private: /* per-core data */
0efd7d
      core file currently open on core_bfd.  */
0efd7d
   core_fns *m_core_vec = NULL;
0efd7d
 
0efd7d
+  /* File-backed address space mappings: some core files include
0efd7d
+     information about memory mapped files.  */
0efd7d
+  target_section_table m_core_file_mappings {};
0efd7d
+
0efd7d
+  /* Build m_core_file_mappings.  Called from the constructor.  */
0efd7d
+  void build_file_mappings ();
0efd7d
+
0efd7d
   /* FIXME: kettenis/20031023: Eventually this field should
0efd7d
      disappear.  */
0efd7d
   struct gdbarch *m_core_gdbarch = NULL;
0efd7d
@@ -150,11 +160,120 @@ core_target::core_target ()
0efd7d
 			   &m_core_section_table.sections_end))
0efd7d
     error (_("\"%s\": Can't find sections: %s"),
0efd7d
 	   bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
0efd7d
+
0efd7d
+  build_file_mappings ();
0efd7d
 }
0efd7d
 
0efd7d
 core_target::~core_target ()
0efd7d
 {
0efd7d
   xfree (m_core_section_table.sections);
0efd7d
+  xfree (m_core_file_mappings.sections);
0efd7d
+}
0efd7d
+
0efd7d
+/* Construct the target_section_table for file-backed mappings if
0efd7d
+   they exist.
0efd7d
+
0efd7d
+   For each unique path in the note, we'll open a BFD with a bfd
0efd7d
+   target of "binary".  This is an unstructured bfd target upon which
0efd7d
+   we'll impose a structure from the mappings in the architecture-specific
0efd7d
+   mappings note.  A BFD section is allocated and initialized for each
0efd7d
+   file-backed mapping.
0efd7d
+
0efd7d
+   We take care to not share already open bfds with other parts of
0efd7d
+   GDB; in particular, we don't want to add new sections to existing
0efd7d
+   BFDs.  We do, however, ensure that the BFDs that we allocate here
0efd7d
+   will go away (be deallocated) when the core target is detached.  */
0efd7d
+
0efd7d
+void
0efd7d
+core_target::build_file_mappings ()
0efd7d
+{
0efd7d
+  std::unordered_map<std::string, struct bfd *> bfd_map;
0efd7d
+
0efd7d
+  /* See linux_read_core_file_mappings() in linux-tdep.c for an example
0efd7d
+     read_core_file_mappings method.  */
0efd7d
+  gdbarch_read_core_file_mappings (m_core_gdbarch, core_bfd,
0efd7d
+
0efd7d
+    /* After determining the number of mappings, read_core_file_mappings
0efd7d
+       will invoke this lambda which allocates target_section storage for
0efd7d
+       the mappings.  */
0efd7d
+    [&] (ULONGEST count)
0efd7d
+      {
0efd7d
+	m_core_file_mappings.sections = XNEWVEC (struct target_section, count);
0efd7d
+	m_core_file_mappings.sections_end = m_core_file_mappings.sections;
0efd7d
+      },
0efd7d
+
0efd7d
+    /* read_core_file_mappings will invoke this lambda for each mapping
0efd7d
+       that it finds.  */
0efd7d
+    [&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
0efd7d
+         const char *filename, const void *other)
0efd7d
+      {
0efd7d
+	/* Architecture-specific read_core_mapping methods are expected to
0efd7d
+	   weed out non-file-backed mappings.  */
0efd7d
+	gdb_assert (filename != nullptr);
0efd7d
+
0efd7d
+	struct bfd *bfd = bfd_map[filename];
0efd7d
+	if (bfd == nullptr)
0efd7d
+	  {
0efd7d
+	    /* Use exec_file_find() to do sysroot expansion.  It'll
0efd7d
+	       also strip the potential sysroot "target:" prefix.  If
0efd7d
+	       there is no sysroot, an equivalent (possibly more
0efd7d
+	       canonical) pathname will be provided.  */
0efd7d
+	    gdb::unique_xmalloc_ptr<char> expanded_fname
0efd7d
+	      = exec_file_find (filename, NULL);
0efd7d
+	    if (expanded_fname == nullptr)
0efd7d
+	      {
0efd7d
+		warning (_("Can't open file %s during file-backed mapping "
0efd7d
+			   "note processing"),
0efd7d
+			 expanded_fname.get ());
0efd7d
+		return;
0efd7d
+	      }
0efd7d
+
0efd7d
+	    bfd = bfd_map[filename] = bfd_openr (expanded_fname.get (),
0efd7d
+	                                         "binary");
0efd7d
+
0efd7d
+	    if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
0efd7d
+	      {
0efd7d
+		/* If we get here, there's a good chance that it's due to
0efd7d
+		   an internal error.  We issue a warning instead of an
0efd7d
+		   internal error because of the possibility that the
0efd7d
+		   file was removed in between checking for its
0efd7d
+		   existence during the expansion in exec_file_find()
0efd7d
+		   and the calls to bfd_openr() / bfd_check_format(). 
0efd7d
+		   Output both the path from the core file note along
0efd7d
+		   with its expansion to make debugging this problem
0efd7d
+		   easier.  */
0efd7d
+		warning (_("Can't open file %s which was expanded to %s "
0efd7d
+			   "during file-backed mapping note processing"),
0efd7d
+			 filename, expanded_fname.get ());
0efd7d
+		if (bfd != nullptr)
0efd7d
+		  bfd_close (bfd);
0efd7d
+		return;
0efd7d
+	      }
0efd7d
+	    /* Ensure that the bfd will be closed when core_bfd is closed. 
0efd7d
+	       This can be checked before/after a core file detach via
0efd7d
+	       "maint info bfds".  */
0efd7d
+	    gdb_bfd_record_inclusion (core_bfd, bfd);
0efd7d
+	  }
0efd7d
+
0efd7d
+	/* Make new BFD section.  All sections have the same name,
0efd7d
+	   which is permitted by bfd_make_section_anyway().  */
0efd7d
+	asection *sec = bfd_make_section_anyway (bfd, "load");
0efd7d
+	if (sec == nullptr)
0efd7d
+	  error (_("Can't make section"));
0efd7d
+	sec->filepos = file_ofs;
0efd7d
+	bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
0efd7d
+	bfd_set_section_size (sec, end - start);
0efd7d
+	bfd_set_section_vma (sec, start);
0efd7d
+	bfd_set_section_lma (sec, start);
0efd7d
+	bfd_set_section_alignment (sec, 2);
0efd7d
+
0efd7d
+	/* Set target_section fields.  */
0efd7d
+	struct target_section *ts = m_core_file_mappings.sections_end++;
0efd7d
+	ts->addr = start;
0efd7d
+	ts->endaddr = end;
0efd7d
+	ts->owner = nullptr;
0efd7d
+	ts->the_bfd_section = sec;
0efd7d
+      });
0efd7d
 }
0efd7d
 
0efd7d
 /* List of all available core_fns.  On gdb startup, each core file
0efd7d
@@ -773,10 +892,21 @@ core_target::xfer_partial (enum target_object object, const char *annex,
0efd7d
 	if (xfer_status == TARGET_XFER_OK)
0efd7d
 	  return TARGET_XFER_OK;
0efd7d
 
0efd7d
-	/* Now check the stratum beneath us; this should be file_stratum.  */
0efd7d
-	xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
0efd7d
-						      writebuf, offset, len,
0efd7d
-						      xfered_len);
0efd7d
+	/* Check file backed mappings.  If they're available, use
0efd7d
+	   core file provided mappings (e.g. from .note.linuxcore.file
0efd7d
+	   or the like) as this should provide a more accurate
0efd7d
+	   result.  If not, check the stratum beneath us, which should
0efd7d
+	   be the file stratum.  */
0efd7d
+	if (m_core_file_mappings.sections != nullptr)
0efd7d
+	  xfer_status = section_table_xfer_memory_partial
0efd7d
+			  (readbuf, writebuf,
0efd7d
+			   offset, len, xfered_len,
0efd7d
+			   m_core_file_mappings.sections,
0efd7d
+			   m_core_file_mappings.sections_end);
0efd7d
+	else
0efd7d
+	  xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
0efd7d
+							writebuf, offset, len,
0efd7d
+							xfered_len);
0efd7d
 	if (xfer_status == TARGET_XFER_OK)
0efd7d
 	  return TARGET_XFER_OK;
0efd7d
 
0efd7d
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
0efd7d
--- a/gdb/linux-tdep.c
0efd7d
+++ b/gdb/linux-tdep.c
0efd7d
@@ -1024,106 +1024,174 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
0efd7d
     }
0efd7d
 }
0efd7d
 
0efd7d
-/* Implement "info proc mappings" for a corefile.  */
0efd7d
+/* Implementation of `gdbarch_read_core_file_mappings', as defined in
0efd7d
+   gdbarch.h.
0efd7d
+   
0efd7d
+   This function reads the NT_FILE note (which BFD turns into the
0efd7d
+   section ".note.linuxcore.file").  The format of this note / section
0efd7d
+   is described as follows in the Linux kernel sources in
0efd7d
+   fs/binfmt_elf.c:
0efd7d
+   
0efd7d
+      long count     -- how many files are mapped
0efd7d
+      long page_size -- units for file_ofs
0efd7d
+      array of [COUNT] elements of
0efd7d
+	long start
0efd7d
+	long end
0efd7d
+	long file_ofs
0efd7d
+      followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
0efd7d
+      
0efd7d
+   CBFD is the BFD of the core file.
0efd7d
+
0efd7d
+   PRE_LOOP_CB is the callback function to invoke prior to starting
0efd7d
+   the loop which processes individual entries.  This callback will
0efd7d
+   only be executed after the note has been examined in enough
0efd7d
+   detail to verify that it's not malformed in some way.
0efd7d
+   
0efd7d
+   LOOP_CB is the callback function that will be executed once
0efd7d
+   for each mapping.  */
0efd7d
 
0efd7d
 static void
0efd7d
-linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
0efd7d
+linux_read_core_file_mappings (struct gdbarch *gdbarch,
0efd7d
+			       struct bfd *cbfd,
0efd7d
+			       gdb::function_view<void (ULONGEST count)>
0efd7d
+			         pre_loop_cb,
0efd7d
+			       gdb::function_view
0efd7d
+			                                ULONGEST start,
0efd7d
+							ULONGEST end,
0efd7d
+							ULONGEST file_ofs,
0efd7d
+							const char *filename,
0efd7d
+							const void *other)>
0efd7d
+				 loop_cb)
0efd7d
 {
0efd7d
-  asection *section;
0efd7d
-  ULONGEST count, page_size;
0efd7d
-  unsigned char *descdata, *filenames, *descend;
0efd7d
-  size_t note_size;
0efd7d
-  unsigned int addr_size_bits, addr_size;
0efd7d
-  struct gdbarch *core_gdbarch = gdbarch_from_bfd (core_bfd);
0efd7d
-  /* We assume this for reading 64-bit core files.  */
0efd7d
+  /* Ensure that ULONGEST is big enough for reading 64-bit core files.  */
0efd7d
   gdb_static_assert (sizeof (ULONGEST) >= 8);
0efd7d
 
0efd7d
-  section = bfd_get_section_by_name (core_bfd, ".note.linuxcore.file");
0efd7d
-  if (section == NULL)
0efd7d
-    {
0efd7d
-      warning (_("unable to find mappings in core file"));
0efd7d
-      return;
0efd7d
-    }
0efd7d
+  /* It's not required that the NT_FILE note exists, so return silently
0efd7d
+     if it's not found.  Beyond this point though, we'll complain
0efd7d
+     if problems are found.  */
0efd7d
+  asection *section = bfd_get_section_by_name (cbfd, ".note.linuxcore.file");
0efd7d
+  if (section == nullptr)
0efd7d
+    return;
0efd7d
 
0efd7d
-  addr_size_bits = gdbarch_addr_bit (core_gdbarch);
0efd7d
-  addr_size = addr_size_bits / 8;
0efd7d
-  note_size = bfd_section_size (section);
0efd7d
+  unsigned int addr_size_bits = gdbarch_addr_bit (gdbarch);
0efd7d
+  unsigned int addr_size = addr_size_bits / 8;
0efd7d
+  size_t note_size = bfd_section_size (section);
0efd7d
 
0efd7d
   if (note_size < 2 * addr_size)
0efd7d
-    error (_("malformed core note - too short for header"));
0efd7d
+    {
0efd7d
+      warning (_("malformed core note - too short for header"));
0efd7d
+      return;
0efd7d
+    }
0efd7d
 
0efd7d
-  gdb::def_vector<unsigned char> contents (note_size);
0efd7d
+  gdb::def_vector<gdb_byte> contents (note_size);
0efd7d
   if (!bfd_get_section_contents (core_bfd, section, contents.data (),
0efd7d
 				 0, note_size))
0efd7d
-    error (_("could not get core note contents"));
0efd7d
+    {
0efd7d
+      warning (_("could not get core note contents"));
0efd7d
+      return;
0efd7d
+    }
0efd7d
 
0efd7d
-  descdata = contents.data ();
0efd7d
-  descend = descdata + note_size;
0efd7d
+  gdb_byte *descdata = contents.data ();
0efd7d
+  char *descend = (char *) descdata + note_size;
0efd7d
 
0efd7d
   if (descdata[note_size - 1] != '\0')
0efd7d
-    error (_("malformed note - does not end with \\0"));
0efd7d
+    {
0efd7d
+      warning (_("malformed note - does not end with \\0"));
0efd7d
+      return;
0efd7d
+    }
0efd7d
 
0efd7d
-  count = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
+  ULONGEST count = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
   descdata += addr_size;
0efd7d
 
0efd7d
-  page_size = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
+  ULONGEST page_size = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
   descdata += addr_size;
0efd7d
 
0efd7d
   if (note_size < 2 * addr_size + count * 3 * addr_size)
0efd7d
-    error (_("malformed note - too short for supplied file count"));
0efd7d
-
0efd7d
-  printf_filtered (_("Mapped address spaces:\n\n"));
0efd7d
-  if (gdbarch_addr_bit (gdbarch) == 32)
0efd7d
-    {
0efd7d
-      printf_filtered ("\t%10s %10s %10s %10s %s\n",
0efd7d
-		       "Start Addr",
0efd7d
-		       "  End Addr",
0efd7d
-		       "      Size", "    Offset", "objfile");
0efd7d
-    }
0efd7d
-  else
0efd7d
     {
0efd7d
-      printf_filtered ("  %18s %18s %10s %10s %s\n",
0efd7d
-		       "Start Addr",
0efd7d
-		       "  End Addr",
0efd7d
-		       "      Size", "    Offset", "objfile");
0efd7d
+      warning (_("malformed note - too short for supplied file count"));
0efd7d
+      return;
0efd7d
     }
0efd7d
 
0efd7d
-  filenames = descdata + count * 3 * addr_size;
0efd7d
-  while (--count > 0)
0efd7d
+  char *filenames = (char *) descdata + count * 3 * addr_size;
0efd7d
+
0efd7d
+  /* Make sure that the correct number of filenames exist.  Complain
0efd7d
+     if there aren't enough or are too many.  */
0efd7d
+  char *f = filenames;
0efd7d
+  for (int i = 0; i < count; i++)
0efd7d
     {
0efd7d
-      ULONGEST start, end, file_ofs;
0efd7d
+      if (f >= descend)
0efd7d
+        {
0efd7d
+	  warning (_("malformed note - filename area is too small"));
0efd7d
+	  return;
0efd7d
+	}
0efd7d
+      f += strnlen (f, descend - f) + 1;
0efd7d
+    }
0efd7d
+  /* Complain, but don't return early if the filename area is too big.  */
0efd7d
+  if (f != descend)
0efd7d
+    warning (_("malformed note - filename area is too big"));
0efd7d
 
0efd7d
-      if (filenames == descend)
0efd7d
-	error (_("malformed note - filenames end too early"));
0efd7d
+  pre_loop_cb (count);
0efd7d
 
0efd7d
-      start = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
+  for (int i = 0; i < count; i++)
0efd7d
+    {
0efd7d
+      ULONGEST start = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
       descdata += addr_size;
0efd7d
-      end = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
+      ULONGEST end = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
       descdata += addr_size;
0efd7d
-      file_ofs = bfd_get (addr_size_bits, core_bfd, descdata);
0efd7d
+      ULONGEST file_ofs
0efd7d
+        = bfd_get (addr_size_bits, core_bfd, descdata) * page_size;
0efd7d
       descdata += addr_size;
0efd7d
+      char * filename = filenames;
0efd7d
+      filenames += strlen ((char *) filenames) + 1;
0efd7d
 
0efd7d
-      file_ofs *= page_size;
0efd7d
-
0efd7d
-      if (gdbarch_addr_bit (gdbarch) == 32)
0efd7d
-	printf_filtered ("\t%10s %10s %10s %10s %s\n",
0efd7d
-			 paddress (gdbarch, start),
0efd7d
-			 paddress (gdbarch, end),
0efd7d
-			 hex_string (end - start),
0efd7d
-			 hex_string (file_ofs),
0efd7d
-			 filenames);
0efd7d
-      else
0efd7d
-	printf_filtered ("  %18s %18s %10s %10s %s\n",
0efd7d
-			 paddress (gdbarch, start),
0efd7d
-			 paddress (gdbarch, end),
0efd7d
-			 hex_string (end - start),
0efd7d
-			 hex_string (file_ofs),
0efd7d
-			 filenames);
0efd7d
-
0efd7d
-      filenames += 1 + strlen ((char *) filenames);
0efd7d
+      loop_cb (i, start, end, file_ofs, filename, nullptr);
0efd7d
     }
0efd7d
 }
0efd7d
 
0efd7d
+/* Implement "info proc mappings" for a corefile.  */
0efd7d
+
0efd7d
+static void
0efd7d
+linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
0efd7d
+{
0efd7d
+  linux_read_core_file_mappings (gdbarch, core_bfd,
0efd7d
+    [=] (ULONGEST count)
0efd7d
+      {
0efd7d
+	printf_filtered (_("Mapped address spaces:\n\n"));
0efd7d
+	if (gdbarch_addr_bit (gdbarch) == 32)
0efd7d
+	  {
0efd7d
+	    printf_filtered ("\t%10s %10s %10s %10s %s\n",
0efd7d
+			     "Start Addr",
0efd7d
+			     "  End Addr",
0efd7d
+			     "      Size", "    Offset", "objfile");
0efd7d
+	  }
0efd7d
+	else
0efd7d
+	  {
0efd7d
+	    printf_filtered ("  %18s %18s %10s %10s %s\n",
0efd7d
+			     "Start Addr",
0efd7d
+			     "  End Addr",
0efd7d
+			     "      Size", "    Offset", "objfile");
0efd7d
+	  }
0efd7d
+      },
0efd7d
+    [=] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
0efd7d
+         const char *filename, const void *other)
0efd7d
+      {
0efd7d
+	if (gdbarch_addr_bit (gdbarch) == 32)
0efd7d
+	  printf_filtered ("\t%10s %10s %10s %10s %s\n",
0efd7d
+			   paddress (gdbarch, start),
0efd7d
+			   paddress (gdbarch, end),
0efd7d
+			   hex_string (end - start),
0efd7d
+			   hex_string (file_ofs),
0efd7d
+			   filename);
0efd7d
+	else
0efd7d
+	  printf_filtered ("  %18s %18s %10s %10s %s\n",
0efd7d
+			   paddress (gdbarch, start),
0efd7d
+			   paddress (gdbarch, end),
0efd7d
+			   hex_string (end - start),
0efd7d
+			   hex_string (file_ofs),
0efd7d
+			   filename);
0efd7d
+      });
0efd7d
+}
0efd7d
+
0efd7d
 /* Implement "info proc" for a corefile.  */
0efd7d
 
0efd7d
 static void
0efd7d
@@ -2471,6 +2539,7 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
0efd7d
   set_gdbarch_info_proc (gdbarch, linux_info_proc);
0efd7d
   set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
0efd7d
   set_gdbarch_core_xfer_siginfo (gdbarch, linux_core_xfer_siginfo);
0efd7d
+  set_gdbarch_read_core_file_mappings (gdbarch, linux_read_core_file_mappings);
0efd7d
   set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
0efd7d
   set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes);
0efd7d
   set_gdbarch_has_shared_address_space (gdbarch,