[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