Is it expected that changes made to a program's address space would not be reverted during reverse debugging?
I have been debugging a program which segfaults when a pointer to strlen
in the GOT becomes corrupted during the course of execution. Thanks to advice stemming from comments to this question, I made the GOT of this program read-only by linking with the -z relro
option; however, this does not prevent the pointer in question from being overwritten. Namely, I can start
the program in gdb, step to the first occurrence of strlen
, verify that the pointer is valid (for example: x/g 0x5555555d10a8 ==> 0x5555555d10a8 <strlen@got.plt>: 0x00007ffff7e8d1e0
), continue
running, and wait for the pointer to become invalid (pointing to a nonsensical address outside the address space of the program; for example: x/g 0x5555555d10a8 ==>
0x5555555d10a8 <strlen@got.plt>: 0x0000000000002156
), prompting a segv
.
However, if I record full
the entire execution (from the first line until the program segfaults), and then awatch
the address with the pointer to strlen
during reverse-continue
, the watchpoint never triggers. And when the program has finally gotten back to instruction #0, the pointer is still pointing to the invalid address that it had when it segfaulted.
This leads to two questions. First, why is the GOT mutable despite the -z relro
linker option? Second, is it expected for a location in memory (the pointer to strlen
) that is altered during program execution to not be restored to its original value during reverse execution?
First, why is the GOT mutable despite the -z relro linker option?
What you are applying with -Wl,-z,relro
is only partial RELRO protection. This option has the main purpose of moving the GOT before the BSS to avoid corruption of entries due to overflows from buffers in the BSS, and also makes a small portion of the GOT read-only. What you want is full RELRO, which is obtained with -Wl,-z,relro,-z,now
. The -z now
linker flag makes the loader resolve all symbols at startup, and then remap the segment containing the GOT as read-only, before starting the program.
Second, is it expected for a location in memory (the pointer to
strlen
) that is altered during program execution to not be restored to its original value during reverse execution?
You probably forgot to set target record-full
before starting debugging, but I'm not sure that has any effect since you already use record full
. Reverse execution is not easy, the debugger might decide not to reverse the memory modifications of the GOT (or other sections) for performance reasons (since those should normally not be touched anyway). GDB's record feature also has some other limitations, like not supporting AVX instructions for example. I don't know much more to give a better answer. You can try your luck with rr
.