aboutsummaryrefslogtreecommitdiff
path: root/src/common/Debugging
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-08-06 23:27:23 +0200
committerShauren <shauren.trinity@gmail.com>2022-01-26 18:43:31 +0100
commit7893ac94a017c25257882bb5b2485c482f25a207 (patch)
tree64fed1f5d17acf1f9caccb7c75a97be06280c5c4 /src/common/Debugging
parent2819951dce545438724719836e3a13d3039b8690 (diff)
Core/CrashHandler: Attempt to extract C++ exception object in uncaught exception hander
(cherry picked from commit 83ed35fe62c16f5697f253a9a44bba7dcb83e80d)
Diffstat (limited to 'src/common/Debugging')
-rw-r--r--src/common/Debugging/WheatyExceptionReport.cpp119
1 files changed, 98 insertions, 21 deletions
diff --git a/src/common/Debugging/WheatyExceptionReport.cpp b/src/common/Debugging/WheatyExceptionReport.cpp
index a5a23d7eb7d..a1d8bb82519 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")
@@ -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