Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
Backtrace.hh
Go to the documentation of this file.
1//
2// MIT License
3// Copyright (c) 2020 Jonathan R. Madsen
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
12// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
13// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
17// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18//
19// Backtrace
20//
21// Description:
22//
23// Prints backtraces after signals are caught. Available on Unix.
24//
25// Usage:
26// A standard set of signals are enabled by default:
27//
28// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
29//
30// These should not interfere with debuggers and/or FPEDetection.
31// In order to turn off handling for one or more signals, one can do:
32//
33// BackTrace::DefaultSignals() = std::set<int>{};
34// BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
35//
36// and so on, *before* creating the run-manager. After the run-manager
37// has been created, one should disable the signals:
38//
39// BackTrace::Disable(BackTrace::DefaultSignals());
40//
41// Additionally, at runtime, the environment variable "BACKTRACE" can
42// be set to select a specific set of signals or none, e.g. in bash:
43//
44// export BACKTRACE="SIGQUIT,SIGSEGV"
45// export BACKTRACE="none"
46//
47// The environment variable is case-insensitive and can use any of the
48// following delimiters: space, comma, semi-colon, colon
49//
50// Author: J.Madsen, 19 October 2020
51// --------------------------------------------------------------------
52
53#ifndef PTL_Backtrace_hh
54#define PTL_Backtrace_hh 1
55
56#include "Threading.hh"
57#include "Types.hh"
58
59#if defined(PTL_UNIX)
60# include <cxxabi.h>
61# include <execinfo.h>
62# include <unistd.h>
63#endif
64
65#if defined(PTL_LINUX)
66# include <features.h>
67#endif
68
69#include <cfenv>
70#include <cmath>
71#include <csignal>
72#include <cstring>
73#include <type_traits>
74
75namespace PTL
76{
77template <typename FuncT, typename... ArgTypes>
78#if __cpp_lib_is_invocable >= 201703
79using ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
80#else
81using ResultOf_t = typename std::result_of<FuncT(ArgTypes...)>::type;
82#endif
83} // namespace PTL
84
85// compatible OS and compiler
86#if defined(PTL_UNIX) && \
87 (defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
88# if !defined(PTL_SIGNAL_AVAILABLE)
89# define PTL_SIGNAL_AVAILABLE
90# endif
91# if !defined(PTL_DEMANGLE_AVAILABLE)
92# define PTL_DEMANGLE_AVAILABLE
93# endif
94#endif
95
96#if !defined(PTL_PSIGINFO_AVAILABLE)
97# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
98# define PTL_PSIGINFO_AVAILABLE 1
99# else
100# define PTL_PSIGINFO_AVAILABLE 0
101# endif
102#endif
103
104//----------------------------------------------------------------------------//
105
106namespace PTL
107{
108inline std::string
109Demangle(const char* _str)
110{
111#if defined(PTL_DEMANGLE_AVAILABLE)
112 // demangling a string when delimiting
113 int _status = 0;
114 char* _ret = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
115 if(_ret && _status == 0)
116 return std::string(const_cast<const char*>(_ret));
117 return _str;
118#else
119 return _str;
120#endif
121}
122
123//----------------------------------------------------------------------------//
124
125inline std::string
126Demangle(const std::string& _str)
127{
128 return Demangle(_str.c_str());
129}
130
131//----------------------------------------------------------------------------//
132
133template <typename Tp>
134inline std::string
136{
137 return Demangle(typeid(Tp).name());
138}
139} // namespace PTL
140
141//----------------------------------------------------------------------------//
142//
143// ONLY IF SIGNAL_AVAILABLE
144//
145//----------------------------------------------------------------------------//
146//
147#if defined(PTL_SIGNAL_AVAILABLE)
148//
149// these are not in the original POSIX.1-1990 standard so we are defining
150// them in case the OS hasn't
151// POSIX-1.2001
152# ifndef SIGTRAP
153# define SIGTRAP 5
154# endif
155// not specified in POSIX.1-2001, but nevertheless appears on most other
156// UNIX systems, where its default action is typically to terminate the
157// process with a core dump.
158# ifndef SIGEMT
159# define SIGEMT 7
160# endif
161// POSIX-1.2001
162# ifndef SIGURG
163# define SIGURG 16
164# endif
165// POSIX-1.2001
166# ifndef SIGXCPU
167# define SIGXCPU 24
168# endif
169// POSIX-1.2001
170# ifndef SIGXFSZ
171# define SIGXFSZ 25
172# endif
173// POSIX-1.2001
174# ifndef SIGVTALRM
175# define SIGVTALRM 26
176# endif
177// POSIX-1.2001
178# ifndef SIGPROF
179# define SIGPROF 27
180# endif
181// POSIX-1.2001
182# ifndef SIGINFO
183# define SIGINFO 29
184# endif
185
186//----------------------------------------------------------------------------//
187
188# include <algorithm>
189# include <array>
190# include <cstdio>
191# include <cstdlib>
192# include <functional>
193# include <iomanip>
194# include <iostream>
195# include <map>
196# include <regex>
197# include <set>
198# include <sstream>
199# include <string>
200# include <tuple>
201# include <vector>
202
203// PTL header
204# include "Threading.hh"
205
206//----------------------------------------------------------------------------//
207
208namespace PTL
209{
210class Backtrace
211{
212public:
213 using sigaction_t = struct sigaction;
214 using exit_action_t = std::function<void(int)>;
215 using frame_func_t = std::function<std::string(const char*)>;
216 using signal_set_t = std::set<int>;
217
218public:
219 struct actions
220 {
221 using id_entry_t = std::tuple<std::string, int, std::string>;
222 using id_list_t = std::vector<id_entry_t>;
223
224 std::map<int, bool> is_active = {};
225 std::map<int, sigaction_t> current = {};
226 std::map<int, sigaction_t> previous = {};
227 std::vector<exit_action_t> exit_actions = {};
228 const id_list_t identifiers = {
229 id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
230 id_entry_t("SIGINT", SIGINT, "interrupt program"),
231 id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
232 id_entry_t("SIGILL", SIGILL, "illegal instruction"),
233 id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
234 id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
235 id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
236 id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
237 id_entry_t("SIGKILL", SIGKILL, "kill program"),
238 id_entry_t("SIGBUS", SIGBUS, "bus error"),
239 id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
240 id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
241 id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
242 id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
243 id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
244 id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
245 id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
246 id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
247 id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
248 id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
249 id_entry_t("SIGTTIN", SIGTTIN,
250 "background read attempted from control terminal"),
251 id_entry_t("SIGTTOU", SIGTTOU,
252 "background write attempted to control terminal"),
253 id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
254 id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
255 id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
256 id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
257 id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
258 id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
259 id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
260 id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
261 id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
262 };
263 };
264
265public:
266 // a functor called for each frame in the backtrace
267 static frame_func_t& FrameFunctor();
268 // default set of signals
270 // the signal handler
271 static void Handler(int sig, siginfo_t* sinfo, void* context);
272 // information message about the signal, performs exit-actions
273 // and prints back-trace
274 static void Message(int sig, siginfo_t* sinfo, std::ostream&);
275 // calls user-provided functions after signal is caught but before abort
276 static void ExitAction(int sig);
277 // enable signals via a string (which is tokenized)
278 static int Enable(const std::string&);
279 // enable signals via set of integers, anything less than zero is ignored
280 static int Enable(const signal_set_t& _signals = DefaultSignals());
281 // disable signals
282 static int Disable(signal_set_t _signals = {});
283 // gets the numeric value for a signal name
284 static int GetSignal(const std::string&);
285 // provides a description of the signal
286 static std::string Description(int sig);
287
288 // adds an exit action
289 template <typename FuncT>
290 static void AddExitAction(FuncT&& func);
291
292 // gets a backtrace of "Depth" frames. The offset parameter is used
293 // to ignore initial frames (such as this function). A callback
294 // can be provided to inspect and/or tweak the frame string
295 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
296 static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
297 FuncT&& func = FrameFunctor());
298
299 // gets a demangled backtrace of "Depth" frames. The offset parameter is
300 // used to ignore initial frames (such as this function). A callback
301 // can be provided to inspect and/or tweak the frame string
302 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
303 static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
304 FuncT&& func = FrameFunctor());
305
306private:
307 static actions& GetData()
308 {
309 static auto _instance = actions{};
310 return _instance;
311 }
312};
313
314//----------------------------------------------------------------------------//
315
316// a functor called for each frame in the backtrace
319{
320 static frame_func_t _instance = [](const char* inp) { return std::string(inp); };
321 return _instance;
322}
323
324//----------------------------------------------------------------------------//
325
326// default set of signals
329{
330 static signal_set_t _instance = {
331 SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
332 };
333 return _instance;
334}
335
336//----------------------------------------------------------------------------//
337
338template <typename FuncT>
339inline void
340Backtrace::AddExitAction(FuncT&& func)
341{
342 GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
343}
344
345//----------------------------------------------------------------------------//
346
347inline void
349{
350 for(auto& itr : GetData().exit_actions)
351 itr(sig);
352}
353
354//----------------------------------------------------------------------------//
355
356template <size_t Depth, size_t Offset, typename FuncT>
357inline std::array<ResultOf_t<FuncT, const char*>, Depth>
358Backtrace::GetMangled(FuncT&& func)
359{
360 static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
361
363 // destination
364 std::array<type, Depth> btrace;
365 btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
366
367 // plus one for this stack-frame
368 std::array<void*, Depth + Offset> buffer;
369 // size of returned buffer
370 auto sz = backtrace(buffer.data(), Depth + Offset);
371 // size of relevant data
372 auto n = sz - Offset;
373
374 // skip ahead (Offset + 1) stack frames
375 char** bsym = backtrace_symbols(buffer.data() + Offset, n);
376
377 // report errors
378 if(bsym == nullptr)
379 perror("backtrace_symbols");
380 else
381 {
382 for(decltype(n) i = 0; i < n; ++i)
383 btrace[i] = func(bsym[i]);
384 free(bsym);
385 }
386 return btrace;
387}
388
389//----------------------------------------------------------------------------//
390
391template <size_t Depth, size_t Offset, typename FuncT>
392inline std::array<ResultOf_t<FuncT, const char*>, Depth>
393Backtrace::GetDemangled(FuncT&& func)
394{
395 auto demangle_bt = [&](const char* cstr) {
396 auto _trim = [](std::string& _sub, size_t& _len) {
397 size_t _pos = 0;
398 while((_pos = _sub.find_first_of(' ')) == 0)
399 {
400 _sub = _sub.erase(_pos, 1);
401 --_len;
402 }
403 while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
404 {
405 _sub = _sub.substr(0, _sub.length() - 1);
406 --_len;
407 }
408 return _sub;
409 };
410
411 auto str = Demangle(std::string(cstr));
412 auto beg = str.find("(");
413 if(beg == std::string::npos)
414 {
415 beg = str.find("_Z");
416 if(beg != std::string::npos)
417 beg -= 1;
418 }
419 auto end = str.find("+", beg);
420 if(beg != std::string::npos && end != std::string::npos)
421 {
422 auto len = end - (beg + 1);
423 auto sub = str.substr(beg + 1, len);
424 auto dem = Demangle(_trim(sub, len));
425 str = str.replace(beg + 1, len, dem);
426 }
427 else if(beg != std::string::npos)
428 {
429 auto len = str.length() - (beg + 1);
430 auto sub = str.substr(beg + 1, len);
431 auto dem = Demangle(_trim(sub, len));
432 str = str.replace(beg + 1, len, dem);
433 }
434 else if(end != std::string::npos)
435 {
436 auto len = end;
437 auto sub = str.substr(beg, len);
438 auto dem = Demangle(_trim(sub, len));
439 str = str.replace(beg, len, dem);
440 }
441 return func(str.c_str());
442 };
443 return GetMangled<Depth, Offset>(demangle_bt);
444}
445
446//----------------------------------------------------------------------------//
447
448inline void
449Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
450{
451 // try to avoid as many dynamic allocations as possible here to avoid
452 // overflowing the signal stack
453
454 // ignore future signals of this type
455 signal(sig, SIG_IGN);
456
457 os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
458 if(sinfo)
459 os << "address: " << sinfo->si_addr << ", ";
460 os << Description(sig) << ". ";
461
462 if(sig == SIGSEGV)
463 {
464 if(sinfo)
465 {
466 switch(sinfo->si_code)
467 {
468 case SEGV_MAPERR: os << "Address not mapped to object."; break;
469 case SEGV_ACCERR: os << "Invalid permissions for mapped object."; break;
470 default:
471 os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
472 break;
473 }
474 }
475 else
476 {
477 os << "Segmentation fault (unknown).";
478 }
479 }
480 else if(sig == SIGFPE)
481 {
482 if(sinfo)
483 {
484 switch(sinfo->si_code)
485 {
486 case FE_DIVBYZERO: os << "Floating point divide by zero."; break;
487 case FE_OVERFLOW: os << "Floating point overflow."; break;
488 case FE_UNDERFLOW: os << "Floating point underflow."; break;
489 case FE_INEXACT: os << "Floating point inexact result."; break;
490 case FE_INVALID: os << "Floating point invalid operation."; break;
491 default:
492 os << "Unknown floating point exception error: " << sinfo->si_code
493 << ".";
494 break;
495 }
496 }
497 else
498 {
499 os << "Unknown floating point exception";
500 if(sinfo)
501 os << ": " << sinfo->si_code;
502 os << ". ";
503 }
504 }
505
506 os << '\n';
507
508 auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
509 char prefix[64];
510 snprintf(prefix, 64, "[PID=%i, TID=%i]", (int) getpid(),
511 (int) Threading::GetThreadId());
512 size_t sz = 0;
513 for(auto& itr : bt)
514 {
515 if(!itr)
516 break;
517 if(strlen(itr) == 0)
518 break;
519 ++sz;
520 }
521 os << "\nBacktrace:\n";
522 auto _w = std::log10(sz) + 1;
523 for(size_t i = 0; i < sz; ++i)
524 {
525 os << prefix << "[" << std::setw(_w) << std::right << i << '/' << std::setw(_w)
526 << std::right << sz << "]> " << std::left << bt.at(i) << '\n';
527 }
528 os << std::flush;
529
530 // exit action could cause more signals to be raise so make sure this is done
531 // after the message has been printed
532 try
533 {
534 ExitAction(sig);
535 } catch(std::exception& e)
536 {
537 std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
538 std::cerr << e.what() << std::endl;
539 }
540}
541
542//----------------------------------------------------------------------------//
543
544inline void
545Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
546{
547 Message(sig, sinfo, std::cerr);
548
549 char msg[1024];
550 snprintf(msg, 1024, "%s", "\n");
551
552 if(sinfo && PTL_PSIGINFO_AVAILABLE > 0)
553 {
554# if PTL_PSIGINFO_AVAILABLE > 0
555 psiginfo(sinfo, msg);
556 fflush(stdout);
557 fflush(stderr);
558# endif
559 }
560 else
561 {
562 std::cerr << msg << std::flush;
563 }
564
565 // ignore any termination signals
566 for(auto itr : { SIGKILL, SIGTERM, SIGABRT })
567 signal(itr, SIG_IGN);
568 abort();
569}
570
571//----------------------------------------------------------------------------//
572
573inline int
574Backtrace::Enable(const signal_set_t& _signals)
575{
576 static bool _first = true;
577 if(_first)
578 {
579 std::string _msg = "!!! Backtrace is activated !!!";
580 std::stringstream _filler;
581 std::stringstream _spacer;
582 _filler.fill('#');
583 _filler << std::setw(_msg.length()) << "";
584 _spacer << std::setw(10) << "";
585 std::cout << "\n\n"
586 << _spacer.str() << _filler.str() << "\n"
587 << _spacer.str() << _msg << "\n"
588 << _spacer.str() << _filler.str() << "\n\n"
589 << std::flush;
590 }
591 _first = false;
592 int cnt = 0;
593 for(const auto& itr : _signals)
594 {
595 if(itr < 0)
596 continue;
597 if(GetData().is_active[itr])
598 continue;
599 ++cnt;
600 sigfillset(&(GetData().current[itr].sa_mask));
601 sigdelset(&(GetData().current[itr].sa_mask), itr);
602 GetData().current[itr].sa_sigaction = &Handler;
603 GetData().current[itr].sa_flags = SA_SIGINFO;
604 sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
605 }
606 return cnt;
607}
608
609//----------------------------------------------------------------------------//
610
611inline int
612Backtrace::Enable(const std::string& _signals)
613{
614 if(_signals.empty())
615 return 0;
616
617 auto _add_signal = [](std::string sig, signal_set_t& _targ) {
618 if(!sig.empty())
619 {
620 for(auto& itr : sig)
621 itr = toupper(itr);
622 _targ.insert(Backtrace::GetSignal(sig));
623 }
624 };
625
626 const std::regex wsp_re("[ ,;:\t\n]+");
627 auto _maxid = GetData().identifiers.size();
628 auto _result = std::vector<std::string>(_maxid, "");
629 std::copy(std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
630 std::sregex_token_iterator(), _result.begin());
631 signal_set_t _sigset{};
632 for(auto& itr : _result)
633 _add_signal(itr, _sigset);
634 return Enable(_sigset);
635}
636
637//----------------------------------------------------------------------------//
638
639inline int
640Backtrace::Disable(signal_set_t _signals)
641{
642 if(_signals.empty())
643 {
644 for(auto& itr : GetData().is_active)
645 _signals.insert(itr.first);
646 }
647
648 int cnt = 0;
649 for(const auto& itr : _signals)
650 {
651 if(itr < 0)
652 continue;
653 if(!GetData().is_active[itr])
654 continue;
655 ++cnt;
656 sigaction(itr, &(GetData().previous[itr]), nullptr);
657 GetData().current.erase(itr);
658 GetData().is_active[itr] = false;
659 }
660 return cnt;
661}
662
663//----------------------------------------------------------------------------//
664
665inline int
666Backtrace::GetSignal(const std::string& sid)
667{
668 for(auto&& itr : GetData().identifiers)
669 {
670 if(std::get<0>(itr) == sid)
671 return std::get<1>(itr);
672 }
673 return -1;
674}
675
676//----------------------------------------------------------------------------//
677
678inline std::string
680{
681 for(auto&& itr : GetData().identifiers)
682 {
683 if(std::get<1>(itr) == sig)
684 {
685 std::stringstream ss;
686 ss << " signal = " << std::setw(8) << std::get<0>(itr)
687 << ", value = " << std::setw(4) << std::get<1>(itr)
688 << ", description = " << std::get<2>(itr);
689 return ss.str();
690 }
691 }
692 std::stringstream ss;
693 ss << " signal = " << std::setw(8) << "unknown"
694 << ", value = " << std::setw(4) << sig;
695 return ss.str();
696}
697
698//----------------------------------------------------------------------------//
699
700} // namespace PTL
701
702#else
703
704# include <array>
705# include <functional>
706# include <map>
707# include <set>
708# include <string>
709# include <tuple>
710# include <vector>
711
712namespace PTL
713{
714// dummy implementation
716{
717public:
719 {};
721 {};
722
725 using exit_action_t = std::function<void(int)>;
726 using frame_func_t = std::function<std::string(const char*)>;
727 using signal_set_t = std::set<int>;
728
729public:
730 struct actions
731 {
732 using id_entry_t = std::tuple<std::string, int, std::string>;
733 using id_list_t = std::vector<id_entry_t>;
734
735 std::map<int, bool> is_active = {};
736 std::map<int, sigaction_t> current = {};
737 std::map<int, sigaction_t> previous = {};
738 std::vector<exit_action_t> exit_actions = {};
740 };
741
742public:
743 static void Handler(int, siginfo_t*, void*) {}
744 static void Message(int, siginfo_t*, std::ostream&) {}
745 static void ExitAction(int) {}
746 static int Enable(const std::string&) { return 0; }
747 static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
748 static int Disable(signal_set_t = {}) { return 0; }
749 static int GetSignal(const std::string&) { return -1; }
750 static std::string Description(int) { return std::string{}; }
751
752 template <typename FuncT>
753 static void AddExitAction(FuncT&&)
754 {}
755
756 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
757 static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
758 FuncT&& func = FrameFunctor())
759 {
761 auto ret = std::array<type, Depth>{};
762 ret.fill(func(""));
763 return ret;
764 }
765
766 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
767 static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
768 FuncT&& func = FrameFunctor())
769 {
771 auto ret = std::array<type, Depth>{};
772 ret.fill(func(""));
773 return ret;
774 }
775
776 // a functor called for each frame in the backtrace
778 {
779 static frame_func_t _instance = [](const char* _s) { return std::string(_s); };
780 return _instance;
781 }
782
783 // default set of signals
785 {
786 static signal_set_t _instance = {};
787 return _instance;
788 }
789
790 static actions& GetData()
791 {
792 static auto _instance = actions{};
793 return _instance;
794 }
795};
796
797//----------------------------------------------------------------------------//
798
799} // namespace PTL
800
801#endif // SIGNAL_AVAILABLE
802#endif // Backtrace_hh
#define PTL_PSIGINFO_AVAILABLE
Definition Backtrace.hh:100
static int Enable(const std::string &)
Definition Backtrace.hh:746
static signal_set_t & DefaultSignals()
Definition Backtrace.hh:784
static std::string Description(int)
Definition Backtrace.hh:750
static void AddExitAction(FuncT &&)
Definition Backtrace.hh:753
static void ExitAction(int)
Definition Backtrace.hh:745
static void Message(int, siginfo_t *, std::ostream &)
Definition Backtrace.hh:744
static int GetSignal(const std::string &)
Definition Backtrace.hh:749
static frame_func_t & FrameFunctor()
Definition Backtrace.hh:777
static int Disable(signal_set_t={})
Definition Backtrace.hh:748
std::function< std::string(const char *)> frame_func_t
Definition Backtrace.hh:726
static int Enable(const signal_set_t &=DefaultSignals())
Definition Backtrace.hh:747
std::set< int > signal_set_t
Definition Backtrace.hh:727
std::function< void(int)> exit_action_t
Definition Backtrace.hh:725
fake_sigaction sigaction_t
Definition Backtrace.hh:724
fake_siginfo siginfo_t
Definition Backtrace.hh:723
static std::array< ResultOf_t< FuncT, const char * >, Depth > GetDemangled(FuncT &&func=FrameFunctor())
Definition Backtrace.hh:767
static std::array< ResultOf_t< FuncT, const char * >, Depth > GetMangled(FuncT &&func=FrameFunctor())
Definition Backtrace.hh:757
static actions & GetData()
Definition Backtrace.hh:790
static void Handler(int, siginfo_t *, void *)
Definition Backtrace.hh:743
typename std::result_of< FuncT(ArgTypes...)>::type ResultOf_t
Definition Backtrace.hh:81
std::string Demangle()
Definition Backtrace.hh:135
std::vector< id_entry_t > id_list_t
Definition Backtrace.hh:733
std::map< int, bool > is_active
Definition Backtrace.hh:735
const id_list_t identifiers
Definition Backtrace.hh:739
std::tuple< std::string, int, std::string > id_entry_t
Definition Backtrace.hh:732
std::map< int, sigaction_t > previous
Definition Backtrace.hh:737
std::vector< exit_action_t > exit_actions
Definition Backtrace.hh:738
std::map< int, sigaction_t > current
Definition Backtrace.hh:736