Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:46

0001 //
0002 // MIT License
0003 // Copyright (c) 2020 Jonathan R. Madsen
0004 // Permission is hereby granted, free of charge, to any person obtaining a copy
0005 // of this software and associated documentation files (the "Software"), to deal
0006 // in the Software without restriction, including without limitation the rights
0007 // to use, copy, modify, merge, publish, distribute, sublicense, and
0008 // copies of the Software, and to permit persons to whom the Software is
0009 // furnished to do so, subject to the following conditions:
0010 // The above copyright notice and this permission notice shall be included in
0011 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
0012 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
0013 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
0014 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
0015 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0016 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0017 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0018 //
0019 // Backtrace
0020 //
0021 // Description:
0022 //
0023 //  Prints backtraces after signals are caught. Available on Unix.
0024 //
0025 // Usage:
0026 //  A standard set of signals are enabled by default:
0027 //
0028 //     SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
0029 //
0030 //  These should not interfere with debuggers and/or FPEDetection.
0031 //  In order to turn off handling for one or more signals, one can do:
0032 //
0033 //    BackTrace::DefaultSignals() = std::set<int>{};
0034 //    BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
0035 //
0036 //  and so on, *before* creating the run-manager. After the run-manager
0037 //  has been created, one should disable the signals:
0038 //
0039 //    BackTrace::Disable(BackTrace::DefaultSignals());
0040 //
0041 //  Additionally, at runtime, the environment variable "BACKTRACE" can
0042 //  be set to select a specific set of signals or none, e.g. in bash:
0043 //
0044 //    export BACKTRACE="SIGQUIT,SIGSEGV"
0045 //    export BACKTRACE="none"
0046 //
0047 //  The environment variable is case-insensitive and can use any of the
0048 //  following delimiters: space, comma, semi-colon, colon
0049 //
0050 // Author: J.Madsen, 19 October 2020
0051 // --------------------------------------------------------------------
0052 
0053 #ifndef PTL_Backtrace_hh
0054 #define PTL_Backtrace_hh 1
0055 
0056 #include "Threading.hh"
0057 #include "Types.hh"
0058 
0059 #if defined(PTL_UNIX)
0060 #    include <cxxabi.h>
0061 #    include <execinfo.h>
0062 #    include <unistd.h>
0063 #endif
0064 
0065 #if defined(PTL_LINUX)
0066 #    include <features.h>
0067 #endif
0068 
0069 #include <cfenv>
0070 #include <cmath>
0071 #include <csignal>
0072 #include <cstring>
0073 #include <type_traits>
0074 
0075 namespace PTL
0076 {
0077 template <typename FuncT, typename... ArgTypes>
0078 #if __cpp_lib_is_invocable >= 201703
0079 using ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
0080 #else
0081 using ResultOf_t = typename std::result_of<FuncT(ArgTypes...)>::type;
0082 #endif
0083 }  // namespace PTL
0084 
0085 // compatible OS and compiler
0086 #if defined(PTL_UNIX) &&                                                                 \
0087     (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
0088 #    if !defined(PTL_SIGNAL_AVAILABLE)
0089 #        define PTL_SIGNAL_AVAILABLE
0090 #    endif
0091 #    if !defined(PTL_DEMANGLE_AVAILABLE)
0092 #        define PTL_DEMANGLE_AVAILABLE
0093 #    endif
0094 #endif
0095 
0096 #if !defined(PTL_PSIGINFO_AVAILABLE)
0097 #    if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
0098 #        define PTL_PSIGINFO_AVAILABLE 1
0099 #    else
0100 #        define PTL_PSIGINFO_AVAILABLE 0
0101 #    endif
0102 #endif
0103 
0104 //----------------------------------------------------------------------------//
0105 
0106 namespace PTL
0107 {
0108 inline std::string
0109 Demangle(const char* _str)
0110 {
0111 #if defined(PTL_DEMANGLE_AVAILABLE)
0112     // demangling a string when delimiting
0113     int   _status = 0;
0114     char* _ret    = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
0115     if(_ret && _status == 0)
0116         return std::string(const_cast<const char*>(_ret));
0117     return _str;
0118 #else
0119     return _str;
0120 #endif
0121 }
0122 
0123 //----------------------------------------------------------------------------//
0124 
0125 inline std::string
0126 Demangle(const std::string& _str)
0127 {
0128     return Demangle(_str.c_str());
0129 }
0130 
0131 //----------------------------------------------------------------------------//
0132 
0133 template <typename Tp>
0134 inline std::string
0135 Demangle()
0136 {
0137     return Demangle(typeid(Tp).name());
0138 }
0139 }  // namespace PTL
0140 
0141 //----------------------------------------------------------------------------//
0142 //
0143 //      ONLY IF SIGNAL_AVAILABLE
0144 //
0145 //----------------------------------------------------------------------------//
0146 //
0147 #if defined(PTL_SIGNAL_AVAILABLE)
0148 //
0149 //  these are not in the original POSIX.1-1990 standard so we are defining
0150 //  them in case the OS hasn't
0151 //  POSIX-1.2001
0152 #    ifndef SIGTRAP
0153 #        define SIGTRAP 5
0154 #    endif
0155 //  not specified in POSIX.1-2001, but nevertheless appears on most other
0156 //  UNIX systems, where its default action is typically to terminate the
0157 //  process with a core dump.
0158 #    ifndef SIGEMT
0159 #        define SIGEMT 7
0160 #    endif
0161 //  POSIX-1.2001
0162 #    ifndef SIGURG
0163 #        define SIGURG 16
0164 #    endif
0165 //  POSIX-1.2001
0166 #    ifndef SIGXCPU
0167 #        define SIGXCPU 24
0168 #    endif
0169 //  POSIX-1.2001
0170 #    ifndef SIGXFSZ
0171 #        define SIGXFSZ 25
0172 #    endif
0173 //  POSIX-1.2001
0174 #    ifndef SIGVTALRM
0175 #        define SIGVTALRM 26
0176 #    endif
0177 //  POSIX-1.2001
0178 #    ifndef SIGPROF
0179 #        define SIGPROF 27
0180 #    endif
0181 //  POSIX-1.2001
0182 #    ifndef SIGINFO
0183 #        define SIGINFO 29
0184 #    endif
0185 
0186 //----------------------------------------------------------------------------//
0187 
0188 #    include <algorithm>
0189 #    include <array>
0190 #    include <cstdio>
0191 #    include <cstdlib>
0192 #    include <functional>
0193 #    include <iomanip>
0194 #    include <iostream>
0195 #    include <map>
0196 #    include <regex>
0197 #    include <set>
0198 #    include <sstream>
0199 #    include <string>
0200 #    include <tuple>
0201 #    include <vector>
0202 
0203 // PTL header
0204 #    include "Threading.hh"
0205 
0206 //----------------------------------------------------------------------------//
0207 
0208 namespace PTL
0209 {
0210 class Backtrace
0211 {
0212 public:
0213     using sigaction_t   = struct sigaction;
0214     using exit_action_t = std::function<void(int)>;
0215     using frame_func_t  = std::function<std::string(const char*)>;
0216     using signal_set_t  = std::set<int>;
0217 
0218 public:
0219     struct actions
0220     {
0221         using id_entry_t = std::tuple<std::string, int, std::string>;
0222         using id_list_t  = std::vector<id_entry_t>;
0223 
0224         std::map<int, bool>        is_active    = {};
0225         std::map<int, sigaction_t> current      = {};
0226         std::map<int, sigaction_t> previous     = {};
0227         std::vector<exit_action_t> exit_actions = {};
0228         const id_list_t            identifiers  = {
0229             id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
0230             id_entry_t("SIGINT", SIGINT, "interrupt program"),
0231             id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
0232             id_entry_t("SIGILL", SIGILL, "illegal instruction"),
0233             id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
0234             id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
0235             id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
0236             id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
0237             id_entry_t("SIGKILL", SIGKILL, "kill program"),
0238             id_entry_t("SIGBUS", SIGBUS, "bus error"),
0239             id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
0240             id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
0241             id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
0242             id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
0243             id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
0244             id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
0245             id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
0246             id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
0247             id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
0248             id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
0249             id_entry_t("SIGTTIN", SIGTTIN,
0250                        "background read attempted from control terminal"),
0251             id_entry_t("SIGTTOU", SIGTTOU,
0252                        "background write attempted to control terminal"),
0253             id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
0254             id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
0255             id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
0256             id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
0257             id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
0258             id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
0259             id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
0260             id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
0261             id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
0262         };
0263     };
0264 
0265 public:
0266     // a functor called for each frame in the backtrace
0267     static frame_func_t& FrameFunctor();
0268     // default set of signals
0269     static signal_set_t& DefaultSignals();
0270     // the signal handler
0271     static void Handler(int sig, siginfo_t* sinfo, void* context);
0272     // information message about the signal, performs exit-actions
0273     // and prints back-trace
0274     static void Message(int sig, siginfo_t* sinfo, std::ostream&);
0275     // calls user-provided functions after signal is caught but before abort
0276     static void ExitAction(int sig);
0277     // enable signals via a string (which is tokenized)
0278     static int Enable(const std::string&);
0279     // enable signals via set of integers, anything less than zero is ignored
0280     static int Enable(const signal_set_t& _signals = DefaultSignals());
0281     // disable signals
0282     static int Disable(signal_set_t _signals = {});
0283     // gets the numeric value for a signal name
0284     static int GetSignal(const std::string&);
0285     // provides a description of the signal
0286     static std::string Description(int sig);
0287 
0288     // adds an exit action
0289     template <typename FuncT>
0290     static void AddExitAction(FuncT&& func);
0291 
0292     // gets a backtrace of "Depth" frames. The offset parameter is used
0293     // to ignore initial frames (such as this function). A callback
0294     // can be provided to inspect and/or tweak the frame string
0295     template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
0296     static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
0297         FuncT&& func = FrameFunctor());
0298 
0299     // gets a demangled backtrace of "Depth" frames. The offset parameter is
0300     // used to ignore initial frames (such as this function). A callback
0301     // can be provided to inspect and/or tweak the frame string
0302     template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
0303     static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
0304         FuncT&& func = FrameFunctor());
0305 
0306 private:
0307     static actions& GetData()
0308     {
0309         static auto _instance = actions{};
0310         return _instance;
0311     }
0312 };
0313 
0314 //----------------------------------------------------------------------------//
0315 
0316 // a functor called for each frame in the backtrace
0317 inline Backtrace::frame_func_t&
0318 Backtrace::FrameFunctor()
0319 {
0320     static frame_func_t _instance = [](const char* inp) { return std::string(inp); };
0321     return _instance;
0322 }
0323 
0324 //----------------------------------------------------------------------------//
0325 
0326 // default set of signals
0327 inline Backtrace::signal_set_t&
0328 Backtrace::DefaultSignals()
0329 {
0330     static signal_set_t _instance = {
0331         SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
0332     };
0333     return _instance;
0334 }
0335 
0336 //----------------------------------------------------------------------------//
0337 
0338 template <typename FuncT>
0339 inline void
0340 Backtrace::AddExitAction(FuncT&& func)
0341 {
0342     GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
0343 }
0344 
0345 //----------------------------------------------------------------------------//
0346 
0347 inline void
0348 Backtrace::ExitAction(int sig)
0349 {
0350     for(auto& itr : GetData().exit_actions)
0351         itr(sig);
0352 }
0353 
0354 //----------------------------------------------------------------------------//
0355 
0356 template <size_t Depth, size_t Offset, typename FuncT>
0357 inline std::array<ResultOf_t<FuncT, const char*>, Depth>
0358 Backtrace::GetMangled(FuncT&& func)
0359 {
0360     static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
0361 
0362     using type = ResultOf_t<FuncT, const char*>;
0363     // destination
0364     std::array<type, Depth> btrace;
0365     btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
0366 
0367     // plus one for this stack-frame
0368     std::array<void*, Depth + Offset> buffer;
0369     // size of returned buffer
0370     auto sz = backtrace(buffer.data(), Depth + Offset);
0371     // size of relevant data
0372     auto n = sz - Offset;
0373 
0374     // skip ahead (Offset + 1) stack frames
0375     char** bsym = backtrace_symbols(buffer.data() + Offset, n);
0376 
0377     // report errors
0378     if(bsym == nullptr)
0379         perror("backtrace_symbols");
0380     else
0381     {
0382         for(decltype(n) i = 0; i < n; ++i)
0383             btrace[i] = func(bsym[i]);
0384         free(bsym);
0385     }
0386     return btrace;
0387 }
0388 
0389 //----------------------------------------------------------------------------//
0390 
0391 template <size_t Depth, size_t Offset, typename FuncT>
0392 inline std::array<ResultOf_t<FuncT, const char*>, Depth>
0393 Backtrace::GetDemangled(FuncT&& func)
0394 {
0395     auto demangle_bt = [&](const char* cstr) {
0396         auto _trim = [](std::string& _sub, size_t& _len) {
0397             size_t _pos = 0;
0398             while((_pos = _sub.find_first_of(' ')) == 0)
0399             {
0400                 _sub = _sub.erase(_pos, 1);
0401                 --_len;
0402             }
0403             while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
0404             {
0405                 _sub = _sub.substr(0, _sub.length() - 1);
0406                 --_len;
0407             }
0408             return _sub;
0409         };
0410 
0411         auto str = Demangle(std::string(cstr));
0412         auto beg = str.find("(");
0413         if(beg == std::string::npos)
0414         {
0415             beg = str.find("_Z");
0416             if(beg != std::string::npos)
0417                 beg -= 1;
0418         }
0419         auto end = str.find("+", beg);
0420         if(beg != std::string::npos && end != std::string::npos)
0421         {
0422             auto len = end - (beg + 1);
0423             auto sub = str.substr(beg + 1, len);
0424             auto dem = Demangle(_trim(sub, len));
0425             str      = str.replace(beg + 1, len, dem);
0426         }
0427         else if(beg != std::string::npos)
0428         {
0429             auto len = str.length() - (beg + 1);
0430             auto sub = str.substr(beg + 1, len);
0431             auto dem = Demangle(_trim(sub, len));
0432             str      = str.replace(beg + 1, len, dem);
0433         }
0434         else if(end != std::string::npos)
0435         {
0436             auto len = end;
0437             auto sub = str.substr(beg, len);
0438             auto dem = Demangle(_trim(sub, len));
0439             str      = str.replace(beg, len, dem);
0440         }
0441         return func(str.c_str());
0442     };
0443     return GetMangled<Depth, Offset>(demangle_bt);
0444 }
0445 
0446 //----------------------------------------------------------------------------//
0447 
0448 inline void
0449 Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
0450 {
0451     // try to avoid as many dynamic allocations as possible here to avoid
0452     // overflowing the signal stack
0453 
0454     // ignore future signals of this type
0455     signal(sig, SIG_IGN);
0456 
0457     os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
0458     if(sinfo)
0459         os << "address: " << sinfo->si_addr << ", ";
0460     os << Description(sig) << ". ";
0461 
0462     if(sig == SIGSEGV)
0463     {
0464         if(sinfo)
0465         {
0466             switch(sinfo->si_code)
0467             {
0468                 case SEGV_MAPERR: os << "Address not mapped to object."; break;
0469                 case SEGV_ACCERR: os << "Invalid permissions for mapped object."; break;
0470                 default:
0471                     os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
0472                     break;
0473             }
0474         }
0475         else
0476         {
0477             os << "Segmentation fault (unknown).";
0478         }
0479     }
0480     else if(sig == SIGFPE)
0481     {
0482         if(sinfo)
0483         {
0484             switch(sinfo->si_code)
0485             {
0486                 case FE_DIVBYZERO: os << "Floating point divide by zero."; break;
0487                 case FE_OVERFLOW: os << "Floating point overflow."; break;
0488                 case FE_UNDERFLOW: os << "Floating point underflow."; break;
0489                 case FE_INEXACT: os << "Floating point inexact result."; break;
0490                 case FE_INVALID: os << "Floating point invalid operation."; break;
0491                 default:
0492                     os << "Unknown floating point exception error: " << sinfo->si_code
0493                        << ".";
0494                     break;
0495             }
0496         }
0497         else
0498         {
0499             os << "Unknown floating point exception";
0500             if(sinfo)
0501                 os << ": " << sinfo->si_code;
0502             os << ". ";
0503         }
0504     }
0505 
0506     os << '\n';
0507 
0508     auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
0509     char prefix[64];
0510     snprintf(prefix, 64, "[PID=%i, TID=%i]", (int) getpid(),
0511              (int) Threading::GetThreadId());
0512     size_t sz = 0;
0513     for(auto& itr : bt)
0514     {
0515         if(!itr)
0516             break;
0517         if(strlen(itr) == 0)
0518             break;
0519         ++sz;
0520     }
0521     os << "\nBacktrace:\n";
0522     auto _w = std::log10(sz) + 1;
0523     for(size_t i = 0; i < sz; ++i)
0524     {
0525         os << prefix << "[" << std::setw(_w) << std::right << i << '/' << std::setw(_w)
0526            << std::right << sz << "]> " << std::left << bt.at(i) << '\n';
0527     }
0528     os << std::flush;
0529 
0530     // exit action could cause more signals to be raise so make sure this is done
0531     // after the message has been printed
0532     try
0533     {
0534         ExitAction(sig);
0535     } catch(std::exception& e)
0536     {
0537         std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
0538         std::cerr << e.what() << std::endl;
0539     }
0540 }
0541 
0542 //----------------------------------------------------------------------------//
0543 
0544 inline void
0545 Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
0546 {
0547     Message(sig, sinfo, std::cerr);
0548 
0549     char msg[1024];
0550     snprintf(msg, 1024, "%s", "\n");
0551 
0552     if(sinfo && PTL_PSIGINFO_AVAILABLE > 0)
0553     {
0554 #    if PTL_PSIGINFO_AVAILABLE > 0
0555         psiginfo(sinfo, msg);
0556         fflush(stdout);
0557         fflush(stderr);
0558 #    endif
0559     }
0560     else
0561     {
0562         std::cerr << msg << std::flush;
0563     }
0564 
0565     // ignore any termination signals
0566     for(auto itr : { SIGKILL, SIGTERM, SIGABRT })
0567         signal(itr, SIG_IGN);
0568     abort();
0569 }
0570 
0571 //----------------------------------------------------------------------------//
0572 
0573 inline int
0574 Backtrace::Enable(const signal_set_t& _signals)
0575 {
0576     static bool _first = true;
0577     if(_first)
0578     {
0579         std::string       _msg = "!!! Backtrace is activated !!!";
0580         std::stringstream _filler;
0581         std::stringstream _spacer;
0582         _filler.fill('#');
0583         _filler << std::setw(_msg.length()) << "";
0584         _spacer << std::setw(10) << "";
0585         std::cout << "\n\n"
0586                   << _spacer.str() << _filler.str() << "\n"
0587                   << _spacer.str() << _msg << "\n"
0588                   << _spacer.str() << _filler.str() << "\n\n"
0589                   << std::flush;
0590     }
0591     _first  = false;
0592     int cnt = 0;
0593     for(const auto& itr : _signals)
0594     {
0595         if(itr < 0)
0596             continue;
0597         if(GetData().is_active[itr])
0598             continue;
0599         ++cnt;
0600         sigfillset(&(GetData().current[itr].sa_mask));
0601         sigdelset(&(GetData().current[itr].sa_mask), itr);
0602         GetData().current[itr].sa_sigaction = &Handler;
0603         GetData().current[itr].sa_flags     = SA_SIGINFO;
0604         sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
0605     }
0606     return cnt;
0607 }
0608 
0609 //----------------------------------------------------------------------------//
0610 
0611 inline int
0612 Backtrace::Enable(const std::string& _signals)
0613 {
0614     if(_signals.empty())
0615         return 0;
0616 
0617     auto _add_signal = [](std::string sig, signal_set_t& _targ) {
0618         if(!sig.empty())
0619         {
0620             for(auto& itr : sig)
0621                 itr = toupper(itr);
0622             _targ.insert(Backtrace::GetSignal(sig));
0623         }
0624     };
0625 
0626     const std::regex wsp_re("[ ,;:\t\n]+");
0627     auto             _maxid  = GetData().identifiers.size();
0628     auto             _result = std::vector<std::string>(_maxid, "");
0629     std::copy(std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
0630               std::sregex_token_iterator(), _result.begin());
0631     signal_set_t _sigset{};
0632     for(auto& itr : _result)
0633         _add_signal(itr, _sigset);
0634     return Enable(_sigset);
0635 }
0636 
0637 //----------------------------------------------------------------------------//
0638 
0639 inline int
0640 Backtrace::Disable(signal_set_t _signals)
0641 {
0642     if(_signals.empty())
0643     {
0644         for(auto& itr : GetData().is_active)
0645             _signals.insert(itr.first);
0646     }
0647 
0648     int cnt = 0;
0649     for(const auto& itr : _signals)
0650     {
0651         if(itr < 0)
0652             continue;
0653         if(!GetData().is_active[itr])
0654             continue;
0655         ++cnt;
0656         sigaction(itr, &(GetData().previous[itr]), nullptr);
0657         GetData().current.erase(itr);
0658         GetData().is_active[itr] = false;
0659     }
0660     return cnt;
0661 }
0662 
0663 //----------------------------------------------------------------------------//
0664 
0665 inline int
0666 Backtrace::GetSignal(const std::string& sid)
0667 {
0668     for(auto&& itr : GetData().identifiers)
0669     {
0670         if(std::get<0>(itr) == sid)
0671             return std::get<1>(itr);
0672     }
0673     return -1;
0674 }
0675 
0676 //----------------------------------------------------------------------------//
0677 
0678 inline std::string
0679 Backtrace::Description(int sig)
0680 {
0681     for(auto&& itr : GetData().identifiers)
0682     {
0683         if(std::get<1>(itr) == sig)
0684         {
0685             std::stringstream ss;
0686             ss << " signal = " << std::setw(8) << std::get<0>(itr)
0687                << ", value = " << std::setw(4) << std::get<1>(itr)
0688                << ", description = " << std::get<2>(itr);
0689             return ss.str();
0690         }
0691     }
0692     std::stringstream ss;
0693     ss << " signal = " << std::setw(8) << "unknown"
0694        << ", value = " << std::setw(4) << sig;
0695     return ss.str();
0696 }
0697 
0698 //----------------------------------------------------------------------------//
0699 
0700 }  // namespace PTL
0701 
0702 #else
0703 
0704 #    include <array>
0705 #    include <functional>
0706 #    include <map>
0707 #    include <set>
0708 #    include <string>
0709 #    include <tuple>
0710 #    include <vector>
0711 
0712 namespace PTL
0713 {
0714 // dummy implementation
0715 class Backtrace
0716 {
0717 public:
0718     struct fake_siginfo
0719     {};
0720     struct fake_sigaction
0721     {};
0722 
0723     using siginfo_t     = fake_siginfo;
0724     using sigaction_t   = fake_sigaction;
0725     using exit_action_t = std::function<void(int)>;
0726     using frame_func_t  = std::function<std::string(const char*)>;
0727     using signal_set_t  = std::set<int>;
0728 
0729 public:
0730     struct actions
0731     {
0732         using id_entry_t = std::tuple<std::string, int, std::string>;
0733         using id_list_t  = std::vector<id_entry_t>;
0734 
0735         std::map<int, bool>        is_active    = {};
0736         std::map<int, sigaction_t> current      = {};
0737         std::map<int, sigaction_t> previous     = {};
0738         std::vector<exit_action_t> exit_actions = {};
0739         const id_list_t            identifiers  = {};
0740     };
0741 
0742 public:
0743     static void        Handler(int, siginfo_t*, void*) {}
0744     static void        Message(int, siginfo_t*, std::ostream&) {}
0745     static void        ExitAction(int) {}
0746     static int         Enable(const std::string&) { return 0; }
0747     static int         Enable(const signal_set_t& = DefaultSignals()) { return 0; }
0748     static int         Disable(signal_set_t = {}) { return 0; }
0749     static int         GetSignal(const std::string&) { return -1; }
0750     static std::string Description(int) { return std::string{}; }
0751 
0752     template <typename FuncT>
0753     static void AddExitAction(FuncT&&)
0754     {}
0755 
0756     template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
0757     static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
0758         FuncT&& func = FrameFunctor())
0759     {
0760         using type = ResultOf_t<FuncT, const char*>;
0761         auto ret   = std::array<type, Depth>{};
0762         ret.fill(func(""));
0763         return ret;
0764     }
0765 
0766     template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
0767     static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
0768         FuncT&& func = FrameFunctor())
0769     {
0770         using type = ResultOf_t<FuncT, const char*>;
0771         auto ret   = std::array<type, Depth>{};
0772         ret.fill(func(""));
0773         return ret;
0774     }
0775 
0776     // a functor called for each frame in the backtrace
0777     static frame_func_t& FrameFunctor()
0778     {
0779         static frame_func_t _instance = [](const char* _s) { return std::string(_s); };
0780         return _instance;
0781     }
0782 
0783     // default set of signals
0784     static signal_set_t& DefaultSignals()
0785     {
0786         static signal_set_t _instance = {};
0787         return _instance;
0788     }
0789 
0790     static actions& GetData()
0791     {
0792         static auto _instance = actions{};
0793         return _instance;
0794     }
0795 };
0796 
0797 //----------------------------------------------------------------------------//
0798 
0799 }  // namespace PTL
0800 
0801 #endif  // SIGNAL_AVAILABLE
0802 #endif  // Backtrace_hh