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

7d6eda
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
7d6eda
From: Keith Seitz <keiths@redhat.com>
7d6eda
Date: Mon, 27 Jul 2020 17:11:49 -0400
7d6eda
Subject: gdb-rhbz1842691-corefile-mem-access-4of15.patch
7d6eda
7d6eda
;; Provide access to non SEC_HAS_CONTENTS core file sections
7d6eda
;; Kevin Buettner, RH BZ 1842961
7d6eda
7d6eda
   Author: Kevin Buettner <kevinb@redhat.com>
7d6eda
   Date:   Wed Mar 4 17:42:42 2020 -0700
7d6eda
7d6eda
    Provide access to non SEC_HAS_CONTENTS core file sections
7d6eda
7d6eda
    Consider the following program:
7d6eda
7d6eda
    - - - mkmmapcore.c - - -
7d6eda
7d6eda
    static char *buf;
7d6eda
7d6eda
    int
7d6eda
    main (int argc, char **argv)
7d6eda
    {
7d6eda
      buf = mmap (NULL, 8192, PROT_READ | PROT_WRITE,
7d6eda
                  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
7d6eda
      abort ();
7d6eda
    }
7d6eda
    - - - end mkmmapcore.c - - -
7d6eda
7d6eda
    Compile it like this:
7d6eda
7d6eda
    gcc -g -o mkmmapcore mkmmapcore.c
7d6eda
7d6eda
    Now let's run it from GDB.  I've already placed a breakpoint on the
7d6eda
    line with the abort() call and have run to that breakpoint.
7d6eda
7d6eda
    Breakpoint 1, main (argc=1, argv=0x7fffffffd678) at mkmmapcore.c:11
7d6eda
    11	  abort ();
7d6eda
    (gdb) x/x buf
7d6eda
    0x7ffff7fcb000:	0x00000000
7d6eda
7d6eda
    Note that we can examine the memory allocated via the call to mmap().
7d6eda
7d6eda
    Now let's try debugging a core file created by running this program.
7d6eda
    Depending on your system, in order to make a core file, you may have to
7d6eda
    run the following as root (or using sudo):
7d6eda
7d6eda
        echo core > /proc/sys/kernel/core_pattern
7d6eda
7d6eda
    It may also be necessary to do:
7d6eda
7d6eda
        ulimit -c unlimited
7d6eda
7d6eda
    I'm using Fedora 31. YMMV if you're using one of the BSDs or some other
7d6eda
    (non-Linux) system.
7d6eda
7d6eda
    This is what things look like when we debug the core file:
7d6eda
7d6eda
        [kev@f31-1 tmp]$ gdb -q ./mkmmapcore core.304767
7d6eda
        Reading symbols from ./mkmmapcore...
7d6eda
        [New LWP 304767]
7d6eda
        Core was generated by `/tmp/mkmmapcore'.
7d6eda
        Program terminated with signal SIGABRT, Aborted.
7d6eda
        #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
7d6eda
        50	  return ret;
7d6eda
        (gdb) x/x buf
7d6eda
        0x7ffff7fcb000:	Cannot access memory at address 0x7ffff7fcb000
7d6eda
7d6eda
    Note that we can no longer access the memory region allocated by mmap().
7d6eda
7d6eda
    Back in 2007, a hack for GDB was added to _bfd_elf_make_section_from_phdr()
7d6eda
    in bfd/elf.c:
7d6eda
7d6eda
    	  /* Hack for gdb.  Segments that have not been modified do
7d6eda
    	     not have their contents written to a core file, on the
7d6eda
    	     assumption that a debugger can find the contents in the
7d6eda
    	     executable.  We flag this case by setting the fake
7d6eda
    	     section size to zero.  Note that "real" bss sections will
7d6eda
    	     always have their contents dumped to the core file.  */
7d6eda
    	  if (bfd_get_format (abfd) == bfd_core)
7d6eda
    	    newsect->size = 0;
7d6eda
7d6eda
    You can find the entire patch plus links to other discussion starting
7d6eda
    here:
7d6eda
7d6eda
        https://sourceware.org/ml/binutils/2007-08/msg00047.html
7d6eda
7d6eda
    This hack sets the size of certain BFD sections to 0, which
7d6eda
    effectively causes GDB to ignore them.  I think it's likely that the
7d6eda
    bug described above existed even before this hack was added, but I
7d6eda
    have no easy way to test this now.
7d6eda
7d6eda
    The output from objdump -h shows the result of this hack:
7d6eda
7d6eda
     25 load13        00000000  00007ffff7fcb000  0000000000000000  00013000  2**12
7d6eda
                      ALLOC
7d6eda
7d6eda
    (The first field, after load13, shows the size of 0.)
7d6eda
7d6eda
    Once the hack is removed, the output from objdump -h shows the correct
7d6eda
    size:
7d6eda
7d6eda
     25 load13        00002000  00007ffff7fcb000  0000000000000000  00013000  2**12
7d6eda
                      ALLOC
7d6eda
7d6eda
    (This is a digression, but I think it's good that objdump will now show
7d6eda
    the correct size.)
7d6eda
7d6eda
    If we remove the hack from bfd/elf.c, but do nothing to GDB, we'll
7d6eda
    see the following regression:
7d6eda
7d6eda
    FAIL: gdb.base/corefile.exp: print coremaker_ro
7d6eda
7d6eda
    The reason for this is that all sections which have the BFD flag
7d6eda
    SEC_ALLOC set, but for which SEC_HAS_CONTENTS is not set no longer
7d6eda
    have zero size.  Some of these sections have data that can (and should)
7d6eda
    be read from the executable.  (Sections for which SEC_HAS_CONTENTS
7d6eda
    is set should be read from the core file; sections which do not have
7d6eda
    this flag set need to either be read from the executable or, failing
7d6eda
    that, from the core file using whatever BFD decides is the best value
7d6eda
    to present to the user - it uses zeros.)
7d6eda
7d6eda
    At present, due to the way that the target strata are traversed when
7d6eda
    attempting to access memory, the non-SEC_HAS_CONTENTS sections will be
7d6eda
    read as zeroes from the process_stratum (which in this case is the
7d6eda
    core file stratum) without first checking the file stratum, which is
7d6eda
    where the data might actually be found.
7d6eda
7d6eda
    What we should be doing is this:
7d6eda
7d6eda
    - Attempt to access core file data for SEC_HAS_CONTENTS sections.
7d6eda
    - Attempt to access executable file data if the above fails.
7d6eda
    - Attempt to access core file data for non SEC_HAS_CONTENTS sections, if
7d6eda
      both of the above fail.
7d6eda
7d6eda
    This corresponds to the analysis of Daniel Jacobowitz back in 2007
7d6eda
    when the hack was added to BFD:
7d6eda
7d6eda
        https://sourceware.org/legacy-ml/binutils/2007-08/msg00045.html
7d6eda
7d6eda
    The difference, observed by Pedro in his review of my v1 patches, is
7d6eda
    that I'm using "the section flags as proxy for the p_filesz/p_memsz
7d6eda
    checks."
7d6eda
7d6eda
    gdb/ChangeLog:
7d6eda
7d6eda
    	PR corefiles/25631
7d6eda
    	* corelow.c (core_target:xfer_partial):  Revise
7d6eda
    	TARGET_OBJECT_MEMORY case to consider non-SEC_HAS_CONTENTS
7d6eda
    	case after first checking the stratum beneath the core
7d6eda
    	target.
7d6eda
    	(has_all_memory): Return true.
7d6eda
    	* target.c (raw_memory_xfer_partial): Revise comment
7d6eda
    	regarding use of has_all_memory.
7d6eda
7d6eda
diff --git a/gdb/corelow.c b/gdb/corelow.c
7d6eda
--- a/gdb/corelow.c
7d6eda
+++ b/gdb/corelow.c
7d6eda
@@ -93,7 +93,7 @@ public:
7d6eda
 
7d6eda
   const char *thread_name (struct thread_info *) override;
7d6eda
 
7d6eda
-  bool has_all_memory () override { return false; }
7d6eda
+  bool has_all_memory () override { return true; }
7d6eda
   bool has_memory () override;
7d6eda
   bool has_stack () override;
7d6eda
   bool has_registers () override;
7d6eda
@@ -754,12 +754,47 @@ core_target::xfer_partial (enum target_object object, const char *annex,
7d6eda
   switch (object)
7d6eda
     {
7d6eda
     case TARGET_OBJECT_MEMORY:
7d6eda
-      return (section_table_xfer_memory_partial
7d6eda
-	      (readbuf, writebuf,
7d6eda
-	       offset, len, xfered_len,
7d6eda
-	       m_core_section_table.sections,
7d6eda
-	       m_core_section_table.sections_end));
7d6eda
+      {
7d6eda
+	enum target_xfer_status xfer_status;
7d6eda
+
7d6eda
+	/* Try accessing memory contents from core file data,
7d6eda
+	   restricting consideration to those sections for which
7d6eda
+	   the BFD section flag SEC_HAS_CONTENTS is set.  */
7d6eda
+	auto has_contents_cb = [] (const struct target_section *s)
7d6eda
+	  {
7d6eda
+	    return ((s->the_bfd_section->flags & SEC_HAS_CONTENTS) != 0);
7d6eda
+	  };
7d6eda
+	xfer_status = section_table_xfer_memory_partial
7d6eda
+			(readbuf, writebuf,
7d6eda
+			 offset, len, xfered_len,
7d6eda
+			 m_core_section_table.sections,
7d6eda
+			 m_core_section_table.sections_end,
7d6eda
+			 has_contents_cb);
7d6eda
+	if (xfer_status == TARGET_XFER_OK)
7d6eda
+	  return TARGET_XFER_OK;
7d6eda
+
7d6eda
+	/* Now check the stratum beneath us; this should be file_stratum.  */
7d6eda
+	xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
7d6eda
+						      writebuf, offset, len,
7d6eda
+						      xfered_len);
7d6eda
+	if (xfer_status == TARGET_XFER_OK)
7d6eda
+	  return TARGET_XFER_OK;
7d6eda
 
7d6eda
+	/* Finally, attempt to access data in core file sections with
7d6eda
+	   no contents.  These will typically read as all zero.  */
7d6eda
+	auto no_contents_cb = [&] (const struct target_section *s)
7d6eda
+	  {
7d6eda
+	    return !has_contents_cb (s);
7d6eda
+	  };
7d6eda
+	xfer_status = section_table_xfer_memory_partial
7d6eda
+			(readbuf, writebuf,
7d6eda
+			 offset, len, xfered_len,
7d6eda
+			 m_core_section_table.sections,
7d6eda
+			 m_core_section_table.sections_end,
7d6eda
+			 no_contents_cb);
7d6eda
+
7d6eda
+	return xfer_status;
7d6eda
+      }
7d6eda
     case TARGET_OBJECT_AUXV:
7d6eda
       if (readbuf)
7d6eda
 	{
7d6eda
diff --git a/gdb/target.c b/gdb/target.c
7d6eda
--- a/gdb/target.c
7d6eda
+++ b/gdb/target.c
7d6eda
@@ -967,8 +967,11 @@ raw_memory_xfer_partial (struct target_ops *ops, gdb_byte *readbuf,
7d6eda
       if (res == TARGET_XFER_UNAVAILABLE)
7d6eda
 	break;
7d6eda
 
7d6eda
-      /* We want to continue past core files to executables, but not
7d6eda
-	 past a running target's memory.  */
7d6eda
+      /* Don't continue past targets which have all the memory.
7d6eda
+         At one time, this code was necessary to read data from
7d6eda
+	 executables / shared libraries when data for the requested
7d6eda
+	 addresses weren't available in the core file.  But now the
7d6eda
+	 core target handles this case itself.  */
7d6eda
       if (ops->has_all_memory ())
7d6eda
 	break;
7d6eda