在C中调用堆栈回溯

我试图在我的断言/exception处理程序中获取调用堆栈回溯。 不能include "execinfo.h"因此不能使用int backtrace(void **buffer, int size); 。 此外,尝试使用__builtin_return_address()但根据: http : //codingrelic.geekhold.com/2009/05/pre-mortem-backtracing.html

…在一些架构上,包括我心爱的MIPS,只有__builtin_return_address(0)可以正常工作.MIPS没有帧指针,这使得很难向后走回堆栈。 帧0可以直接使用返回地址寄存器。

如何重现完整的调用堆栈回溯?

我已成功使用此处描述的方法,从MIPS32上的堆栈获取调用跟踪。

然后,您可以打印出调用堆栈:

 void *retaddrs[16]; int n, i; n = get_call_stack_no_fp (retaddrs, 16); printf ("CALL STACK: "); for (i = 0; i < n; i++) { printf ("0x%08X ", (uintptr_t)retaddrs[i]); } printf ("\r\n"); 

...如果你有ELF文件,那么使用addr2line将返回地址转换为函数名:

 addr2line -a -f -p -e xxxxxxx.elf addr addr ... 

当使用这样的方法时,包括中断和exception处理程序或代码优化结果当然有很多问题。 但是,它有时可能会有所帮助。

我已成功使用@Erki A建议的方法并在此处进行了描述。 以下是该方法的简短摘要:

问题:
获得没有帧指针的调用堆栈。 解决方案主要思想:从汇编代码中总结调试器从调试信息中理解的内容。 我们需要的信息: 1。保留退货地址的地方。 2.堆栈指针递减的数量。

要重现整个堆栈跟踪,需要:

  1. Get the current $sp and $ra 2. Scan towards the beginning of the function and look for "addui sp,sp,spofft" command (spofft<0) 3. Reprodece prev. $sp (sp- spofft) 4. Scan forward and look for "sw r31,raofft(sp)" 5. Prev. return address stored at [sp+ raofft] 

上面我描述了一次迭代。 当$ ra为0时你停止。如何获得第一个$ ra?

  __builtin_return_address(0) 

如何获得第一个$ sp?

  register unsigned sp asm("29"); asm("" : "=r" (sp)); 

***由于我的大多数文件都是使用micro-mips优化编译的,因此我不得不处理micro-mips-ISA。 当我尝试分析使用microMips优化编译的代码时出现了很多问题(请记住,每一步的目标都是重现prev.ra和prev.sp):它使事情变得更复杂:

  1. ra ($31) register contain unaligned return address. You may find more information at Linked questions. The unaligned ra helps you understand that you run over different ISA(micro-mips-isa) 2. There are functions that do not move the sp. You can find more information [here][3]. (If a "leaf" function only modifies the temporary registers and returns to a return statement in its caller's code, then there is no need for $ra to be changed, and there is no need for a stack frame for that function.) 3. Functions that do not store the ra 4. MicroMips instructions can be both - 16bit and 32bit: run over the commnds using unsinged short*. 5. There are functions that perform "addiu sp, sp, spofft" more than once 6. micro-mips-isa has couple variations for the same command for example: addiu,addiusp. 

我已经决定忽略部分问题,这就是为什么它适用于95%的案例。