diff --git a/src/SignalHandling.hpp b/src/SignalHandling.hpp index 879d3d8..cc02f07 100644 --- a/src/SignalHandling.hpp +++ b/src/SignalHandling.hpp @@ -2,8 +2,8 @@ #define ARBUTILS_SIGNALHANDLING_HPP #if PRETTYTRACES && !WINDOWS #define BACKWARD_HAS_DW 1 -#endif #include "../extern/backward.hpp" +#endif #include "Exception.hpp" // Sourced from https://github.com/bombela/backward-cpp/blob/master/backward.hpp#L3849 @@ -150,180 +150,6 @@ namespace ArbUt { #endif // BACKWARD_SYSTEM_LINUX || BACKWARD_SYSTEM_DARWIN -#ifdef BACKWARD_SYSTEM_WINDOWS - - class SignalHandling { - public: - SignalHandling(void(callback)(const char*) = nullptr, const std::vector& = std::vector()) - : reporter_thread_([]() { - /* We handle crashes in a utility thread: - backward structures and some Windows functions called here - need stack space, which we do not have when we encounter a - stack overflow. - To support reporting stack traces during a stack overflow, - we create a utility thread at startup, which waits until a - crash happens or the program exits normally. */ - - { - std::unique_lock lk(mtx()); - cv().wait(lk, [] { return crashed() != crash_status::running; }); - } - if (crashed() == crash_status::crashed) { - handle_stacktrace(skip_recs()); - } - { - std::unique_lock lk(mtx()); - crashed() = crash_status::ending; - } - cv().notify_one(); - }) { - SetUnhandledExceptionFilter(crash_handler); - _callback = callback; - - signal(SIGABRT, signal_handler); - _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - - std::set_terminate(&terminator); - std::set_unexpected(&terminator); - _set_purecall_handler(&terminator); - _set_invalid_parameter_handler(&invalid_parameter_handler); - } - bool loaded() const { return true; } - - ~SignalHandling() { - { - std::unique_lock lk(mtx()); - crashed() = crash_status::normal_exit; - } - - cv().notify_one(); - - reporter_thread_.join(); - } - - void SetCallback(void (*callback)(const char*)) { _callback = callback; } - - private: - static void (*_callback)(const char*); - - static CONTEXT* ctx() { - static CONTEXT data; - return &data; - } - - enum class crash_status { running, crashed, normal_exit, ending }; - - static crash_status& crashed() { - static crash_status data; - return data; - } - - static std::mutex& mtx() { - static std::mutex data; - return data; - } - - static std::condition_variable& cv() { - static std::condition_variable data; - return data; - } - - static HANDLE& thread_handle() { - static HANDLE handle; - return handle; - } - - std::thread reporter_thread_; - - // TODO: how not to hardcode these? - static const constexpr int signal_skip_recs = -#ifdef __clang__ - // With clang, RtlCaptureContext also captures the stack frame of the - // current function Below that, there ar 3 internal Windows functions - 4 -#else - // With MSVC cl, RtlCaptureContext misses the stack frame of the current - // function The first entries during StackWalk are the 3 internal Windows - // functions - 3 -#endif - ; - - static int& skip_recs() { - static int data; - return data; - } - - static inline void terminator() { - crash_handler(signal_skip_recs); - abort(); - } - - static inline void signal_handler(int) { - crash_handler(signal_skip_recs); - abort(); - } - - static inline void __cdecl invalid_parameter_handler(const wchar_t*, const wchar_t*, const wchar_t*, - unsigned int, uintptr_t) { - crash_handler(signal_skip_recs); - abort(); - } - - NOINLINE static LONG WINAPI crash_handler(EXCEPTION_POINTERS* info) { - // The exception info supplies a trace from exactly where the issue was, - // no need to skip records - crash_handler(0, info->ContextRecord); - return EXCEPTION_CONTINUE_SEARCH; - } - - NOINLINE static void crash_handler(int skip, CONTEXT* ct = nullptr) { - - if (ct == nullptr) { - RtlCaptureContext(ctx()); - } else { - memcpy(ctx(), ct, sizeof(CONTEXT)); - } - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &thread_handle(), 0, FALSE, - DUPLICATE_SAME_ACCESS); - - skip_recs() = skip; - - { - std::unique_lock lk(mtx()); - crashed() = crash_status::crashed; - } - - cv().notify_one(); - - { - std::unique_lock lk(mtx()); - cv().wait(lk, [] { return crashed() != crash_status::crashed; }); - } - } - - static void handle_stacktrace(int skip_frames = 0) { - // printer creates the TraceResolver, which can supply us a machine type - // for stack walking. Without this, StackTrace can only guess using some - // macros. - // StackTrace also requires that the PDBs are already loaded, which is done - // in the constructor of TraceResolver - backward::Printer printer; - - backward::StackTrace st; - st.set_machine_type(printer.resolver().machine_type()); - st.set_context(ctx()); - st.set_thread_handle(thread_handle()); - st.load_here(32 + skip_frames); - st.skip_n_firsts(skip_frames); - - printer.address = true; - printer.print(st, std::cerr); - } - }; - -#endif // BACKWARD_SYSTEM_WINDOWS - #ifdef BACKWARD_SYSTEM_UNKNOWN class SignalHandling {