【发布时间】:2011-10-08 08:05:18
【问题描述】:
我有一个针对 Linux 交叉编译的 C++ 应用程序,该应用程序在 ARM CortexA9 处理器上运行,该处理器因 SIGFPE/算术异常而崩溃。最初我认为这是因为 gcc 的 -O3 标志引入的一些优化,但后来我在调试模式下构建它,它仍然崩溃。
我使用捕获异常的 gdb 调试了应用程序,但不幸的是,触发异常的操作似乎也破坏了堆栈,因此我无法获得有关代码中导致这种情况发生的位置的任何详细信息。我最终能得到的唯一细节是触发异常的操作(来自以下堆栈跟踪):
3 raise() 0x402720ac
2 __aeabi_uldivmod() 0x400bb0b8
1 __divsi3() 0x400b9880
__aeabi_uldivmod() 正在执行无符号长长除法和提醒,因此我尝试了蛮力方法并在我的代码中搜索了可能使用该操作但没有太大成功的地方,因为它被证明是一项艰巨的任务。此外,我尝试用零检查潜在的除法,但代码库再次非常大,并且检查每个除法运算是一种繁琐且有些愚蠢的方法。所以必须有一种更聪明的方法来弄清楚发生了什么。
当调试器无能为力时,是否有任何技术可以追踪此类异常的原因?
更新: 在处理十六进制数字、转储内存和进行堆栈取证(感谢 Crashworks)后,我在 ARM 编译器文档中发现了这个宝石(即使我没有使用 ARM Ltd.编译器):
整数除零错误可以通过以下方式捕获和识别 重新实现适当的 C 库帮助函数。这 发生被零除时的默认行为是当信号 使用函数,或 __rt_raise() 或 __aeabi_idiv0() 被重新实现,__aeabi_idiv0() 是 叫。否则,除法函数返回零。 __aeabi_idiv0() 使用附加参数 DIVBYZERO 引发 SIGFPE。
所以我在 __aeabi_idiv0(_aeabi_ldiv0) et Voila! 处放置了一个断点,在被完全丢弃之前我有完整的堆栈跟踪。感谢大家提供非常丰富的答案!
免责声明:“获胜”的答案是完全主观地选择的,考虑到它的建议对我的调试工作的重要性,因为不止一个是信息丰富且真正有用的。
【问题讨论】:
-
我最近做了一个关于追踪各种疯狂的发布模式崩溃的演讲,包括粉碎的堆栈。我的幻灯片主要涵盖 x86 和 PowerPC,但 PPC 与 ARM 非常相似,因此其中一种技术可能会有所帮助(关于堆栈框架布局的模特定细节)。幻灯片在这里:crashworks.org/gdc11/…
标签: c++ linux gcc embedded arm