如何转到GDB中的上一行?


75

gdb是否有可能在当前正在执行的行之前转到一行。例如:


void my_fun( somePtrType** arr,int start,int end)
{
 // arr is an array of pointers to somePtrType
  //line a
 ... some assignments
 swap(&arr[ind1] , &arr[ind2] ) ;
 //line b (current line )
}

我目前在b行,可以检查arr那里的值,但是我想回到a行并检查当时的内容arr

我认为这可能是不可能的,因为调试器可以慢动作地运行代码,但不能使其反向执行。
还有更多见识..

Answers:


114

是! 使用新的7.0 gdb版本,您可以做到这一点!

该命令将是“ reverse-step”或“ reverse-next”。

您可以从ftp.gnu.org获取gdb-7.0:/ pub / gnu / gdb

如果您遇到错误:请在开始执行后,Target child does not support this command.尝试target record在执行开始时添加run

编辑:由于target record不建议使用GDB 7.6 ,请target record-full改用。


6
该命令存在,但此处“目标孩子不支持它” =(反正投票
表决

@MichaelSnyder gdb 6.x在哪里?
SIFE 2013年

26
我得到了Target multi-thread does not support this command.:(
Derek朕会功夫2015年

现在我明白了:键入start...然后键入target record-full。快捷方式是rn
user2023370 '20

record一样的target record-full吗?它似乎对我有用
2020年


10

Mozilla rr

https://github.com/mozilla/rr

GDB的内置记录和重放具有严格的限制,例如,不支持AVX指令:gdb反向调试失败,显示“过程记录不支持地址处的指令0xf0d”

rr的优点:

  • 目前更加可靠。我已经测试了几种复杂软件的相对长期运行。
  • 还提供了带有gdbserver协议的GDB接口,使其成为了很好的替代品
  • 大多数程序的性能下降很小,我自己也没有注意到它
  • 生成的跟踪在磁盘上很小,因为只记录了很少的非确定性事件,到目前为止,我不必担心它们的大小

下面的例子展示了它的某些功能,尤其是reverse-nextreverse-stepreverse-continue命令。

在Ubuntu 18.04上安装:

sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
sudo cpupower frequency-set -g performance
# Overcome "rr needs /proc/sys/kernel/perf_event_paranoid <= 1, but it is 3."
echo 'kernel.perf_event_paranoid=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

测试程序:

反向

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int f() {
    int i;
    i = 0;
    i = 1;
    i = 2;
    return i;
}

int main(void) {
    int i;

    i = 0;
    i = 1;
    i = 2;

    /* Local call. */
    f();

    printf("i = %d\n", i);

    /* Is randomness completely removed?
     * Recently fixed: https://github.com/mozilla/rr/issues/2088 */
    i = time(NULL);
    printf("time(NULL) = %d\n", i);

    return EXIT_SUCCESS;
}

编译并运行:

gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay

现在您就处于GDB会话中,可以正确地进行调试了:

(rr) break main
Breakpoint 1 at 0x55da250e96b0: file a.c, line 16.
(rr) continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;
(rr) next
17          i = 1;
(rr) print i
$1 = 0
(rr) next
18          i = 2;
(rr) print i
$2 = 1
(rr) reverse-next
17          i = 1;
(rr) print i
$3 = 0
(rr) next
18          i = 2;
(rr) print i
$4 = 1
(rr) next
21          f();
(rr) step
f () at a.c:7
7           i = 0;
(rr) reverse-step
main () at a.c:21
21          f();
(rr) next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) reverse-next
23          printf("i = %d\n", i);
(rr) next
i = 2
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$5 = 1509245372
(rr) reverse-next
27          i = time(NULL);
(rr) next
28          printf("time(NULL) = %d\n", i);
(rr) print i
$6 = 1509245372
(rr) reverse-continue
Continuing.

Breakpoint 1, main () at a.c:16
16          i = 0;

rr通过首先运行程序来实现此目的,该程序以记录在每个非确定性事件(例如线程切换)上发生的情况的方式进行记录。

然后,在第二次重播运行中,它使用该跟踪文件(该文件非常小)来准确地重构原始非确定性运行中发生的事情,但是以确定性的方式向前或向后进行。

rr最初是由Mozilla开发的,旨在帮助他们重现在第二天的夜间测试中出现的计时错误。但是,当您有一个只在执行过程中几个小时内发生的错误时,反向调试方面也是至关重要的,因为您通常想退后一步检查以前的状态导致了后来的失败。

我认为rr最严重的局限性是:

UndoDB是rr的商业替代品:https ://undo.io两者都是基于跟踪/重播的,但是我不确定它们在功能和性能方面如何进行比较。


5

简短答案:否。

有关解决方法,请阅读以下内容。

尽管在b行无法确定a处的值,但可以通过仅击中一个断点来记录a和b以及其他位置处的arr值。

  • 使用“ display”命令(显示variable_name,其中variable_name将根据需要查找,用arr,* arr,** arr替换),以便在遇到任何断点时,将variable_name的内容转储到屏幕。请注意,当variabe_name在范围内时,您可以添加到显示列表中,这样可能需要您等待第一个断点。
  • 在您想记录variable_name值的代码的各个位置创建断点。这样的断点将在第a行。
  • 对于每个断点,请使用命令(命令breakpoint_number)并指示您的断点不要停止程序的执行。您需要使用的命令是继续,然后是end。请参见下面的示例。

(gdb)命令1

输入命中断点1的命令,每行一个。结束时说“结束”。

继续

结束

  • 在b行上放置一个断点。

现在,当所有其他记录断点都被命中时,arr的值将被转储到屏幕上,但是断点将不等待用户交互,而是将自动继续。当您在b行达到断点时,您可以看到arr的过去值,该值将记录在gdb本身中。

根据情况,您还可以转储(和显示)许多有用的信息。例如,如果在循环中调用了10000次以上函数,则可能还需要转储循环计数器(例如i)。这确实取决于您要实现的目标。


1
即使可能进行真正的反向调试,这也是一项非常有用的技术!反向调试具有缺点:速度慢,不被任何地方支持并且保存的记录数有限。但是,请编辑您的答案以考虑新的发展。
misiu_mp 2011年

4

如果您的程序很短,通常的窍门是,

  1. 在上一行放置一个新的断点
    • 触发r重新启动调试

GDB就是这样做的!


1

不是gdb,但是您可以使用名为qira的调试器轻松返回历史记录。您可以使用向上和向下箭头来回移动,也可以突出显示已更改的寄存器。

在此处输入图片说明


1

根据GDB docs和“如果目标环境支持”,是的。


AFAIU,已经在Linux / i386和x86_64目标的GDB CVS Head中实现了反向调试。
俄罗斯

0

如果您为arr设置的代码刚好在“ a行”(通常是这种情况)上方,则可以执行以下操作:

tbreak myfilename.c:123 (第123行是arr设置代码的开头),然后

jump 123

“ tbreak”可防止gdb在跳转后继续(恢复)程序。

那么您可以单步执行设置代码,也可以仅在“ a行”处设置一个断点,然后继续


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.