From ef4376cb6ee4d83a7aed3c0747547d2104f1621b Mon Sep 17 00:00:00 2001 From: Prcuvu Date: Tue, 1 Oct 2019 14:56:09 +0800 Subject: [PATCH] Implement a working CrashHandler::ExceptionHandler for Windows x64 --- src/CMakeData-os.cmake | 5 ++++ src/archutils/Win32/Crash.cpp | 30 ++++++++++++++++++-- src/archutils/Win32/ExceptionHandler_x64.asm | 29 +++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/archutils/Win32/ExceptionHandler_x64.asm diff --git a/src/CMakeData-os.cmake b/src/CMakeData-os.cmake index 4da9486e4d..0e39e1f17a 100644 --- a/src/CMakeData-os.cmake +++ b/src/CMakeData-os.cmake @@ -57,6 +57,11 @@ else() "archutils/Win32/WindowsDialogBox.cpp" "archutils/Win32/WindowsResources.rc") + if(MSVC AND SM_WIN32_ARCH EQUAL "x64") + enable_language(ASM_MASM) + list(APPEND SMDATA_OS_SRC "archutils/Win32/ExceptionHandler_x64.asm") + endif() + list(APPEND SMDATA_OS_HPP "archutils/Win32/AppInstance.h" "archutils/Win32/arch_setup.h" diff --git a/src/archutils/Win32/Crash.cpp b/src/archutils/Win32/Crash.cpp index ca46fae0f7..f8f11417fe 100644 --- a/src/archutils/Win32/Crash.cpp +++ b/src/archutils/Win32/Crash.cpp @@ -266,7 +266,7 @@ void RunChild() } } -static long MainExceptionHandler( EXCEPTION_POINTERS *pExc ) +/* static */ long MainExceptionHandler( EXCEPTION_POINTERS *pExc ) { // Flush the log so it isn't cut off at the end. /* 1. We can't do regular file access in the crash handler. @@ -291,7 +291,11 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc ) case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_FLT_INEXACT_RESULT: +#if _WIN64 + pExc->ContextRecord->FltSave.ControlWord |= 0x3F; +#else pExc->ContextRecord->FloatSave.ControlWord |= 0x3F; +#endif return EXCEPTION_CONTINUE_EXECUTION; } @@ -356,6 +360,7 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc ) return EXCEPTION_EXECUTE_HANDLER; } +#if !_WIN64 long __stdcall CrashHandler::ExceptionHandler( EXCEPTION_POINTERS *pExc ) { /* If the stack overflowed, we have a very limited amount of stack space. @@ -376,6 +381,7 @@ long __stdcall CrashHandler::ExceptionHandler( EXCEPTION_POINTERS *pExc ) return MainExceptionHandler( pExc ); } +#endif ////////////////////////////////////////////////////////////////////////////// @@ -449,7 +455,7 @@ static bool IsExecutableProtection(DWORD dwProtect) { return false; } -static bool PointsToValidCall( unsigned long ptr ) +static bool PointsToValidCall( ULONG_PTR ptr ) { char buf[7]; int len = 7; @@ -473,9 +479,15 @@ void CrashHandler::do_backtrace( const void **buf, size_t size, * due to stack corruption, we might not be able to get any frames from the * stack. Pull it out of pContext->Eip, which is always valid, and then * discard the first stack frame if it's the same. */ +#if _WIN64 + if( buf+1 != pLast && pContext->Rip != 0 ) + { + *buf = (void *) pContext->Rip; +#else if( buf+1 != pLast && pContext->Eip != 0 ) { *buf = (void *) pContext->Eip; +#endif ++buf; } @@ -495,9 +507,15 @@ void CrashHandler::do_backtrace( const void **buf, size_t size, } // Walk up the stack. +#if _WIN64 + const char *lpAddr = (const char *)pContext->Rsp; + + const void *data = (void *) pContext->Rip; +#else const char *lpAddr = (const char *)pContext->Esp; const void *data = (void *) pContext->Eip; +#endif do { if( buf == pLast ) break; @@ -506,7 +524,11 @@ void CrashHandler::do_backtrace( const void **buf, size_t size, /* The first entry is usually EIP. We already logged it; skip it, so we don't always * show the first frame twice. */ +#if _WIN64 + if( bFirst && data == (void *) pContext->Rip ) +#else if( bFirst && data == (void *) pContext->Eip ) +#endif fValid = false; bFirst = false; @@ -518,7 +540,11 @@ void CrashHandler::do_backtrace( const void **buf, size_t size, if (!IsExecutableProtection(meminfo.Protect) || meminfo.State!=MEM_COMMIT) fValid = false; +#if _WIN64 + if ( data != (void *) pContext->Rip && !PointsToValidCall((unsigned long)data) ) +#else if ( data != (void *) pContext->Eip && !PointsToValidCall((unsigned long)data) ) +#endif fValid = false; } diff --git a/src/archutils/Win32/ExceptionHandler_x64.asm b/src/archutils/Win32/ExceptionHandler_x64.asm new file mode 100644 index 0000000000..5eadcaaba8 --- /dev/null +++ b/src/archutils/Win32/ExceptionHandler_x64.asm @@ -0,0 +1,29 @@ +extrn ?MainExceptionHandler@@YAJPEAU_EXCEPTION_POINTERS@@@Z : PROC +extrn VirtualAlloc : PROC + +.code + +; long __stdcall CrashHandler::ExceptionHandler( EXCEPTION_POINTERS *pExc ); +?ExceptionHandler@CrashHandler@@YAJPEAU_EXCEPTION_POINTERS@@@Z PROC + +push rbp +mov rbp, rsp +push rsi +mov rsi, rcx +xor rcx, rcx ; lpAddress = nullptr +mov rdx, 8000h ; dwSize = iSize +mov r8d, 00003000h; flAllocationType = MEM_COMMIT | MEM_RESERVE +mov r9d, 04h ; flProtect = PAGE_READWRITE +call VirtualAlloc ; char *pStack = (char *) VirtualAlloc( nullptr, iSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); +add rax, 8000h ; pStack += iSize; +mov rcx, rsi ; Restore pExc +pop rsi +; mov rsp, rax ; FIXME: This instruction causes MainExceptionHandler abortion. +call ?MainExceptionHandler@@YAJPEAU_EXCEPTION_POINTERS@@@Z +mov rsp, rbp +pop rbp +ret + +?ExceptionHandler@CrashHandler@@YAJPEAU_EXCEPTION_POINTERS@@@Z ENDP + +END