diff --git a/inc/config.h b/inc/config.h index bdb7d9b..966d4fd 100644 --- a/inc/config.h +++ b/inc/config.h @@ -64,6 +64,7 @@ typedef struct CNCDDRAWCONFIG BOOL fix_alt_key_stuck; BOOL fix_not_responding; BOOL no_compat_warning; + BOOL ignore_exceptions; BOOL wine_allow_resize; int guard_lines; int max_resolutions; diff --git a/src/config.c b/src/config.c index deabcf0..05b19ef 100644 --- a/src/config.c +++ b/src/config.c @@ -77,6 +77,7 @@ void cfg_load() GET_BOOL(GameHandlesClose, "game_handles_close", FALSE); GET_BOOL(g_config.fix_not_responding, "fix_not_responding", FALSE); GET_BOOL(g_config.no_compat_warning, "no_compat_warning", FALSE); + GET_BOOL(g_config.ignore_exceptions, "ignore_exceptions", FALSE); GET_BOOL(g_config.wine_allow_resize, "wine_allow_resize", FALSE); GET_INT(g_config.guard_lines, "guard_lines", 200); GET_INT(g_config.max_resolutions, "max_resolutions", 0); @@ -309,6 +310,7 @@ static void cfg_create_ini() "game_handles_close=false\n" "fix_not_responding=false\n" "no_compat_warning=false\n" + "ignore_exceptions=false\n" "wine_allow_resize=false\n" "guard_lines=200\n" "max_resolutions=0\n" diff --git a/src/debug.c b/src/debug.c index 96b1b25..47229cd 100644 --- a/src/debug.c +++ b/src/debug.c @@ -14,6 +14,8 @@ #include "versionhelpers.h" #include "utils.h" #include "dllmain.h" +#include "config.h" +#include "patch.h" double g_dbg_frame_time = 0; @@ -35,59 +37,98 @@ static int g_dbg_crash_count = 0; LONG WINAPI dbg_exception_handler(EXCEPTION_POINTERS* exception) { - g_dbg_crash_count++; - - HANDLE dmp = - CreateFile( - g_dbg_crash_count == 1 ? g_dbg_dmp_path1 : g_dbg_dmp_path2, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE | FILE_SHARE_READ, - 0, - CREATE_ALWAYS, - 0, - 0); - - if (dmp != INVALID_HANDLE_VALUE) + if (!exception || !exception->ExceptionRecord) { - MINIDUMP_EXCEPTION_INFORMATION info; - info.ThreadId = GetCurrentThreadId(); - info.ExceptionPointers = exception; - info.ClientPointers = TRUE; + if (g_dbg_exception_filter) + return g_dbg_exception_filter(exception); - MiniDumpWriteDump( - GetCurrentProcess(), - GetCurrentProcessId(), - dmp, - 0, - &info, - NULL, - NULL); - - CloseHandle(dmp); + return EXCEPTION_EXECUTE_HANDLER; } - if (exception && exception->ExceptionRecord) + if (exception->ExceptionRecord->ExceptionCode != STATUS_PRIVILEGED_INSTRUCTION || !g_config.ignore_exceptions) { - HMODULE mod = NULL; - char filename[MAX_PATH] = { 0 }; + g_dbg_crash_count++; + + HANDLE dmp = + CreateFile( + g_dbg_crash_count == 1 ? g_dbg_dmp_path1 : g_dbg_dmp_path2, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + 0, + CREATE_ALWAYS, + 0, + 0); + + if (dmp != INVALID_HANDLE_VALUE) + { + MINIDUMP_EXCEPTION_INFORMATION info; + info.ThreadId = GetCurrentThreadId(); + info.ExceptionPointers = exception; + info.ClientPointers = TRUE; + + MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + dmp, + 0, + &info, + NULL, + NULL); + + CloseHandle(dmp); + } + } + + HMODULE mod = NULL; + char filename[MAX_PATH] = { 0 }; #if defined(_MSC_VER) /* comment this out just to keep the mingw build win2000 compatible */ - if (GetModuleHandleExA( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - exception->ExceptionRecord->ExceptionAddress, - &mod)) - { - GetModuleFileNameA(mod, filename, sizeof(filename) - 1); - } + if (GetModuleHandleExA( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + exception->ExceptionRecord->ExceptionAddress, + &mod)) + { + GetModuleFileNameA(mod, filename, sizeof(filename) - 1); + } #endif - TRACE( - "Exception at %p (%p+%p), Code=%08X - %s\n", - exception->ExceptionRecord->ExceptionAddress, - mod, - (int)exception->ExceptionRecord->ExceptionAddress - (int)mod, - exception->ExceptionRecord->ExceptionCode, - filename); + TRACE( + "Exception at %p (%p+%p), Code=%08X - %s\n", + exception->ExceptionRecord->ExceptionAddress, + mod, + (int)exception->ExceptionRecord->ExceptionAddress - (int)mod, + exception->ExceptionRecord->ExceptionCode, + filename); + + if (g_config.ignore_exceptions && + exception->ContextRecord && + exception->ExceptionRecord->ExceptionAddress && + exception->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) + { + size_t size = 0; + BYTE* addr = exception->ExceptionRecord->ExceptionAddress; + switch (*addr) + { + case 0xE4: // IN ib + case 0xE5: // IN id + case 0xE6: // OUT ib + case 0xE7: // OUT ib + size = 2; + break; + case 0xEC: // IN ib + case 0xED: // IN id + case 0xEE: // OUT + case 0xEF: // OUT + size = 1; + break; + } + + if (size) + { + exception->ContextRecord->Eip += size; + patch_clear((void*)addr, 0x90, (char*)addr + size); + return EXCEPTION_CONTINUE_EXECUTION; + } } if (g_dbg_exception_filter) @@ -111,6 +152,46 @@ void __cdecl dbg_invoke_watson( TerminateProcess(GetCurrentProcess(), STATUS_INVALID_CRUNTIME_PARAMETER); } +#else +LONG WINAPI dbg_exception_handler(EXCEPTION_POINTERS* exception) +{ + if (exception && + exception->ContextRecord && + exception->ExceptionRecord && + exception->ExceptionRecord->ExceptionAddress && + exception->ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) + { + size_t size = 0; + BYTE* addr = exception->ExceptionRecord->ExceptionAddress; + switch (*addr) + { + case 0xE4: // IN ib + case 0xE5: // IN id + case 0xE6: // OUT ib + case 0xE7: // OUT ib + size = 2; + break; + case 0xEC: // IN ib + case 0xED: // IN id + case 0xEE: // OUT + case 0xEF: // OUT + size = 1; + break; + } + + if (size) + { + exception->ContextRecord->Eip += size; + patch_clear((void*)addr, 0x90, (char*)addr + size); + return EXCEPTION_CONTINUE_EXECUTION; + } + } + + if (g_dbg_exception_filter) + return g_dbg_exception_filter(exception); + + return EXCEPTION_EXECUTE_HANDLER; +} #endif void dbg_init() diff --git a/src/dllmain.c b/src/dllmain.c index 3956081..691db28 100644 --- a/src/dllmain.c +++ b/src/dllmain.c @@ -43,9 +43,14 @@ BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) #ifdef _DEBUG dbg_init(); g_dbg_exception_filter = real_SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)dbg_exception_handler); -#endif - cfg_load(); +#else + cfg_load(); + if (g_config.ignore_exceptions) + { + g_dbg_exception_filter = real_SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)dbg_exception_handler); + } +#endif char buf[1024];