【问题标题】:Stacktrace on ARM cortex-M4ARM cortex-M4 上的堆栈跟踪
【发布时间】:2017-06-23 15:25:47
【问题描述】:

当我在 ARM cortex-M4 (Thumb) 上遇到故障处理程序时,我会在故障发生之前获得 CPU 寄存器的快照。有了这些信息,我可以找到它所在的堆栈指针。现在,我想要的是回溯它传递的所有函数。我在这里看到的唯一问题是我没有帧指针,所以我无法真正看到某个子程序将 LR 无限保存在哪里。

如果帧指针在 r7 中不可用,如何解决这个问题?

【问题讨论】:

  • 反汇编代码,看看栈上有什么。
  • 你用的是什么调试器?我知道 Keil Uvision 上有一个调用堆栈。你是不是在绊倒某种陷阱?
  • @KooroshHajiani 我没有使用调试器,我的目标正在免费运行并且具有日志记录(printf 样式)功能。
  • 在某些情况下,无法返回的函数(因为while (1) 或其他原因)不会推送 LR,因为它永远不会再次使用它。在这些情况下,您可以在 while (while (dummy == 0)) 中使用非常量对象全局变量来欺骗编译器,并使其认为函数可以返回。这是否符合您的问题?

标签: c arm cortex-m


【解决方案1】:

This blog post 参考 MIPS 架构讨论了这个问题 - 这些原则可以很容易地适应 ARM 架构。

简而言之,它描述了为给定 SP 和 PC 定位堆栈帧的三种可能性:

  • 使用编译器生成的调试信息(不包含在可执行映像中)进行计算。
  • 使用编译器生成的堆栈展开(异常处理)信息(包含在可执行映像中)进行计算。
  • 扫描调用站点以找到调整堆栈指针的序言或尾声代码,并从中推断出堆栈帧地址。

显然它非常依赖于编译器和编译器选项,并且不能保证在所有情况下都能正常工作。

【讨论】:

  • 在 SO 上有无数关于尝试使用 (gnu) 工具检查堆栈跟踪的 cortex-m 问题,听起来好像被打破了。只需查看代码以及您在其中的位置即可了解如何展开堆栈(反汇编和当前 pc 和 sp 值)。
  • @old_timer:第三种技术正是这样做的 - 以编程方式,根据 OP,但手动检查应用相同的原则。
【解决方案2】:

R7 不是 M4 上的帧指针,而是 R11。 R7 是 Cortex-M0+/M1 的 FP,通常只有较低的寄存器可用。无论如何,当 Cortex-M 使用 BL 和变体调用函数时,它会将返回地址保存到 LR(链接寄存器)中。在函数入口处,LR 被保存到堆栈中。所以理论上,要获得调用跟踪,你会“追逐” LR 链。

不幸的是,LR 在堆栈上的保存位置不是由调用约定定义的,它的位置必须从 DWARF 记录中该函数条目的调试信息中推断出来(在 . .elf 文件)。我不知道是否有一个实用程序可以从 ELF 文件中提取 LR 位置,但应该不会太难。

【讨论】:

    【解决方案3】:

    ImageCraft 的 Richard 是对的。

    更多信息可以找到here

    这适用于 C 代码。我很难将它应用到 C++ 中,但这并非不可能。

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    猜你喜欢
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 2018-09-29
    • 2017-12-03
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 2016-03-01
    相关资源
    最近更新 更多