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) 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> 103 using G4ResultOf_t = std::invoke_result_t<Func << 103 using G4ResultOf_t = typename std::result_of<FuncT>::type; 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 int _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 && _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> << 206 # include <functional> 205 # include <functional> 207 # include <iomanip> 206 # include <iomanip> 208 # include <iostream> 207 # include <iostream> 209 # include <map> 208 # include <map> >> 209 # include <mutex> 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(int)>; 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<int>; 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, int, 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::shared_ptr<std::mutex> lock = std::make_shared<std::mutex>(); 234 std::map<G4int, sigaction_t> current << 234 std::map<int, bool> is_active = {}; 235 std::map<G4int, sigaction_t> previous << 235 std::map<int, sigaction_t> current = {}; >> 236 std::map<int, sigaction_t> previous = {}; 236 std::vector<exit_action_t> exit_actions = 237 std::vector<exit_action_t> exit_actions = {}; 237 const id_list_t identifiers = 238 const id_list_t identifiers = { 238 id_entry_t("SIGHUP", SIGHUP, "terminal l 239 id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"), 239 id_entry_t("SIGINT", SIGINT, "interrupt 240 id_entry_t("SIGINT", SIGINT, "interrupt program"), 240 id_entry_t("SIGQUIT", SIGQUIT, "quit pro 241 id_entry_t("SIGQUIT", SIGQUIT, "quit program"), 241 id_entry_t("SIGILL", SIGILL, "illegal in 242 id_entry_t("SIGILL", SIGILL, "illegal instruction"), 242 id_entry_t("SIGTRAP", SIGTRAP, "trace tr 243 id_entry_t("SIGTRAP", SIGTRAP, "trace trap"), 243 id_entry_t("SIGABRT", SIGABRT, "abort pr 244 id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"), 244 id_entry_t("SIGEMT", SIGEMT, "emulate in 245 id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"), 245 id_entry_t("SIGFPE", SIGFPE, "floating-p 246 id_entry_t("SIGFPE", SIGFPE, "floating-point exception"), 246 id_entry_t("SIGKILL", SIGKILL, "kill pro 247 id_entry_t("SIGKILL", SIGKILL, "kill program"), 247 id_entry_t("SIGBUS", SIGBUS, "bus error" 248 id_entry_t("SIGBUS", SIGBUS, "bus error"), 248 id_entry_t("SIGSEGV", SIGSEGV, "segmenta 249 id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"), 249 id_entry_t("SIGSYS", SIGSYS, "non-existe 250 id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"), 250 id_entry_t("SIGPIPE", SIGPIPE, "write on 251 id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"), 251 id_entry_t("SIGALRM", SIGALRM, "real-tim 252 id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"), 252 id_entry_t("SIGTERM", SIGTERM, "software 253 id_entry_t("SIGTERM", SIGTERM, "software termination signal"), 253 id_entry_t("SIGURG", SIGURG, "urgent con 254 id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"), 254 id_entry_t("SIGSTOP", SIGSTOP, "stop (ca 255 id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"), 255 id_entry_t("SIGTSTP", SIGTSTP, "stop sig 256 id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"), 256 id_entry_t("SIGCONT", SIGCONT, "continue 257 id_entry_t("SIGCONT", SIGCONT, "continue after stop"), 257 id_entry_t("SIGCHLD", SIGCHLD, "child st 258 id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"), 258 id_entry_t("SIGTTIN", SIGTTIN, 259 id_entry_t("SIGTTIN", SIGTTIN, 259 "background read attempted fr 260 "background read attempted from control terminal"), 260 id_entry_t("SIGTTOU", SIGTTOU, 261 id_entry_t("SIGTTOU", SIGTTOU, 261 "background write attempted t 262 "background write attempted to control terminal"), 262 id_entry_t("SIGIO ", SIGIO, "I/O is poss 263 id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"), 263 id_entry_t("SIGXCPU", SIGXCPU, "cpu time 264 id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"), 264 id_entry_t("SIGXFSZ", SIGXFSZ, "file siz 265 id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"), 265 id_entry_t("SIGVTALRM", SIGVTALRM, "virt 266 id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"), 266 id_entry_t("SIGPROF", SIGPROF, "profilin 267 id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"), 267 id_entry_t("SIGWINCH", SIGWINCH, "Window 268 id_entry_t("SIGWINCH", SIGWINCH, "Window size change"), 268 id_entry_t("SIGINFO", SIGINFO, "status r 269 id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"), 269 id_entry_t("SIGUSR1", SIGUSR1, "User def 270 id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"), 270 id_entry_t("SIGUSR2", SIGUSR2, "User def 271 id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2") 271 }; 272 }; 272 }; 273 }; 273 274 274 public: 275 public: 275 // a functor called for each frame in the ba 276 // a functor called for each frame in the backtrace 276 static frame_func_t& FrameFunctor(); 277 static frame_func_t& FrameFunctor(); 277 // default set of signals 278 // default set of signals 278 static signal_set_t& DefaultSignals(); 279 static signal_set_t& DefaultSignals(); 279 // the signal handler 280 // the signal handler 280 static void Handler(G4int sig, siginfo_t* si << 281 static void Handler(int sig, siginfo_t* sinfo, void* context); 281 // information message about the signal, per 282 // information message about the signal, performs exit-actions 282 // and prints back-trace 283 // and prints back-trace 283 static void Message(G4int sig, siginfo_t* si << 284 static void Message(int sig, siginfo_t* sinfo, std::ostream&); 284 // calls user-provided functions after signa 285 // calls user-provided functions after signal is caught but before abort 285 static void ExitAction(G4int sig); << 286 static void ExitAction(int sig); 286 // enable signals via a string (which is tok 287 // enable signals via a string (which is tokenized) 287 static G4int Enable(const std::string&); << 288 static int Enable(const std::string&); 288 // enable signals via set of integers, anyth 289 // enable signals via set of integers, anything less than zero is ignored 289 static G4int Enable(const signal_set_t& _sig << 290 static int Enable(const signal_set_t& _signals = DefaultSignals()); 290 // disable signals 291 // disable signals 291 static G4int Disable(signal_set_t _signals = << 292 static int Disable(signal_set_t _signals = {}); 292 // gets the numeric value for a signal name 293 // gets the numeric value for a signal name 293 static G4int GetSignal(const std::string&); << 294 static int GetSignal(const std::string&); 294 // provides a description of the signal 295 // provides a description of the signal 295 static std::string Description(G4int sig); << 296 static std::string Description(int sig); 296 297 297 // adds an exit action 298 // adds an exit action 298 template <typename FuncT> 299 template <typename FuncT> 299 static void AddExitAction(FuncT&& func); 300 static void AddExitAction(FuncT&& func); 300 301 301 // gets a backtrace of "Depth" frames. The o 302 // gets a backtrace of "Depth" frames. The offset parameter is used 302 // to ignore initial frames (such as this fu 303 // to ignore initial frames (such as this function). A callback 303 // can be provided to inspect and/or tweak t 304 // can be provided to inspect and/or tweak the frame string 304 template <std::size_t Depth, std::size_t Off << 305 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t> 305 static std::array<G4ResultOf_t<FuncT, const << 306 static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled( 306 FuncT&& func = FrameFunctor()); 307 FuncT&& func = FrameFunctor()); 307 308 308 // gets a demangled backtrace of "Depth" fra 309 // gets a demangled backtrace of "Depth" frames. The offset parameter is 309 // used to ignore initial frames (such as th 310 // used to ignore initial frames (such as this function). A callback 310 // can be provided to inspect and/or tweak t 311 // can be provided to inspect and/or tweak the frame string 311 template <std::size_t Depth, std::size_t Off << 312 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t> 312 static std::array<G4ResultOf_t<FuncT, const << 313 static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled( 313 FuncT&& func = FrameFunctor()); 314 FuncT&& func = FrameFunctor()); 314 315 315 private: 316 private: 316 static actions& GetData() 317 static actions& GetData() 317 { 318 { 318 static auto _instance = actions{}; 319 static auto _instance = actions{}; 319 return _instance; 320 return _instance; 320 } 321 } 321 }; 322 }; 322 323 323 //-------------------------------------------- 324 //----------------------------------------------------------------------------// 324 325 325 // a functor called for each frame in the back 326 // a functor called for each frame in the backtrace 326 inline G4Backtrace::frame_func_t& G4Backtrace: 327 inline G4Backtrace::frame_func_t& G4Backtrace::FrameFunctor() 327 { 328 { 328 static frame_func_t _instance = [](const cha 329 static frame_func_t _instance = [](const char* inp) { return G4String(inp); }; 329 return _instance; 330 return _instance; 330 } 331 } 331 332 332 //-------------------------------------------- 333 //----------------------------------------------------------------------------// 333 334 334 // default set of signals 335 // default set of signals 335 inline G4Backtrace::signal_set_t& G4Backtrace: 336 inline G4Backtrace::signal_set_t& G4Backtrace::DefaultSignals() 336 { 337 { 337 static signal_set_t _instance = { SIGQUIT, S 338 static signal_set_t _instance = { SIGQUIT, SIGILL, SIGABRT, 338 SIGKILL, S 339 SIGKILL, SIGBUS, SIGSEGV }; 339 return _instance; 340 return _instance; 340 } 341 } 341 342 342 //-------------------------------------------- 343 //----------------------------------------------------------------------------// 343 344 344 template <typename FuncT> 345 template <typename FuncT> 345 inline void G4Backtrace::AddExitAction(FuncT&& 346 inline void G4Backtrace::AddExitAction(FuncT&& func) 346 { 347 { 347 GetData().exit_actions.emplace_back(std::for 348 GetData().exit_actions.emplace_back(std::forward<FuncT>(func)); 348 } 349 } 349 350 350 //-------------------------------------------- 351 //----------------------------------------------------------------------------// 351 352 352 inline void G4Backtrace::ExitAction(G4int sig) << 353 inline void G4Backtrace::ExitAction(int sig) 353 { 354 { 354 for(auto& itr : GetData().exit_actions) 355 for(auto& itr : GetData().exit_actions) 355 itr(sig); 356 itr(sig); 356 } 357 } 357 358 358 //-------------------------------------------- 359 //----------------------------------------------------------------------------// 359 360 360 template <std::size_t Depth, std::size_t Offse << 361 template <size_t Depth, size_t Offset, typename FuncT> 361 inline std::array<G4ResultOf_t<FuncT, const ch << 362 inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth> 362 G4Backtrace::GetMangled(FuncT&& func) 363 G4Backtrace::GetMangled(FuncT&& func) 363 { 364 { 364 static_assert((Depth - Offset) >= 1, "Error 365 static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1"); 365 366 366 using type = G4ResultOf_t<FuncT, const char* << 367 using type = G4ResultOf_t<FuncT(const char*)>; 367 // destination 368 // destination 368 std::array<type, Depth> btrace; 369 std::array<type, Depth> btrace; 369 btrace.fill((std::is_pointer<type>::value) ? 370 btrace.fill((std::is_pointer<type>::value) ? nullptr : type{}); 370 371 371 // plus one for this stack-frame 372 // plus one for this stack-frame 372 std::array<void*, Depth + Offset> buffer; 373 std::array<void*, Depth + Offset> buffer; 373 // size of returned buffer 374 // size of returned buffer 374 auto sz = backtrace(buffer.data(), Depth + O 375 auto sz = backtrace(buffer.data(), Depth + Offset); 375 // size of relevant data 376 // size of relevant data 376 auto n = sz - Offset; 377 auto n = sz - Offset; 377 378 378 // skip ahead (Offset + 1) stack frames 379 // skip ahead (Offset + 1) stack frames 379 char** bsym = backtrace_symbols(buffer.data( << 380 char** bsym = backtrace_symbols(buffer.data() + Offset, n); 380 381 381 // report errors 382 // report errors 382 if(bsym == nullptr) 383 if(bsym == nullptr) 383 perror("backtrace_symbols"); 384 perror("backtrace_symbols"); 384 else 385 else 385 { 386 { 386 for(decltype(n) i = 0; i < n; ++i) 387 for(decltype(n) i = 0; i < n; ++i) 387 btrace[i] = func(bsym[i]); 388 btrace[i] = func(bsym[i]); 388 free(bsym); 389 free(bsym); 389 } 390 } 390 return btrace; 391 return btrace; 391 } 392 } 392 393 393 //-------------------------------------------- 394 //----------------------------------------------------------------------------// 394 395 395 template <std::size_t Depth, std::size_t Offse << 396 template <size_t Depth, size_t Offset, typename FuncT> 396 inline std::array<G4ResultOf_t<FuncT, const ch << 397 inline std::array<G4ResultOf_t<FuncT(const char*)>, Depth> 397 G4Backtrace::GetDemangled(FuncT&& func) 398 G4Backtrace::GetDemangled(FuncT&& func) 398 { 399 { 399 auto demangle_bt = [&](const char* cstr) { 400 auto demangle_bt = [&](const char* cstr) { 400 auto _trim = [](std::string& _sub, std::si << 401 auto _trim = [](std::string& _sub, size_t& _len) { 401 std::size_t _pos = 0; << 402 size_t _pos = 0; 402 while((_pos = _sub.find_first_of(' ')) = 403 while((_pos = _sub.find_first_of(' ')) == 0) 403 { 404 { 404 _sub = _sub.erase(_pos, 1); 405 _sub = _sub.erase(_pos, 1); 405 --_len; 406 --_len; 406 } 407 } 407 while((_pos = _sub.find_last_of(' ')) == 408 while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1) 408 { 409 { 409 _sub = _sub.substr(0, _sub.length() - 410 _sub = _sub.substr(0, _sub.length() - 1); 410 --_len; 411 --_len; 411 } 412 } 412 return _sub; 413 return _sub; 413 }; 414 }; 414 415 415 auto str = G4Demangle(std::string(cstr)); 416 auto str = G4Demangle(std::string(cstr)); 416 auto beg = str.find('('); << 417 auto beg = str.find("("); 417 if(beg == std::string::npos) 418 if(beg == std::string::npos) 418 { 419 { 419 beg = str.find("_Z"); 420 beg = str.find("_Z"); 420 if(beg != std::string::npos) 421 if(beg != std::string::npos) 421 beg -= 1; 422 beg -= 1; 422 } 423 } 423 auto end = str.find('+', beg); << 424 auto end = str.find("+", beg); 424 if(beg != std::string::npos && end != std: 425 if(beg != std::string::npos && end != std::string::npos) 425 { 426 { 426 auto len = end - (beg + 1); 427 auto len = end - (beg + 1); 427 auto sub = str.substr(beg + 1, len); 428 auto sub = str.substr(beg + 1, len); 428 auto dem = G4Demangle(_trim(sub, len)); 429 auto dem = G4Demangle(_trim(sub, len)); 429 str = str.replace(beg + 1, len, dem 430 str = str.replace(beg + 1, len, dem); 430 } 431 } 431 else if(beg != std::string::npos) 432 else if(beg != std::string::npos) 432 { 433 { 433 auto len = str.length() - (beg + 1); 434 auto len = str.length() - (beg + 1); 434 auto sub = str.substr(beg + 1, len); 435 auto sub = str.substr(beg + 1, len); 435 auto dem = G4Demangle(_trim(sub, len)); 436 auto dem = G4Demangle(_trim(sub, len)); 436 str = str.replace(beg + 1, len, dem 437 str = str.replace(beg + 1, len, dem); 437 } 438 } 438 else if(end != std::string::npos) 439 else if(end != std::string::npos) 439 { 440 { 440 auto len = end; 441 auto len = end; 441 auto sub = str.substr(beg, len); 442 auto sub = str.substr(beg, len); 442 auto dem = G4Demangle(_trim(sub, len)); 443 auto dem = G4Demangle(_trim(sub, len)); 443 str = str.replace(beg, len, dem); 444 str = str.replace(beg, len, dem); 444 } 445 } 445 return func(str.c_str()); 446 return func(str.c_str()); 446 }; 447 }; 447 return GetMangled<Depth, Offset>(demangle_bt 448 return GetMangled<Depth, Offset>(demangle_bt); 448 } 449 } 449 450 450 //-------------------------------------------- 451 //----------------------------------------------------------------------------// 451 452 452 inline void G4Backtrace::Message(G4int sig, si << 453 inline void G4Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os) 453 { 454 { 454 // try to avoid as many dynamic allocations << 455 std::stringstream message; 455 // overflowing the signal stack << 456 message << "\n### CAUGHT SIGNAL: " << sig << " ### "; 456 << 457 if(sinfo) 457 // ignore future signals of this type << 458 message << "address: " << sinfo->si_addr << ", "; 458 signal(sig, SIG_IGN); << 459 message << Description(sig) << ". "; 459 << 460 os << "\n### CAUGHT SIGNAL: " << sig << " ## << 461 if(sinfo != nullptr) << 462 os << "address: " << sinfo->si_addr << ", << 463 os << Description(sig) << ". "; << 464 460 465 if(sig == SIGSEGV) 461 if(sig == SIGSEGV) 466 { 462 { 467 if(sinfo != nullptr) << 463 if(sinfo) 468 { 464 { 469 switch(sinfo->si_code) 465 switch(sinfo->si_code) 470 { 466 { 471 case SEGV_MAPERR: 467 case SEGV_MAPERR: 472 os << "Address not mapped to object. << 468 message << "Address not mapped to object."; 473 break; 469 break; 474 case SEGV_ACCERR: 470 case SEGV_ACCERR: 475 os << "Invalid permissions for mappe << 471 message << "Invalid permissions for mapped object."; 476 break; 472 break; 477 default: 473 default: 478 os << "Unknown segmentation fault er << 474 message << "Unknown segmentation fault error: " << sinfo->si_code >> 475 << "."; 479 break; 476 break; 480 } 477 } 481 } 478 } 482 else 479 else 483 { 480 { 484 os << "Segmentation fault (unknown)."; << 481 message << "Segmentation fault (unknown)."; 485 } 482 } 486 } 483 } 487 else if(sig == SIGFPE) 484 else if(sig == SIGFPE) 488 { 485 { 489 if(sinfo != nullptr) << 486 if(sinfo) 490 { 487 { 491 switch(sinfo->si_code) 488 switch(sinfo->si_code) 492 { 489 { 493 case FE_DIVBYZERO: 490 case FE_DIVBYZERO: 494 os << "Floating point divide by zero << 491 message << "Floating point divide by zero."; 495 break; 492 break; 496 case FE_OVERFLOW: 493 case FE_OVERFLOW: 497 os << "Floating point overflow."; << 494 message << "Floating point overflow."; 498 break; 495 break; 499 case FE_UNDERFLOW: 496 case FE_UNDERFLOW: 500 os << "Floating point underflow."; << 497 message << "Floating point underflow."; 501 break; 498 break; 502 case FE_INEXACT: 499 case FE_INEXACT: 503 os << "Floating point inexact result << 500 message << "Floating point inexact result."; 504 break; 501 break; 505 case FE_INVALID: 502 case FE_INVALID: 506 os << "Floating point invalid operat << 503 message << "Floating point invalid operation."; 507 break; 504 break; 508 default: 505 default: 509 os << "Unknown floating point except << 506 message << "Unknown floating point exception error: " 510 << "."; << 507 << sinfo->si_code << "."; 511 break; 508 break; 512 } 509 } 513 } 510 } 514 else 511 else 515 { 512 { 516 os << "Unknown floating point exception" << 513 message << "Unknown floating point exception"; 517 if(sinfo != nullptr) << 514 if(sinfo) 518 os << ": " << sinfo->si_code; << 515 message << ": " << sinfo->si_code; 519 os << ". "; << 516 message << ". "; 520 } 517 } 521 } 518 } 522 519 523 os << '\n'; << 520 message << std::endl; 524 << 525 auto bt = GetMangled<256, 3>([](const char* << 526 char prefix[64]; << 527 snprintf(prefix, 64, "[PID=%i, TID=%i]", (G4 << 528 (G4int) G4Threading::G4GetThreadId( << 529 std::size_t sz = 0; << 530 for(auto& itr : bt) << 531 { << 532 if(itr == nullptr) << 533 break; << 534 if(strlen(itr) == 0) << 535 break; << 536 ++sz; << 537 } << 538 os << "\nBacktrace:\n"; << 539 auto _w = std::log10(sz) + 1; << 540 for(std::size_t i = 0; i < sz; ++i) << 541 { << 542 os << prefix << "[" << std::setw(_w) << st << 543 << std::setw(_w) << std::right << sz << << 544 << '\n'; << 545 } << 546 os << std::flush; << 547 << 548 // exit action could cause more signals to b << 549 // after the message has been printed << 550 try 521 try 551 { 522 { >> 523 sigignore(sig); 552 ExitAction(sig); 524 ExitAction(sig); 553 } catch(std::exception& e) 525 } catch(std::exception& e) 554 { 526 { 555 std::cerr << "ExitAction(" << sig << ") th 527 std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl; 556 std::cerr << e.what() << std::endl; 528 std::cerr << e.what() << std::endl; 557 } 529 } >> 530 >> 531 auto bt = GetDemangled<256, 3>(FrameFunctor()); >> 532 std::stringstream prefix; >> 533 prefix << "[PID=" << getpid() << ", TID=" << G4Threading::G4GetThreadId() >> 534 << "]"; >> 535 std::vector<G4String> btvec; >> 536 for(auto& itr : bt) >> 537 { >> 538 if(itr.length() > 0) >> 539 btvec.emplace_back(std::move(itr)); >> 540 } >> 541 std::stringstream serr; >> 542 serr << "\nBacktrace:\n"; >> 543 auto _w = std::log10(btvec.size()) + 1; >> 544 for(size_t i = 0; i < btvec.size(); ++i) >> 545 { >> 546 serr << prefix.str() << "[" << std::setw(_w) << std::right << i << '/' >> 547 << std::setw(_w) << std::right << btvec.size() << "]> " << std::left >> 548 << btvec.at(i) << '\n'; >> 549 } >> 550 os << serr.str().c_str() << '\n'; >> 551 os << message.str() << std::flush; 558 } 552 } 559 553 560 //-------------------------------------------- 554 //----------------------------------------------------------------------------// 561 555 562 inline void G4Backtrace::Handler(G4int sig, si << 556 inline void G4Backtrace::Handler(int sig, siginfo_t* sinfo, void*) 563 { 557 { 564 Message(sig, sinfo, std::cerr); << 558 std::unique_lock<std::mutex> lk{ *(GetData().lock) }; 565 559 566 char msg[1024]; << 560 { 567 snprintf(msg, 1024, "%s", "\n"); << 561 std::stringstream msg; >> 562 Message(sig, sinfo, msg); >> 563 std::cerr << msg.str() << std::flush; >> 564 } 568 565 569 if((sinfo != nullptr) && G4PSIGINFO_AVAILABL << 566 std::stringstream msg; >> 567 msg << "\n\n"; >> 568 >> 569 if(sinfo && G4PSIGINFO_AVAILABLE > 0) 570 { 570 { 571 # if G4PSIGINFO_AVAILABLE > 0 571 # if G4PSIGINFO_AVAILABLE > 0 572 psiginfo(sinfo, msg); << 572 psiginfo(sinfo, msg.str().c_str()); 573 fflush(stdout); << 574 fflush(stderr); << 575 # endif 573 # endif 576 } 574 } 577 else 575 else 578 { 576 { 579 std::cerr << msg << std::flush; << 577 std::cerr << msg.str() << std::endl; 580 } 578 } 581 579 582 // ignore any termination signals 580 // ignore any termination signals 583 signal(SIGKILL, SIG_IGN); << 581 sigignore(SIGKILL); 584 signal(SIGTERM, SIG_IGN); << 582 sigignore(SIGTERM); 585 signal(SIGABRT, SIG_IGN); << 583 sigignore(SIGABRT); 586 abort(); 584 abort(); 587 } 585 } 588 586 589 //-------------------------------------------- 587 //----------------------------------------------------------------------------// 590 588 591 inline G4int G4Backtrace::Enable(const signal_ << 589 inline int G4Backtrace::Enable(const signal_set_t& _signals) 592 { 590 { 593 static G4bool _first = true; << 591 static bool _first = true; >> 592 std::unique_lock<std::mutex> lk{ *(GetData().lock) }; 594 if(_first) 593 if(_first) 595 { 594 { 596 std::string _msg = "!!! G4Backtrace is act 595 std::string _msg = "!!! G4Backtrace is activated !!!"; 597 std::stringstream _filler; 596 std::stringstream _filler; 598 std::stringstream _spacer; 597 std::stringstream _spacer; 599 _filler.fill('#'); 598 _filler.fill('#'); 600 _filler << std::setw((G4int)_msg.length()) << 599 _filler << std::setw(_msg.length()) << ""; 601 _spacer << std::setw(10) << ""; 600 _spacer << std::setw(10) << ""; 602 std::cout << "\n\n" 601 std::cout << "\n\n" 603 << _spacer.str() << _filler.str( 602 << _spacer.str() << _filler.str() << "\n" 604 << _spacer.str() << _msg << "\n" 603 << _spacer.str() << _msg << "\n" 605 << _spacer.str() << _filler.str( 604 << _spacer.str() << _filler.str() << "\n\n" 606 << std::flush; 605 << std::flush; 607 } 606 } 608 _first = false; 607 _first = false; 609 G4int cnt = 0; << 608 int cnt = 0; 610 for(auto& itr : _signals) 609 for(auto& itr : _signals) 611 { 610 { 612 if(itr < 0) 611 if(itr < 0) 613 continue; 612 continue; 614 if(GetData().is_active[itr]) 613 if(GetData().is_active[itr]) 615 continue; 614 continue; 616 ++cnt; 615 ++cnt; 617 sigfillset(&(GetData().current[itr].sa_mas 616 sigfillset(&(GetData().current[itr].sa_mask)); 618 sigdelset(&(GetData().current[itr].sa_mask 617 sigdelset(&(GetData().current[itr].sa_mask), itr); 619 GetData().current[itr].sa_sigaction = &Han 618 GetData().current[itr].sa_sigaction = &Handler; 620 GetData().current[itr].sa_flags = SA_S 619 GetData().current[itr].sa_flags = SA_SIGINFO; 621 sigaction(itr, &(GetData().current[itr]), 620 sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr])); 622 } 621 } 623 return cnt; 622 return cnt; 624 } 623 } 625 624 626 //-------------------------------------------- 625 //----------------------------------------------------------------------------// 627 626 628 inline G4int G4Backtrace::Enable(const std::st << 627 inline int G4Backtrace::Enable(const std::string& _signals) 629 { 628 { 630 if(_signals.empty()) 629 if(_signals.empty()) 631 return 0; 630 return 0; 632 631 633 auto _add_signal = [](std::string sig, signa 632 auto _add_signal = [](std::string sig, signal_set_t& _targ) { 634 if(!sig.empty()) 633 if(!sig.empty()) 635 { 634 { 636 for(auto& itr : sig) 635 for(auto& itr : sig) 637 itr = (char)std::toupper(itr); << 636 itr = toupper(itr); 638 _targ.insert(G4Backtrace::GetSignal(sig) 637 _targ.insert(G4Backtrace::GetSignal(sig)); 639 } 638 } 640 }; 639 }; 641 640 642 const std::regex wsp_re("[ ,;:\t\n]+"); 641 const std::regex wsp_re("[ ,;:\t\n]+"); 643 auto _maxid = GetData().identifiers.size(); 642 auto _maxid = GetData().identifiers.size(); 644 auto _result = std::vector<std::string>(_max 643 auto _result = std::vector<std::string>(_maxid, ""); 645 std::copy( 644 std::copy( 646 std::sregex_token_iterator(_signals.begin( 645 std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1), 647 std::sregex_token_iterator(), _result.begi 646 std::sregex_token_iterator(), _result.begin()); 648 signal_set_t _sigset{}; 647 signal_set_t _sigset{}; 649 for(auto& itr : _result) 648 for(auto& itr : _result) 650 _add_signal(itr, _sigset); 649 _add_signal(itr, _sigset); 651 return Enable(_sigset); 650 return Enable(_sigset); 652 } 651 } 653 652 654 //-------------------------------------------- 653 //----------------------------------------------------------------------------// 655 654 656 inline G4int G4Backtrace::Disable(signal_set_t << 655 inline int G4Backtrace::Disable(signal_set_t _signals) 657 { 656 { >> 657 std::unique_lock<std::mutex> lk{ *(GetData().lock) }; >> 658 658 if(_signals.empty()) 659 if(_signals.empty()) 659 { 660 { 660 for(auto& itr : GetData().is_active) 661 for(auto& itr : GetData().is_active) 661 _signals.insert(itr.first); 662 _signals.insert(itr.first); 662 } 663 } 663 664 664 G4int cnt = 0; << 665 int cnt = 0; 665 for(auto& itr : _signals) 666 for(auto& itr : _signals) 666 { 667 { 667 if(itr < 0) 668 if(itr < 0) 668 continue; 669 continue; 669 if(!GetData().is_active[itr]) 670 if(!GetData().is_active[itr]) 670 continue; 671 continue; 671 ++cnt; 672 ++cnt; 672 sigaction(itr, &(GetData().previous[itr]), 673 sigaction(itr, &(GetData().previous[itr]), nullptr); 673 GetData().current.erase(itr); 674 GetData().current.erase(itr); 674 GetData().is_active[itr] = false; 675 GetData().is_active[itr] = false; 675 } 676 } 676 return cnt; 677 return cnt; 677 } 678 } 678 679 679 //-------------------------------------------- 680 //----------------------------------------------------------------------------// 680 681 681 inline G4int G4Backtrace::GetSignal(const std: << 682 inline int G4Backtrace::GetSignal(const std::string& sid) 682 { 683 { 683 for(auto&& itr : GetData().identifiers) 684 for(auto&& itr : GetData().identifiers) 684 { 685 { 685 if(std::get<0>(itr) == sid) 686 if(std::get<0>(itr) == sid) 686 return std::get<1>(itr); 687 return std::get<1>(itr); 687 } 688 } 688 return -1; 689 return -1; 689 } 690 } 690 691 691 //-------------------------------------------- 692 //----------------------------------------------------------------------------// 692 693 693 inline std::string G4Backtrace::Description(G4 << 694 inline std::string G4Backtrace::Description(int sig) 694 { 695 { 695 for(auto&& itr : GetData().identifiers) 696 for(auto&& itr : GetData().identifiers) 696 { 697 { 697 if(std::get<1>(itr) == sig) 698 if(std::get<1>(itr) == sig) 698 { 699 { 699 std::stringstream ss; 700 std::stringstream ss; 700 ss << " signal = " << std::setw(8) << st 701 ss << " signal = " << std::setw(8) << std::get<0>(itr) 701 << ", value = " << std::setw(4) << st 702 << ", value = " << std::setw(4) << std::get<1>(itr) 702 << ", description = " << std::get<2>( 703 << ", description = " << std::get<2>(itr); 703 return ss.str(); 704 return ss.str(); 704 } 705 } 705 } 706 } 706 std::stringstream ss; 707 std::stringstream ss; 707 ss << " signal = " << std::setw(8) << "unkno 708 ss << " signal = " << std::setw(8) << "unknown" 708 << ", value = " << std::setw(4) << sig; 709 << ", value = " << std::setw(4) << sig; 709 return ss.str(); 710 return ss.str(); 710 } 711 } 711 712 712 //-------------------------------------------- 713 //----------------------------------------------------------------------------// 713 714 714 #else 715 #else 715 716 716 # include <array> 717 # include <array> 717 # include <functional> 718 # include <functional> 718 # include <map> 719 # include <map> 719 # include <set> 720 # include <set> 720 # include <string> 721 # include <string> 721 # include <tuple> 722 # include <tuple> 722 # include <vector> 723 # include <vector> 723 724 724 // dummy implementation 725 // dummy implementation 725 class G4Backtrace 726 class G4Backtrace 726 { 727 { 727 public: 728 public: 728 struct fake_siginfo 729 struct fake_siginfo 729 {}; 730 {}; 730 struct fake_sigaction 731 struct fake_sigaction 731 {}; 732 {}; 732 733 733 using siginfo_t = fake_siginfo; 734 using siginfo_t = fake_siginfo; 734 using sigaction_t = fake_sigaction; 735 using sigaction_t = fake_sigaction; 735 using exit_action_t = std::function<void(G4i << 736 using exit_action_t = std::function<void(int)>; 736 using frame_func_t = std::function<G4String( 737 using frame_func_t = std::function<G4String(const char*)>; 737 using signal_set_t = std::set<G4int>; << 738 using signal_set_t = std::set<int>; 738 739 739 public: 740 public: 740 struct actions 741 struct actions 741 { 742 { 742 using id_entry_t = std::tuple<std::string, << 743 using id_entry_t = std::tuple<std::string, int, std::string>; 743 using id_list_t = std::vector<id_entry_t>; 744 using id_list_t = std::vector<id_entry_t>; 744 745 745 std::map<G4int, G4bool> is_active = {}; << 746 std::map<int, bool> is_active = {}; 746 std::map<G4int, sigaction_t> current = {}; << 747 std::map<int, sigaction_t> current = {}; 747 std::map<G4int, sigaction_t> previous = {} << 748 std::map<int, sigaction_t> previous = {}; 748 std::vector<exit_action_t> exit_actions = 749 std::vector<exit_action_t> exit_actions = {}; 749 const id_list_t identifiers = {}; 750 const id_list_t identifiers = {}; 750 }; 751 }; 751 752 752 public: 753 public: 753 static void Handler(G4int, siginfo_t*, void* << 754 static void Handler(int, siginfo_t*, void*) {} 754 static void Message(G4int, siginfo_t*, std:: << 755 static void Message(int, siginfo_t*, std::ostream&) {} 755 static void ExitAction(G4int) {} << 756 static void ExitAction(int) {} 756 static G4int Enable(const std::string&) { re << 757 static int Enable(const std::string&) { return 0; } 757 static G4int Enable(const signal_set_t& = De << 758 static int Enable(const signal_set_t& = DefaultSignals()) { return 0; } 758 static G4int Disable(signal_set_t = {}) { re << 759 static int Disable(signal_set_t = {}) { return 0; } 759 static G4int GetSignal(const std::string&) { << 760 static int GetSignal(const std::string&) { return -1; } 760 static std::string Description(G4int) { retu << 761 static std::string Description(int) { return std::string{}; } 761 762 762 template <typename FuncT> 763 template <typename FuncT> 763 static void AddExitAction(FuncT&&) 764 static void AddExitAction(FuncT&&) 764 {} 765 {} 765 766 766 template <std::size_t Depth, std::size_t Off << 767 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t> 767 static std::array<G4ResultOf_t<FuncT, const << 768 static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetMangled( 768 FuncT&& func = FrameFunctor()) 769 FuncT&& func = FrameFunctor()) 769 { 770 { 770 using type = G4ResultOf_t<FuncT, const cha << 771 using type = G4ResultOf_t<FuncT(const char*)>; 771 auto ret = std::array<type, Depth>{}; 772 auto ret = std::array<type, Depth>{}; 772 ret.fill(func("")); 773 ret.fill(func("")); 773 return ret; 774 return ret; 774 } 775 } 775 776 776 template <std::size_t Depth, std::size_t Off << 777 template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t> 777 static std::array<G4ResultOf_t<FuncT, const << 778 static std::array<G4ResultOf_t<FuncT(const char*)>, Depth> GetDemangled( 778 FuncT&& func = FrameFunctor()) 779 FuncT&& func = FrameFunctor()) 779 { 780 { 780 using type = G4ResultOf_t<FuncT, const cha << 781 using type = G4ResultOf_t<FuncT(const char*)>; 781 auto ret = std::array<type, Depth>{}; 782 auto ret = std::array<type, Depth>{}; 782 ret.fill(func("")); 783 ret.fill(func("")); 783 return ret; 784 return ret; 784 } 785 } 785 786 786 // a functor called for each frame in the ba 787 // a functor called for each frame in the backtrace 787 static frame_func_t& FrameFunctor() 788 static frame_func_t& FrameFunctor() 788 { 789 { 789 static frame_func_t _instance = [](const c 790 static frame_func_t _instance = [](const char* _s) { return G4String(_s); }; 790 return _instance; 791 return _instance; 791 } 792 } 792 793 793 // default set of signals 794 // default set of signals 794 static signal_set_t& DefaultSignals() 795 static signal_set_t& DefaultSignals() 795 { 796 { 796 static signal_set_t _instance = {}; 797 static signal_set_t _instance = {}; 797 return _instance; 798 return _instance; 798 } 799 } 799 800 800 static actions& GetData() 801 static actions& GetData() 801 { 802 { 802 static auto _instance = actions{}; 803 static auto _instance = actions{}; 803 return _instance; 804 return _instance; 804 } 805 } 805 }; 806 }; 806 807 807 //-------------------------------------------- 808 //----------------------------------------------------------------------------// 808 809 809 #endif // G4SIGNAL_AVAILABLE 810 #endif // G4SIGNAL_AVAILABLE 810 #endif // G4Backtrace_hh 811 #endif // G4Backtrace_hh 811 812