debugging 如何到广发上一行?

w41d8nur  于 2023-06-23  发布在  其他
关注(0)|答案(9)|浏览(94)

在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的内容。
我认为这可能是不可能的,因为调试器可以以慢动作运行代码,但不能使其向后执行。
还有什么见解。

zbdgwd5y

zbdgwd5y1#

是的!有了新版本的7.0 gdb,你就可以做到这一点!
该命令将是“reverse-step”或“reverse-next”。
您可以从www.example.com获取gdb-7.0ftp.gnu.org:/pub/gnu/gdb
如果您遇到错误:Target child does not support this command.然后尝试在启动run之后在执行开始时添加target record
编辑:由于GDB 7.6 target record已弃用,请改用target record-full

4sup72z8

4sup72z82#

是的,这是可能的,而且很简单,现在,用真实的的硬件(即。而不仅仅是VM)。GDB-7.0支持在原生Linux x86机器上使用reverse-step和reverse-continue等命令进行反向调试。
这里有一个教程:http://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial

fwzugrvs

fwzugrvs3#

    • mozilla rr**

https://github.com/mozilla/rr
广发银行内置的录制和回放有严重的局限性,例如:不支持AVX指令:gdb反向调试失败,并显示"Process record does not support instruction 0xf0d at address"
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

测试程序:
reverse.c

#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开发的,用于帮助他们重现第二天夜间测试中出现的计时错误。但是反向调试方面也是基本的,当你有一个bug,只发生在执行的几个小时内,因为你经常想后退一步,检查什么以前的状态导致后来的失败。
在我看来,rr最严重的局限是:

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

3xiyfsfu

3xiyfsfu4#

如果你的程序很短,通常的技巧是,

  • 在上一行放置一个新断点
  • 启动**r**以重新启动调试
    GDB就是做这个的!
kx5bkwkv

kx5bkwkv5#

简答:没有

有关解决方法,请参阅下文。
虽然在第B行无法确定第a行的值,但可以通过只命中一个断点来记录a和b以及其他位置的arr值。

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

(gdb)命令1
在命中断点1时键入命令,每行一个。最后写一行“结束”。
继续
结束

  • 在b行上设置断点。

现在,当所有其他日志断点都被命中时,arr的值将被转储到屏幕上,但断点不会等待用户交互,而是自动继续。当你在b行遇到一个断点时,你可以看到arr过去的值,这些值将被记录在gdb本身中。
根据具体情况,您还可以转储(和显示)许多有用的信息。例如,如果上面的函数在一个循环中被调用了10000次,你可能还想转储一个循环计数器(比如i)。这真的取决于你想达到什么目的。

5ssjco0h

5ssjco0h6#

如果arr的设置代码位于“a行”的上方(这是一个非常常见的场景),你可以这样做:
tbreak myfilename.c:123(第123行是arr的设置代码的开始)然后

jump 123

“tbreak”防止gdb在跳转后继续(恢复)程序。
然后你可以单步执行安装代码或者在“a行”设置一个断点并继续

p4rjhz4m

p4rjhz4m7#

根据GDB文档,“如果目标环境支持它”,是的。

qlckcl4x

qlckcl4x8#

这在GDB中通常是不可能的,但是您可以使用一个名为QIRA的调试器轻松地回到历史中。您可以使用向上和向下箭头来回移动,它还突出显示哪些寄存器已更改。

lo8azlld

lo8azlld9#

每个人都希望有一个像这样的全知调试器:https://web.archive.org/web/20150915150119/http://www.lambdacs.com/debugger/,但它们(取决于语言/机器)很难制作,而且有很多簿记工作要做。
目前,在真实的的硬件上而不是在虚拟机中,几乎不可能做到这一点。

相关问题