ARM cortex m3中的调用堆栈展开

tvmytwxo  于 2023-08-03  发布在  其他
关注(0)|答案(5)|浏览(121)

我想创建一个调试工具,这将有助于我更好地调试我的应用程序。我正在使用bare-bones(没有操作系统)。在Atmel的SAM 3上使用IAR嵌入式工作台。
我有一个看门狗定时器,它在超时的情况下调用特定的IRQ(这将在发布时被软件重置所取代)。在IRQ处理程序中,我想打印出(UART)堆栈跟踪,即看门狗超时发生的确切位置。
我在网上找了找,没有找到任何实现该功能的。
有人知道如何处理这种事情吗?
编辑:好的,我设法从堆栈中获取了返回地址,所以我确切地知道WDT超时发生的位置。展开整个堆栈并不像它最初出现时那么简单,因为每个函数将不同数量的局部变量推入堆栈。
我最终得到的代码是这样的(对于其他人来说,他们可能会发现它很有用)

void WDT_IrqHandler( void )
{
    uint32_t * WDT_Address;
    Wdt *pWdt = WDT ;
    volatile uint32_t dummy ;
    WDT_Address = (uint32_t *) __get_MSP() + 16 ;
    LogFatal ("Watchdog Timer timeout,The Return Address is %#X", *WDT_Address);
    /* Clear status bit to acknowledge interrupt */
    dummy = pWdt->WDT_SR ;

}

字符串

2w2cym1i

2w2cym1i1#

ARM定义了一对节,.ARM.exidx和.ARM.extbl,它们包含足够的信息来展开堆栈,而不需要调试符号。这些部分用于异常处理,但您也可以使用它们来执行回溯。添加-funwind-tables以强制GCC包含这些部分。

af7jpaap

af7jpaap2#

它应该是相当直接的前进,以遵循执行。不是在你的isr中编程。。
我们从ARM ARM知道,在Cortex-M3上,它将xPSR、ReturnAddress、LR(R14)、R12、R3、R2、R1和R 0推送到堆栈上。mangles的LR,使它可以检测从中断返回,然后调用入口点列在向量表。如果你在asm中实现你的isr来控制堆栈,你可以有一个简单的循环来禁用中断源(关闭wdt,不管怎样,这将花费一些时间),然后进入一个循环来转储堆栈的一部分。
从这个转储文件中,你会看到lr/return地址,被中断的函数/指令,从程序的反汇编中,你可以看到编译器为每个函数在堆栈上放置了什么,在每个阶段减去它,然后尽可能地回到你喜欢的位置,或者尽可能地回到你打印的堆栈内容。
你也可以在ram中复制一个栈,然后再分析它,而不是在isr中做这样的事情(复制仍然需要太多的时间,但比等待uart的干扰更小)。
如果你所追求的只是被中断的指令的地址,这是最琐碎的任务,只需从堆栈中读取它,它将位于已知的位置,并将其打印出来。

h4cxqtbf

h4cxqtbf3#

要在ARM上实现这一点,您需要告诉编译器生成堆栈帧。例如使用gcc,选中选项-mapcs-frame。它可能不是你需要的,但这将是一个开始。
如果你没有这个,几乎不可能“展开”堆栈,因为你需要每个函数的确切堆栈使用情况取决于参数和局部变量。
如果您正在寻找一些示例代码,您可以在Linux内核源代码中检查dump_stack(),并找到为ARM执行的相关代码。

ycl3bljg

ycl3bljg4#

我听到我的名字了吗?:)
您可能需要一点内联汇编。只需确定堆栈帧的格式,以及哪个寄存器保存ordinary 1堆栈指针,并将相关值传输到C变量中,您可以从中格式化字符串以输出到UART。
这不应该太棘手,但当然(相当低级)你需要注意细节。
1如“非例外”;我不确定ARM是否对普通代码和异常有不同的堆栈。

relj7zay

relj7zay5#

您的看门狗定时器可以在任何时候触发,即使堆栈没有包含足够的信息来展开(例如堆栈空间已被分配用于寄存器溢出,但寄存器尚未被复制)。
对于正确优化的代码,您需要调试信息,句号。从看门狗定时器中可以做的只是一个寄存器和堆栈转储,其格式必须是机器可读的,足以允许转换为gdb的核心转储。

相关问题