13#define _ThrowInfo ThrowInfo
24#define CrashFolder _T("Crashes")
25#pragma comment(linker, "/DEFAULTLIB:dbghelp.lib")
26#pragma comment(linker, "/DEFAULTLIB:wbemuuid.lib")
31 DWORD formatResult = FormatMessage(
32 FORMAT_MESSAGE_ALLOCATE_BUFFER |
33 FORMAT_MESSAGE_FROM_SYSTEM,
36 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
39 if (formatResult != 0)
40 return (LPTSTR)lpMsgBuf;
43 LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30);
44 snprintf(msgBuf, 30,
"Unknown error: %u", dw);
56#pragma warning(disable: 4073)
85 if (!IsDebuggerPresent())
87 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
88 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
89 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
90 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
110PEXCEPTION_POINTERS pExceptionInfo)
115 return EXCEPTION_EXECUTE_HANDLER;
119 TCHAR module_folder_name[MAX_PATH];
120 GetModuleFileName(
nullptr, module_folder_name, MAX_PATH);
121 TCHAR* pos = _tcsrchr(module_folder_name,
'\\');
127 TCHAR crash_folder_path[MAX_PATH];
128 _stprintf_s(crash_folder_path,
"%s\\%s", module_folder_name,
CrashFolder);
129 if (!CreateDirectory(crash_folder_path,
nullptr))
131 if (GetLastError() != ERROR_ALREADY_EXISTS)
136 GetLocalTime(&systime);
138 crash_folder_path,
GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
141 crash_folder_path,
GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
148 FILE_FLAG_WRITE_THROUGH,
153 MINIDUMP_EXCEPTION_INFORMATION info;
154 info.ClientPointers = FALSE;
155 info.ExceptionPointers = pExceptionInfo;
156 info.ThreadId = GetCurrentThreadId();
158 MINIDUMP_USER_STREAM additionalStream = {};
159 MINIDUMP_USER_STREAM_INFORMATION additionalStreamInfo = {};
161 if (pExceptionInfo->ExceptionRecord->ExceptionCode ==
EXCEPTION_ASSERTION_FAILURE && pExceptionInfo->ExceptionRecord->NumberParameters > 0)
163 additionalStream.Type = CommentStreamA;
164 additionalStream.Buffer =
reinterpret_cast<PVOID
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0]);
165 additionalStream.BufferSize = strlen(
reinterpret_cast<char const*
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0])) + 1;
167 additionalStreamInfo.UserStreamArray = &additionalStream;
168 additionalStreamInfo.UserStreamCount = 1;
171 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
172 m_hDumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, &additionalStreamInfo,
nullptr);
190 return EXCEPTION_EXECUTE_HANDLER;
195 RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0,
nullptr);
205 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
206 0, KEY_QUERY_VALUE, &hKey);
207 if (lRet != ERROR_SUCCESS)
210 DWORD cntBytes =
sizeof(szTmp);
211 lRet = ::RegQueryValueEx(hKey, _T(
"ProcessorNameString"),
nullptr,
nullptr,
212 (LPBYTE)szTmp, &cntBytes);
213 if (lRet != ERROR_SUCCESS)
216 sProcessorName[0] =
'\0';
219 while (iswspace(*psz))
221 _tcsncpy(sProcessorName, psz, maxcount);
228 if constexpr (std::is_same_v<TCHAR, char>)
229 ::wcstombs_s(
nullptr, dst, src,
size);
231 ::wcscpy_s(dst,
size, src);
236 *szVersion = _T(
'\0');
243 RTL_OSVERSIONINFOEXW osvi = { };
244 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOEXW);
245 NTSTATUS bVersionEx =
RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);
246 if (FAILED(bVersionEx))
248 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOW);
253 TCHAR szCSDVersion[256];
254 ToTchar(osvi.szCSDVersion, szCSDVersion);
257 switch (osvi.dwPlatformId)
260 case VER_PLATFORM_WIN32_NT:
263 BYTE suiteMask = osvi.wReserved[0];
264 BYTE productType = osvi.wReserved[1];
266 WORD suiteMask = osvi.wSuiteMask;
267 BYTE productType = osvi.wProductType;
271 if (osvi.dwMajorVersion == 10)
273 if (productType == VER_NT_WORKSTATION)
274 _tcsncat(szVersion, _T(
"Windows 10 "), cntMax);
276 _tcsncat(szVersion, _T(
"Windows Server 2016 "), cntMax);
278 else if (osvi.dwMajorVersion == 6)
280 if (productType == VER_NT_WORKSTATION)
282 if (osvi.dwMinorVersion == 3)
283 _tcsncat(szVersion, _T(
"Windows 8.1 "), cntMax);
284 else if (osvi.dwMinorVersion == 2)
285 _tcsncat(szVersion, _T(
"Windows 8 "), cntMax);
286 else if (osvi.dwMinorVersion == 1)
287 _tcsncat(szVersion, _T(
"Windows 7 "), cntMax);
289 _tcsncat(szVersion, _T(
"Windows Vista "), cntMax);
291 else if (osvi.dwMinorVersion == 3)
292 _tcsncat(szVersion, _T(
"Windows Server 2012 R2 "), cntMax);
293 else if (osvi.dwMinorVersion == 2)
294 _tcsncat(szVersion, _T(
"Windows Server 2012 "), cntMax);
295 else if (osvi.dwMinorVersion == 1)
296 _tcsncat(szVersion, _T(
"Windows Server 2008 R2 "), cntMax);
298 _tcsncat(szVersion, _T(
"Windows Server 2008 "), cntMax);
300 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
301 _tcsncat(szVersion, _T(
"Microsoft Windows Server 2003 "), cntMax);
302 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
303 _tcsncat(szVersion, _T(
"Microsoft Windows XP "), cntMax);
304 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
305 _tcsncat(szVersion, _T(
"Microsoft Windows 2000 "), cntMax);
306 else if (osvi.dwMajorVersion <= 4)
307 _tcsncat(szVersion, _T(
"Microsoft Windows NT "), cntMax);
313 if (productType == VER_NT_WORKSTATION)
315 if (osvi.dwMajorVersion == 4)
316 _tcsncat(szVersion, _T(
"Workstation 4.0 "), cntMax);
317 else if (suiteMask & VER_SUITE_PERSONAL)
318 _tcsncat(szVersion, _T(
"Home Edition "), cntMax);
319 else if (suiteMask & VER_SUITE_EMBEDDEDNT)
320 _tcsncat(szVersion, _T(
"Embedded "), cntMax);
322 _tcsncat(szVersion, _T(
"Professional "), cntMax);
325 else if (productType == VER_NT_SERVER)
327 if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
329 if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
330 _tcsncat(szVersion, _T(
"Essentials "), cntMax);
331 else if (suiteMask & VER_SUITE_DATACENTER)
332 _tcsncat(szVersion, _T(
"Datacenter "), cntMax);
333 else if (suiteMask & VER_SUITE_ENTERPRISE)
334 _tcsncat(szVersion, _T(
"Enterprise "), cntMax);
336 _tcsncat(szVersion, _T(
"Standard "), cntMax);
338 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
340 if (suiteMask & VER_SUITE_DATACENTER)
341 _tcsncat(szVersion, _T(
"Datacenter Edition "), cntMax);
342 else if (suiteMask & VER_SUITE_ENTERPRISE)
343 _tcsncat(szVersion, _T(
"Enterprise Edition "), cntMax);
344 else if (suiteMask == VER_SUITE_BLADE)
345 _tcsncat(szVersion, _T(
"Web Edition "), cntMax);
347 _tcsncat(szVersion, _T(
"Standard Edition "), cntMax);
349 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
351 if (suiteMask & VER_SUITE_DATACENTER)
352 _tcsncat(szVersion, _T(
"Datacenter Server "), cntMax);
353 else if (suiteMask & VER_SUITE_ENTERPRISE)
354 _tcsncat(szVersion, _T(
"Advanced Server "), cntMax);
356 _tcsncat(szVersion, _T(
"Server "), cntMax);
360 if (suiteMask & VER_SUITE_ENTERPRISE)
361 _tcsncat(szVersion, _T(
"Server 4.0, Enterprise Edition "), cntMax);
363 _tcsncat(szVersion, _T(
"Server 4.0 "), cntMax);
369 if (osvi.dwMajorVersion == 4 && _tcsicmp(szCSDVersion, _T(
"Service Pack 6")) == 0)
375 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey);
376 if (lRet == ERROR_SUCCESS)
378 _stprintf_s(wszTmp, _T(
"Service Pack 6a (Version %d.%d, Build %d)"),
379 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
380 _tcsncat(szVersion, wszTmp, cntMax);
384 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
385 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
386 _tcsncat(szVersion, wszTmp, cntMax);
392 if (!_tcslen(szCSDVersion))
393 _stprintf_s(wszTmp, _T(
"(Version %d.%d, Build %d)"),
394 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
396 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
397 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
398 _tcsncat(szVersion, wszTmp, cntMax);
403 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
404 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
405 _tcsncat(szVersion, wszTmp, cntMax);
416 HRESULT hres = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
420 std::shared_ptr<void> com(
nullptr, [](
void*)
427 hres = CoInitializeSecurity(
432 RPC_C_AUTHN_LEVEL_DEFAULT,
433 RPC_C_IMP_LEVEL_IMPERSONATE,
444 std::shared_ptr<IWbemLocator> loc = []() -> std::shared_ptr<IWbemLocator>
446 IWbemLocator* tmp =
nullptr;
447 HRESULT hres = CoCreateInstance(
450 CLSCTX_INPROC_SERVER,
452 reinterpret_cast<LPVOID*
>(&tmp));
457 return { tmp, [](IWbemLocator* ptr) {
if (ptr) ptr->Release(); } };
467 std::shared_ptr<IWbemServices> svc = [loc]() ->std::shared_ptr<IWbemServices>
469 IWbemServices* tmp =
nullptr;
470 HRESULT hres = loc->ConnectServer(
471 bstr_t(L
"ROOT\\CIMV2"),
475 WBEM_FLAG_CONNECT_USE_MAX_WAIT,
484 return { tmp, [](IWbemServices* ptr) {
if (ptr) ptr->Release(); } };
492 hres = CoSetProxyBlanket(
497 RPC_C_AUTHN_LEVEL_CALL,
498 RPC_C_IMP_LEVEL_IMPERSONATE,
510 std::shared_ptr<IEnumWbemClassObject> queryResult = [svc]() -> std::shared_ptr<IEnumWbemClassObject>
512 IEnumWbemClassObject* tmp =
nullptr;
513 HRESULT hres = svc->ExecQuery(
515 bstr_t(
"SELECT Caption, CSDVersion FROM Win32_OperatingSystem"),
516 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
523 return { tmp, [](IEnumWbemClassObject* ptr) {
if (ptr) ptr->Release(); } };
533 IWbemClassObject* fields =
nullptr;
536 queryResult->Next(WBEM_INFINITE, 1, &fields, &rows);
542 fields->Get(L
"Caption", 0, &field,
nullptr,
nullptr);
543 TCHAR buf[256] = { };
545 _tcsncat(szVersion, buf, cntMax);
546 VariantClear(&field);
548 fields->Get(L
"CSDVersion", 0, &field,
nullptr,
nullptr);
549 if (field.vt == VT_BSTR)
551 _tcsncat(szVersion, _T(
" "), cntMax);
552 memset(buf, 0,
sizeof(buf));
555 _tcsncat(szVersion, buf, cntMax);
557 VariantClear(&field);
570 SYSTEM_INFO SystemInfo;
571 ::GetSystemInfo(&SystemInfo);
573 MEMORYSTATUS MemoryStatus;
574 MemoryStatus.dwLength =
sizeof (MEMORYSTATUS);
575 ::GlobalMemoryStatus(&MemoryStatus);
577 Log(_T(
"//=====================================================\r\n"));
579 Log(_T(
"*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
580 sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
582 Log(_T(
"*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
583 SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
586 Log(_T(
"\r\n*** Operation System ***\r\n%s\r\n"), sString);
588 Log(_T(
"\r\n*** Operation System:\r\n<unknown>\r\n"));
596 DWORD dwOwnerPID = GetCurrentProcessId();
597 DWORD dwCurrentTID = GetCurrentThreadId();
600 HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
601 if (hThreadSnap == INVALID_HANDLE_VALUE)
605 te32.dwSize =
sizeof(THREADENTRY32);
609 if (!Thread32First(hThreadSnap, &te32))
611 CloseHandle(hThreadSnap);
621 if (te32.th32OwnerProcessID == dwOwnerPID && te32.th32ThreadID != dwCurrentTID)
624 context.ContextFlags = 0xffffffff;
625 HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
false, te32.th32ThreadID);
628 if (GetThreadContext(threadHandle, &context))
630 CloseHandle(threadHandle);
633 }
while (Thread32Next(hThreadSnap, &te32));
636 CloseHandle(hThreadSnap);
644PEXCEPTION_POINTERS pExceptionInfo)
649 GetLocalTime(&systime);
653 Log(_T(
"Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
654 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
658 Log(_T(
"\r\n//=====================================================\r\n"));
659 Log(_T(
"Exception code: %08X %s\r\n"),
660 pExceptionRecord->ExceptionCode,
664 pExceptionRecord->ExceptionAddress =
reinterpret_cast<PVOID
>(pExceptionRecord->ExceptionInformation[1]);
665 Log(_T(
"Assertion message: %s\r\n"), pExceptionRecord->ExceptionInformation[0]);
669 TCHAR szFaultingModule[MAX_PATH];
674 sizeof(szFaultingModule),
677#if defined(_M_IX86) || defined(_M_ARM)
678 Log(_T(
"Fault address: %08X %02X:%08X %s\r\n"),
679 pExceptionRecord->ExceptionAddress,
680 section, offset, szFaultingModule);
682#if defined(_M_X64) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined (_M_ARM64EC)
683 Log(_T(
"Fault address: %016I64X %02X:%016I64X %s\r\n"),
684 pExceptionRecord->ExceptionAddress,
685 section, offset, szFaultingModule);
688 PCONTEXT pCtx = pExceptionInfo->ContextRecord;
692 Log(_T(
"\r\nRegisters:\r\n"));
694 Log(_T(
"EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
695 , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
696 pCtx->Esi, pCtx->Edi);
698 Log(_T(
"CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
699 Log(_T(
"SS:ESP:%04X:%08X EBP:%08X\r\n"),
700 pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
701 Log(_T(
"DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
702 pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
703 Log(_T(
"Flags:%08X\r\n"), pCtx->EFlags);
707 Log(_T(
"\r\nRegisters:\r\n"));
708 Log(_T(
"RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
709 _T(
"R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
710 , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
711 pCtx->Rsi, pCtx->Rdi, pCtx->R8, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
712 Log(_T(
"CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
713 Log(_T(
"SS:RSP:%04X:%016I64X RBP:%08X\r\n"),
714 pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
715 Log(_T(
"DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
716 pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
717 Log(_T(
"Flags:%08X\r\n"), pCtx->EFlags);
721 Log(_T(
"\r\nRegisters:\r\n"));
722 Log(_T(
"X0:%016I64X\r\nX1:%016I64X\r\nX2:%016I64X\r\nX3:%016I64X\r\nX4:%016I64X\r\nX5:%016I64X\r\n"),
723 _T(
"X6:%016I64X\r\nX7:%016I64X\r\nX8:%016I64X\r\nX9:%016I64X\r\nX10:%016I64X\r\nX11:%016I64X\r\nX12:%016I64X\r\nX13:%016I64X\r\n"),
724 _T(
"X14:%016I64X\r\nX15:%016I64X\r\nX16:%016I64X\r\nX17:%016I64X\r\nX18:%016I64X\r\nX19:%016I64X\r\nX20:%016I64X\r\nX21:%016I64X\r\n"),
725 _T(
"X22:%016I64X\r\nX23:%016I64X\r\nX24:%016I64X\r\nX25:%016I64X\r\nX26:%016I64X\r\nX27:%016I64X\r\nX28:%016I64X\r\n"),
726 pCtx->X0, pCtx->X1, pCtx->X2, pCtx->X3, pCtx->X4, pCtx->X5,
727 pCtx->X6, pCtx->X7, pCtx->X8, pCtx->X9, pCtx->X10, pCtx->X11, pCtx->X12, pCtx->X13,
728 pCtx->X14, pCtx->X15, pCtx->X16, pCtx->X17, pCtx->X18, pCtx->X19, pCtx->X20, pCtx->X21,
729 pCtx->X22, pCtx->X23, pCtx->X24, pCtx->X25, pCtx->X26, pCtx->X27, pCtx->X28);
730 Log(_T(
"LR:%016I64X\r\n"), pCtx->Lr);
731 Log(_T(
"PC:%016I64X\r\n"), pCtx->Pc);
732 Log(_T(
"SP:%016I64X FP:%016I64X\r\n"), pCtx->Sp, pCtx->Fp);
733 Log(_T(
"Flags:%08X\r\n"), pCtx->Cpsr);
736 SymSetOptions(SYMOPT_DEFERRED_LOADS);
739 if (!SymInitialize(GetCurrentProcess(),
nullptr, TRUE))
743 Log(_T(
"SYMBOL HANDLER ERROR (THIS IS NOT THE CRASH ERROR)\r\n\r\n"));
744 Log(_T(
"Couldn't initialize symbol handler for process when generating crash report\r\n"));
746 Log(_T(
"THE BELOW CALL STACKS MIGHT HAVE MISSING OR INACCURATE FILE/FUNCTION NAMES\r\n\r\n"));
750 if (pExceptionRecord->ExceptionCode == 0xE06D7363 && pExceptionRecord->NumberParameters >= 2)
752 PVOID exceptionObject =
reinterpret_cast<PVOID
>(pExceptionRecord->ExceptionInformation[1]);
753 ThrowInfo
const* throwInfo =
reinterpret_cast<ThrowInfo const*
>(pExceptionRecord->ExceptionInformation[2]);
754#if _EH_RELATIVE_TYPEINFO
756 auto resolveExceptionRVA = [pExceptionRecord](
int32 rva) -> DWORD_PTR
758 return rva + (pExceptionRecord->NumberParameters >= 4 ? pExceptionRecord->ExceptionInformation[3] : 0);
762 auto resolveExceptionRVA = [](
void const* input) ->
void const* {
return input; };
765 CatchableTypeArray
const* catchables =
reinterpret_cast<CatchableTypeArray const*
>(resolveExceptionRVA(throwInfo->pCatchableTypeArray));
766 CatchableType
const* catchable = catchables->nCatchableTypes ?
reinterpret_cast<CatchableType const*
>(resolveExceptionRVA(catchables->arrayOfCatchableTypes[0])) :
nullptr;
767 TypeDescriptor
const* exceptionTypeinfo = catchable ?
reinterpret_cast<TypeDescriptor const*
>(resolveExceptionRVA(catchable->pType)) :
nullptr;
769 if (exceptionTypeinfo)
771 void* stdExceptionTypeInfo = []() ->
void*
776 return __RTtypeid(&fake);
783 std::exception
const* exceptionPtr = [](
void* object, TypeDescriptor
const* typeInfo,
void* stdExceptionTypeInfo) -> std::exception
const*
792 return reinterpret_cast<std::exception const*
>(__RTDynamicCast(
object, 0, stdExceptionTypeInfo, (
void*)typeInfo,
false));
798 }(exceptionObject, exceptionTypeinfo, stdExceptionTypeInfo);
801 if (!exceptionPtr && exceptionTypeinfo == stdExceptionTypeInfo)
802 exceptionPtr =
reinterpret_cast<std::exception*
>(exceptionObject);
804 Log(_T(
"\r\nUncaught C++ exception info:"));
806 Log(_T(
" %s"), exceptionPtr->what());
810 char undName[MAX_SYM_NAME] = { };
811 if (UnDecorateSymbolName(&exceptionTypeinfo->name[1], &undName[0], MAX_SYM_NAME, UNDNAME_32_BIT_DECODE | UNDNAME_NAME_ONLY | UNDNAME_NO_ARGUMENTS))
813 char buf[MAX_SYM_NAME +
sizeof(SYMBOL_INFO)] = { };
814 PSYMBOL_INFO sym = (PSYMBOL_INFO)&buf[0];
815 sym->SizeOfStruct =
sizeof(SYMBOL_INFO);
816 sym->MaxNameLen = MAX_SYM_NAME;
817 if (SymGetTypeFromName(
m_hProcess, (ULONG64)GetModuleHandle(
nullptr), undName, sym))
819 sym->Address = pExceptionRecord->ExceptionInformation[1];
821 char const* variableName =
"uncaught_exception";
822 memset(sym->Name, 0, MAX_SYM_NAME);
823 memcpy(sym->Name, variableName, strlen(variableName));
830 CONTEXT trashableContext = *pCtx;
837 Log(_T(
"========================\r\n"));
838 Log(_T(
"Local Variables And Parameters\r\n"));
840 trashableContext = *pCtx;
844 SymCleanup(GetCurrentProcess());
848 __except (EXCEPTION_EXECUTE_HANDLER)
850 Log(_T(
"Error writing the crash log\r\n"));
860 #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x);
886 case 0xE06D7363:
return _T(
"Unhandled C++ exception");
892 static TCHAR szBuffer[512] = { 0 };
894 FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
895 GetModuleHandle(_T(
"NTDLL.DLL")),
896 dwCode, 0, szBuffer,
sizeof(szBuffer),
nullptr);
909PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset)
911 MEMORY_BASIC_INFORMATION mbi;
913 if (!VirtualQuery(addr, &mbi,
sizeof(mbi)))
916 DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
921 if (!GetModuleFileName((HMODULE)hMod, szModule, len))
925 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
928 PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
930 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
932 DWORD_PTR rva = (DWORD_PTR)addr - hMod;
937 i < pNtHdr->FileHeader.NumberOfSections;
940 DWORD_PTR sectionStart = pSection->VirtualAddress;
941 DWORD_PTR sectionEnd = sectionStart
942 + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
945 if ((rva >= sectionStart) && (rva <= sectionEnd))
951 offset = rva - sectionStart;
965 si.SizeOfStruct =
sizeof(SYMBOL_INFO);
966 si.MaxNameLen =
sizeof(name);
975bool bWriteVariables, HANDLE pThreadHandle)
977 Log(_T(
"\r\nCall stack:\r\n"));
979 Log(_T(
"Address Frame Function SourceFile\r\n"));
981 DWORD dwMachineType = 0;
985 memset(&sf, 0,
sizeof(sf));
988 sf.AddrPC.Mode = AddrModeFlat;
989 sf.AddrStack.Mode = AddrModeFlat;
990 sf.AddrFrame.Mode = AddrModeFlat;
993 sf.AddrPC.Offset = pContext->Eip;
994 sf.AddrStack.Offset = pContext->Esp;
995 sf.AddrFrame.Offset = pContext->Ebp;
996 dwMachineType = IMAGE_FILE_MACHINE_I386;
998 sf.AddrPC.Offset = pContext->Rip;
999 sf.AddrStack.Offset = pContext->Rsp;
1000 sf.AddrFrame.Offset = pContext->Rbp;
1001 dwMachineType = IMAGE_FILE_MACHINE_AMD64;
1002#elif defined(_M_ARM64)
1003 sf.AddrPC.Offset = pContext->Pc;
1004 sf.AddrStack.Offset = pContext->Sp;
1005 sf.AddrFrame.Offset = pContext->Fp;
1006 dwMachineType = IMAGE_FILE_MACHINE_ARM64;
1012 if (! StackWalk64(dwMachineType,
1014 pThreadHandle !=
nullptr ? pThreadHandle : GetCurrentThread(),
1018 SymFunctionTableAccess64,
1022 if (0 == sf.AddrFrame.Offset)
1025 Log(_T(
"%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1026#elif defined(_M_X64) || defined(_M_ARM64)
1027 Log(_T(
"%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1030 DWORD64 symDisplacement = 0;
1041 Log(_T(
"%hs+%I64X"), sip.si.Name, symDisplacement);
1046 TCHAR szModule[MAX_PATH] = _T(
"");
1048 DWORD_PTR offset = 0;
1051 szModule,
sizeof(szModule), section, offset);
1053 Log(_T(
"%04X:%08X %s"), section, offset, szModule);
1054#elif defined(_M_X64) || defined(_M_ARM64)
1055 Log(_T(
"%04X:%016I64X %s"), section, offset, szModule);
1060 IMAGEHLP_LINE64 lineInfo = {
sizeof(IMAGEHLP_LINE64) };
1061 DWORD dwLineDisplacement;
1062 if (SymGetLineFromAddr64(
m_hProcess, sf.AddrPC.Offset,
1063 &dwLineDisplacement, &lineInfo))
1065 Log(_T(
" %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
1071 if (bWriteVariables)
1074 IMAGEHLP_STACK_FRAME imagehlpStackFrame;
1075 imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
1076 SymSetContext(
m_hProcess, &imagehlpStackFrame,
nullptr);
1096PSYMBOL_INFO pSymInfo,
1106 __except (EXCEPTION_EXECUTE_HANDLER)
1108 Log(_T(
"punting on symbol %s, partial output:\r\n"), pSymInfo->Name);
1116#define REG_L(x) ((BYTE)(((DWORD_PTR)(x)) & 0xff))
1117#define REG_H(x) ((BYTE)((((DWORD_PTR)(x)) >> 8) & 0xff))
1118#define REG_X(x) ((WORD)(((DWORD_PTR)(x)) & 0xffff))
1119#define REG_E(x) ((DWORD)(((DWORD_PTR)(x)) & 0xffffffff))
1120#define REG_R(x) ((DWORD64)(((DWORD_PTR)(x)) & 0xffffffffffffffff))
1121#define CPU_REG(reg, field, part) case reg: return part(context->field);
1150#elif defined (_M_X64)
1220#elif defined(_M_ARM64)
1309 if (pSym->Tag == SymTagFunction)
1312 DWORD_PTR pVariable = pSym->Address;
1315 if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_FRAMERELATIVE
1316 || (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE && pSym->Register ==
CV_ALLREG_VFRAME))
1318 pVariable += pCtx->
sf->AddrFrame.Offset;
1320 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE)
1326 pVariable += *registerValue;
1328 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
1331 if (!registerVariableStorage)
1334 pVariable =
reinterpret_cast<DWORD_PTR
>(&*registerVariableStorage);
1344 if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
1346 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
1352 DumpTypeIndex(pSym->ModBase, pSym->TypeIndex, pVariable, bHandled, pSym->Name,
"",
false,
true);
1364 if (pSym->Name[0] !=
'\0')
1368 FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable,
sizeof(buffer));
1397 if (!SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
1402 WCHAR * pwszTypeName;
1403 if (SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
1407 if (wcscmp(pwszTypeName, L
"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
1409 LocalFree(pwszTypeName);
1414 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1421 wcstombs(buffer, pwszTypeName,
sizeof(buffer));
1423 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1428 else if (buffer[0] !=
'\0')
1431 LocalFree(pwszTypeName);
1433 else if (
Name !=
nullptr &&
Name[0] !=
'\0')
1439 if (typeTag == SymTagBaseClass)
1447 case SymTagPointerType:
1448 if (SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1450 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1454 SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
1456 char addressStr[40];
1457 memset(addressStr, 0,
sizeof(addressStr));
1472 logChildren =
false;
1475 if (address == 0 || address == DWORD_PTR(-1))
1476 logChildren =
false;
1478 DumpTypeIndex(modBase, innerTypeID, address, bHandled,
Name, addressStr,
false, logChildren);
1488 else if (address == DWORD_PTR(-1))
1494 SymGetTypeInfo(
m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
1502 else if (address == 0)
1504 else if (address == DWORD_PTR(-1))
1513 if (SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1516 if (!SymGetTypeInfo(
m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
1519 switch (innerTypeTag)
1523 logChildren =
false;
1525 offset, bHandled,
symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1527 case SymTagPointerType:
1528 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1531 offset, bHandled,
symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1533 case SymTagArrayType:
1535 offset, bHandled,
symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1542 case SymTagArrayType:
1543 if (SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1549 offset, bHandled,
Name,
"",
false,
false);
1555 DWORD elementsCount;
1556 if (SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
1557 symbolDetails.top().Suffix +=
"[" + std::to_string(elementsCount) +
"]";
1571 SymGetTypeInfo(
m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
1578 FormatOutputValue(buffer, basicType, length, (PVOID)offset,
sizeof(buffer), elementsCount);
1584 bool elementHandled =
false;
1588 if (firstElementValue.empty())
1590 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1591 firstElementValue = buffer;
1597 DumpTypeIndex(modBase, innerTypeID, offset + length * index, elementHandled,
"",
"",
false,
false);
1598 if (!elementHandled)
1600 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1606 symbolDetails.top().Suffix =
"[" + std::to_string(index) +
"]";
1616 case SymTagBaseType:
1625 DWORD dwChildrenCount = 0;
1626 SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
1628 if (!dwChildrenCount)
1634 struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
1636 ULONG MoreChildIds[1024*2];
1637 FINDCHILDREN(){
Count =
sizeof(MoreChildIds) /
sizeof(MoreChildIds[0]);}
1640 children.Count = dwChildrenCount;
1644 if (!SymGetTypeInfo(
m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
1651 for (
unsigned i = 0; i < dwChildrenCount; i++)
1654 SymGetTypeInfo(
m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);
1656 if (symTag == SymTagFunction ||
1657 symTag == SymTagEnum ||
1658 symTag == SymTagTypedef ||
1659 symTag == SymTagVTable)
1664 SymGetTypeInfo(
m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);
1682 DWORD dwMemberOffset;
1683 SymGetTypeInfo(
m_hProcess, modBase, children.ChildId[i],
1684 TI_GET_OFFSET, &dwMemberOffset);
1687 DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
1690 children.ChildId[i],
1691 dwFinalOffset, bHandled2,
"",
"",
true,
true);
1702 SymGetTypeInfo(
m_hProcess, modBase, children.ChildId[i],
1703 TI_GET_TYPEID, &typeId);
1707 SymGetTypeInfo(
m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
1710 FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset,
sizeof(buffer));
1725size_t countOverride)
1734 if (countOverride != 0)
1735 length = countOverride;
1737 length = strlen((
char*)pAddress);
1739 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s...\"", (
int)(
bufferSize - 6), (
char*)pAddress);
1741 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s\"", (
int)length, (
char*)pAddress);
1746 std::string* value =
static_cast<std::string*
>(pAddress);
1748 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s...\"", (
int)(
bufferSize - 6), value->c_str());
1750 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%s\"", value->c_str());
1756 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", *(PBYTE)pAddress);
1757 else if (length == 2)
1758 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", *(PWORD)pAddress);
1759 else if (length == 4)
1762 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%f", *(PFLOAT)pAddress);
1764 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", *(PDWORD)pAddress);
1766 else if (length == 8)
1770 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%f",
1771 *(
double *)pAddress);
1774 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%I64X",
1775 *(DWORD64*)pAddress);
1780 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%I64X", (DWORD64)pAddress);
1782 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", (DWORD)pAddress);
1788 __except (EXCEPTION_EXECUTE_HANDLER)
1791 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%I64X <Unable to read memory>", (DWORD64)pAddress);
1793 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X <Unable to read memory>", (DWORD)pAddress);
1802 if (SymGetTypeInfo(
m_hProcess, modBase, typeIndex,
1803 TI_GET_BASETYPE, &basicType))
1811 if (SymGetTypeInfo(
m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId))
1813 if (SymGetTypeInfo(
m_hProcess, modBase, typeId, TI_GET_BASETYPE,
1827 return *(PDWORD_PTR)address;
1829 __except (EXCEPTION_EXECUTE_HANDLER)
1831 return DWORD_PTR(-1);
1842 va_start(argptr, format);
1895 if (!formatted.empty())
1901 if (
Name ==
"passwd" ||
Name ==
"password")
1902 Value =
"<sensitive data>";
1903 formatted +=
" = " +
Value;
#define EXCEPTION_ASSERTION_FAILURE
std::optional< T > Optional
Optional helper class to wrap optional values within.
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define CPU_REG(reg, field, part)
void ToTchar(wchar_t const *src, TCHAR(&dst)[size])
LPTSTR ErrorMessage(DWORD dw)
WheatyExceptionReport g_WheatyExceptionReport
char const *const rgBaseType[]
#define WER_SMALL_BUFFER_SIZE
#define WER_MAX_NESTING_LEVEL
#define WER_MAX_ARRAY_ELEMENTS_COUNT
std::set< SymbolPair > SymbolPairs
static LPCTSTR GetExceptionString(DWORD dwCode)
static FILE * m_hReportFile
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD §ion, DWORD_PTR &offset)
static bool alreadyCrashed
static int __cdecl Log(const TCHAR *format,...)
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID)
static BOOL _GetProcessorName(TCHAR *sProcessorName, DWORD maxcount)
static bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext *)
static void PrintSystemInfo()
static void PrintSymbolDetail()
static SymbolPairs symbols
static void FormatOutputValue(char *pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride=0)
static BOOL _GetWindowsVersionFromWMI(TCHAR *szVersion, DWORD cntMax)
static void ClearSymbols()
static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const *, char const *, bool, bool)
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
static _invalid_parameter_handler m_previousCrtHandler
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase)
static HANDLE m_hDumpFile
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address)
static std::mutex alreadyCrashedLock
static TCHAR m_szDumpFileName[MAX_PATH]
static pRtlGetVersion RtlGetVersion
static BOOL _GetWindowsVersion(TCHAR *szVersion, DWORD cntMax)
static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle)
static void PushSymbolDetail()
NTSTATUS(NTAPI * pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation)
static void PopSymbolDetail()
static bool StoreSymbol(DWORD type, DWORD_PTR offset)
static Optional< DWORD_PTR > GetIntegerRegisterValue(PCONTEXT context, ULONG registerId)
static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo)
static void printTracesForAllThreads(bool)
static std::stack< SymbolDetail > symbolDetails
static LONG WINAPI WheatyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
static void __cdecl WheatyCrtHandler(wchar_t const *expression, wchar_t const *function, wchar_t const *file, unsigned int line, uintptr_t pReserved)
static TCHAR m_szLogFileName[MAX_PATH]
TC_COMMON_API char const * GetFullVersion()
TC_COMMON_API char const * GetHash()
constexpr std::size_t size()