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