diff --git a/CMakeLists.txt b/CMakeLists.txt index 963ffe4f1..210cc62a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,6 +202,10 @@ if(WITH_LIBDWARFS) endif() endif() + if(WIN32) + find_package(cpptrace REQUIRED CONFIG) + endif() + pkg_check_modules(LIBCRYPTO REQUIRED IMPORTED_TARGET libcrypto>=${LIBCRYPTO_REQUIRED_VERSION}) pkg_check_modules(LIBARCHIVE REQUIRED IMPORTED_TARGET libarchive>=${LIBARCHIVE_REQUIRED_VERSION}) pkg_check_modules(XXHASH REQUIRED IMPORTED_TARGET libxxhash>=${XXHASH_REQUIRED_VERSION}) @@ -662,6 +666,7 @@ foreach(tgt ${LIBDWARFS_TARGETS} ${LIBDWARFS_OBJECT_TARGETS} dwarfs_test_helpers if(WIN32) target_link_libraries(${tgt} PRIVATE ntdll.lib dbghelp.lib) + target_link_libraries(${tgt} PRIVATE cpptrace::cpptrace) endif() endforeach() diff --git a/src/tool/safe_main.cpp b/src/tool/safe_main.cpp index 56ca4e9bf..1c68e2680 100644 --- a/src/tool/safe_main.cpp +++ b/src/tool/safe_main.cpp @@ -33,6 +33,9 @@ int safe_main(std::function fn) { try { install_signal_handlers(); setup_default_locale(); +#ifdef _WIN32 + ::_set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif return fn(); } catch (...) { diff --git a/src/util.cpp b/src/util.cpp index 7d0427bd5..c485db3e5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -45,9 +45,15 @@ #include +#ifdef _WIN32 +#include +#include +#include +#else #ifdef DWARFS_STACKTRACE_ENABLED #include #endif +#endif #include #include @@ -358,10 +364,73 @@ int get_current_umask() { return mask; } +#ifdef _WIN32 + +namespace { + +std::vector suspend_other_threads() { + std::vector handles; + DWORD currend_tid = ::GetCurrentThreadId(); + DWORD current_pid = ::GetCurrentProcessId(); + + HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + return handles; + } + + THREADENTRY32 te; + te.dwSize = sizeof(THREADENTRY32); + + if (::Thread32First(snapshot, &te)) { + do { + if (te.th32OwnerProcessID == current_pid && + te.th32ThreadID != currend_tid) { + HANDLE th = + ::OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, + FALSE, te.th32ThreadID); + if (th) { + if (::SuspendThread(th) != static_cast(-1)) { + handles.push_back(th); + } else { + ::CloseHandle(th); + } + } + } + } while (::Thread32Next(snapshot, &te)); + } + + ::CloseHandle(snapshot); + + return handles; +} + +void resume_suspended_threads(const std::vector& handles) { + for (auto th : handles) { + ::ResumeThread(th); + ::CloseHandle(th); + } +} + +void abort_handler(int signal) { + auto suspended = suspend_other_threads(); + std::cerr << "Caught signal " << signal << "\n"; + cpptrace::generate_trace().print(); + resume_suspended_threads(suspended); + ::exit(1); +} + +} // namespace + +#endif + void install_signal_handlers() { +#ifdef _WIN32 + ::signal(SIGABRT, abort_handler); +#else #ifdef DWARFS_STACKTRACE_ENABLED folly::symbolizer::installFatalSignalHandler(); #endif +#endif } } // namespace dwarfs diff --git a/vcpkg.json b/vcpkg.json index 06d0ce23b..fbb2f7619 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -15,6 +15,7 @@ "boost-uuid", "boost-variant", "brotli", + "cpptrace", "date", "double-conversion", "fmt",