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

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