61#define G4Backtrace_hh 1
67#if defined(__APPLE__) || defined(__MACH__)
74#elif defined(__linux__) || defined(__linux) || defined(linux) || \
75 defined(__gnu_linux__)
82#elif defined(__unix__) || defined(__unix) || defined(unix)
100#include <type_traits>
102template <
typename FuncT>
106#if defined(G4UNIX) && \
107 (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
108# if !defined(G4SIGNAL_AVAILABLE)
109# define G4SIGNAL_AVAILABLE
111# if !defined(G4DEMANGLE_AVAILABLE)
112# define G4DEMANGLE_AVAILABLE
116#if !defined(G4PSIGINFO_AVAILABLE)
117# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
118# define G4PSIGINFO_AVAILABLE 1
120# define G4PSIGINFO_AVAILABLE 0
128#if defined(G4DEMANGLE_AVAILABLE)
131 char* _ret = ::abi::__cxa_demangle(_str,
nullptr,
nullptr, &_status);
132 if(_ret && _status == 0)
133 return G4String(
const_cast<const char*
>(_ret));
149template <
typename Tp>
161#if defined(G4SIGNAL_AVAILABLE)
205# include <functional>
230 using id_entry_t = std::tuple<std::string, int, std::string>;
231 using id_list_t = std::vector<id_entry_t>;
233 std::shared_ptr<std::mutex> lock = std::make_shared<std::mutex>();
235 std::map<int, sigaction_t>
current = {};
236 std::map<int, sigaction_t>
previous = {};
239 id_entry_t(
"SIGHUP", SIGHUP,
"terminal line hangup"),
240 id_entry_t(
"SIGINT", SIGINT,
"interrupt program"),
241 id_entry_t(
"SIGQUIT", SIGQUIT,
"quit program"),
242 id_entry_t(
"SIGILL", SIGILL,
"illegal instruction"),
244 id_entry_t(
"SIGABRT", SIGABRT,
"abort program (formerly SIGIOT)"),
245 id_entry_t(
"SIGEMT", SIGEMT,
"emulate instruction executed"),
246 id_entry_t(
"SIGFPE", SIGFPE,
"floating-point exception"),
247 id_entry_t(
"SIGKILL", SIGKILL,
"kill program"),
249 id_entry_t(
"SIGSEGV", SIGSEGV,
"segmentation violation"),
250 id_entry_t(
"SIGSYS", SIGSYS,
"non-existent system call invoked"),
251 id_entry_t(
"SIGPIPE", SIGPIPE,
"write on a pipe with no reader"),
252 id_entry_t(
"SIGALRM", SIGALRM,
"real-time timer expired"),
253 id_entry_t(
"SIGTERM", SIGTERM,
"software termination signal"),
254 id_entry_t(
"SIGURG", SIGURG,
"urgent condition present on socket"),
255 id_entry_t(
"SIGSTOP", SIGSTOP,
"stop (cannot be caught or ignored)"),
256 id_entry_t(
"SIGTSTP", SIGTSTP,
"stop signal generated from keyboard"),
257 id_entry_t(
"SIGCONT", SIGCONT,
"continue after stop"),
258 id_entry_t(
"SIGCHLD", SIGCHLD,
"child status has changed"),
260 "background read attempted from control terminal"),
262 "background write attempted to control terminal"),
263 id_entry_t(
"SIGIO ", SIGIO,
"I/O is possible on a descriptor"),
264 id_entry_t(
"SIGXCPU", SIGXCPU,
"cpu time limit exceeded"),
265 id_entry_t(
"SIGXFSZ", SIGXFSZ,
"file size limit exceeded"),
266 id_entry_t(
"SIGVTALRM", SIGVTALRM,
"virtual time alarm"),
267 id_entry_t(
"SIGPROF", SIGPROF,
"profiling timer alarm"),
268 id_entry_t(
"SIGWINCH", SIGWINCH,
"Window size change"),
269 id_entry_t(
"SIGINFO", SIGINFO,
"status request from keyboard"),
270 id_entry_t(
"SIGUSR1", SIGUSR1,
"User defined signal 1"),
271 id_entry_t(
"SIGUSR2", SIGUSR2,
"User defined signal 2")
288 static int Enable(
const std::string&);
294 static int GetSignal(
const std::string&);
299 template <
typename FuncT>
305 template <
size_t Depth,
size_t Offset = 0,
typename FuncT = frame_func_t>
312 template <
size_t Depth,
size_t Offset = 0,
typename FuncT = frame_func_t>
319 static auto _instance = actions{};
338 static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
339 SIGKILL, SIGBUS, SIGSEGV };
345template <
typename FuncT>
355 for(
auto& itr :
GetData().exit_actions)
361template <
size_t Depth,
size_t Offset,
typename FuncT>
362inline std::array<
G4ResultOf_t<FuncT(
const char*)>, Depth>
365 static_assert((Depth - Offset) >= 1,
"Error Depth - Offset should be >= 1");
369 std::array<type, Depth> btrace;
370 btrace.fill((std::is_pointer<type>::value) ?
nullptr : type{});
373 std::array<void*, Depth + Offset>
buffer;
375 auto sz = backtrace(
buffer.data(), Depth + Offset);
377 auto n = sz - Offset;
380 char** bsym = backtrace_symbols(
buffer.data() + Offset, n);
384 perror(
"backtrace_symbols");
387 for(
decltype(n) i = 0; i <
n; ++i)
388 btrace[i] = func(bsym[i]);
396template <
size_t Depth,
size_t Offset,
typename FuncT>
397inline std::array<
G4ResultOf_t<FuncT(
const char*)>, Depth>
400 auto demangle_bt = [&](
const char* cstr) {
401 auto _trim = [](std::string& _sub,
size_t& _len) {
403 while((_pos = _sub.find_first_of(
' ')) == 0)
405 _sub = _sub.erase(_pos, 1);
408 while((_pos = _sub.find_last_of(
' ')) == _sub.length() - 1)
410 _sub = _sub.substr(0, _sub.length() - 1);
417 auto beg = str.find(
"(");
418 if(beg == std::string::npos)
420 beg = str.find(
"_Z");
421 if(beg != std::string::npos)
424 auto end = str.find(
"+", beg);
425 if(beg != std::string::npos && end != std::string::npos)
427 auto len = end - (beg + 1);
428 auto sub = str.substr(beg + 1, len);
430 str = str.replace(beg + 1, len, dem);
432 else if(beg != std::string::npos)
434 auto len = str.length() - (beg + 1);
435 auto sub = str.substr(beg + 1, len);
437 str = str.replace(beg + 1, len, dem);
439 else if(end != std::string::npos)
442 auto sub = str.substr(beg, len);
444 str = str.replace(beg, len, dem);
446 return func(str.c_str());
448 return GetMangled<Depth, Offset>(demangle_bt);
455 std::stringstream message;
456 message <<
"\n### CAUGHT SIGNAL: " << sig <<
" ### ";
458 message <<
"address: " << sinfo->si_addr <<
", ";
465 switch(sinfo->si_code)
468 message <<
"Address not mapped to object.";
471 message <<
"Invalid permissions for mapped object.";
474 message <<
"Unknown segmentation fault error: " << sinfo->si_code
481 message <<
"Segmentation fault (unknown).";
484 else if(sig == SIGFPE)
488 switch(sinfo->si_code)
491 message <<
"Floating point divide by zero.";
494 message <<
"Floating point overflow.";
497 message <<
"Floating point underflow.";
500 message <<
"Floating point inexact result.";
503 message <<
"Floating point invalid operation.";
506 message <<
"Unknown floating point exception error: "
507 << sinfo->si_code <<
".";
513 message <<
"Unknown floating point exception";
515 message <<
": " << sinfo->si_code;
520 message << std::endl;
525 }
catch(std::exception& e)
527 std::cerr <<
"ExitAction(" << sig <<
") threw an exception" << std::endl;
528 std::cerr << e.what() << std::endl;
535 std::vector<G4String> btvec;
539 btvec.emplace_back(std::move(itr));
541 std::stringstream serr;
542 serr <<
"\nBacktrace:\n";
543 auto _w = std::log10(btvec.size()) + 1;
544 for(
size_t i = 0; i < btvec.size(); ++i)
546 serr <<
prefix.str() <<
"[" << std::setw(_w) << std::right << i <<
'/'
547 << std::setw(_w) << std::right << btvec.size() <<
"]> " << std::left
548 << btvec.at(i) <<
'\n';
550 os << serr.str().c_str() <<
'\n';
551 os << message.str() << std::flush;
558 std::unique_lock<std::mutex> lk{ *(
GetData().lock) };
561 std::stringstream msg;
563 std::cerr << msg.str() << std::flush;
566 std::stringstream msg;
571# if G4PSIGINFO_AVAILABLE > 0
572 psiginfo(sinfo, msg.str().c_str());
577 std::cerr << msg.str() << std::endl;
591 static bool _first =
true;
592 std::unique_lock<std::mutex> lk{ *(
GetData().lock) };
595 std::string _msg =
"!!! G4Backtrace is activated !!!";
596 std::stringstream _filler;
597 std::stringstream _spacer;
599 _filler << std::setw(_msg.length()) <<
"";
600 _spacer << std::setw(10) <<
"";
602 << _spacer.str() << _filler.str() <<
"\n"
603 << _spacer.str() << _msg <<
"\n"
604 << _spacer.str() << _filler.str() <<
"\n\n"
609 for(
auto& itr : _signals)
616 sigfillset(&(
GetData().current[itr].sa_mask));
617 sigdelset(&(
GetData().current[itr].sa_mask), itr);
620 sigaction(itr, &(
GetData().current[itr]), &(
GetData().previous[itr]));
632 auto _add_signal = [](std::string sig,
signal_set_t& _targ) {
641 const std::regex wsp_re(
"[ ,;:\t\n]+");
643 auto _result = std::vector<std::string>(_maxid,
"");
645 std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
646 std::sregex_token_iterator(), _result.begin());
648 for(
auto& itr : _result)
649 _add_signal(itr, _sigset);
657 std::unique_lock<std::mutex> lk{ *(
GetData().lock) };
662 _signals.insert(itr.first);
666 for(
auto& itr : _signals)
673 sigaction(itr, &(
GetData().previous[itr]),
nullptr);
684 for(
auto&& itr :
GetData().identifiers)
686 if(std::get<0>(itr) == sid)
687 return std::get<1>(itr);
696 for(
auto&& itr :
GetData().identifiers)
698 if(std::get<1>(itr) == sig)
700 std::stringstream ss;
701 ss <<
" signal = " << std::setw(8) << std::get<0>(itr)
702 <<
", value = " << std::setw(4) << std::get<1>(itr)
703 <<
", description = " << std::get<2>(itr);
707 std::stringstream ss;
708 ss <<
" signal = " << std::setw(8) <<
"unknown"
709 <<
", value = " << std::setw(4) << sig;
718# include <functional>
743 using id_entry_t = std::tuple<std::string, int, std::string>;
757 static int Enable(
const std::string&) {
return 0; }
763 template <
typename FuncT>
767 template <
size_t Depth,
size_t Offset = 0,
typename FuncT = frame_func_t>
772 auto ret = std::array<type, Depth>{};
777 template <
size_t Depth,
size_t Offset = 0,
typename FuncT = frame_func_t>
782 auto ret = std::array<type, Depth>{};
803 static auto _instance =
actions{};
typename std::result_of< FuncT >::type G4ResultOf_t
#define G4PSIGINFO_AVAILABLE
static void Handler(int, siginfo_t *, void *)
fake_sigaction sigaction_t
static std::string Description(int)
static signal_set_t & DefaultSignals()
static int Enable(const std::string &)
static void ExitAction(int)
static void AddExitAction(FuncT &&)
static frame_func_t & FrameFunctor()
static actions & GetData()
std::set< int > signal_set_t
static int GetSignal(const std::string &)
static std::array< G4ResultOf_t< FuncT(const char *)>, Depth > GetMangled(FuncT &&func=FrameFunctor())
std::function< void(int)> exit_action_t
std::function< G4String(const char *)> frame_func_t
static void Message(int, siginfo_t *, std::ostream &)
static std::array< G4ResultOf_t< FuncT(const char *)>, Depth > GetDemangled(FuncT &&func=FrameFunctor())
static int Enable(const signal_set_t &=DefaultSignals())
static int Disable(signal_set_t={})
std::map< int, sigaction_t > previous
std::vector< exit_action_t > exit_actions
const id_list_t identifiers
std::map< int, bool > is_active
std::vector< id_entry_t > id_list_t
std::map< int, sigaction_t > current
std::tuple< std::string, int, std::string > id_entry_t