谦逊的面包 · Entity Framework 异常: ...· 2 周前 · |
忧郁的皮带 · DateTimeOffset 建構函式 ...· 1 周前 · |
难过的盒饭 · 花费110从哥布林洞窟中救出的女骑士_哔哩哔 ...· 5 月前 · |
不爱学习的墨镜 · 如何报答救命恩人? - 现世情人是尾狐 - ...· 1 年前 · |
冲动的梨子 · 木村心美声优出道 ...· 1 年前 · |
光明磊落的葫芦 · 与腾讯达成数字化合作 “2020 ...· 1 年前 · |
坏坏的饭盒 · 她是我的全部_百度百科· 1 年前 · |
我希望有一种方法可以在抛出异常时向用户报告堆栈跟踪。做这件事最好的方法是什么?这需要大量的额外代码吗?
回答问题的步骤:
如果可能的话,我希望它是便携的。我希望弹出信息,这样用户就可以复制堆栈跟踪,并在出现错误时通过电子邮件发送给我。
这取决于哪种平台。
在GCC上,这是相当微不足道的,更多细节请参见 this post 。
在MSVC上,您可以使用 StackWalker 库来处理Windows所需的所有底层API调用。
您必须找出将此功能集成到应用程序中的最佳方法,但您需要编写的代码量应该是最少的。
在Windows上,请查看 BugTrap 。它不再是原来的链接,但它仍然可以在CodeProject上使用。
AFAIK libunwind非常便携,到目前为止我还没有发现更容易使用的东西。
Cpp-tool ex_diag - easyweight,多平台,最少的资源使用,简单灵活的跟踪。
Poppy 不仅可以收集堆栈跟踪,还可以收集参数值、局部变量等导致崩溃的所有信息。
下面的代码在抛出异常后立即停止执行。您需要设置一个windows_exception_handler和一个终止处理程序。我在MinGW 32位上测试了这一点。
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
int main(int argc, char *argv[])
SetUnhandledExceptionFilter(windows_exception_handler);
}
检查windows_exception_handler函数的以下代码: http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
我也有类似的问题,虽然我喜欢可移植性,但我只需要gcc的支持。在gcc中,execinfo.h和 backtrace 调用都是可用的。为了分解函数名,Bingmann先生让 a nice piece of code. 在异常上转储回溯,我创建了一个在构造函数中打印回溯的异常。如果我希望它能处理库中抛出的异常,它可能需要重新构建/链接,以便使用回溯异常。
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
print_stacktrace();
void chicken(void)
throw btoverflow_error( "too big" );
void duck(void)
chicken();
void turkey(void)
duck();
int main( int argc, char *argv[])
turkey();
catch( btoverflow_error e)
printf( "caught exception: %s\n", e.what() );
}
使用gcc 4.8.4编译和运行这段代码会产生一个回溯,其中包含无误的C++函数名称:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
我推荐 http://stacktrace.sourceforge.net/ 项目。它支持Windows、Mac OS和Linux
如果您使用的是Boost 1.65或更高版本,则可以使用 boost::stacktrace
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
如果你正在使用C++,并且不想/不能使用Boost,你可以使用下面的代码 [link to the original site] 打印带有不同名称的回溯。
请注意,此解决方案特定于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++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// 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);
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
free(funcname);
free(symbollist);
#endif // _STACKTRACE_H_
哈!
OSX的一个工作示例(现在在Catalina 10.15上测试)。显然不能移植到linux/windows上。这可能会对某些人有用。
在"Mew-exception“字符串中,您可以使用回溯和/或backtrace_symbols函数
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
int a = 10; ++a;
throw std::runtime_error("Mew!");
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
谦逊的面包 · Entity Framework 异常: 'OFFSET' 附近有语法错误。\r\n在 FETCH 语句中选项 NEXT 的用法无效。\r\n关键字 'AS' 附近有语法错误。 - 不是豆豆 - 博客 2 周前 |
坏坏的饭盒 · 她是我的全部_百度百科 1 年前 |