[PATCH 3/4] Provide access to non SEC_HAS_CONTENTS core file sections

Pedro Alves palves@redhat.com
Wed May 20 16:04:07 GMT 2020


On 5/12/20 9:40 AM, Kevin Buettner via Gdb-patches wrote:
>> Are these cases truly indistinguishable from the cases where data
>> shouldn't be read from the executable?  I don't mean from the current
>> bfd data structures, but from the data in the core file and the executable.
>> It's kind of fascinating that that's the case, and if so, it would sound
>> like a nasty bug in either the core format or in the Linux kernel for
>> producing such cores with which we have to apply heuristics.
> The core file shows a "FileSiz" of 0 for cases when we shouldn't
> look first at the core file.  

What I'm saying is that this "look first in the core" algorithm seems
like an heuristic.  As in, maybe it only fails in some corner cases,
but still, it's an heuristic that can fail sometimes.  And that to me
indicates a flaw in the design somewhere.  Maybe it's all we can do with
the available data, but I'd still call it a flaw.

Here's an example of the heuristic failing.  Say, a program uses mmap(MAP_FIXED) to
inject a new mapping at an address range that overlaps some file-backed mappings,
and then never touches that new mapping's addresses.  In this scenario we end up
with a core with a FileSiz==0 section for the never-written-to mapping, and thus
when reading from that mapping's addresses, GDB reads the data from the executable,
while instead we should have read the data as 0, because that's what you
had at runtime.  

This is actually easy to reproduce.  Like so:

$ cat mmap.c
#include <sys/mman.h>
#include <stdlib.h>

int
main ()
{
  abort ();
  return 0;
}

$ gcc mmap.c -o mmap -g3 -O0

$ gdb -q ~/tmp/mmap 
Reading symbols from /home/pedro/tmp/mmap...
(gdb) start
Temporary breakpoint 1 at 0x4004db: file mmap.c, line 7.
Starting program: /home/pedro/tmp/mmap 

Temporary breakpoint 1, main () at mmap.c:7
7         abort ();
(gdb) info proc mappings 
process 4523
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /home/pedro/tmp/mmap
            0x600000           0x601000     0x1000        0x0 /home/pedro/tmp/mmap
            0x601000           0x602000     0x1000     0x1000 /home/pedro/tmp/mmap
      0x7ffff7a22000     0x7ffff7bcf000   0x1ad000        0x0 /usr/lib64/libc-2.26.so
      0x7ffff7bcf000     0x7ffff7dce000   0x1ff000   0x1ad000 /usr/lib64/libc-2.26.so
      0x7ffff7dce000     0x7ffff7dd2000     0x4000   0x1ac000 /usr/lib64/libc-2.26.so
      0x7ffff7dd2000     0x7ffff7dd4000     0x2000   0x1b0000 /usr/lib64/libc-2.26.so
      0x7ffff7dd4000     0x7ffff7dd8000     0x4000        0x0 
      0x7ffff7dd8000     0x7ffff7dfd000    0x25000        0x0 /usr/lib64/ld-2.26.so
      0x7ffff7fb8000     0x7ffff7fba000     0x2000        0x0 
      0x7ffff7ff7000     0x7ffff7ffa000     0x3000        0x0 [vvar]
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x24000 /usr/lib64/ld-2.26.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x25000 /usr/lib64/ld-2.26.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffdd000     0x7ffffffff000    0x22000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

(gdb) p mmap (0x400000, getpagesize (), 0, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0)
$1 = (void *) 0x400000
(gdb) set code-cache off 
(gdb) disassemble 
Dump of assembler code for function main:
   0x00000000004004d7 <+0>:     add    %al,(%rax)
   0x00000000004004d9 <+2>:     add    %al,(%rax)
=> 0x00000000004004db <+4>:     add    %al,(%rax)
   0x00000000004004dd <+6>:     add    %al,(%rax)
   0x00000000004004df <+8>:     add    %al,(%rax)
End of assembler dump.
(gdb) 
(gdb) detach
Detaching from program: /home/pedro/tmp/mmap, process 4523
[Inferior 1 (process 4523) detached]
(gdb) q

The process crashed at this point and the kernel generated
a core dump.  Loading the resulting core into gdb (this is a GDB with your
v2 patches), we see:

$ gdb -q ~/tmp/mmap -c ./core.4523
Reading symbols from /home/pedro/tmp/mmap...
[New LWP 4523]
Core was generated by `/home/pedro/tmp/mmap'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  main () at mmap.c:7
7         abort ();
(gdb) set code-cache off 
(gdb) disassemble 
Dump of assembler code for function main:
   0x00000000004004d7 <+0>:     push   %rbp
   0x00000000004004d8 <+1>:     mov    %rsp,%rbp
=> 0x00000000004004db <+4>:     callq  0x4003f0 <abort@plt>
End of assembler dump.
(gdb) 

Disassembling is still showing the .text read from the
executable, instead of zeroes (i.e., "add %al,(%rax)"), which is
incorrect.  If you debug that gdb, you can see that gdb does not
find a section with contents for that address, and then tries
reading from the executable, which finds the data.  The next
step of reading from sections with no contents would succeed,
since there's a matching section in the core, but we never
get there.

Thanks,
Pedro Alves



More information about the Gdb-patches mailing list