C++ 在异常时显示堆栈跟踪
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/691719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ display stack trace on exception
提问by rlbond
I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
如果抛出异常,我想有一种方法向用户报告堆栈跟踪。做这个的最好方式是什么?是否需要大量额外的代码?
To answer questions:
回答问题:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
如果可能的话,我希望它是便携式的。我希望弹出信息,以便用户可以复制堆栈跟踪,并在出现错误时通过电子邮件将其发送给我。
采纳答案by Andrew Grant
It depends which platform.
这取决于哪个平台。
On GCC it's pretty trivial, see this postfor more details.
在 GCC 上它非常简单,有关更多详细信息,请参阅此帖子。
On MSVC then you can use the StackWalkerlibrary that handles all of the underlying API calls needed for Windows.
在 MSVC 上,您可以使用StackWalker库来处理 Windows 所需的所有底层 API 调用。
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
您必须找出将此功能集成到您的应用程序中的最佳方式,但您需要编写的代码量应该最少。
回答by Thomas Tempelmann
Andrew Grant's answer does nothelp getting a stack trace of the throwingfunction, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
Andrew Grant 的回答无助于获取抛出函数的堆栈跟踪,至少在 GCC中没有帮助,因为 throw 语句不会自行保存当前堆栈跟踪,并且 catch 处理程序将无法访问堆栈跟踪那一点再说。
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
使用 GCC 解决此问题的唯一方法是确保在 throw 指令点生成堆栈跟踪,并将其与异常对象一起保存。
This method requires, of course, that every code that throws an exception uses that particular Exception class.
当然,此方法要求抛出异常的每个代码都使用该特定的 Exception 类。
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net- I haven't used it yet but it looks promising.
2017 年 7 月 11 日更新:有关一些有用的代码,请查看 cahit beyaz 的答案,该答案指向http://stacktrace.sourceforge.net- 我还没有使用它,但看起来很有希望。
回答by vasek
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
如果您使用的是 Boost 1.65 或更高版本,则可以使用boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
回答by bobobobo
回答by GPMueller
I would like to add a standard library option(i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
我想添加一个标准库选项(即跨平台)如何生成异常回溯,该选项已在C++11 中可用:
Use std::nested_exception
and std::throw_with_nested
使用std::nested_exception
和std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing. It is described on StackOverflow hereand here, how you can get a backtrace on your exceptionsinside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
这不会给你一个堆栈放松,但在我看来是下一个最好的事情。在此处和此处的StackOverflow 上进行了描述,您可以通过简单地编写一个适当的异常处理程序来重新抛出嵌套异常,从而在不需要调试器或繁琐的日志记录的情况下获得代码中异常的回溯。
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
由于您可以使用任何派生的异常类来执行此操作,因此您可以向此类回溯添加大量信息!您也可以在 GitHub 上查看我的MWE,其中的回溯如下所示:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
回答by cahit beyaz
I recommend http://stacktrace.sourceforge.net/project. It support Windows, Mac OS and also Linux
我推荐http://stacktrace.sourceforge.net/项目。它支持 Windows、Mac OS 和 Linux
回答by sundeep singh
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
如果您使用的是 C++ 并且不想/不能使用 Boost,您可以使用以下代码[link to the original site]打印带有 demangled 名称的回溯。
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
请注意,此解决方案特定于 Linux。它使用 GNU 的 libc 函数 backtrace()/backtrace_symbols()(来自 execinfo.h)来获取回溯,然后使用 __cxa_demangle()(来自 cxxabi.h)来对回溯符号名称进行整理。
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '##代码##';
*begin_offset++ = '##代码##';
*end_offset = '##代码##';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
哼!
回答by Nico Brailovsky
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
AFAIK libunwind 非常便携,到目前为止我还没有发现任何更容易使用的东西。
回答by Nico Brailovsky
回答by Tasos Parisinos
on linux with g++ check out this lib
在带有 g++ 的 linux 上查看这个库
https://sourceforge.net/projects/libcsdbg
https://sourceforge.net/projects/libcsdbg
it does all the work for you
它为您完成所有工作