【问题标题】:gdb showing incorrect back trace by pointing at the wrong line of codegdb 通过指向错误的代码行显示不正确的回溯
【发布时间】:2016-01-17 22:00:33
【问题描述】:

我们可以通过在源代码中调用多个 abort 来通过非常简单的示例重现此问题。在下面的示例代码中,我们总共有四个不同条件的中止调用,但是当我们使用优化标志(-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 正常工作? (不删除优化) 在此先感谢您的帮助。

【问题讨论】:

  • 不一定,你应该说 waht 是有这个问题的 gdb 的确切版本。还有 gccbinutils 的确切版本。什么平台以及在 Linux 的情况下是哪个发行版。

标签: c gcc optimization gdb abort


【解决方案1】:

在这种情况下是否可以让 gdb 正常工作?

GDB 在这种情况下工作正常:它向您展示了 实际 发生了什么,即 ...

(不移除优化)

...编译器发现多个路径导致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.

您所有的ifs 都完全优化了。

如果你想区分这两种情况,你必须让编译器知道路径是等价的。

在当前翻译单元中调用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+1a+2 等来防止编译器合并单独的路径。如果你只是调用my_abort(a),编译器可能仍然将它们合并在一起,就像你写的一样:

if (a >= 0 && a <= 2) my_abort(a);

请注意,如果您使用整个程序优化,即使是这种外部函数方法也可能会失败。

【讨论】:

  • 我想知道是否有任何编译器会将您对 my_abort 的使用优化为 if (a &gt;= 0 &amp;&amp; a &lt;=2) my_abort (a + a + 1);。可能不会……
  • 感谢您的快速解决。
  • 感谢您的快速解决方案。不幸的是,我无法修改我们的源代码,因为它是一个非常大的项目。在这种情况下,我们有多个中止调用,我只想打印一条警告消息。因为只有在我们有多个 abort 调用的情况下才会出现问题。在使用优化时真的有可能知道我们只有一个调用还是多个调用?提前致谢。
  • 有没有什么办法可以使用 volatile 代替产生副作用以达到优化的目的,而无需额外的代码?比如给自己分配一个局部变量。
猜你喜欢
  • 2018-03-18
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
相关资源
最近更新 更多