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