【问题描述】
本地移植适配的Cmback-tarce工具,适配验证过程在此贴中有介绍(RA8 Freertos 使用 CmBacktrace 调试死机问题),我们在IAR 的Debug 仿真时在hardfault 函数中设置断点,触发hardfault 时在还 hardfault 中断函数中停下,此时通过IAR 去查看函数的调用栈路径,只有进入异常时的汇编入口的函数没有之前触发异常的函数信息。
虽然我们还是可以使用Cmback-tarce 的打印信息回溯出异常触发的时机,不过我们在调试环境下还是在IAR下能直接看出来更方便调查问题。
【原因确认】
我们在IDE中其他中断中下断点,是能够在调用栈中查看到中断打断应用程序的位置,为什么在hardfault中断就不能显示了呢。
上述是我们在Uart 接收中断中下的断点,这时就能看到中断在ilde中打断了程序的运行跳转到Dma 串口接收的的中断栈中。
同样是中断为什么有的中断触发能显示出触发异常前的调用关系,为啥有的就不行呢?带着这个疑问,我们把重点放在了两个函数的实现上,查看代码发现Cmback-tarce 函数的hardfault 的中断处理函数的实现试用汇编实现的对应代码如下:
现在怀疑方向有了,这个函数的实现也比较简单,我们把这个函数变成用C代码实现是不是就能显示出hardfault 前的完整调用关系。
上述代码中只用了几条汇编我们如何将上述汇编代码转换成C函数,我们可以试用内嵌汇编,查看IAR 的开发手册,从中可以知道IAR 的C内嵌汇编写法和GNU类似。
对于GCC的内嵌汇编的写法如下帖子有记录内嵌汇编的规则:
【功能修改】
按照上面的描述,我们按照cmback-trace中hardfault 异常的汇编代码修改为C内嵌汇编的形式实现,对应代码实现如下:
/** * @brief This function handles HardFault. */ __attribute__((naked)) void HardFault_Handler(void) { __asm volatile( "mov r0, lr \n" "mov r1, sp \n" "bl cm_backtrace_fault \n" "b . \n"); }
【功能验证】
将hardfault 中断入口修改为C代码的内嵌汇编实现后在次在hardfault 中断入口函数添加断点后就可以查看到hardfault 触发的调用路径了。
在触发异常的函数中可以看到触发异常的点,及异常原因为非对齐访问造成的死机。
至此已经解决我们的问题了,IAR cm-backtrace 库下已经可以查看到调用栈了。