I have a core dump of an executable that was NOT built with debug symbols.
Can I recover argv contents to see what the command line was?
If I run gdb, I can see a backtrace, and I can navigate to the main() frame. Once there, is there a way to recover argv, without knowing its exact address?
I am on x86_x64 (Intel Xeon CPU) running a CEntOS Linux distro/kernel,
One reason I am hopeful is that the core dump seems to show a partial argv.
(The program is postgres, and when I load the core file, gdb prints a message that includes the postgres db-user name, client OP address, and first 10 characters of the query))
On
x86_64the arguments are passed in%rdi,%rsi, etc. registers (calling convention).Therefore, when you step into the
mainframe, you should be able to:Unfortunately, GDB will not normally restore
$rdiand$rsiwhen you switch frames. So this example doesn’t work:So you’ll have to work some more …
What you can do is use the knowledge of how Linux stack is set up at process startup, combined with the fact that GDB will restore stack pointer:
So now we expect the original
%rspto be$rsp+8(one POP, two PUSHes), but it could be at$rsp+16due to alignment that was done at instruction0x0000000000400449Let’s see what’s there …
That looks promising: 4 (suspected argc), followed by 4 non-NULL pointers, followed by NULL.
Let’s see if that pans out:
Indeed, that’s how I invoked the binary. As a final sanity check, does
0x00007fffbe5d6ecflook like part of the enovironment?Yep, that’s the beginning (or the end) of the environment.
So there you have it.
Final notes: if GDB didn’t print
<optimized out>so much, we could have recoveredargcandargvfrom frame #5. There is work on both GDB and GCC sides to make GDB print much less of “optimized out” …Also, when loading the core, my GDB prints:
negating the need for this whole exercise. However, that only works for short command lines, while the solution above will work for any command line.