2

我想创建一个调试工具来帮助我更好地调试我的应用程序。我正在做准系统(没有操作系统)。在 Atmel 的 SAM3 上使用 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 ;

}
4

5 回答 5

6

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

于 2014-04-19T17:36:34.107 回答
4

要使用 ARM 执行此操作,您需要告诉编译器生成堆栈帧。例如使用 gcc,检查选项-mapcs-frame. 它可能不是您需要的,但这将是一个开始。

如果你没有这个,几乎不可能“展开”堆栈,因为你需要根据参数和局部变量为每个函数提供确切的堆栈使用情况。

如果您正在寻找一些示例代码,您可以查看dump_stack()Linux 内核源代码,并找到为 ARM 执行的相关代码。

于 2012-07-04T11:41:38.600 回答
3

遵循执行应该非常简单。不在您的 isr 中以编程方式...

我们从 ARM 知道,在 Cortex-M3 上,它会将 xPSR、ReturnAddress、LR (R14)、R12、R3、R2、R1 和 R0 推入堆栈。破坏 lr 以便它可以检测到中断返回,然后调用向量表中列出的入口点。如果你在 asm 中实现你的 isr 来控制堆栈,你可以有一个简单的循环来禁用中断源(关闭 wdt,无论如何,这将需要一些时间)然后进入循环转储一部分堆。

从该转储中,您将看到 lr/返回地址,被中断的函数/指令,从程序的反汇编中,您可以看到编译器为每个函数放置在堆栈上的内容,在每个阶段减去它并继续回溯到您喜欢的回溯或回溯到您打印堆栈内容的回溯。

您还可以在 ram 中制作堆栈的副本并稍后对其进行剖析,而不是在 isr 中执行此类操作(副本仍然需要太多时间,但比在 uart 上等待的干扰要小)。

如果你所追求的只是被中断的指令的地址,那是最简单的任务,只需从堆栈中读取它,它将在一个已知的位置,然后打印出来。

于 2012-07-04T14:51:48.423 回答
2

我听到我的名字了吗?:)

您可能需要一点内联汇编。只需弄清楚堆栈帧的格式,以及哪个寄存器保存普通的1堆栈指针,并将相关值传输到 C 变量中,您可以从中格式化字符串以输出到 UART。

它不应该太棘手,但当然(相当低级)你需要注意细节。

1如“无例外”;实际上,不确定ARM是否对普通代码和异常有不同的堆栈。

于 2012-07-04T09:11:55.787 回答
0

你的看门狗定时器可以在任何时候触发,即使堆栈不包含足够的信息来展开(例如,堆栈空间已分配给寄存器溢出,但寄存器尚未复制)。

对于适当优化的代码,您需要调试信息、句号。看门狗定时器所能做的就是寄存器和堆栈转储,其格式机器可读,足以允许转换为gdb.

于 2012-07-04T12:04:14.280 回答