为什么在使用浮点控制时限制了GDB回溯?

时间:2019-09-24 20:22:14

标签: gdb

按照此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保留跟踪信息?

1 个答案:

答案 0 :(得分:0)

  

是否可以使用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可以很容易地向您显示堆栈跟踪。

    仅当您的程序是确定性的时,此方法才有效。