Initial commit

This commit is contained in:
nmzik
2026-07-16 10:21:41 +02:00
commit 147188b143
427 changed files with 205923 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
#include "common/hostException.h"
#include <atomic>
#include <cstdio>
#include <cstdlib>
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
#include <windows.h> // IWYU pragma: keep
#endif
// IWYU pragma: no_include <errhandlingapi.h>
// IWYU pragma: no_include <excpt.h>
// IWYU pragma: no_include <minwinbase.h>
// IWYU pragma: no_include <minwindef.h>
// IWYU pragma: no_include <wtypes.h>
namespace Common::HostException {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
static std::atomic<Handler> g_handler {nullptr};
static std::atomic_uint32_t g_install_state {0};
static thread_local bool g_in_exception_filter = false;
static_assert(decltype(g_handler)::is_always_lock_free);
static_assert(decltype(g_install_state)::is_always_lock_free);
[[noreturn]] static void FailFast(const char* reason) noexcept {
std::fputs("HostException fail-fast: ", stderr);
std::fputs(reason != nullptr ? reason : "unspecified", stderr);
std::fputc('\n', stderr);
std::fflush(stderr);
TerminateProcess(GetCurrentProcess(), static_cast<UINT>(EXCEPTION_NONCONTINUABLE_EXCEPTION));
std::_Exit(321);
}
class FilterScope final {
public:
FilterScope() noexcept {
if (g_in_exception_filter) {
FailFast("nested exception while resolving a host fault");
}
g_in_exception_filter = true;
}
~FilterScope() { g_in_exception_filter = false; }
KYTY_CLASS_NO_COPY(FilterScope);
};
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) {
FilterScope filter_scope;
auto* exception_record = exception->ExceptionRecord;
if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C ||
exception_record->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) {
return EXCEPTION_CONTINUE_SEARCH;
}
if (exception_record->ExceptionCode == 0x406D1388) {
// Set a thread name.
return EXCEPTION_CONTINUE_EXECUTION;
}
ExceptionInfo info {};
info.exception_address = reinterpret_cast<uint64_t>(exception_record->ExceptionAddress);
info.native_code = exception_record->ExceptionCode;
info.native_context = exception->ContextRecord;
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
info.type = ExceptionType::AccessViolation;
switch (exception_record->ExceptionInformation[0]) {
case 0: info.access_violation_type = AccessViolationType::Read; break;
case 1: info.access_violation_type = AccessViolationType::Write; break;
case 8: info.access_violation_type = AccessViolationType::Execute; break;
default: info.access_violation_type = AccessViolationType::Unknown; break;
}
info.access_violation_vaddr = exception_record->ExceptionInformation[1];
} else if (exception_record->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
info.type = ExceptionType::IllegalInstruction;
} else {
printf("Unhandled win exception: code=0x%08" PRIx32 ", addr=0x%016" PRIx64
", rip=0x%016" PRIx64 ", rsp=0x%016" PRIx64 ", rbp=0x%016" PRIx64 "\n",
static_cast<uint32_t>(exception_record->ExceptionCode),
reinterpret_cast<uint64_t>(exception_record->ExceptionAddress),
exception->ContextRecord->Rip, exception->ContextRecord->Rsp,
exception->ContextRecord->Rbp);
return EXCEPTION_CONTINUE_SEARCH;
}
info.rax = exception->ContextRecord->Rax;
info.rbx = exception->ContextRecord->Rbx;
info.rcx = exception->ContextRecord->Rcx;
info.rdx = exception->ContextRecord->Rdx;
info.rsi = exception->ContextRecord->Rsi;
info.rdi = exception->ContextRecord->Rdi;
info.rbp = exception->ContextRecord->Rbp;
info.rsp = exception->ContextRecord->Rsp;
info.r8 = exception->ContextRecord->R8;
info.r9 = exception->ContextRecord->R9;
info.r10 = exception->ContextRecord->R10;
info.r11 = exception->ContextRecord->R11;
info.r12 = exception->ContextRecord->R12;
info.r13 = exception->ContextRecord->R13;
info.r14 = exception->ContextRecord->R14;
info.r15 = exception->ContextRecord->R15;
if (g_install_state.load(std::memory_order_acquire) == 0) {
FailFast("host exception handler is not installed");
}
const auto handler = g_handler.load(std::memory_order_acquire);
if (handler == nullptr) {
FailFast("host exception callback is null");
}
return handler(info) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
#endif
bool InstallHandler(Handler handler) {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
if (handler == nullptr) {
return false;
}
uint32_t expected_state = 0;
if (!g_install_state.compare_exchange_strong(expected_state, 1, std::memory_order_acq_rel)) {
return expected_state == 2 && g_handler.load(std::memory_order_acquire) == handler;
}
g_handler.store(handler, std::memory_order_release);
if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr) {
g_handler.store(nullptr, std::memory_order_release);
g_install_state.store(0, std::memory_order_release);
printf("AddVectoredExceptionHandler() failed\n");
return false;
}
g_install_state.store(2, std::memory_order_release);
return true;
#else
(void)handler;
return false;
#endif
}
} // namespace Common::HostException