我们可以通过在源代码中调用多个中止调用来使用非常简单的示例重现此问题。在下面的示例代码中,我们在不同条件下总共有四个中止调用,但是当我们使用优化标志 (-O3) 进行编译时,我们只能看到一个中止调用的调试信息。因此,在这四个中止调用中发生崩溃的地方,gdb 总是给出具有调试信息的调用。
#include <stdio.h>
#include <stdlib.h>
void level_aa(int a)
{
if (a == 0)
abort();
if (a == 1)
abort();
if (a == 2)
abort();
abort();
}
int main(int argc,char *argv[])
{ int D;
D = atoi(argv[1]);
printf(" Value = %d", D);
level_aa(D);
return 0;
}
使用优化标志 (-O3) 编译上述代码并使用 gdb 运行以重现问题。
>gcc -g -O3 abort_crash.c -o abort
>gdb ./abort
(gdb)run 1
(gdb) bt
#0 0x00007ffff7ab2945 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff7ab3f21 in *__GI_abort () at abort.c:92
#2 0x0000000000400634 in level_aa (a=<optimized out>) at abort_crash.c:13
#3 main (argc=<optimized out>, argv=<optimized out>) at abort_crash.c:20
(gdb)
如果我们观察第 2 帧(#2),崩溃实际上发生在第 9 行,但 gdb 显示第 13 行。我可以理解它的发生是因为源代码的优化。 在这种情况下是否可以使 gdb 正常工作? (不删除优化) 在此先感谢您的帮助。
最佳答案
Is it possible to make gdb work fine in this case?
GDB 在这种情况下工作正常:它向您显示实际 发生了什么,即...
(with out removing optimization)
... 编译器发现多个路径导致abort
函数不能返回且没有副作用,所以合并这些路径,减少生成代码的大小。看看生成的程序集:
(gdb) disas level_aa
Dump of assembler code for function level_aa:
0x0000000000400620 <+0>: sub $0x8,%rsp
0x0000000000400624 <+4>: callq 0x4004b0 <abort@plt>
End of assembler dump.
您所有的if
都完全优化了。
如果您想区分不同的情况,您必须让编译器知道这些路径不是等价的。
调用printf
,或调用当前翻译单元中编译器不可见的外部函数(函数本身可能调用abort
):
extern int my_abort(int); // must be in a different TU
void level_aa(int a)
{
if (a == 0)
my_abort(a + 1);
if (a == 1)
my_abort(a + 2);
if (a == 2)
my_abort(a + 3);
abort();
}
注意:需要a+1
、a+2
等来防止编译器合并单独的路径。如果您只是调用 my_abort(a)
,编译器可能仍将它们合并在一起,就好像您这样写:
if (a >= 0 && a <= 2) my_abort(a);
请注意,如果您使用整个程序优化,即使这种外部函数方法也可能会失败。
关于c - gdb 通过指向错误的代码行显示不正确的回溯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33216397/