用 GDB nexti 解释段错误的原因

Interpreting cause of segfault with GDB nexti

所以,我正在调试一个通过 SIGSEGV 神秘崩溃的程序。该程序是单线程的。

我之前调试过很多段错误——其中大部分归结为堆栈或堆损坏。使用 valgrind 调试堆损坏问题通常很容易。堆栈损坏比较棘手,但是当 GDB 显示您的堆栈损坏时,您通常至少可以判断出堆栈损坏是问题所在。

但是,在这里我遇到了一个我以前从未见过的非常奇怪的问题。使用 GDB 逐条指令执行,我看到段错误在 callq 指令之后立即发生。除了 callq 地址不是从寄存器或内存动态加载 - 它只是一个 static 函数地址:

(gdb) ni
0x00007ffff659c423      223         setPolicyDocumentLoader(docLoader);
1: x/i $pc
=> 0x7ffff659c423 <WebCore::FrameLoader::init()+351>:   mov    %rdx,%rsi
(gdb)
0x00007ffff659c426      223         setPolicyDocumentLoader(docLoader);
1: x/i $pc
=> 0x7ffff659c426 <WebCore::FrameLoader::init()+354>:   mov    %rax,%rdi
(gdb)
0x00007ffff659c429      223         setPolicyDocumentLoader(docLoader);
1: x/i $pc
=> 0x7ffff659c429 <WebCore::FrameLoader::init()+357>:
    callq  0x7ffff53a2d50 <_ZN7WebCore11FrameLoader23setPolicyDocumentLoaderEPNS_14DocumentLoaderE@plt>
(gdb) ni

Program received signal SIGSEGV, Segmentation fault.
0x0000000000683670 in ?? ()
1: x/i $pc
=> 0x683670:    add    %al,(%rax)
(gdb) 

所以,它一执行callq到地址0x7ffff53a2d50,就突然出现segfaults。

我意识到,一般来说,Whosebug 不可能对大多数段错误或类似问题有太大帮助,因为原因往往对某些特定情况非常具体,通常只是通过以下方式归结为内存损坏程序员错误。

但我仍然认为问这个问题是值得的,因为这对我来说根本就没有任何意义。 可能 OS 在程序执行 callq 指令到合法 静态 [=31= 时传递 SIGSEGV ] 确定函数地址?

as soon as it executes callq to the address 0x7ffff53a2d50, it suddenly segfaults.

这通常是堆栈溢出造成的。

寻找深度递归(使用where命令)。还要查看 info proc map.

输出中的堆栈区域(包含当前 $rsp 值)

nexti 将执行下一条指令,但如果指令是 call,则它会一直执行到函数 returns。来自 GDB manual:

nexti, nexti arg, ni

Execute one machine instruction, but if it is a function call, proceed until the function returns. An argument is a repeat count, as in next.

当您执行 callq 时,调试器调用了该函数,但随后在执行该函数的过程中某处崩溃。如果您想进入函数调用,那么我建议您在点击 callq 0x7ffff53a2d50

时使用 stepi