C++ 当Cortex-M3出现硬故障时,如何保留堆栈跟踪?

C++ 当Cortex-M3出现硬故障时,如何保留堆栈跟踪?,c++,c,cortex-m3,freertos,C++,C,Cortex M3,Freertos,使用以下设置: 基于Cortex-M3的µC 使用C和C++ FreeRtos 7.5.3 月蚀 Segger Jlink与JLinkGDBServer 使用JLinkGDBServer和eclipse作为调试前端,我在遍历代码时总是有一个很好的stacktrace。在使用Code freertos工具(eclipse插件)时,我还可以看到当前未运行的所有线程的堆栈跟踪(没有该插件,我只看到活动线程的堆栈跟踪)。到目前为止还不错 但是现在,当我的应用程序陷入硬故障时,stacktrace

使用以下设置:

  • 基于Cortex-M3的µC
  • 使用C和C++
  • FreeRtos 7.5.3
  • 月蚀
  • Segger Jlink与JLinkGDBServer
使用JLinkGDBServer和eclipse作为调试前端,我在遍历代码时总是有一个很好的stacktrace。在使用Code freertos工具(eclipse插件)时,我还可以看到当前未运行的所有线程的堆栈跟踪(没有该插件,我只看到活动线程的堆栈跟踪)。到目前为止还不错

但是现在,当我的应用程序陷入硬故障时,stacktrace就丢失了。 我知道如何找出导致硬故障的代码地址的技术(如图所示)。 但与完整stacktrace相比,这是非常糟糕的信息

好的,有时当陷入硬故障时,无法保留堆栈跟踪,例如,当堆栈被故障代码损坏时。但是如果堆栈是健康的,我认为获取堆栈跟踪是可能的(不是吗?)

我认为在hardfault中丢失stacktrace的原因是,Cortex-M3架构会自动将stackpointer从PSP切换到MSP。一个想法是,现在(可能)将MSP设置为之前的PSP值(可能需要做一些额外的堆栈准备?)

在硬故障情况下,有没有关于如何这样做或其他方法来保留stacktrace的建议

编辑2015-07-07,添加更多详细信息

我使用此代码来挑衅硬故障:

__attribute__((optimize("O0"))) static void checkHardfault() {
    volatile uint32_t* varAtOddAddress = (uint32_t*)-1;
    (*varAtOddAddress)++;
}
当进入
checkHardfault()
时,我的stacktrace看起来像这样:

gdb-> backtrace
#0  checkHardfault () at Main.cxx:179
#1  0x100360f6 in GetOneEvent () at Main.cxx:185
#2  0x1003604e in executeMainLoop () at Main.cxx:121
#3  0x1001783a in vMainTask (pvParameters=0x0) at Main.cxx:408
#4  0x00000000 in ?? ()
当运行到硬故障(在
(*varatodaddress)+
)并发现自己在
硬故障处理程序()中时,堆栈跟踪是:

gdb-> backtrace
#0  HardFault_Handler () at Hardfault.c:312
#1  <signal handler called>
#2  0x10015f36 in prvPortStartFirstTask () at freertos/portable/GCC/ARM_CM3/port.c:224
#3  0x10015fd6 in xPortStartScheduler () at freertos/portable/GCC/ARM_CM3/port.c:301
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
gdb->backtrace
#0 HardFault\u处理程序()位于HardFault.c:312
#1  
#freertos/portable/GCC/ARM_CM3/port.c:224处prvPortStartFirstTask()中的2 0x10015f36
#freertos/portable/GCC/ARM_CM3/port.c:301上的xPortStartScheduler()中的3 0x10015fd6
回溯已停止:此帧内部的上一帧(堆栈损坏?)

让调试器向您提供硬故障之前状态的详细信息的最快方法是将处理器返回到硬故障之前的状态

在调试器中,编写一个脚本,从各种硬件寄存器获取信息,并将PC、LR、R0-R14恢复到导致硬故障之前的状态,然后执行堆栈转储


当然,这并不总是有帮助的,当你最终在硬故障,因为弹出的东西从一个吹堆栈或跺脚的东西在内存中。您通常会损坏一堆重要的寄存器,返回内存中的某个疯狂点,然后执行其中的任何内容。在真正的问题发生后,您可能会导致数千(数百万?)个周期的硬断层

考虑使用以下gdb宏恢复寄存器内容:

define hfstack
    set $frame_ptr = (unsigned *)$sp
    if $lr & 0x10
        set $sp = $frame_ptr + (8 * 4)
    else
        set $sp = $frame_ptr + (26 * 4)
    end
    set $lr = $frame_ptr[5]
    set $pc = $frame_ptr[6]
    bt
end

document hfstack
set the correct stack context after a hard fault on Cortex M
end

我可以给你一个STM32的解决方案,它是基于大脑皮层的。请看我在类似问题上给出的两个答案,并且(这一个更详细,因为它指的是你问题范围之外的一个特定问题)。如果记忆正常,然后PC和LR在中断发生之前将最后两个函数的地址存储在调用堆栈中,R0到R3存储传递给这些函数的参数。建议的解决方案与上所述的相同(正如我在问题中也提到的)。它只是给
PC
留下了一个提示,最终导致了硬故障(以及
LR
中的一个调用级别,正如我现在从您的评论中了解到的),但它不会提供堆栈跟踪。@Joe您能在这方面取得进展吗?事实证明,我也处于类似的情况