来自未处理异常的c ++堆栈跟踪?

c-u*_*hin 31 c++ callstack exception-handling stack-trace unhandled-exception

之前已经问过这个问题,并且有特定于Windows的答案,但没有令人满意的gcc答案.我可以set_terminate()用来设置一个函数,terminate()当抛出未处理的异常时,该函数将被调用(代替).我知道如何使用backtrace库从程序中的给定点生成堆栈跟踪.但是,当我的终止替换被调用时,这将无济于事,因为此时堆栈已被解除.

然而,如果我只是允许程序abort(),它将产生一个核心转储,其中包含从抛出异常的点开始的完整堆栈信息.所以信息就在那里 - 但是有没有一种编程方式来获取它,例如它可以被记录,而不是必须检查核心文件?

Sam*_*ler 28

编辑答案:

您可以使用std :: set_terminate

#include <cstdlib>
#include <iostream>
#include <stdexcept>

#include <execinfo.h>

void
handler()
{
    void *trace_elems[20];
    int trace_elem_count(backtrace( trace_elems, 20 ));
    char **stack_syms(backtrace_symbols( trace_elems, trace_elem_count ));
    for ( int i = 0 ; i < trace_elem_count ; ++i )
    {
        std::cout << stack_syms[i] << "\n";
    }
    free( stack_syms );

    exit(1);
}   

int foo()
{
    throw std::runtime_error( "hello" );
}   

void bar()
{
    foo();
}

void baz()
{
    bar();
}

int
main()
{
    std::set_terminate( handler );
    baz();
}
Run Code Online (Sandbox Code Playgroud)

给出这个输出:

samm@macmini ~> ./a.out 
./a.out [0x10000d20]
/usr/lib/libstdc++.so.6 [0xf9bb8c8]
/usr/lib/libstdc++.so.6 [0xf9bb90c]
/usr/lib/libstdc++.so.6 [0xf9bbaa0]
./a.out [0x10000c18]
./a.out [0x10000c70]
./a.out [0x10000ca0]
./a.out [0x10000cdc]
/lib/libc.so.6 [0xfe4dd80]
/lib/libc.so.6 [0xfe4dfc0]
samjmill@bgqfen4 ~> 
Run Code Online (Sandbox Code Playgroud)

假设你的二进制文件中有调试符号,那么你可以使用addr2line构建一个更漂亮的堆栈跟踪postmortem

samm@macmini ~> addr2line 0x10000c18
/home/samm/foo.cc:23
samm@macmini ~> 
Run Code Online (Sandbox Code Playgroud)

原始答案如下


我一直在使用,在过去这样做的boost :: ERROR_INFO注射使用堆栈跟踪backtraceexecinfo.h入所引发的异常.

typedef boost::error_info<struct tag_stack_str,std::string> stack_info;
Run Code Online (Sandbox Code Playgroud)

然后,当捕获异常时,您可以这样做

} catch ( const std::exception& e ) {                                                                                                            
    if ( std::string const *stack boost::get_error_info<stack_error_info>(e) ) {                    
        std::cout << stack << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 山姆,你的榜样是邪恶的.它改变了你的用户名和主机名;-) (4认同)
  • @AlexKremer YMMD:D (2认同)