用 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
所以,我正在调试一个通过 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