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.
251 lines
8.9 KiB
251 lines
8.9 KiB
20 years ago
|
/** @file
|
||
|
|
||
|
$Id$
|
||
|
|
||
|
$Date$
|
||
|
$Author$
|
||
|
|
||
|
@copy © Marc Wäckerlin
|
||
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||
|
|
||
|
*/
|
||
13 years ago
|
#include <mrw/stacktrace.hxx>
|
||
|
#include <mrw/exception.hxx>
|
||
18 years ago
|
#include <csignal>
|
||
21 years ago
|
#include <exception>
|
||
|
#include <log4cxx/logger.h>
|
||
|
|
||
18 years ago
|
|
||
|
// support for log4cxx 0.9.7 and for new CVS version
|
||
|
#ifndef LOG4CXX_LOCATION
|
||
|
# define MRW_LOG4CXX_LOCATION __FILE__, __LINE__
|
||
|
#define MRW_LEVEL_DEBUG ::log4cxx::Level::DEBUG
|
||
|
#define MRW_LEVEL_INFO ::log4cxx::Level::INFO
|
||
|
#define MRW_LEVEL_WARN ::log4cxx::Level::WARN
|
||
|
#define MRW_LEVEL_ERROR ::log4cxx::Level::ERROR
|
||
|
#define MRW_LEVEL_FATAL ::log4cxx::Level::FATAL
|
||
|
#else
|
||
|
# define LOG4CXX_CVS
|
||
|
# define MRW_LOG4CXX_LOCATION \
|
||
|
::log4cxx::spi::LocationInfo(__FILE__, __FUNCTION__, __LINE__)
|
||
|
#define MRW_LEVEL_DEBUG ::log4cxx::Level::getDebug()
|
||
|
#define MRW_LEVEL_INFO ::log4cxx::Level::getInfo()
|
||
|
#define MRW_LEVEL_WARN ::log4cxx::Level::getWarn()
|
||
|
#define MRW_LEVEL_ERROR ::log4cxx::Level::getError()
|
||
|
#define MRW_LEVEL_FATAL ::log4cxx::Level::getFatal()
|
||
19 years ago
|
#endif
|
||
|
|
||
21 years ago
|
namespace mrw {
|
||
|
|
||
|
/** @addtogroup AutoTrace
|
||
|
|
||
|
@section trclog4cxx Trace using the log4cxx Library
|
||
|
|
||
|
If you link to the library @c libmrwexclog4cxx using a linker
|
||
20 years ago
|
option such as: @c -lmrwexclog4cxx, then an unexpected and a
|
||
|
terminate handler are registered, that trace a fatal error using
|
||
18 years ago
|
the log4cxx library. 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!
|
||
21 years ago
|
|
||
|
The log4cxx library is located at:
|
||
|
- http://logging.apache.org/log4cxx
|
||
|
|
||
|
@note The configurator is not installed automatically. If you
|
||
|
want to trace e.g. on the console, you have to call @c
|
||
|
log4cxx::BasicConfigurator::configure(); as first statement in
|
||
20 years ago
|
your @c main(). @see @ref AutoInitLog4cxx if you also want to
|
||
|
automatically configure @c log4cxx.
|
||
21 years ago
|
*/
|
||
|
//@{
|
||
|
|
||
|
/** @brief unexpected handler, that traces using log4cxx
|
||
|
|
||
|
The unexpected handler is installed automatically when you link
|
||
|
to @c -lmrwexclog4cxx. The implementation of this unexpected
|
||
|
handler is as follows:
|
||
|
|
||
|
@code
|
||
|
void unexpected_log4cxx() {
|
||
18 years ago
|
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
|
||
21 years ago
|
logger->fatal("Unexpected Exception", __FILE__, __LINE__);
|
||
20 years ago
|
StackTrace::createSymtable();
|
||
|
std::string st((std::string)StackTrace());
|
||
21 years ago
|
try {
|
||
|
throw;
|
||
|
} catch (const mrw::exception& x) {
|
||
|
logger->fatal(std::string("Reason:\n")+x.what()
|
||
20 years ago
|
+"\nStack:+\n"+x.stacktrace());
|
||
21 years ago
|
} catch (const std::exception& x) {
|
||
|
logger->fatal(std::string("Reason:\n")+x.what()
|
||
20 years ago
|
+"\nStack:\n"+st);
|
||
21 years ago
|
} catch (...) {
|
||
20 years ago
|
logger->fatal(std::string("Reason: **** not available ****")
|
||
|
+"\nStack:\n"+st);
|
||
21 years ago
|
}
|
||
|
throw std::bad_exception();
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
*/
|
||
|
void unexpected_log4cxx() {
|
||
18 years ago
|
static const std::string name("mrw.stacktrace");
|
||
|
log4cxx::LoggerPtr logger
|
||
|
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
|
||
|
static const std::string txt("Unexpected Exception");
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
|
||
20 years ago
|
StackTrace::createSymtable();
|
||
|
std::string st((std::string)StackTrace());
|
||
21 years ago
|
try {
|
||
|
throw;
|
||
|
} catch (const mrw::exception& x) {
|
||
18 years ago
|
std::string txt(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:\n"+x.stacktrace());
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
21 years ago
|
} catch (const std::exception& x) {
|
||
18 years ago
|
std::string txt(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:\n"+st);
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
21 years ago
|
} catch (...) {
|
||
18 years ago
|
std::string txt(std::string("Reason: **** not available ****")
|
||
|
+"\nStack:\n"+st);
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
21 years ago
|
}
|
||
|
throw std::bad_exception();
|
||
|
}
|
||
|
|
||
20 years ago
|
/** @brief terminate handler, that traces using log4cxx
|
||
|
|
||
|
The terminate handler is installed automatically when you link
|
||
|
to @c -lmrwexclog4cxx. The implementation of this terminate
|
||
|
handler is as follows:
|
||
|
|
||
|
@code
|
||
|
void terminate_log4cxx() {
|
||
18 years ago
|
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
|
||
20 years ago
|
logger->fatal("Uncaught Exception", __FILE__, __LINE__);
|
||
|
StackTrace::createSymtable();
|
||
|
std::string st((std::string)StackTrace());
|
||
|
try {
|
||
|
throw;
|
||
|
exit(0);
|
||
|
} catch (const mrw::exception& x) {
|
||
|
logger->fatal(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:+\n"+x.stacktrace());
|
||
|
} catch (const std::exception& x) {
|
||
|
logger->fatal(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:\n"+st);
|
||
|
} catch (...) {
|
||
|
logger->fatal(std::string("Reason: **** not available ****")
|
||
|
+"\nStack:\n"+st);
|
||
|
}
|
||
|
exit(1);
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
*/
|
||
|
void terminate_log4cxx() {
|
||
18 years ago
|
static const std::string name("mrw.stacktrace");
|
||
|
log4cxx::LoggerPtr logger
|
||
|
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
|
||
|
static const std::string txt("Uncaught Exception");
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
|
||
20 years ago
|
StackTrace::createSymtable();
|
||
|
std::string st((std::string)StackTrace());
|
||
|
try {
|
||
|
throw;
|
||
|
} catch (const mrw::exception& x) {
|
||
18 years ago
|
std::string txt(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:\n"+x.stacktrace());
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
20 years ago
|
} catch (const std::exception& x) {
|
||
18 years ago
|
std::string txt(std::string("Reason:\n")+x.what()
|
||
|
+"\nStack:\n"+st);
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
20 years ago
|
} catch (...) {
|
||
18 years ago
|
std::string txt(std::string("Reason: **** not available ****")
|
||
|
+"\nStack:\n"+st);
|
||
|
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
|
||
20 years ago
|
}
|
||
|
exit(1);
|
||
|
}
|
||
18 years ago
|
|
||
|
/** @brief segmentation-fault handler, that traces using log4cxx
|
||
20 years ago
|
|
||
18 years ago
|
The segmentation-fault handler is installed automatically when you link
|
||
|
to @c -lmrwexclog4cxx. The implementation of this handler is as follows:
|
||
|
|
||
|
@code
|
||
|
void signal_log4cxx(int sig) {
|
||
|
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 SIGIOT: txt="SIGIOT: PDP-11 'iot' instruction"; break;
|
||
|
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
|
||
|
case SIGEMT: txt="SIGEMT: Emulator trap."; break;
|
||
|
case SIGSYS: txt="SIGSYS: Bad system call."; break;
|
||
|
default: txt="Unknown Signal Nr. "+sig; break;
|
||
|
}
|
||
|
StackTrace::createSymtable();
|
||
|
std::string st((std::string)StackTrace());
|
||
|
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
|
||
|
logger->fatal("Aborted by signal: "+txt+"\nStack:\n"+st);
|
||
|
if (abort) exit(1);
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
|
*/
|
||
|
void signal_log4cxx(int sig) {
|
||
|
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());
|
||
|
static const std::string name("mrw.stacktrace");
|
||
|
log4cxx::LoggerPtr logger
|
||
|
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
|
||
|
std::string errtxt("Aborted by signal: "+txt+"\nStack:\n"+st);
|
||
|
logger->fatal(log4cxx::String(errtxt.begin(), errtxt.end()));
|
||
|
if (abort) exit(1);
|
||
|
}
|
||
21 years ago
|
|
||
|
class AutoStackTrace {
|
||
|
public:
|
||
|
AutoStackTrace() {
|
||
|
std::set_unexpected(&mrw::unexpected_log4cxx);
|
||
20 years ago
|
std::set_terminate(&mrw::terminate_log4cxx);
|
||
18 years ago
|
std::signal(SIGFPE, &mrw::signal_log4cxx);
|
||
|
std::signal(SIGILL, &mrw::signal_log4cxx);
|
||
|
std::signal(SIGSEGV, &mrw::signal_log4cxx);
|
||
|
std::signal(SIGBUS, &mrw::signal_log4cxx);
|
||
|
std::signal(SIGTRAP, &mrw::signal_log4cxx);
|
||
|
std::signal(SIGSYS, &mrw::signal_log4cxx);
|
||
21 years ago
|
}
|
||
|
};
|
||
|
|
||
18 years ago
|
//@}
|
||
|
|
||
21 years ago
|
// initialize stack traces (load symbols)
|
||
|
static AutoStackTrace _autoStackTrace;
|
||
|
|
||
|
}
|