Fix coredump debugging (#1079)

* Fix coredump debugging

This commit fixes our headaches with core files debugging.

The TL;DR is that we will now try to parse `info proc mappings` and
`maintenance info sections` to give users best possible UX/vmmaps
information.

Related:
* https://sourceware.org/bugzilla/show_bug.cgi?id=29508
* https://github.com/pwndbg/pwndbg/issues/985
* https://github.com/pwndbg/pwndbg/issues/954

* cleanup

* cleanup

* Fix core dbg when EHDR map is not mapped
pull/1080/head
Disconnect3d 3 years ago committed by GitHub
parent a00ba56872
commit c10c8f840b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -240,6 +240,11 @@ def get_ehdr(pointer):
vmmap = pwndbg.vmmap.find(pointer)
base = None
# If there is no vmmap for the requested address, we can't do much
# (e.g. it could have been unmapped for whatever reason)
if vmmap is None:
return None, None
# We first check if the beginning of the page contains the ELF magic
if pwndbg.memory.read(vmmap.start, 4) == b'\x7fELF':
base = vmmap.start

@ -34,6 +34,13 @@ custom_pages = []
kernel_vmmap_via_pt = pwndbg.config.Parameter('kernel-vmmap-via-page-tables', True, 'When on, it reads vmmap for kernels via page tables, otherwise uses QEMU kernel\'s `monitor info mem` command')
@pwndbg.memoize.reset_on_objfile
@pwndbg.memoize.reset_on_start
def is_corefile():
return gdb.execute('info target', to_string=True).startswith('Local core dump file')
@pwndbg.memoize.reset_on_start
@pwndbg.memoize.reset_on_stop
def get():
@ -49,6 +56,12 @@ def get():
else:
pages.extend(kernel_vmmap_via_monitor_info_mem())
if not pages:
pages.extend(coredump_maps())
# TODO/FIXME: Do we still need it after coredump_maps()?
# Add tests for other cases and see if this is needed e.g. for QEMU user
# if not, remove the code below & cleanup other parts of Pwndbg codebase
if not pages:
# If debuggee is launched from a symlink the debuggee memory maps will be
# labeled with symlink path while in normal scenario the /proc/pid/maps
@ -154,6 +167,86 @@ def clear_custom_page():
pwndbg.memoize.reset()
@pwndbg.memoize.reset_on_objfile
@pwndbg.memoize.reset_on_start
def coredump_maps():
"""
Parses `info proc mappings` and `maintenance info sections`
and tries to make sense out of the result :)
"""
pages = []
for line in gdb.execute('info proc mappings', to_string=True).splitlines():
# We look for lines like:
# ['0x555555555000', '0x555555556000', '0x1000', '0x1000', '/home/user/a.out']
try:
start, _end, size, offset, objfile = line.split()
start, size, offset = int(start, 16), int(size, 16), int(offset, 16)
except (IndexError, ValueError):
continue
# Note: we set flags=0 because we do not have this information here
pages.append(pwndbg.memory.Page(start, size, 0, offset, objfile))
for line in gdb.execute('maintenance info sections', to_string=True).splitlines():
# We look for lines like:
# ['[9]', '0x00000000->0x00000150', 'at', '0x00098c40:', '.auxv', 'HAS_CONTENTS']
# ['[15]', '0x555555555000->0x555555556000', 'at', '0x00001430:', 'load2', 'ALLOC', 'LOAD', 'READONLY', 'CODE', 'HAS_CONTENTS']
try:
_idx, start_end, _at, offset, name, *flags_list = line.split()
start, end = map(lambda v: int(v, 16), start_end.split('->'))
offset = int(offset[:-1], 16)
except (IndexError, ValueError):
continue
# Note: can we deduce anything from 'ALLOC', 'HAS_CONTENTS' or 'LOAD' flags?
flags = 0
if 'READONLY' in flags_list: flags |= 4
if 'DATA' in flags_list: flags |= 2
if 'CODE' in flags_list: flags |= 1
# Now, if the section is already in pages, just add its perms
known_page = False
for page in pages:
if start in page:
page.flags |= flags
known_page = True
break
if known_page:
continue
pages.append(pwndbg.memory.Page(start, end-start, flags, offset, name))
# If the last page starts on e.g. 0xffffffffff600000 it must be vsyscall
vsyscall_page = pages[-1]
if vsyscall_page.start > 0xffffffffff000000 and vsyscall_page.flags & 1:
vsyscall_page.objfile = '[vsyscall]'
# Detect stack based on addresses in AUXV from stack memory
stack_addr = None
# TODO/FIXME: Can we uxe `pwndbg.auxv.get()` for this somehow?
auxv = gdb.execute('info auxv', to_string=True).splitlines()
for line in auxv:
if 'AT_EXECFN' in line:
try:
stack_addr = int(line.split()[-2], 16)
except Exception as e:
pass
break
if stack_addr is not None:
for page in pages:
if stack_addr in page:
page.objfile = '[stack]'
page.flags |= 6
break
return tuple(pages)
@pwndbg.memoize.reset_on_start
@pwndbg.memoize.reset_on_stop
def proc_pid_maps():

Loading…
Cancel
Save