C语言中的调用堆栈回溯

C语言中的调用堆栈回溯,c,gcc,mips,C,Gcc,Mips,我试图在断言/异常处理程序中获取调用堆栈回溯。不能包括“execinfo.h”因此不能使用int backtrace(void**buffer,int size)。 此外,尝试使用\u内置\u返回\u地址(),但符合以下要求: 。。。在某些体系结构上,包括我心爱的MIPS,只有内置返回地址(0)起作用。MIPS没有帧指针,因此很难返回堆栈。帧0可以直接使用返回地址寄存器 如何重现完整的调用堆栈回溯?我已成功使用所述方法,从MIPS32上的堆栈获取调用跟踪 然后可以打印出调用堆栈: void *r

我试图在断言/异常处理程序中获取调用堆栈回溯。不能
包括“execinfo.h”
因此不能使用
int backtrace(void**buffer,int size)。
此外,尝试使用
\u内置\u返回\u地址()
,但符合以下要求:

。。。在某些体系结构上,包括我心爱的MIPS,只有内置返回地址(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");

当使用这样的方法时,当然会有很多陷阱,包括中断和异常处理程序或代码优化的结果。不过,它有时可能会有所帮助。

我已经成功地使用了所描述的方法,从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");

当使用这样的方法时,当然会有很多陷阱,包括中断和异常处理程序或代码优化的结果。但尽管如此,它有时可能会有所帮助。

我已经成功地使用了@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] 
如何获得第一个$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%的情况下有效。

我成功地使用了@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] 
如何获得第一个$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%的情况。

“不能包含“execinfo.h”,因为它在我的平台中缺失。(错误1致命错误:execinfo.h:没有这样的文件或目录…)好的,那么我想那是因为缺少帧指针。。。看起来有一个巨大的路障挡在你的路上。你是否尝试过
#include
而不是
#include“execinfo.h”
?我不记得它在gcc上是否重要,但在某些编译器上确实重要。如果可以的话,你真的应该使用
backtrace()
,因为它很酷。试过了,它很酷,但是不见了…”不能包括“execinfo.h”,因为它在我的平台上不见了。(错误1致命错误:execinfo.h:没有这样的文件或目录…)好的,那么我想那是因为缺少帧指针。。。看起来有一个巨大的路障挡在你的路上。你是否尝试过
#include
而不是
#include“execinfo.h”
?我不记得它在gcc上是否重要,但在某些编译器上确实重要。如果可以的话,你真的应该使用
backtrace()
,因为它很酷。试过了,它很酷,但是不见了。。。