/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; ckerlin
@ license LGPL , see file < a href = " license.html " > COPYING < / a >
*/
# include <mrw/stacktrace.hpp>
# include <mrw/exception.hpp>
# include <csignal>
# include <exception>
# include <iostream>
namespace mrw {
/** @addtogroup grpStackTrace */
//@{
/** @defgroup AutoTrace Automated Unexpected and Terminate Handler
with Stack Trace
@ brief Don ' t care about the unexpected handler , don ' t care about
a try - catch in the main , let the library do all the repetitive
work for you .
For all your programs it is recommended to implement an
identical unexpected handler , that rethrows , catches the @ c
mrw : : exception , @ c std : : exception and all unknown exceptions ,
traces them and finally quits with a throw of a @ c
std : : bad_exception . You are also required to write a @ c try @ c
catch block around all in your @ c main , so that you don ' t miss
any exception . The only thing that may be different from project
to project is , how tracing is done . The MRW C + + Class Library
provides you with additional libraries you can link to . By
linking to the library , you get an unexpected handler and an
exception trace in the @ c main for free : You don ' t need to add a
single line of code , just link to one more library ! The
libraries differ in how tracing is done .
The Implementation is done with a static instance of a class that
sets the unexpected handler in the constructor .
@ section trcstderr Trace using std : : cerr
If you link to the library @ c libmrwexcstderr using a linker
option such as : @ c - lmrwexcstderr , then an unexpected and a
terminate handler are registered , that trace to the standard
error stream @ c std : : cerr . Also for all know signals there ' s a
signal handler to trace the stack before termination ( except in
case of a @ c SIGTRAP , wehere the program is not terminated ) . You
don ' t need to change a single line in your code !
*/
//@{
/** @brief unexpected handler, that traces to @c std::cerr
The unexpected handler is installed automatically when you link
to @ c - lmrwexcstderr . The implementation of this unexpected
handler is as follows :
@ code
void unexpected_stderr ( ) {
std : : cerr < < " UNEXPECTED EXCEPTION: ---------------------------- " < < std : : endl ;
try {
StackTrace : : createSymtable ( ) ;
throw ;
} catch ( const mrw : : exception & x ) {
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < x . stacktrace ( ) ;
} catch ( const std : : exception & x ) {
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl < < st ;
} catch ( . . . ) {
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
std : : cerr < < " ---------- Reason: **** not available **** " < < std : : endl
< < " ---------- Stack: " < < std : : endl < < st ;
}
std : : cerr < < " ------------------------------------------------- " < < std : : endl ;
throw std : : bad_exception ( ) ;
}
@ endcode
*/
void unexpected_stderr ( ) {
std : : cerr < < " UNEXPECTED EXCEPTION: ---------------------------- " < < std : : endl ;
try {
StackTrace : : createSymtable ( ) ;
throw ;
} catch ( const mrw : : exception & x ) {
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < x . stacktrace ( ) ;
} catch ( const std : : exception & x ) {
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl < < st ;
} catch ( . . . ) {
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
std : : cerr < < " ---------- Reason: **** not available **** " < < std : : endl
< < " ---------- Stack: " < < std : : endl < < st ;
}
std : : cerr < < " ------------------------------------------------- " < < std : : endl ;
throw std : : bad_exception ( ) ;
}
/** @brief terminate handler, that traces to @c std::cerr
The terminate handler is installed automatically when you link
to @ c - lmrwexcstderr . The implementation of this terminate
handler is as follows :
@ code
void terminate_stderr ( ) {
std : : cerr < < " UNCAUGHT EXCEPTION: ---------------------------- " < < std : : endl ;
try {
throw ;
} catch ( const mrw : : exception & x ) {
StackTrace : : createSymtable ( ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < x . stacktrace ( ) ;
} catch ( const std : : exception & x ) {
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: **** not available **** " < < std : : endl ;
} catch ( . . . ) {
std : : cerr < < " ---------- Reason: **** not available **** " < < std : : endl
< < " ---------- Stack: **** not available **** " < < std : : endl ;
}
std : : cerr < < " ------------------------------------------------- " < < std : : endl ;
exit ( 1 ) ;
}
@ endcode
*/
void terminate_stderr ( ) {
std : : cerr < < " UNCAUGHT EXCEPTION: ---------------------------- " < < std : : endl ;
try {
throw ;
} catch ( const mrw : : exception & x ) {
StackTrace : : createSymtable ( ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < x . stacktrace ( ) ;
} catch ( const std : : exception & x ) {
std : : cerr < < " ---------- Reason: " < < std : : endl
< < x . what ( ) < < std : : endl
< < " ---------- Stack: **** not available **** " < < std : : endl ;
} catch ( . . . ) {
std : : cerr < < " ---------- Reason: **** not available **** " < < std : : endl
< < " ---------- Stack: **** not available **** " < < std : : endl ;
}
std : : cerr < < " ------------------------------------------------- " < < std : : endl ;
exit ( 1 ) ;
}
/** @brief segmentation-fault handler, that traces using stderr
The segmentation - fault handler is installed automatically when you link
to @ c - lmrwexcstderr . The implementation of this handler is as follows :
@ code
void signal_stderr ( int sig ) {
std : : cerr < < " SIGNAL RECEIVED: ------------------------------- " < < std : : endl ;
std : : string txt ;
bool abort ( true ) ;
switch ( sig ) {
case SIGFPE : txt = " SIGFPE: Arithmetic error. " ; break ;
case SIGILL : txt = " SIGILL: Illegal instruction. " ; break ;
case SIGSEGV : txt = " SIGSEGV: Segmentation fault "
" (invalid access to valid memory). " ; break ;
case SIGBUS : txt = " SIGBUS: Invalid pointer dereference "
" (access to an invalid memory address). " ; break ;
case SIGABRT : txt = " SIGABRT: Funktion 'abort' was called. " ; break ;
case SIGTRAP : txt = " SIGTRAP: Breakpoint instruction. " ; abort = false ; break ;
case SIGSYS : txt = " SIGSYS: Bad system call. " ; break ;
default : txt = " Unknown Signal Nr. " + sig ; break ;
}
StackTrace : : createSymtable ( ) ;
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
stderr : : LoggerPtr logger ( stderr : : Logger : : getLogger ( _T ( " mrw.stacktrace " ) ) ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < " Aborted by signal: " < < txt < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < st < < std : : endl
< < " ------------------------------------------------- " < < std : : endl ;
if ( abort ) exit ( 1 ) ;
}
@ endcode
*/
void signal_stderr ( int sig ) {
std : : cerr < < " SIGNAL RECEIVED: ------------------------------- " < < std : : endl ;
std : : string txt ;
bool abort ( true ) ;
switch ( sig ) {
case SIGFPE : txt = " SIGFPE: Arithmetic error. " ; break ;
case SIGILL : txt = " SIGILL: Illegal instruction. " ; break ;
case SIGSEGV : txt = " SIGSEGV: Segmentation fault "
" (invalid access to valid memory). " ; break ;
case SIGBUS : txt = " SIGBUS: Invalid pointer dereference "
" (access to an invalid memory address). " ; break ;
case SIGABRT : txt = " SIGABRT: Funktion 'abort' was called. " ; break ;
case SIGTRAP : txt = " SIGTRAP: Breakpoint instruction. " ; abort = false ; break ;
case SIGSYS : txt = " SIGSYS: Bad system call. " ; break ;
default : txt = " Unknown Signal Nr. " + sig ; break ;
}
StackTrace : : createSymtable ( ) ;
std : : string st ( ( std : : string ) StackTrace ( ) ) ;
std : : cerr < < " ---------- Reason: " < < std : : endl
< < " Aborted by signal: " < < txt < < std : : endl
< < " ---------- Stack: " < < std : : endl
< < st < < std : : endl
< < " ------------------------------------------------- " < < std : : endl ;
if ( abort ) exit ( 1 ) ;
}
//@}
//@}
class AutoStackTrace {
public :
AutoStackTrace ( ) {
std : : set_unexpected ( & mrw : : unexpected_stderr ) ;
std : : set_terminate ( & mrw : : terminate_stderr ) ;
std : : signal ( SIGFPE , & mrw : : signal_stderr ) ;
std : : signal ( SIGILL , & mrw : : signal_stderr ) ;
std : : signal ( SIGSEGV , & mrw : : signal_stderr ) ;
std : : signal ( SIGBUS , & mrw : : signal_stderr ) ;
std : : signal ( SIGIOT , & mrw : : signal_stderr ) ;
std : : signal ( SIGTRAP , & mrw : : signal_stderr ) ;
std : : signal ( SIGSYS , & mrw : : signal_stderr ) ;
}
} ;
// initialize stack traces (load symbols)
static AutoStackTrace _autoStackTrace ;
}