cel*_*vek 9 c++ linux embedded gcc arm
我为在ARM CortexA9处理器上运行的Linux交叉编译了一个C++应用程序,该处理器因SIGFPE/Arithmetic异常而崩溃.最初我认为这是因为gcc 的-O3标志引入了一些优化,但后来我在调试模式下构建它仍然崩溃.
我使用gdb调试了应用程序,它捕获了异常,但不幸的是,触发异常的操作似乎也使堆栈无效,因此我无法获得有关该代码中导致这种情况发生的位置的任何详细信息.我最终得到的唯一细节是触发异常的操作(来自下面的堆栈跟踪):
3 raise() 0x402720ac
2 __aeabi_uldivmod() 0x400bb0b8
1 __divsi3() 0x400b9880
Run Code Online (Sandbox Code Playgroud)
该__aeabi_uldivmod() ,所以我尝试蛮力方法,并搜查了我的代码,因为它被证明是一项艰巨的任务,可能会使用操作,但没有取得多大成功的地方正在执行一个unsigned long长除法和提醒.此外,我试图通过零来检查潜在的划分,但再次检查代码库是否非常大并且检查每个除法操作这是一个麻烦且有些愚蠢的方法.所以必须有一个更聪明的方法来弄清楚发生了什么.
当调试器无法帮助时,是否有任何技术可以追踪此类异常的原因?
更新:在对十六进制数字进行处理,转储内存和进行堆栈取证之后(感谢Crashworks)我在ARM编译器文档中遇到了这个gem(即使我没有使用ARM Ltd.编译器):
通过重新实现适当的C库辅助函数,可以捕获并识别整数除零错误.除以零时的默认行为是,当使用信号函数或重新实现__rt_raise()或__aeabi_idiv0()时,调用__aeabi_idiv0().否则,除法函数返回零.__aeabi_idiv0()使用附加参数DIVBYZERO引发SIGFPE.
所以我在__aeabi_idiv0(_aeabi_ldiv0)et Voila上放了一个断点!在完全删除之前我有完整的堆栈跟踪.感谢大家提供的非常丰富的答案!
免责声明:"获胜"答案是单独和主观地选择考虑到其建议对我的调试工作的重量,因为不止一个是提供信息,真的很有帮助.
我的第一个建议是打开一个内存窗口,查看堆栈指针周围的区域,然后深入挖掘它,看看你是否可以在附近找到未损坏的堆栈帧,这可能会让你知道崩溃的位置.通常堆栈交换只会烧掉几个堆栈帧,所以如果你向上看几百个字节,你就可以通过受损区域并大致了解代码的位置.您甚至可以向下看堆栈,假设死函数可能在它死之前调用了其他函数,因此可能有一个旧帧仍在内存中指向当前IP.
在评论中,我链接了一些演示幻灯片,演示了PowerPC上的技术 - 在类似的拙劣堆栈崩溃案例研究中查看#73-86左右.显然,你的ARM堆栈帧将以不同的方式布局,但一般原则是成立的.