mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/CrashHandler: Attempt to extract C++ exception object in uncaught exception hander
(cherry picked from commit 83ed35fe62)
This commit is contained in:
@@ -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")
|
||||
@@ -585,6 +587,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, nullptr);
|
||||
@@ -620,27 +696,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
|
||||
|
||||
Reference in New Issue
Block a user