Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C堆栈跟踪中缺少函数调用_C++_C_Debugging_Gcc_Stack Trace - Fatal编程技术网

C++ C堆栈跟踪中缺少函数调用

C++ C堆栈跟踪中缺少函数调用,c++,c,debugging,gcc,stack-trace,C++,C,Debugging,Gcc,Stack Trace,我正在我的代码中导入一个堆栈跟踪C代码(在堆栈溢出的某处找到),以跟踪分配了内存块的位置: struct layout { struct layout *ebp; void *ret; }; struct layout *fr; __asm__("movl %%ebp, %[fp]" : /* output */ [fp] "=r" (fr)); for (int i=1 ; i<8 && (unsigned char*) fr > dsRAM; i++)

我正在我的代码中导入一个堆栈跟踪C代码(在堆栈溢出的某处找到),以跟踪分配了内存块的位置:

struct layout
{
  struct layout *ebp;
  void *ret;
};

struct layout *fr;
__asm__("movl %%ebp, %[fp]" :  /* output */ [fp] "=r" (fr));
for (int i=1 ; i<8 && (unsigned char*) fr > dsRAM; i++) {
  x[i] = (size_t) fr->ret;
  fr = fr->ebp;
}
我尝试使用
\uuuu内置\uReturn\uAddress()
,但是我用更长的代码得到了几乎相同的结果

编辑:我注意到我系统性地缺少了
操作符new的调用者
,如果_Znwj的代码没有设置堆栈帧,这可以解释。因此,问题清单变成:

  • 如果TestBasicScript()函数调用不在堆栈帧列表中,GDB如何找到它

  • 如何配置链接步骤,以便使用libstdc++的调试友好变体(如果有)


最初的子问题“是否有编译时选项可以保证我可以100%跟踪malloc克隆的调用?”由@chqrlie回答:
-O0
是我所需要的全部。但是,只有在所有我的二进制文件(包括共享库)上应用时,它才会有效。

编译器可能不会总是生成一个堆栈帧,其中
%ebp
指向前一帧。对于某些函数,它可能会生成使用基于
%esp
的寻址来检索参数的代码,对于其他函数,它可能会生成带有跳转的尾部递归,而不是调用/ret序列。尝试扫描堆栈跟踪时,堆栈跟踪可能不完整


尝试在禁用优化的情况下编译整个项目(
-O0
)。

有些框架可能会被忽略,例如内联和优化(尽管提供的cflag不包含优化标志,默认为AFAIK no optimization)

无论如何,对于GCC,有内置的堆栈遍历支持,通过使用
backtrace()
backtrace\u symbols()
,或者结合使用
abi::\uuucxa\u demangle()
,您也可以尝试这些

另一个选择是使用,我也尝试过,效果很好(在其源代码中,您可以看到一些用于应用程序内堆栈遍历的有用技术)

对于优化(发布)的可执行文件,上述所有操作通常都不能很好地工作,特别是如果它们不包含调试信息(尽管可能已生成并存储在一旁),那么打印的堆栈将毫无用处(除了由于优化而跳过的帧)

一种即使对优化代码也有效的终极技术是生成核心转储。这里有关于堆栈的所有信息(二进制文件本身不需要包含debuginfo,它可以放在一边,只用于脱机检查内核),作为堆栈上所有变量的附加值,还有关于当前运行的所有线程的信息等。 对于跟踪内存分配来说,这可能是一种过分的做法(速度也相当慢),但有时它会非常有用。在我的一个项目中,我创建了这样一个核心转储程序的工作实现,它仍然存在于生产代码中

请注意,您实际上可以在不终止应用程序的情况下生成应用程序的核心转储—我创建的实现基本上如下所示:

  • fork()
    应该生成核心转储的点处的进程
  • 子进程调用
    abort()
  • 原始父进程使用
    waitpid()
    等待子进程生成核心转储并终止(使用一个保护计数器不永远等待)
  • 然后原始进程继续运行(并将诊断核心与用于生成核心的分叉进程的PID一起生成的消息写入日志)
事实证明,这在某些情况下非常有效,因为发布生产应用程序需要诊断堆栈跟踪


编辑:我也尝试过的另一个选项是使用
ptrace()。其工作方式与此类似-通过
fork()
生成子进程,然后在其中调用
ptrace(ptrace\u TRACEME)
;然后,父进程可以发出各种
ptrace()
调用来检查子进程的堆栈(在
fork()
点上,它恰好与父进程的堆栈相同)。我认为libunwind源代码包含了它的用法,因此您可以在那里检查它。

谢谢,但不幸的是,
-O0
没有改变任何东西。
-mno也没有忽略叶帧指针
@PypeBros:您是否查看了为跟踪中缺失的函数生成的代码?不过,可能是我遗漏了什么。我的代码是用-O0编译的,但不是libstdc++。。。因此,如果_Znwj(operator new)不提供堆栈帧,它将中断跟踪,显示operator new调用方的堆栈帧,返回地址在operator new内……我本来以为我会使用
backtrace()
,但不幸的是,出于某种原因,它依赖于malloc。正如你自己所说的,堆芯倾倒在这里会有过多的杀伤力,而且很难进行后期处理。我将保留该技术用于其他用途。您也可以尝试使用gdb也使用的
ptrace()
(更新了帖子)谢谢,但我认为您缺少核心点。这不是关于我还可以使用什么来获取堆栈帧列表,而是关于“GDB使用了哪些额外的信息,允许它在没有堆栈帧支持的情况下在调用跟踪中向我显示一个项”。检查libunwind源代码,据我所知有一些“魔力”在某些情况下重建适当的堆栈帧。正如我所提到的,GDB似乎正在使用ptrace()调用,这
CFLAGS += -I libgeds/source/ -I wrappers -I $(DEVKITPRO)/include -DARM9 \
   -include wrappers/nds/system.h -include wrappers/fake.h
CFLAGS += -m32 -Duint=uint32_t -g -Wall -Weffc++ -fno-omit-frame-pointer