diff options
author | Shauren <shauren.trinity@gmail.com> | 2020-08-06 23:27:23 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2020-08-07 17:19:16 +0200 |
commit | 83ed35fe62c16f5697f253a9a44bba7dcb83e80d (patch) | |
tree | c5e6f8206fba2dba0c06413fc09f2717386d6a89 /src/common | |
parent | 764f22fc9157ad184baa38995ee4e2d821299935 (diff) |
Core/CrashHandler: Attempt to extract C++ exception object in uncaught exception hander
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/Debugging/WheatyExceptionReport.cpp | 119 |
1 files changed, 98 insertions, 21 deletions
diff --git a/src/common/Debugging/WheatyExceptionReport.cpp b/src/common/Debugging/WheatyExceptionReport.cpp index c4de34bb38c..c95d5fd4d3b 100644 --- a/src/common/Debugging/WheatyExceptionReport.cpp +++ b/src/common/Debugging/WheatyExceptionReport.cpp @@ -25,6 +25,8 @@ #include "Errors.h" #include "GitRevision.h" #include <algorithm> +#include <ehdata.h> +#include <rttidata.h> #define CrashFolder _T("Crashes") #pragma comment(linker, "/DEFAULTLIB:dbghelp.lib") @@ -582,6 +584,80 @@ PEXCEPTION_POINTERS pExceptionInfo) ErrorMessage(GetLastError())); } + if (pExceptionRecord->ExceptionCode == 0xE06D7363 && pExceptionRecord->NumberParameters >= 2) + { + PVOID exceptionObject = reinterpret_cast<PVOID>(pExceptionRecord->ExceptionInformation[1]); + ThrowInfo const* throwInfo = reinterpret_cast<ThrowInfo const*>(pExceptionRecord->ExceptionInformation[2]); + auto resolveExceptionRVA = [pExceptionRecord](int32 rva) -> DWORD_PTR + { + return rva + (pExceptionRecord->NumberParameters >= 4 ? pExceptionRecord->ExceptionInformation[3] : 0); + }; + + CatchableTypeArray const* catchables = reinterpret_cast<CatchableTypeArray const*>(resolveExceptionRVA(throwInfo->pCatchableTypeArray)); + CatchableType const* catchable = catchables->nCatchableTypes ? reinterpret_cast<CatchableType const*>(resolveExceptionRVA(catchables->arrayOfCatchableTypes[0])) : nullptr; + TypeDescriptor const* exceptionTypeinfo = catchable ? reinterpret_cast<TypeDescriptor const*>(resolveExceptionRVA(catchable->pType)) : nullptr; + + if (exceptionTypeinfo) + { + void* stdExceptionTypeInfo = []() -> void* + { + try + { + std::exception fake; + return __RTtypeid(&fake); + } + catch (...) + { + return nullptr; + } + }(); + std::exception const* exceptionPtr = [](void* object, TypeDescriptor const* typeInfo, void* stdExceptionTypeInfo) -> std::exception const* + { + try + { + // real_type descriptor is obtained by parsing throwinfo + // equivalent to expression like this + // std::exception* e = object; + // real_type* r = dynamic_cast<real_type*>(e); + // return r; + return reinterpret_cast<std::exception const*>(__RTDynamicCast(object, 0, stdExceptionTypeInfo, (void*)typeInfo, false)); + } + catch (...) + { + return nullptr; + } + }(exceptionObject, exceptionTypeinfo, stdExceptionTypeInfo); + + // dynamic_cast<type>(variable_that_already_has_that_type) is optimized away by compiler and attempting to call __RTDynamicCast fails for it + if (!exceptionPtr && exceptionTypeinfo == stdExceptionTypeInfo) + exceptionPtr = reinterpret_cast<std::exception*>(exceptionObject); + + Log(_T("\r\nUncaught C++ exception info:")); + if (exceptionPtr) + Log(_T(" %s"), exceptionPtr->what()); + + Log(_T("\r\n")); + + char undName[MAX_SYM_NAME] = { }; + if (UnDecorateSymbolName(&exceptionTypeinfo->name[1], &undName[0], MAX_SYM_NAME, UNDNAME_32_BIT_DECODE | UNDNAME_NAME_ONLY | UNDNAME_NO_ARGUMENTS)) + { + char buf[MAX_SYM_NAME + sizeof(SYMBOL_INFO)] = { }; + PSYMBOL_INFO sym = (PSYMBOL_INFO)&buf[0]; + sym->SizeOfStruct = sizeof(SYMBOL_INFO); + sym->MaxNameLen = MAX_SYM_NAME; + if (SymGetTypeFromName(m_hProcess, (ULONG64)GetModuleHandle(nullptr), undName, sym)) + { + sym->Address = pExceptionRecord->ExceptionInformation[1]; + sym->Flags = 0; + char const* variableName = "uncaught_exception"; + memset(sym->Name, 0, MAX_SYM_NAME); + memcpy(sym->Name, variableName, strlen(variableName)); + FormatSymbolValue(sym, nullptr); + } + } + } + } + CONTEXT trashableContext = *pCtx; WriteStackDetails(&trashableContext, false, NULL); @@ -617,27 +693,28 @@ LPCTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) switch (dwCode) { EXCEPTION(ACCESS_VIOLATION) - EXCEPTION(DATATYPE_MISALIGNMENT) - EXCEPTION(BREAKPOINT) - EXCEPTION(SINGLE_STEP) - EXCEPTION(ARRAY_BOUNDS_EXCEEDED) - EXCEPTION(FLT_DENORMAL_OPERAND) - EXCEPTION(FLT_DIVIDE_BY_ZERO) - EXCEPTION(FLT_INEXACT_RESULT) - EXCEPTION(FLT_INVALID_OPERATION) - EXCEPTION(FLT_OVERFLOW) - EXCEPTION(FLT_STACK_CHECK) - EXCEPTION(FLT_UNDERFLOW) - EXCEPTION(INT_DIVIDE_BY_ZERO) - EXCEPTION(INT_OVERFLOW) - EXCEPTION(PRIV_INSTRUCTION) - EXCEPTION(IN_PAGE_ERROR) - EXCEPTION(ILLEGAL_INSTRUCTION) - EXCEPTION(NONCONTINUABLE_EXCEPTION) - EXCEPTION(STACK_OVERFLOW) - EXCEPTION(INVALID_DISPOSITION) - EXCEPTION(GUARD_PAGE) - EXCEPTION(INVALID_HANDLE) + EXCEPTION(DATATYPE_MISALIGNMENT) + EXCEPTION(BREAKPOINT) + EXCEPTION(SINGLE_STEP) + EXCEPTION(ARRAY_BOUNDS_EXCEEDED) + EXCEPTION(FLT_DENORMAL_OPERAND) + EXCEPTION(FLT_DIVIDE_BY_ZERO) + EXCEPTION(FLT_INEXACT_RESULT) + EXCEPTION(FLT_INVALID_OPERATION) + EXCEPTION(FLT_OVERFLOW) + EXCEPTION(FLT_STACK_CHECK) + EXCEPTION(FLT_UNDERFLOW) + EXCEPTION(INT_DIVIDE_BY_ZERO) + EXCEPTION(INT_OVERFLOW) + EXCEPTION(PRIV_INSTRUCTION) + EXCEPTION(IN_PAGE_ERROR) + EXCEPTION(ILLEGAL_INSTRUCTION) + EXCEPTION(NONCONTINUABLE_EXCEPTION) + EXCEPTION(STACK_OVERFLOW) + EXCEPTION(INVALID_DISPOSITION) + EXCEPTION(GUARD_PAGE) + EXCEPTION(INVALID_HANDLE) + case 0xE06D7363: return _T("Unhandled C++ exception"); } // If not one of the "known" exceptions, try to get the string |