【问题标题】:Why is GDB backtrace limited when using floating point control?为什么使用浮点控制时 GDB 回溯受限?
【发布时间】:2019-09-25 04:58:15
【问题描述】:

按照question 的建议,我将#include <fenv.h>feenableexcept(FE_ALL_EXCEPT & ~FE_INEXACT); 添加到我的主要源代码中,并使用g++ -O0 -Wall -Wextra -Werror -g main.cpp -o main.o 编译它。项目中的所有文件都是使用 make 以这种方式编译的。 feenableexcept 仅被添加到 main。事物通过相同的-O0 和-g 链接在一起。然后我以gdb a.out 运行可执行文件。调试器给了我预期的SIGFPE 但是回溯不提供通常有用的信息。相反,我得到了这样的列表:

Program received signal SIGFPE, Arithmetic exception.
0x00002aaaabe19c0d in _amd_handle_error () from /lib64/libm.so.6
(gdb) bt                                                        
#0  0x00002aaaabe19c0d in _amd_handle_error () from /lib64/libm.so.6
#1  0x00002aaaabe19cca in _pow_special () from /lib64/libm.so.6     
#2  0x00002aaaabdf6c12 in pow () from /lib64/libm.so.6              
#3  0xbfc971b779361ea1 in ?? ()                                     
#4  0x3fe85bf701f137d7 in ?? ()                                     
#5  0x3fe914100cd71275 in ?? ()                                     
#6  0x00007fffffffa420 in ?? ()                                     
#7  0x00007fffffff9960 in ?? ()                                     
#8  0x3fe7c514ca0e522d in ?? ()                                     
#9  0x0000000000000000 in ?? () 

如果我尝试查看框架,我将毫无用处。在这种情况下,函数pow 在出现浮点错误的代码区域中被多次使用。知道我是如何到达pow 是这里缺少的信息。

通常当我使用-O0-g 时,我会得到与跟踪相关的函数、文件和行号。如果我使用相同的可执行文件设置断点并从断点回溯,我会得到有用的信息。

Breakpoint 1, SurfaceModel::ProcessGroups (this=0x7fffffff9f30) at source/SurfaceModel.cpp:398
398             vector<Group>::iterator it;
(gdb) bt
#0  SurfaceModel::ProcessGroups (this=0x7fffffff9f30) at source/SurfaceModel.cpp:398
#1  0x00000000006768e6 in MainLoop (logFile=...) at source/main.cpp:94
#2  0x0000000000676337 in main (argc=1, argv=0x7fffffffbe18) at source/main.cpp:41

然后我在代码中添加了*(int*)0=0; 以强制出现段错误,以查看这是否与信号有关。我也在那里得到了有用的信息。

Program received signal SIGSEGV, Segmentation fault.
0x000000000061f42a in SurfaceModel::ClearGroupHeatRates (this=0x7fffffff9f30) at source/SurfaceModel.cpp:456
456             *(int*)0=0; // force a seg fault
(gdb) bt
#0  0x000000000061f42a in SurfaceModel::ClearGroupHeatRates (this=0x7fffffff9f30) at source/SurfaceModel.cpp:456
#1  0x0000000000676ba5 in MainLoop (logFile=...) at source/pilager.cpp:137
#2  0x0000000000676341 in main (argc=1, argv=0x7fffffffbe18) at source/pilager.cpp:41

这似乎只与我对浮点控制所做的事情有关。我正在运行 GDB 7.12,这是用 GCC 5.3.0 编译的。有没有办法使用SIGFPE 保存跟踪信息?

【问题讨论】:

  • 您使用的是什么版本的 GLIBC,您在什么平台上?

标签: gdb


【解决方案1】:

有没有办法使用 SIGFPE 保存跟踪信息?

跟踪信息与引发哪个信号无关,与引发它的函数无关。

不知何故,您的pow 缺少展开描述符(这是 GDB 用来展开堆栈的)。

这通常发生在汇编级实现(开发人员忽略放入适当的.cfi 指令)或使用损坏的编译器构建代码时。

损坏的编译器似乎不太可能,而且我找不到任何使用汇编实现pow 的最新版本的 GLIBC。

要恢复堆栈,可以使用以下技术:

  1. 使用反向调试器(例如rr)并从SIGFPE 向后退。这是最好的解决方案,但我怀疑 rr 是否适用于您的(显然很老的)系统。
  2. 计算崩溃前pow 被调用的次数:

    (gdb) break pow (gdb) commands 1 silent cont end (gdb) run # run until SIGFPE (gdb) info break
    您现在将知道在崩溃之前调用了多少次 pow

    再次运行程序,忽略断点$N-1 次(您需要先从断点中删除命令并使用 GDB ignore 1 $N-1 命令)。您现在应该在崩溃前停止,因为您仍然不在pow 内,GDB 应该可以轻松地向您显示堆栈跟踪。

    这种方法仅适用于您的程序是确定性的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 2020-05-13
    • 2020-09-18
    • 2020-03-31
    • 2016-08-05
    相关资源
    最近更新 更多