From 4076a5b758b83c8156e3df6ffc3466e9f5ab7436 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Wed, 6 Jul 2022 09:21:23 +0100 Subject: [PATCH 1/2] EmuException: allow skipping of instructions that trigger unhandled exceptions. In many cases, this will result in more instability, however, it is useful as a debugging tool: some games that would otherwise be working are let down by a *single* invalid read or write, and skipping over that instruction allows the game to be played. This can enable further research/debugging within the title. --- src/common/Logging.cpp | 2 +- src/core/kernel/support/Emu.cpp | 37 ++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/common/Logging.cpp b/src/common/Logging.cpp index 2ed0571bc..b70ff740c 100644 --- a/src/common/Logging.cpp +++ b/src/common/Logging.cpp @@ -313,7 +313,7 @@ PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, con uType |= MB_OKCANCEL; break; case PopupButtons::AbortRetryIgnore: - uType |= MB_RETRYCANCEL; + uType |= MB_ABORTRETRYIGNORE; break; case PopupButtons::YesNoCancel: uType |= MB_YESNOCANCEL; diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index 0c11fa848..dedc211aa 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -124,7 +124,7 @@ bool EmuExceptionBreakpointAsk(LPEXCEPTION_POINTERS e) // We can skip Xbox as long as they are logged so we know about them // There's no need to prevent emulation, we can just pretend we have a debugger attached and continue // This is because some games (such as Crash Bandicoot) spam exceptions; - e->ContextRecord->Eip += EmuX86_OpcodeSize((uint8_t*)e->ContextRecord->Eip); // Skip 1 size bytes + e->ContextRecord->Eip += EmuX86_OpcodeSize((uint8_t*)e->ContextRecord->Eip); // Skip 1 instruction return true; #if 1 @@ -157,19 +157,29 @@ bool EmuExceptionBreakpointAsk(LPEXCEPTION_POINTERS e) #endif } -void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e) +bool EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e) { EmuExceptionPrintDebugInformation(e, /*IsBreakpointException=*/false); - if (PopupFatalEx(nullptr, PopupButtons::OkCancel, PopupReturn::Ok, + auto result = PopupFatalEx(nullptr, PopupButtons::AbortRetryIgnore, PopupReturn::Abort, " The running xbe has encountered an unhandled exception (Code := 0x%.8X) at address 0x%.08X.\n" "\n" - " Press \"OK\" to terminate emulation.\n" - " Press \"Cancel\" to debug.", - e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip) == PopupReturn::Ok) + " Press \"Abort\" to terminate emulation.\n" + " Press \"Retry\" to debug.\n" + " Press \"Ignore\" to attempt to continue emulation.", + e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip); + + if (result == PopupReturn::Abort) { EmuExceptionExitProcess(); } + else if (result == PopupReturn::Ignore) + { + e->ContextRecord->Eip += EmuX86_OpcodeSize((uint8_t*)e->ContextRecord->Eip); // Skip 1 instruction + return true; + } + + return false; } // Returns weither the given address is part of an Xbox managed memory region @@ -185,7 +195,7 @@ bool IsXboxCodeAddress(xbox::addr_xt addr) #include "distorm.h" bool EmuX86_DecodeOpcode(const uint8_t* Eip, _DInst& info); void EmuX86_DistormLogInstruction(const uint8_t* Eip, _DInst& info, LOG_LEVEL log_level); -void genericException(EXCEPTION_POINTERS *e) { +bool genericException(EXCEPTION_POINTERS *e) { _DInst info; if (EmuX86_DecodeOpcode((uint8_t*)e->ContextRecord->Eip, info)) { EmuX86_DistormLogInstruction((uint8_t*)e->ContextRecord->Eip, info, LOG_LEVEL::FATAL); @@ -200,11 +210,14 @@ void genericException(EXCEPTION_POINTERS *e) { } // Bypass exception + return false; } else { // notify user - EmuExceptionNonBreakpointUnhandledShow(e); + return EmuExceptionNonBreakpointUnhandledShow(e); } + + return false; } bool IsRdtscInstruction(xbox::addr_xt addr); // Implemented in CxbxKrnl.cpp @@ -270,8 +283,7 @@ bool EmuTryHandleException(EXCEPTION_POINTERS *e) // Check if lle exception is already called first before emu exception. if (bOverrideEmuException) { - genericException(e); - return false; + return genericException(e); } if (e->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) { @@ -309,10 +321,7 @@ bool EmuTryHandleException(EXCEPTION_POINTERS *e) } } - genericException(e); - - // Unhandled exception : - return false; + return genericException(e); } long WINAPI EmuException(struct _EXCEPTION_POINTERS* e) From 5f3cfdeb77d37b62febab257d0ee62763d50cb40 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Fri, 8 Jul 2022 11:37:48 +0100 Subject: [PATCH 2/2] address feedback --- src/core/kernel/support/Emu.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/kernel/support/Emu.cpp b/src/core/kernel/support/Emu.cpp index dedc211aa..da98ab08f 100644 --- a/src/core/kernel/support/Emu.cpp +++ b/src/core/kernel/support/Emu.cpp @@ -169,12 +169,9 @@ bool EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e) " Press \"Ignore\" to attempt to continue emulation.", e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip); - if (result == PopupReturn::Abort) - { + if (result == PopupReturn::Abort) { EmuExceptionExitProcess(); - } - else if (result == PopupReturn::Ignore) - { + } else if (result == PopupReturn::Ignore) { e->ContextRecord->Eip += EmuX86_OpcodeSize((uint8_t*)e->ContextRecord->Eip); // Skip 1 instruction return true; } @@ -195,7 +192,8 @@ bool IsXboxCodeAddress(xbox::addr_xt addr) #include "distorm.h" bool EmuX86_DecodeOpcode(const uint8_t* Eip, _DInst& info); void EmuX86_DistormLogInstruction(const uint8_t* Eip, _DInst& info, LOG_LEVEL log_level); -bool genericException(EXCEPTION_POINTERS *e) { +bool genericException(EXCEPTION_POINTERS *e) +{ _DInst info; if (EmuX86_DecodeOpcode((uint8_t*)e->ContextRecord->Eip, info)) { EmuX86_DistormLogInstruction((uint8_t*)e->ContextRecord->Eip, info, LOG_LEVEL::FATAL);