I am currently attempting to debug a crash of a c++ application that corrupted the stack. After some investigation I am very sure I know valid $rsp and $rip address that correspond to a very useful frame on the stack that should be uncorrupted.
It would be incredibly useful to be able to use all of gdb's built-in features for dealing with dynamically addressed calls when it has a valid stack. Unfortunately gdb cannot set these register values directly when debugging a core file, and I have found a feature request literally a decade old asking for this functionality.
Is there some way to edit the core file directly to set these values? Or does lldb potentially allow you to override these register values when debugging a core file?
Is there some way to edit the core file directly to set these values?
Sure -- the values are stored in the core
somewhere; the trick is finding out where exactly.
The register values are stored in the PRSTATUS
notes (the first such note is usually the one corresponding to the crashing thread).
You can examine the notes from your existing core
with elfutils
eu-readelf -Wn core
. The output will look similar to:
Note segment of 5200 bytes at offset 0x580:
Owner Data size Type
CORE 336 PRSTATUS
info.si_signo: 3, info.si_code: 0, info.si_errno: 0, cursig: 3
sigpend: <>
sighold: <>
pid: 4174783, ppid: 140563, pgrp: 4174783, sid: 140563
utime: 0.000000, stime: 0.000000, cutime: 0.000000, cstime: 0.000000
orig_rax: 230, fpvalid: 1
r15: 140725686367064 r14: 1
r13: 140725686367064 r12: 140725686366544
rbp: 0x00007ffd408bf190 rbx: 60
r11: 514 r10: 140725686366608
r9: 0 r8: 0
rax: -516 rcx: 139740173005747
rdx: 140725686366544 rsi: 0
rdi: 0 rip: 0x00007f17cb5f73b3
rflags: 0x0000000000000202 rsp: 0x00007ffd408bf138
fs.base: 0x00007f17cb525740 gs.base: 0x0000000000000000
cs: 0x0033 ss: 0x002b ds: 0x0000 es: 0x0000 fs: 0x0000 gs: 0x0000
Here you can see that the Note
is at offset 0x580
, and the rsp
register is somewhere within it.
From here, you can use offsetof(struct elf_prstatus, pr_reg)
(112
on x86_64
), and offsetof(struct user_regs_struct, rsp)
(152
).
If my arithmetic is correct, the value of rsp
should be at 0x580 + 20 + 112 + 152
. Let's check this:
xxd -e -s $((0x580+20+112+152)) -g8 core | head -1
0000069c: 00007ffd408bf138 000000000000002b 8..@....+.......
So overwriting the 8-byte value at offset 0x69c
into this core
should produce desired result.
P.S. Where did the extra 20
come from? The Elf64_Nhdr
has a few data items before the note data starts: n_namesz, n_descsz, n_type
(each 4 bytes), followed by note name (CORE\0
here), rounded up to 4-byte boundary (so 8 bytes total).