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)
88#if defined(G4UNIX) && !defined(WIN32)
100#include <type_traits>
102template <
typename FuncT,
typename... ArgTypes>
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 !=
nullptr) && _status == 0)
133 return G4String(
const_cast<const char*
>(_ret));
149template <
typename Tp>
161#if defined(G4SIGNAL_AVAILABLE)
206# include <functional>
230 using id_entry_t = std::tuple<std::string, G4int, std::string>;
231 using id_list_t = std::vector<id_entry_t>;
234 std::map<G4int, sigaction_t>
current = {};
235 std::map<G4int, sigaction_t>
previous = {};
238 id_entry_t(
"SIGHUP", SIGHUP,
"terminal line hangup"),
239 id_entry_t(
"SIGINT", SIGINT,
"interrupt program"),
240 id_entry_t(
"SIGQUIT", SIGQUIT,
"quit program"),
241 id_entry_t(
"SIGILL", SIGILL,
"illegal instruction"),
243 id_entry_t(
"SIGABRT", SIGABRT,
"abort program (formerly SIGIOT)"),
244 id_entry_t(
"SIGEMT", SIGEMT,
"emulate instruction executed"),
245 id_entry_t(
"SIGFPE", SIGFPE,
"floating-point exception"),
246 id_entry_t(
"SIGKILL", SIGKILL,
"kill program"),
248 id_entry_t(
"SIGSEGV", SIGSEGV,
"segmentation violation"),
249 id_entry_t(
"SIGSYS", SIGSYS,
"non-existent system call invoked"),
250 id_entry_t(
"SIGPIPE", SIGPIPE,
"write on a pipe with no reader"),
251 id_entry_t(
"SIGALRM", SIGALRM,
"real-time timer expired"),
252 id_entry_t(
"SIGTERM", SIGTERM,
"software termination signal"),
253 id_entry_t(
"SIGURG", SIGURG,
"urgent condition present on socket"),
254 id_entry_t(
"SIGSTOP", SIGSTOP,
"stop (cannot be caught or ignored)"),
255 id_entry_t(
"SIGTSTP", SIGTSTP,
"stop signal generated from keyboard"),
256 id_entry_t(
"SIGCONT", SIGCONT,
"continue after stop"),
257 id_entry_t(
"SIGCHLD", SIGCHLD,
"child status has changed"),
259 "background read attempted from control terminal"),
261 "background write attempted to control terminal"),
262 id_entry_t(
"SIGIO ", SIGIO,
"I/O is possible on a descriptor"),
263 id_entry_t(
"SIGXCPU", SIGXCPU,
"cpu time limit exceeded"),
264 id_entry_t(
"SIGXFSZ", SIGXFSZ,
"file size limit exceeded"),
265 id_entry_t(
"SIGVTALRM", SIGVTALRM,
"virtual time alarm"),
266 id_entry_t(
"SIGPROF", SIGPROF,
"profiling timer alarm"),
267 id_entry_t(
"SIGWINCH", SIGWINCH,
"Window size change"),
268 id_entry_t(
"SIGINFO", SIGINFO,
"status request from keyboard"),
269 id_entry_t(
"SIGUSR1", SIGUSR1,
"User defined signal 1"),
270 id_entry_t(
"SIGUSR2", SIGUSR2,
"User defined signal 2")
298 template <
typename FuncT>
304 template <std::
size_t Depth, std::
size_t Offset = 0,
typename FuncT = frame_func_t>
305 static std::array<G4ResultOf_t<FuncT, const char*>, Depth>
GetMangled(
311 template <std::
size_t Depth, std::
size_t Offset = 0,
typename FuncT = frame_func_t>
312 static std::array<G4ResultOf_t<FuncT, const char*>, Depth>
GetDemangled(
318 static auto _instance = actions{};
337 static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT,
338 SIGKILL, SIGBUS, SIGSEGV };
344template <
typename FuncT>
354 for(
auto& itr :
GetData().exit_actions)
360template <std::
size_t Depth, std::
size_t Offset,
typename FuncT>
361inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
364 static_assert((Depth - Offset) >= 1,
"Error Depth - Offset should be >= 1");
368 std::array<type, Depth> btrace;
369 btrace.fill((std::is_pointer<type>::value) ?
nullptr : type{});
372 std::array<void*, Depth + Offset> buffer;
374 auto sz = backtrace(buffer.data(), Depth + Offset);
376 auto n = sz - Offset;
379 char** bsym = backtrace_symbols(buffer.data() + Offset, (
G4int)n);
383 perror(
"backtrace_symbols");
386 for(
decltype(n) i = 0; i <
n; ++i)
387 btrace[i] = func(bsym[i]);
395template <std::
size_t Depth, std::
size_t Offset,
typename FuncT>
396inline std::array<G4ResultOf_t<FuncT, const char*>, Depth>
399 auto demangle_bt = [&](
const char* cstr) {
400 auto _trim = [](std::string& _sub, std::size_t& _len) {
401 std::size_t _pos = 0;
402 while((_pos = _sub.find_first_of(
' ')) == 0)
404 _sub = _sub.erase(_pos, 1);
407 while((_pos = _sub.find_last_of(
' ')) == _sub.length() - 1)
409 _sub = _sub.substr(0, _sub.length() - 1);
416 auto beg = str.find(
'(');
417 if(beg == std::string::npos)
419 beg = str.find(
"_Z");
420 if(beg != std::string::npos)
423 auto end = str.find(
'+', beg);
424 if(beg != std::string::npos && end != std::string::npos)
426 auto len = end - (beg + 1);
427 auto sub = str.substr(beg + 1, len);
429 str = str.replace(beg + 1, len, dem);
431 else if(beg != std::string::npos)
433 auto len = str.length() - (beg + 1);
434 auto sub = str.substr(beg + 1, len);
436 str = str.replace(beg + 1, len, dem);
438 else if(end != std::string::npos)
441 auto sub = str.substr(beg, len);
443 str = str.replace(beg, len, dem);
445 return func(str.c_str());
458 signal(sig, SIG_IGN);
460 os <<
"\n### CAUGHT SIGNAL: " << sig <<
" ### ";
462 os <<
"address: " << sinfo->si_addr <<
", ";
469 switch(sinfo->si_code)
472 os <<
"Address not mapped to object.";
475 os <<
"Invalid permissions for mapped object.";
478 os <<
"Unknown segmentation fault error: " << sinfo->si_code <<
".";
484 os <<
"Segmentation fault (unknown).";
487 else if(sig == SIGFPE)
491 switch(sinfo->si_code)
494 os <<
"Floating point divide by zero.";
497 os <<
"Floating point overflow.";
500 os <<
"Floating point underflow.";
503 os <<
"Floating point inexact result.";
506 os <<
"Floating point invalid operation.";
509 os <<
"Unknown floating point exception error: " << sinfo->si_code
516 os <<
"Unknown floating point exception";
518 os <<
": " << sinfo->si_code;
527 snprintf(
prefix, 64,
"[PID=%i, TID=%i]", (
G4int) getpid(),
538 os <<
"\nBacktrace:\n";
539 auto _w = std::log10(sz) + 1;
540 for(std::size_t i = 0; i < sz; ++i)
542 os <<
prefix <<
"[" << std::setw(_w) << std::right << i <<
'/'
543 << std::setw(_w) << std::right << sz <<
"]> " << std::left << bt.at(i)
553 }
catch(std::exception& e)
555 std::cerr <<
"ExitAction(" << sig <<
") threw an exception" << std::endl;
556 std::cerr << e.what() << std::endl;
564 Message(sig, sinfo, std::cerr);
567 snprintf(msg, 1024,
"%s",
"\n");
571# if G4PSIGINFO_AVAILABLE > 0
572 psiginfo(sinfo, msg);
579 std::cerr << msg << std::flush;
583 signal(SIGKILL, SIG_IGN);
584 signal(SIGTERM, SIG_IGN);
585 signal(SIGABRT, SIG_IGN);
593 static G4bool _first =
true;
596 std::string _msg =
"!!! G4Backtrace is activated !!!";
597 std::stringstream _filler;
598 std::stringstream _spacer;
600 _filler << std::setw((
G4int)_msg.length()) <<
"";
601 _spacer << std::setw(10) <<
"";
603 << _spacer.str() << _filler.str() <<
"\n"
604 << _spacer.str() << _msg <<
"\n"
605 << _spacer.str() << _filler.str() <<
"\n\n"
610 for(
auto& itr : _signals)
617 sigfillset(&(
GetData().current[itr].sa_mask));
618 sigdelset(&(
GetData().current[itr].sa_mask), itr);
621 sigaction(itr, &(
GetData().current[itr]), &(
GetData().previous[itr]));
633 auto _add_signal = [](std::string sig,
signal_set_t& _targ) {
637 itr = (char)std::toupper(itr);
642 const std::regex wsp_re(
"[ ,;:\t\n]+");
644 auto _result = std::vector<std::string>(_maxid,
"");
646 std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
647 std::sregex_token_iterator(), _result.begin());
649 for(
auto& itr : _result)
650 _add_signal(itr, _sigset);
660 for(
auto& itr :
GetData().is_active)
661 _signals.insert(itr.first);
665 for(
auto& itr : _signals)
672 sigaction(itr, &(
GetData().previous[itr]),
nullptr);
683 for(
auto&& itr :
GetData().identifiers)
685 if(std::get<0>(itr) == sid)
686 return std::get<1>(itr);
695 for(
auto&& itr :
GetData().identifiers)
697 if(std::get<1>(itr) == sig)
699 std::stringstream ss;
700 ss <<
" signal = " << std::setw(8) << std::get<0>(itr)
701 <<
", value = " << std::setw(4) << std::get<1>(itr)
702 <<
", description = " << std::get<2>(itr);
706 std::stringstream ss;
707 ss <<
" signal = " << std::setw(8) <<
"unknown"
708 <<
", value = " << std::setw(4) << sig;
717# include <functional>
742 using id_entry_t = std::tuple<std::string, G4int, std::string>;
762 template <
typename FuncT>
766 template <std::
size_t Depth, std::
size_t Offset = 0,
typename FuncT = frame_func_t>
767 static std::array<G4ResultOf_t<FuncT, const char*>, Depth>
GetMangled(
771 auto ret = std::array<type, Depth>{};
776 template <std::
size_t Depth, std::
size_t Offset = 0,
typename FuncT = frame_func_t>
777 static std::array<G4ResultOf_t<FuncT, const char*>, Depth>
GetDemangled(
781 auto ret = std::array<type, Depth>{};
802 static auto _instance =
actions{};
std::invoke_result_t< FuncT, ArgTypes... > G4ResultOf_t
#define G4PSIGINFO_AVAILABLE
static G4int Enable(const signal_set_t &=DefaultSignals())
static G4int Disable(signal_set_t={})
fake_sigaction sigaction_t
static std::array< G4ResultOf_t< FuncT, const char * >, Depth > GetDemangled(FuncT &&func=FrameFunctor())
static signal_set_t & DefaultSignals()
std::set< G4int > signal_set_t
static G4int Enable(const std::string &)
static std::array< G4ResultOf_t< FuncT, const char * >, Depth > GetMangled(FuncT &&func=FrameFunctor())
static void AddExitAction(FuncT &&)
std::function< void(G4int)> exit_action_t
static std::string Description(G4int)
static frame_func_t & FrameFunctor()
static void Message(G4int, siginfo_t *, std::ostream &)
static void ExitAction(G4int)
static actions & GetData()
static void Handler(G4int, siginfo_t *, void *)
std::function< G4String(const char *)> frame_func_t
static G4int GetSignal(const std::string &)
std::vector< exit_action_t > exit_actions
const id_list_t identifiers
std::map< G4int, sigaction_t > current
std::vector< id_entry_t > id_list_t
std::map< G4int, G4bool > is_active
std::tuple< std::string, G4int, std::string > id_entry_t
std::map< G4int, sigaction_t > previous