简体   繁体   English

ARM cortex-M4 上的堆栈跟踪

[英]Stacktrace on ARM cortex-M4

When I run into a fault handler on my ARM cortex-M4 (Thumb) I get a snapshot of the CPU register just before the fault occured.当我在 ARM cortex-M4 (Thumb) 上遇到故障处理程序时,我会在故障发生之前获得 CPU 寄存器的快照。 With this information I can find the stack pointer where it was.有了这些信息,我可以找到堆栈指针所在的位置。 Now, what I want is to backtrace through all functions it passed.现在,我想要的是回溯它通过的所有函数。 The only problem I see here is that I don't have a frame pointer, so I cannot really see where a certain subroutine has saved the LR, ad infinitum.我在这里看到的唯一问题是我没有帧指针,所以我无法真正看到某个子程序在哪里保存了 LR,无穷无尽。

How would one tackle this problem if the frame pointer is not available in r7?如果帧指针在 r7 中不可用,如何解决这个问题?

This blog post discusses this issue with reference to the MIPS architecture - the principles can be readily adapted to ARM architectures. 这篇博客文章参考 MIPS 架构讨论了这个问题 - 这些原则可以很容易地适应 ARM 架构。

In short, it describes three possibilities for locating the stack frame for a given SP and PC:简而言之,它描述了为给定的 SP 和 PC 定位堆栈帧的三种可能性:

  • Using compiler-generated debug information (not included in the executable image) to calculate it.使用编译器生成的调试信息(不包含在可执行映像中)来计算它。
  • Using compiler-generated stack-unwinding (exception handling) information (included in the executable image) to calculate it.使用编译器生成的堆栈展开(异常处理)信息(包含在可执行映像中)来计算它。
  • Scanning the call site to locate the prologue or epilogue code that adjusts the stack pointer, and deducing the stack frame address from that.扫描调用站点以定位调整堆栈指针的序言或尾声代码,并从中推导出堆栈帧地址。

Obviously it's very compiler- and compiler-option dependent, and not guaranteed to work in all cases.显然,它非常依赖于编译器和编译器选项,并不能保证在所有情况下都能正常工作。

R7 is not the frame pointer on the M4, it's R11. R7 不是 M4 上的帧指针,而是 R11。 R7 is the FP for Cortex-M0+/M1 where only the lower registers are generally available. R7 是 Cortex-M0+/M1 的 FP,通常只有较低的寄存器可用。 In anycase, when Cortex-M makes a call to a function using BL and variants, it saves the return address into LR (link register).无论如何,当 Cortex-M 使用 BL 和变体调用函数时,它会将返回地址保存到 LR(链接寄存器)中。 At function entry, the LR is saved onto the stack.在函数入口处,LR 被保存到堆栈中。 So in theory, to get a call trace, you would "chase" the chain of the LRs.所以理论上,要获得呼叫跟踪,您将“追踪”LR 链。

Unfortunately , the saved location of LR on the stack is not defined by the calling convention, and its location must be deduced from the debug info for that function entry in the DWARF records (in the .elf file).不幸的是,LR 在堆栈上的保存位置不是由调用约定定义的,它的位置必须从 DWARF 记录(在 .elf 文件中)中该函数条目的调试信息中推导出来。 I do not know if there is an utility that would extract the LR locations from an ELF file, but it should not be too difficult.我不知道是否有可以从 ELF 文件中提取 LR 位置的实用程序,但应该不会太难。

Richard at ImageCraft is right. ImageCraft 的 Richard 是对的。

More information can be found here更多信息可以在这里找到

This works fine with C code.这适用于 C 代码。 I had a harder applying it to C++ but it's not impossible.我更难将它应用于 C++,但这并非不可能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM