This question has been asked before and there have been windows-specific answers but no satisfactory gcc answer. I can use set_terminate()
to set a function that will be called (in place of terminate()
) when an unhandled exception is thrown. I know how to use the backtrace library to generate a stack trace from a given point in the program. However, this won't help when my terminate-replacement is called since at that point the stack has been unwound.
Yet if I simply allow the program to abort()
, it will produce a core-dump which contains the full stack information from the point at which the exception was thrown. So the information is there -- but is there a programmatic way to get it, for example so it can be logged, rather than having to examine a core file?
Edited Answer:
You can use 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();
}
giving this output:
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 ~>
assuming you have debug symbols in your binary, you can then use addr2line to construct a prettier stack trace postmortem
samm@macmini ~> addr2line 0x10000c18
/home/samm/foo.cc:23
samm@macmini ~>
original answer is below
I've done this in the past using boost::error_info to inject the stack trace using backtrace
from execinfo.h
into an exception that is thrown.
typedef boost::error_info<struct tag_stack_str,std::string> stack_info;
Then when catching the exceptions, you can do
} catch ( const std::exception& e ) {
if ( std::string const *stack boost::get_error_info<stack_error_info>(e) ) {
std::cout << stack << std::endl;
}
}