I am trying to figure out a way to follow the propagation of values through function calls and variable copies in a program using GDB reverse debugging. I have used GDB a lot in the past, but am relatively new to reverse-debugging.
I think it is easiest to frame the question with an example. Take a look at this program.
void FnA(int x) {
printf("x=%d\n", x)
}
void FnB(int y) {
int y_copy = y;
FnA(y_copy);
}
void FnC(int z) {
FnB(z);
}
int main() {
int i;
i = 5;
FnC(i);
}
I compile the program, and then spin up GDB to run the compiled executable, using reverse-debugging. I set a breakpoint at the printf
in FnA
, then let the program begin executing, which causes me to hit that breakpoint. From here, I want to answer the question "Where was the last time that x
was written to?" I could do a watch -l x
and then reverse-continue
. However, that will just take me to the beginning of FnA
, because that is where x
began its lifetime on the stack. What I am really interested in is the assignment of i = 5
all the way back in main
because that is where x
's value originated from. From the time that i = 5
happened, really the value of x
was just propagated through function parameters and variable copies, like so: main:i -> FnC:z -> FnB:y -> FnB:y_copy -> FnA:x
.
Obviously I could figure this out with some GDB-fu combined with human intuition, but I am trying to make this process as automated as possible. I eventually want to try this in more complex software, where using human-intuition and GDB-fu would be rather tedious.
Is there a convenient way to accomplish this in GDB with reverse-debugging? Is GDB capable of automatically figuring out and following these value propagations?
PS: To be specific, am actually using GDB with rr. rr is just a wrapper around gdb to allow for deterministic and reproducible execution contexts. I think/hope the core question remains the same, regardless of whether i'm using gdb with or without rr.