diff --git a/core/libs/prx/libc/src/specifics/windows/CrashReport.cpp b/core/libs/prx/libc/src/specifics/windows/CrashReport.cpp index c23d288aa9..3d685d640a 100644 --- a/core/libs/prx/libc/src/specifics/windows/CrashReport.cpp +++ b/core/libs/prx/libc/src/specifics/windows/CrashReport.cpp @@ -381,6 +381,9 @@ LONG WINAPI ReportCrash(EXCEPTION_POINTERS* info) { if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && record->NumberParameters >= 2) { const char* kind = record->ExceptionInformation[0] == 0 ? "read" : record->ExceptionInformation[0] == 1 ? "write" : "execute"; Report(" %s of 0x%016llx\n", kind, static_cast(record->ExceptionInformation[1])); + std::uint8_t trap[2]; + if (record->ExceptionInformation[0] == 0 && record->ExceptionInformation[1] == ~0ull && ReadCode(context->Rip, trap, sizeof(trap)) == sizeof(trap) && trap[0] == 0xcd && trap[1] == 0x45) + Report(" guest abort() (int 0x45)\n"); } Report(" rax %016llx rbx %016llx rcx %016llx rdx %016llx\n", context->Rax, context->Rbx, context->Rcx, context->Rdx); Report(" rsi %016llx rdi %016llx rbp %016llx rsp %016llx\n", context->Rsi, context->Rdi, context->Rbp, context->Rsp); diff --git a/core/libs/tests/WindowsExceptions.cpp b/core/libs/tests/WindowsExceptions.cpp index 19a4bb2e86..d7adc8c92e 100644 --- a/core/libs/tests/WindowsExceptions.cpp +++ b/core/libs/tests/WindowsExceptions.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -74,7 +75,7 @@ static int RunThrowChild() { return 100; } -static void testUnhandledThrowSite() { +static std::string RunChild(const wchar_t* argument, DWORD& exitCode) { SECURITY_ATTRIBUTES attributes{}; attributes.nLength = sizeof(attributes); attributes.bInheritHandle = TRUE; @@ -84,7 +85,6 @@ static void testUnhandledThrowSite() { RequireHandle(SetHandleInformation(readPipe, HANDLE_FLAG_INHERIT, 0) != 0); std::array image{}; RequireHandle(GetModuleFileNameW(nullptr, image.data(), static_cast(image.size())) != 0); - const wchar_t* argument = L"\" throw-uncaught"; std::array command{}; const std::size_t imageLength = std::wcslen(image.data()); const std::size_t argumentLength = std::wcslen(argument); @@ -110,22 +110,47 @@ static void testUnhandledThrowSite() { } CloseHandle(readPipe); RequireHandle(WaitForSingleObject(child.hProcess, 20000) == WAIT_OBJECT_0); - DWORD exitCode = 0; RequireHandle(GetExitCodeProcess(child.hProcess, &exitCode) != 0); CloseHandle(child.hProcess); output[outputLength < output.size() ? outputLength : output.size() - 1] = 0; + return std::string(output.data()); +} + +static void testUnhandledThrowSite() { + DWORD exitCode = 0; + const std::string output = RunChild(L"\" throw-uncaught", exitCode); RequireHandle(exitCode == 0xC0000409); - const char* probeMarker = std::strstr(output.data(), "probe "); + const char* probeMarker = std::strstr(output.c_str(), "probe "); RequireHandle(probeMarker != nullptr); const auto probe = static_cast(std::strtoull(probeMarker + 6, nullptr, 16)); RequireHandle(probe != 0); - const char* marker = std::strstr(output.data(), "thrown from "); + const char* marker = std::strstr(output.c_str(), "thrown from "); RequireHandle(marker != nullptr); const auto logged = static_cast(std::strtoull(marker + 13, nullptr, 16)); RequireHandle(logged != 0); if (logged <= probe || logged - probe >= 0x1000) throw std::runtime_error("unhandled exception named the wrapper instead of the throw site"); } +[[gnu::noinline, noreturn]] static void GuestAbortProbe() { + __asm__ volatile("int $0x45"); + __builtin_unreachable(); +} + +static int RunAbortChild() { + std::fprintf(stderr, "abort probe\n"); + std::fflush(stderr); + GuestAbortProbe(); +} + +static void testGuestAbortReport() { + DWORD exitCode = 0; + const std::string output = RunChild(L"\" guest-abort", exitCode); + char code[16]; + std::snprintf(code, sizeof(code), "0x%08lx", static_cast(exitCode)); + if (exitCode != 0xC0000005 || output.find("guest abort() (int 0x45)") == std::string::npos) + throw std::runtime_error(std::string("guest abort child exited with ") + code + " and printed:\n" + output); +} + static int destroyed; struct Guard { ~Guard() { ++destroyed; } }; static void ThrowNested() { @@ -273,10 +298,12 @@ static void testUnwindThroughRuntimeModules() { int main(int argc, char** argv) { if (argc > 1) { if (std::strcmp(argv[1], "throw-uncaught") == 0) return RunThrowChild(); + if (std::strcmp(argv[1], "guest-abort") == 0) return RunAbortChild(); return 100; } TestTypeInfoVtables(); testUnhandledThrowSite(); + testGuestAbortReport(); testExceptionPointer(); testFutureException(); testMadeExceptionPointer();