C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
9.2 KiB

/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
*/
#include <mrw/stacktrace.hxx>
#include <mrw/exception.hxx>
#include <csignal>
#include <exception>
#include <iostream>
namespace mrw {
/** @addtogroup grpStackTrace */
20 years ago
//@{
/** @defgroup AutoTrace Automated Unexpected and Terminate Handler
with Stack Trace
20 years ago
@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.
20 years ago
For all your programs it is recommended to implement an
identical unexpected handler, that rethrows, catches the @c
20 years ago
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.
20 years ago
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!
20 years ago
*/
//@{
/** @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();
20 years ago
throw;
} catch (const mrw::exception& x) {
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl
<<x.stacktrace();
20 years ago
} catch (const std::exception& x) {
std::string st((std::string)StackTrace());
20 years ago
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack: "<<std::endl<<st;
20 years ago
} catch (...) {
std::string st((std::string)StackTrace());
20 years ago
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
<<"---------- Stack:"<<std::endl<<st;
20 years ago
}
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);
}
20 years ago
//@}
//@}
class AutoStackTrace {
public:
AutoStackTrace() {
20 years ago
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;
}