当Cortex-M3进入hardfault时,如何保留堆栈跟踪?

时间:2015-07-06 20:53:24

标签: c++ c cortex-m3 freertos

使用以下设置:

使用JLinkGDBServer和eclipse作为调试前端,在单步执行代码时总是有一个很好的堆栈跟踪。当使用Code Confidence freertos工具(eclipse插件)时,我也看到当前没有运行的所有线程的堆栈跟踪(没有该插件,我只看到活动线程的堆栈跟踪)。到目前为止一切都很好。

但是现在,当我的应用程序陷入严重错误时,堆栈跟踪就会丢失。 好吧,我知道如何找出导致硬错误的代码地址的技术(如here所示)。 但与完全堆栈跟踪相比,这是非常糟糕的信息。

好的,有时候当遇到硬错误时,无法保留堆栈跟踪,例如当堆栈被错误的代码破坏时。但是如果堆栈是健康的,我认为获得堆栈跟踪可能是可能的(不是吗?)。

我认为在硬错误中丢失堆栈跟踪的原因是,堆栈指针会被Cortex-M3架构自动从PSP切换到MSP。现在有一个想法,(可能)将MSP设置为之前的PSP值(并且可能需要进行一些额外的堆栈预制?)。

关于在硬错误中如何保留堆栈跟踪的方法或其他方法的任何建议?

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

我使用此代码挑起一个严厉的错误:

__attribute__((optimize("O0"))) static void checkHardfault() {
    volatile uint32_t* varAtOddAddress = (uint32_t*)-1;
    (*varAtOddAddress)++;
}

当进入checkHardfault()时,我的堆栈跟踪看起来很像这样:

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 ?? ()

当遇到硬错误((*varAtOddAddress)++;)并发现自己在HardFault_Handler()内时,堆栈跟踪是:

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?)

2 个答案:

答案 0 :(得分:1)

让调试器在硬故障之前为您提供状态详细信息的最快方法是将处理器恢复到硬故障之前的状态。

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

当然,当你最终遇到硬故障时,这并不总是有用的,因为从堆栈中弹出东西或者踩在内存中的东西。你通常倾向于破坏一堆重要的寄存器,回到内​​存中的一些疯狂的位置,然后执行那里的任何事情。在您遇到真正的问题后,最终可能会导致数千(数百万?)个周期出现故障。

答案 1 :(得分:0)

考虑使用以下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