Core/CrashHandler: Attempt to extract C++ exception object in uncaught exception hander

This commit is contained in:
Shauren
2020-08-06 23:27:23 +02:00
parent 764f22fc91
commit 83ed35fe62

View File

@@ -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