Kev*_*vin 80 c windows debugging cross-platform stack-trace
我知道没有标准的C函数来做到这一点.我想知道Windows和*nix上的技术是什么?(Windows XP是我现在最重要的操作系统.)
san*_*iyn 79
glibc提供了backtrace()函数.
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Tom*_*Tom 28
有backtrace()和backtrace_symbols():
从手册页:
#include <execinfo.h>
#include <stdio.h>
...
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; ++i) {
printf("%s\n", strs[i]);
}
free(strs);
...
Run Code Online (Sandbox Code Playgroud)
以更方便/ OOP方式使用它的一种方法是将backtrace_symbols()的结果保存在异常类构造函数中.因此,无论何时抛出该类型的异常,都会有堆栈跟踪.然后,只提供打印出来的功能.例如:
class MyException : public std::exception {
char ** strs;
MyException( const std::string & message ) {
int i, frames = backtrace(callstack, 128);
strs = backtrace_symbols(callstack, frames);
}
void printStackTrace() {
for (i = 0; i
...
try {
throw MyException("Oops!");
} catch ( MyException e ) {
e.printStackTrace();
}
塔达!
注意:启用优化标志可能会导致生成的堆栈跟踪不准确.理想情况下,可以使用此功能启用调试标志并关闭优化标志.
Mar*_*ark 22
我们已经将它用于我们的项目:
https://www.codeproject.com/kb/threads/stackwalker.aspx
代码是一个混乱的恕我直言,但它运作良好.仅限Windows.
Chr*_*n.K 20
对于Windows,请检查StackWalk64()API(也在32位Windows上).对于UNIX,您应该使用操作系统的本机方式来执行此操作,或者如果可用,则回退到glibc的backtrace().
但是请注意,在本机代码中使用Stacktrace很少是一个好主意 - 不是因为它不可能,而是因为你在尝试实现错误的东西.
大多数时候人们试图在一个特殊情况下获得一个堆栈跟踪,例如当一个异常被捕获时,一个断言失败或者 - 最糟糕且最错误的是 - 当你得到致命的"异常"或信号如同分段违规.
考虑到最后一个问题,大多数API都要求您明确分配内存或者可以在内部执行.在您的程序目前所处的脆弱状态下这样做可能会使事情变得更糟.例如,崩溃报告(或coredump)不会反映问题的实际原因,但是您尝试处理它的失败.
我假设你正在努力实现致命错误处理的事情,因为大多数人似乎都在尝试使用堆栈跟踪.如果是这样,我将依赖调试器(在开发期间)并让进程coredump in production(或windows上的mini-dump).与适当的符号管理一起,您应该毫不费力地确定事后验证的原因.
小智 5
对于 Windows,CaptureStackBackTrace()这也是一个选项,它在用户端需要的准备代码比StackWalk64()原来少。(另外,对于我遇到的类似情况,CaptureStackBackTrace()最终比 工作得更好(更可靠)StackWalk64()。)
小智 5
您应该使用unwind 库。
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (ctr >= 10) break;
a[ctr++] = ip;
}
Run Code Online (Sandbox Code Playgroud)
除非您从共享库进行调用,否则您的方法也可以正常工作。
addr2lineLinux上可以使用该命令获取对应PC的源码函数/行号。
您可以通过向后遍历堆栈来完成此操作。但实际上,在每个函数开头将标识符添加到调用堆栈并在末尾弹出它,然后只需打印内容通常更容易。它有点像 PITA,但效果很好,最终会节省您的时间。