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