diff --git a/gdb/corelow.c b/gdb/corelow.c
index 5cd058d599..7a71174062 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -122,9 +122,21 @@ private: /* per-core data */
      sections --- those should come only from pure executable or
      shared library bfds.  The core bfd sections are an implementation
      detail of the core target, just like ptrace is for unix child
-     targets.  */
+     targets.
+     
+     Immediately after being read, sections with no contents will be
+     removed from this table and placed in the "no contents" table;
+     see below.  */
   target_section_table m_core_section_table {};
 
+  /* The core's "no contents" section table.  These sections represent
+     regions of memory which were not modified while the process was
+     live.  Data in these sections are either found in the exec file
+     or represent regions of memory which were allocated, but never
+     written to.  */
+     
+  target_section_table m_core_no_contents_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;
@@ -147,11 +159,24 @@ core_target::core_target ()
 			   &m_core_section_table.sections_end))
     error (_("\"%s\": Can't find sections: %s"),
 	   bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
+
+  /* Place sections which have the BFD flag SEC_ALLOC set, but
+     for which SEC_HAS_CONTENTS is not set into a separate section
+     table.  */
+  split_section_table (&m_core_section_table,
+                       &m_core_no_contents_section_table,
+		       [](struct target_section *s) -> bool
+		         {
+			   flagword flags = s->the_bfd_section->flags;
+			   return ((flags & SEC_ALLOC)
+			           && !(flags & SEC_HAS_CONTENTS));
+			 });
 }
 
 core_target::~core_target ()
 {
   xfree (m_core_section_table.sections);
+  xfree (m_core_no_contents_section_table.sections);
 }
 
 /* List of all available core_fns.  On gdb startup, each core file
@@ -731,6 +756,7 @@ void
 core_target::files_info ()
 {
   print_section_info (&m_core_section_table, core_bfd);
+  print_section_info (&m_core_no_contents_section_table, core_bfd);
 }
 
 enum target_xfer_status
@@ -741,12 +767,52 @@ 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 in
+	 m_core_section_table.	Due to the partitioning (splitting)
+	 which occurs after the core's section table has been read in,
+	 this table will consist only of sections for which the BFD
+	 section flag SEC_HAS_CONTENTS is set.	*/
+      xfer_status = section_table_xfer_memory_partial
+		      (readbuf, writebuf,
+		       offset, len, xfered_len,
+		       m_core_section_table.sections,
+		       m_core_section_table.sections_end,
+		       NULL);
+      if (xfer_status == TARGET_XFER_OK)
+	return TARGET_XFER_OK;
+
+      /* If the above failed, we need to see if memory contents are
+	 available from exec file prior to examining those sections
+	 in the core file for which we know only the size of the
+	 section.  */
+      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, but we
+	 leave it to the underlying layers to decide what to do.  */
+      xfer_status = section_table_xfer_memory_partial
+		      (readbuf, writebuf,
+		       offset, len, xfered_len,
+		       m_core_no_contents_section_table.sections,
+		       m_core_no_contents_section_table.sections_end,
+		       NULL);
+
+      /* If none of the above attempts worked to access the memory in
+	 question, return TARGET_XFER_UNAVAILABLE.  Due to the fact
+	 that the exec file stratum has already been considered, we
+	 want to prevent it from being examined yet again (at a higher
+	 level).  */
+      if (xfer_status == TARGET_XFER_OK)
+	return TARGET_XFER_OK;
+      else
+	return TARGET_XFER_UNAVAILABLE;
 
     case TARGET_OBJECT_AUXV:
       if (readbuf)
