我试图找出一种方法来使用 GDB 反向调试在程序中通过函数调用和变量副本来跟踪值的传播。我过去经常使用 GDB,但对反向调试相对较新。
我认为用一个例子来描述这个问题是最容易的。看看这个程序。
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);
}
我编译程序,然后使用反向调试启动 GDB 以运行编译后的可执行文件。printf
我在in处设置了一个断点FnA
,然后让程序开始执行,这导致我命中了那个断点。从这里,我想回答“最后一次x
写信到哪里?”这个问题。我可以做一个watch -l x
然后reverse-continue
。然而,这只会把我带到 的开头FnA
,因为那是x
它在堆栈上的生命周期开始的地方。我真正感兴趣的是i = 5
一路回溯的赋值,main
因为那是x
's 价值的来源。从i = 5
发生的那一刻起,真正的价值x
只是通过函数参数和变量副本传播,如下所示:main:i -> FnC:z -> FnB:y -> FnB:y_copy -> FnA:x
.
显然,我可以通过一些 GDB-fu 结合人类直觉来解决这个问题,但我正在努力使这个过程尽可能自动化。我最终想在更复杂的软件中尝试这个,使用人类直觉和 GDB-fu 会相当乏味。
有没有一种方便的方法可以通过反向调试在 GDB 中完成此任务?GDB 是否能够自动找出并遵循这些价值传播?
PS:具体来说,我实际上是在使用 GDB 和rr。rr 只是 gdb 的一个包装器,以允许确定性和可重现的执行上下文。我认为/希望核心问题保持不变,无论我是否使用带或不带 rr 的 gdb。