Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarSignalHandler_windows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/StarSignalHandler_windows.cpp')
-rw-r--r--source/core/StarSignalHandler_windows.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/source/core/StarSignalHandler_windows.cpp b/source/core/StarSignalHandler_windows.cpp
new file mode 100644
index 0000000..0445aba
--- /dev/null
+++ b/source/core/StarSignalHandler_windows.cpp
@@ -0,0 +1,190 @@
+#include "StarSignalHandler.hpp"
+#include "StarFormat.hpp"
+#include "StarString.hpp"
+#include "StarLogging.hpp"
+
+#include <windows.h>
+
+namespace Star {
+
+String g_sehMessage;
+
+struct SignalHandlerImpl {
+ bool handlingFatal;
+ bool handlingInterrupt;
+ bool interrupted;
+
+ PVOID handler;
+
+ SignalHandlerImpl() : handlingFatal(false), handlingInterrupt(false), interrupted(false) {}
+
+ ~SignalHandlerImpl() {
+ setHandleFatal(false);
+ setHandleInterrupt(false);
+ }
+
+ void setHandleFatal(bool b) {
+ handlingFatal = b;
+
+ if (handler) {
+ RemoveVectoredExceptionHandler(handler);
+ handler = nullptr;
+ }
+
+ if (handlingFatal)
+ handler = AddVectoredExceptionHandler(1, vectoredExceptionHandler);
+ }
+
+ void setHandleInterrupt(bool b) {
+ handlingInterrupt = b;
+
+ SetConsoleCtrlHandler(nullptr, false);
+
+ if (handlingInterrupt)
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleCtrlHandler, true);
+ }
+
+ static void sehTrampoline() {
+ fatalError(g_sehMessage.utf8Ptr(), true);
+ }
+
+ static void handleFatalError(String const& msg, PEXCEPTION_POINTERS ExceptionInfo) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
+ String mode;
+ DWORD modeFlag = ExceptionInfo->ExceptionRecord->ExceptionInformation[0];
+ if (modeFlag == 0)
+ mode = "Read";
+ else if (modeFlag == 1)
+ mode = "Write";
+ else if (modeFlag == 8)
+ mode = "Execute";
+ else
+ mode = strf("Mode(%s)", modeFlag);
+ g_sehMessage = strf("Access violation detected at %s (%s of address %s)",
+ ExceptionInfo->ExceptionRecord->ExceptionAddress,
+ mode,
+ (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
+ } else {
+ g_sehMessage = msg;
+ g_sehMessage = strf("%s (%p @ %s)",
+ g_sehMessage,
+ ExceptionInfo->ExceptionRecord->ExceptionCode,
+ ExceptionInfo->ExceptionRecord->ExceptionAddress);
+ for (DWORD i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++)
+ g_sehMessage = strf("%s [%s]", g_sehMessage, (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[i]);
+ }
+
+// setup a hijack into our own trampoline as if the failure actually was a
+// function call
+#ifdef STAR_ARCHITECTURE_X86_64
+ DWORD64 rsp = ExceptionInfo->ContextRecord->Rsp - 8;
+ DWORD64 rip = ExceptionInfo->ContextRecord->Rip; // an offset avoid the issue of gdb thinking
+ // the error is one statement too early, but
+ // the offset is instruction dependent, and we
+ // don't know its size + 1;
+ *((DWORD64*)rsp) = rip;
+ ExceptionInfo->ContextRecord->Rsp = rsp;
+ ExceptionInfo->ContextRecord->Rip = (DWORD64)&sehTrampoline;
+#else
+ DWORD esp = ExceptionInfo->ContextRecord->Esp - 4;
+ DWORD eip = ExceptionInfo->ContextRecord->Eip; // an offset avoid the issue of gdb thinking the
+ // error is one statement too early, but the
+ // offset is instruction dependent, and we don't
+ // know its size + 1;
+ *((DWORD*)esp) = eip;
+ ExceptionInfo->ContextRecord->Esp = esp;
+ ExceptionInfo->ContextRecord->Eip = (DWORD)&sehTrampoline;
+#endif
+ }
+
+ static LONG CALLBACK vectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
+ fatalError("Stack overflow encountered", false);
+ }
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
+ handleFatalError("Access violation detected", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+ if ((ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)) {
+ handleFatalError("Illegal instruction encountered", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if ((ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_DENORMAL_OPERAND)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_INEXACT_RESULT)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_INVALID_OPERATION)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_OVERFLOW)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_STACK_CHECK)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_UNDERFLOW)
+
+ ) {
+ handleFatalError("Floating point exception", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) {
+ handleFatalError("Division by zero", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_OVERFLOW) {
+ handleFatalError("Integer overflow", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ if ((ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_IN_PAGE_ERROR)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INVALID_DISPOSITION)
+ || (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_INVALID_HANDLE)) {
+ handleFatalError("Error occured", ExceptionInfo);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ static BOOL WINAPI consoleCtrlHandler(DWORD) {
+ if (SignalHandler::s_singleton)
+ SignalHandler::s_singleton->interrupted = true;
+ return true;
+ }
+};
+
+SignalHandlerImplUPtr SignalHandler::s_singleton;
+
+SignalHandler::SignalHandler() {
+ if (s_singleton)
+ throw StarException("Singleton SignalHandler has been constructed twice!");
+
+ s_singleton = make_unique<SignalHandlerImpl>();
+}
+
+SignalHandler::~SignalHandler() {
+ s_singleton.reset();
+}
+
+void SignalHandler::setHandleFatal(bool handleFatal) {
+ s_singleton->setHandleFatal(handleFatal);
+}
+
+bool SignalHandler::handlingFatal() const {
+ return s_singleton->handlingFatal;
+}
+
+void SignalHandler::setHandleInterrupt(bool handleInterrupt) {
+ s_singleton->setHandleInterrupt(handleInterrupt);
+}
+
+bool SignalHandler::handlingInterrupt() const {
+ return s_singleton->handlingInterrupt;
+}
+
+bool SignalHandler::interruptCaught() const {
+ return s_singleton->interrupted;
+}
+
+}