70 m_tempPathBuffer(static_cast<TCHAR*>(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, m_tempPathBufferChars * sizeof(TCHAR)))),
71 m_previousFilter(SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter)),
72 m_previousCrtHandler(_set_invalid_parameter_handler(WheatyCrtHandler)),
73 m_reportFile(nullptr),
75 m_process(GetCurrentProcess()),
76 m_alreadyCrashed(false),
77 m_alreadyCrashedLock(SRWLOCK_INIT),
78 RtlGetVersion((pRtlGetVersion)GetProcAddress(GetModuleHandle(_T(
"ntdll.dll")),
"RtlGetVersion"))
80 if (!IsDebuggerPresent())
82 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
83 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
84 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
85 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
88 if (std::exchange(g_WheatyExceptionReport,
this) !=
nullptr)
89 throw std::logic_error(
"Only one instance of WheatyExceptionReport can exist");
118 AcquireSRWLockExclusive(&m_alreadyCrashedLock);
119 auto guard = Trinity::make_unique_ptr_with_deleter<&ReleaseSRWLockExclusive>(&m_alreadyCrashedLock);
121 if (m_alreadyCrashed)
122 return EXCEPTION_EXECUTE_HANDLER;
124 m_alreadyCrashed =
true;
126 auto prepareCrashFolder = [
this]<
typename Char>(Char
const* path) -> TCHAR*
131 std::basic_string_view<Char> processPath = path;
133 auto filenameSeparator = processPath.rfind(
'\\');
134 if (filenameSeparator == std::basic_string_view<Char>::npos)
137 std::basic_string_view<Char> processName = processPath.substr(filenameSeparator + 1);
138 if (processName.empty())
141 processPath.remove_suffix(processName.length());
143 TCHAR* buffer = m_tempPathBuffer;
146 if constexpr (std::is_same_v<wchar_t, Char>)
151 if (!CreateDirectory(m_tempPathBuffer,
nullptr) && GetLastError() != ERROR_ALREADY_EXISTS)
155 GetLocalTime(&systime);
158 if constexpr (std::is_same_v<wchar_t, Char>)
159 buffer += _stprintf_s(buffer, m_tempPathBufferChars - (buffer - m_tempPathBuffer), _T(
"\\%" PRSTRc "_%.*" PRSTRw "_[%u_%u_%u_%u_%u_%u]."),
162 buffer += _stprintf_s(buffer, m_tempPathBufferChars - (buffer - m_tempPathBuffer), _T(
"\\%" PRSTRc "_%.*" PRSTRc "_[%u_%u_%u_%u_%u_%u]."),
168 TCHAR* crashPath =
nullptr;
171 if (
char const* processName = _pgmptr)
172 crashPath = prepareCrashFolder(processName);
173 else if (
wchar_t const* wprocessName = _wpgmptr)
174 crashPath = prepareCrashFolder(wprocessName);
179 _tcscpy_s(crashPath, m_tempPathBufferChars - (crashPath - m_tempPathBuffer), _T(
"dmp"));
180 m_dumpFile = CreateFile(m_tempPathBuffer,
185 FILE_FLAG_WRITE_THROUGH,
188 if (m_dumpFile && m_dumpFile != INVALID_HANDLE_VALUE)
190 MINIDUMP_EXCEPTION_INFORMATION info;
191 info.ClientPointers = FALSE;
192 info.ExceptionPointers = pExceptionInfo;
193 info.ThreadId = GetCurrentThreadId();
195 MINIDUMP_USER_STREAM additionalStream = {};
196 MINIDUMP_USER_STREAM_INFORMATION additionalStreamInfo = {};
198 if (pExceptionInfo->ExceptionRecord->ExceptionCode ==
EXCEPTION_ASSERTION_FAILURE && pExceptionInfo->ExceptionRecord->NumberParameters > 0)
200 additionalStream.Type = CommentStreamA;
201 additionalStream.Buffer =
reinterpret_cast<PVOID
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0]);
202 additionalStream.BufferSize = strlen(
reinterpret_cast<char const*
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0])) + 1;
204 additionalStreamInfo.UserStreamArray = &additionalStream;
205 additionalStreamInfo.UserStreamCount = 1;
208 MiniDumpWriteDump(m_process, GetCurrentProcessId(),
209 m_dumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, &additionalStreamInfo,
nullptr);
211 CloseHandle(m_dumpFile);
214 _tcscpy_s(crashPath, m_tempPathBufferChars - (crashPath - m_tempPathBuffer), _T(
"txt"));
215 m_reportFile = _tfopen(m_tempPathBuffer, _T(
"wb"));
219 GenerateExceptionReport(pExceptionInfo);
221 fclose(m_reportFile);
222 m_reportFile =
nullptr;
225 if (m_previousFilter)
226 return m_previousFilter(pExceptionInfo);
228 return EXCEPTION_EXECUTE_HANDLER;
274 *szVersion = _T(
'\0');
281 RTL_OSVERSIONINFOEXW osvi = { };
282 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOEXW);
283 NTSTATUS bVersionEx =
RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);
284 if (FAILED(bVersionEx))
286 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOW);
291 TCHAR szCSDVersion[256];
292 ToTchar(osvi.szCSDVersion, szCSDVersion);
295 switch (osvi.dwPlatformId)
298 case VER_PLATFORM_WIN32_NT:
301 BYTE suiteMask = osvi.wReserved[0];
302 BYTE productType = osvi.wReserved[1];
304 WORD suiteMask = osvi.wSuiteMask;
305 BYTE productType = osvi.wProductType;
309 if (osvi.dwMajorVersion == 10)
311 if (productType == VER_NT_WORKSTATION)
312 _tcsncat(szVersion, _T(
"Windows 10 "), cntMax);
314 _tcsncat(szVersion, _T(
"Windows Server 2016 "), cntMax);
316 else if (osvi.dwMajorVersion == 6)
318 if (productType == VER_NT_WORKSTATION)
320 if (osvi.dwMinorVersion == 3)
321 _tcsncat(szVersion, _T(
"Windows 8.1 "), cntMax);
322 else if (osvi.dwMinorVersion == 2)
323 _tcsncat(szVersion, _T(
"Windows 8 "), cntMax);
324 else if (osvi.dwMinorVersion == 1)
325 _tcsncat(szVersion, _T(
"Windows 7 "), cntMax);
327 _tcsncat(szVersion, _T(
"Windows Vista "), cntMax);
329 else if (osvi.dwMinorVersion == 3)
330 _tcsncat(szVersion, _T(
"Windows Server 2012 R2 "), cntMax);
331 else if (osvi.dwMinorVersion == 2)
332 _tcsncat(szVersion, _T(
"Windows Server 2012 "), cntMax);
333 else if (osvi.dwMinorVersion == 1)
334 _tcsncat(szVersion, _T(
"Windows Server 2008 R2 "), cntMax);
336 _tcsncat(szVersion, _T(
"Windows Server 2008 "), cntMax);
338 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
339 _tcsncat(szVersion, _T(
"Microsoft Windows Server 2003 "), cntMax);
340 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
341 _tcsncat(szVersion, _T(
"Microsoft Windows XP "), cntMax);
342 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
343 _tcsncat(szVersion, _T(
"Microsoft Windows 2000 "), cntMax);
344 else if (osvi.dwMajorVersion <= 4)
345 _tcsncat(szVersion, _T(
"Microsoft Windows NT "), cntMax);
351 if (productType == VER_NT_WORKSTATION)
353 if (osvi.dwMajorVersion == 4)
354 _tcsncat(szVersion, _T(
"Workstation 4.0 "), cntMax);
355 else if (suiteMask & VER_SUITE_PERSONAL)
356 _tcsncat(szVersion, _T(
"Home Edition "), cntMax);
357 else if (suiteMask & VER_SUITE_EMBEDDEDNT)
358 _tcsncat(szVersion, _T(
"Embedded "), cntMax);
360 _tcsncat(szVersion, _T(
"Professional "), cntMax);
363 else if (productType == VER_NT_SERVER)
365 if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
367 if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
368 _tcsncat(szVersion, _T(
"Essentials "), cntMax);
369 else if (suiteMask & VER_SUITE_DATACENTER)
370 _tcsncat(szVersion, _T(
"Datacenter "), cntMax);
371 else if (suiteMask & VER_SUITE_ENTERPRISE)
372 _tcsncat(szVersion, _T(
"Enterprise "), cntMax);
374 _tcsncat(szVersion, _T(
"Standard "), cntMax);
376 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
378 if (suiteMask & VER_SUITE_DATACENTER)
379 _tcsncat(szVersion, _T(
"Datacenter Edition "), cntMax);
380 else if (suiteMask & VER_SUITE_ENTERPRISE)
381 _tcsncat(szVersion, _T(
"Enterprise Edition "), cntMax);
382 else if (suiteMask == VER_SUITE_BLADE)
383 _tcsncat(szVersion, _T(
"Web Edition "), cntMax);
385 _tcsncat(szVersion, _T(
"Standard Edition "), cntMax);
387 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
389 if (suiteMask & VER_SUITE_DATACENTER)
390 _tcsncat(szVersion, _T(
"Datacenter Server "), cntMax);
391 else if (suiteMask & VER_SUITE_ENTERPRISE)
392 _tcsncat(szVersion, _T(
"Advanced Server "), cntMax);
394 _tcsncat(szVersion, _T(
"Server "), cntMax);
398 if (suiteMask & VER_SUITE_ENTERPRISE)
399 _tcsncat(szVersion, _T(
"Server 4.0, Enterprise Edition "), cntMax);
401 _tcsncat(szVersion, _T(
"Server 4.0 "), cntMax);
407 if (osvi.dwMajorVersion == 4 && _tcsicmp(szCSDVersion, _T(
"Service Pack 6")) == 0)
413 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey);
414 if (lRet == ERROR_SUCCESS)
416 _stprintf_s(wszTmp, _T(
"Service Pack 6a (Version %d.%d, Build %d)"),
417 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
418 _tcsncat(szVersion, wszTmp, cntMax);
422 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
423 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
424 _tcsncat(szVersion, wszTmp, cntMax);
430 if (!_tcslen(szCSDVersion))
431 _stprintf_s(wszTmp, _T(
"(Version %d.%d, Build %d)"),
432 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
434 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
435 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
436 _tcsncat(szVersion, wszTmp, cntMax);
441 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
442 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
443 _tcsncat(szVersion, wszTmp, cntMax);
460 HRESULT hres = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
468 hres = CoInitializeSecurity(
473 RPC_C_AUTHN_LEVEL_DEFAULT,
474 RPC_C_IMP_LEVEL_IMPERSONATE,
487 IWbemLocator* tmp =
nullptr;
488 HRESULT hres = CoCreateInstance(
491 CLSCTX_INPROC_SERVER,
493 reinterpret_cast<LPVOID*
>(&tmp));
495 return SUCCEEDED(hres) ? tmp :
nullptr;
507 IWbemServices* tmp =
nullptr;
508 HRESULT hres = loc->ConnectServer(
509 bstr_t(L
"ROOT\\CIMV2"),
513 WBEM_FLAG_CONNECT_USE_MAX_WAIT,
519 return SUCCEEDED(hres) ? tmp :
nullptr;
527 hres = CoSetProxyBlanket(
532 RPC_C_AUTHN_LEVEL_CALL,
533 RPC_C_IMP_LEVEL_IMPERSONATE,
547 IEnumWbemClassObject* tmp =
nullptr;
548 HRESULT hres = svc->ExecQuery(
550 bstr_t(
"SELECT Caption, CSDVersion FROM Win32_OperatingSystem"),
551 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
555 return SUCCEEDED(hres) ? tmp :
nullptr;
565 auto [fields, rows] = [&]
567 IWbemClassObject* fields =
nullptr;
569 HRESULT hres = queryResult->Next(WBEM_INFINITE, 1, &fields, &rows);
571 return SUCCEEDED(hres) && rows
572 ? std::pair(wbem_class_object_ptr(fields), rows)
573 : std::pair(wbem_class_object_ptr(), ULONG(0));
576 if (!fields || !rows)
581 fields->Get(L
"Caption", 0, &field,
nullptr,
nullptr);
582 TCHAR buf[256] = { };
584 _tcsncat(szVersion, buf, cntMax);
585 VariantClear(&field);
587 fields->Get(L
"CSDVersion", 0, &field,
nullptr,
nullptr);
588 if (field.vt == VT_BSTR)
590 _tcsncat(szVersion, _T(
" "), cntMax);
591 memset(buf, 0,
sizeof(buf));
594 _tcsncat(szVersion, buf, cntMax);
596 VariantClear(&field);
633 DWORD dwOwnerPID = GetCurrentProcessId();
634 DWORD dwCurrentTID = GetCurrentThreadId();
636 HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
637 if (hThreadSnap == INVALID_HANDLE_VALUE)
641 te32.dwSize =
sizeof(THREADENTRY32);
645 if (!Thread32First(hThreadSnap, &te32))
647 CloseHandle(hThreadSnap);
657 if (te32.th32OwnerProcessID == dwOwnerPID && te32.th32ThreadID != dwCurrentTID)
660 context.ContextFlags = 0xffffffff;
661 HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
false, te32.th32ThreadID);
664 if (GetThreadContext(threadHandle, &context))
666 CloseHandle(threadHandle);
669 }
while (Thread32Next(hThreadSnap, &te32));
672 CloseHandle(hThreadSnap);
680PEXCEPTION_POINTERS pExceptionInfo)
685 GetLocalTime(&systime);
689 Log(_T(
"Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
690 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
694 Log(_T(
"\r\n//=====================================================\r\n"));
695 Log(_T(
"Exception code: %08X %s\r\n"),
696 pExceptionRecord->ExceptionCode,
700 pExceptionRecord->ExceptionAddress =
reinterpret_cast<PVOID
>(pExceptionRecord->ExceptionInformation[1]);
701 Log(_T(
"Assertion message: %" PRSTRc "\r\n"), pExceptionRecord->ExceptionInformation[0]);
713#if defined(_M_IX86) || defined(_M_ARM)
714 Log(_T(
"Fault address: %08X %02X:%08X %s\r\n"),
715 pExceptionRecord->ExceptionAddress,
716 section, offset, szFaultingModule);
718#if defined(_M_X64) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined (_M_ARM64EC)
719 Log(_T(
"Fault address: %016I64X %02X:%016I64X %s\r\n"),
720 pExceptionRecord->ExceptionAddress,
721 section, offset, szFaultingModule);
724 PCONTEXT pCtx = pExceptionInfo->ContextRecord;
728 Log(_T(
"\r\nRegisters:\r\n"));
730 Log(_T(
"EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
731 , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
732 pCtx->Esi, pCtx->Edi);
734 Log(_T(
"CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
735 Log(_T(
"SS:ESP:%04X:%08X EBP:%08X\r\n"),
736 pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
737 Log(_T(
"DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
738 pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
739 Log(_T(
"Flags:%08X\r\n"), pCtx->EFlags);
743 Log(_T(
"\r\nRegisters:\r\n"));
744 Log(_T(
"RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
745 _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")
746 , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
747 pCtx->Rsi, pCtx->Rdi, pCtx->R8, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
748 Log(_T(
"CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
749 Log(_T(
"SS:RSP:%04X:%016I64X RBP:%08X\r\n"),
750 pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
751 Log(_T(
"DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
752 pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
753 Log(_T(
"Flags:%08X\r\n"), pCtx->EFlags);
757 Log(_T(
"\r\nRegisters:\r\n"));
758 Log(_T(
"X0:%016I64X\r\nX1:%016I64X\r\nX2:%016I64X\r\nX3:%016I64X\r\nX4:%016I64X\r\nX5:%016I64X\r\n"),
759 _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"),
760 _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"),
761 _T(
"X22:%016I64X\r\nX23:%016I64X\r\nX24:%016I64X\r\nX25:%016I64X\r\nX26:%016I64X\r\nX27:%016I64X\r\nX28:%016I64X\r\n"),
762 pCtx->X0, pCtx->X1, pCtx->X2, pCtx->X3, pCtx->X4, pCtx->X5,
763 pCtx->X6, pCtx->X7, pCtx->X8, pCtx->X9, pCtx->X10, pCtx->X11, pCtx->X12, pCtx->X13,
764 pCtx->X14, pCtx->X15, pCtx->X16, pCtx->X17, pCtx->X18, pCtx->X19, pCtx->X20, pCtx->X21,
765 pCtx->X22, pCtx->X23, pCtx->X24, pCtx->X25, pCtx->X26, pCtx->X27, pCtx->X28);
766 Log(_T(
"LR:%016I64X\r\n"), pCtx->Lr);
767 Log(_T(
"PC:%016I64X\r\n"), pCtx->Pc);
768 Log(_T(
"SP:%016I64X FP:%016I64X\r\n"), pCtx->Sp, pCtx->Fp);
769 Log(_T(
"Flags:%08X\r\n"), pCtx->Cpsr);
772 SymSetOptions(SYMOPT_DEFERRED_LOADS);
775 if (!SymInitialize(
m_process,
nullptr, TRUE))
779 Log(_T(
"SYMBOL HANDLER ERROR (THIS IS NOT THE CRASH ERROR)\r\n\r\n"));
780 Log(_T(
"Couldn't initialize symbol handler for process when generating crash report\r\n"));
782 Log(_T(
"THE BELOW CALL STACKS MIGHT HAVE MISSING OR INACCURATE FILE/FUNCTION NAMES\r\n\r\n"));
786 if (pExceptionRecord->ExceptionCode == 0xE06D7363 && pExceptionRecord->NumberParameters >= 2)
788 PVOID exceptionObject =
reinterpret_cast<PVOID
>(pExceptionRecord->ExceptionInformation[1]);
789 ThrowInfo
const* throwInfo =
reinterpret_cast<ThrowInfo const*
>(pExceptionRecord->ExceptionInformation[2]);
790#if _EH_RELATIVE_TYPEINFO
792 auto resolveExceptionRVA = [pExceptionRecord](
int32 rva) -> DWORD_PTR
794 return rva + (pExceptionRecord->NumberParameters >= 4 ? pExceptionRecord->ExceptionInformation[3] : 0);
798 auto resolveExceptionRVA = [](
void const* input) ->
void const* {
return input; };
801 CatchableTypeArray
const* catchables =
reinterpret_cast<CatchableTypeArray const*
>(resolveExceptionRVA(throwInfo->pCatchableTypeArray));
802 CatchableType
const* catchable = catchables->nCatchableTypes ?
reinterpret_cast<CatchableType const*
>(resolveExceptionRVA(catchables->arrayOfCatchableTypes[0])) :
nullptr;
803 TypeDescriptor
const* exceptionTypeinfo = catchable ?
reinterpret_cast<TypeDescriptor const*
>(resolveExceptionRVA(catchable->pType)) :
nullptr;
805 if (exceptionTypeinfo)
807 void* stdExceptionTypeInfo = []() ->
void*
812 return __RTtypeid(&fake);
819 std::exception
const* exceptionPtr = [](
void* object, TypeDescriptor
const* typeInfo,
void* stdExceptionTypeInfo) -> std::exception
const*
828 return reinterpret_cast<std::exception const*
>(__RTDynamicCast(
object, 0, stdExceptionTypeInfo, (
void*)typeInfo,
false));
834 }(exceptionObject, exceptionTypeinfo, stdExceptionTypeInfo);
837 if (!exceptionPtr && exceptionTypeinfo == stdExceptionTypeInfo)
838 exceptionPtr =
reinterpret_cast<std::exception*
>(exceptionObject);
840 Log(_T(
"\r\nUncaught C++ exception info:"));
842 Log(_T(
" %s"), exceptionPtr->what());
846 char undName[MAX_SYM_NAME] = { };
847 if (UnDecorateSymbolName(&exceptionTypeinfo->name[1], &undName[0], MAX_SYM_NAME, UNDNAME_32_BIT_DECODE | UNDNAME_NAME_ONLY | UNDNAME_NO_ARGUMENTS))
849 char buf[MAX_SYM_NAME +
sizeof(SYMBOL_INFO)] = { };
850 PSYMBOL_INFO sym = (PSYMBOL_INFO)&buf[0];
851 sym->SizeOfStruct =
sizeof(SYMBOL_INFO);
852 sym->MaxNameLen = MAX_SYM_NAME;
853 if (SymGetTypeFromName(
m_process, (ULONG64)GetModuleHandle(
nullptr), undName, sym))
855 sym->Address = pExceptionRecord->ExceptionInformation[1];
857 char const* variableName =
"uncaught_exception";
858 memset(sym->Name, 0, MAX_SYM_NAME);
859 memcpy(sym->Name, variableName, strlen(variableName));
866 CONTEXT trashableContext = *pCtx;
873 Log(_T(
"========================\r\n"));
874 Log(_T(
"Local Variables And Parameters\r\n"));
876 trashableContext = *pCtx;
884 __except (EXCEPTION_EXECUTE_HANDLER)
886 Log(_T(
"Error writing the crash log\r\n"));
945PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset)
947 MEMORY_BASIC_INFORMATION mbi;
949 if (!VirtualQuery(addr, &mbi,
sizeof(mbi)))
952 DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
957 if (!GetModuleFileName((HMODULE)hMod, szModule, len))
961 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
964 PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
966 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
968 DWORD_PTR rva = (DWORD_PTR)addr - hMod;
973 i < pNtHdr->FileHeader.NumberOfSections;
976 DWORD_PTR sectionStart = pSection->VirtualAddress;
977 DWORD_PTR sectionEnd = sectionStart
978 + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
981 if ((rva >= sectionStart) && (rva <= sectionEnd))
987 offset = rva - sectionStart;
1027bool bWriteVariables, HANDLE pThreadHandle)
1029 Log(_T(
"\r\nCall stack:\r\n"));
1031 Log(_T(
"Address Frame Function SourceFile\r\n"));
1033 DWORD dwMachineType = 0;
1036 STACKFRAME_EX sf = {};
1037 sf.StackFrameSize =
sizeof(sf);
1040 sf.AddrPC.Mode = AddrModeFlat;
1041 sf.AddrStack.Mode = AddrModeFlat;
1042 sf.AddrFrame.Mode = AddrModeFlat;
1045 sf.AddrPC.Offset = pContext->Eip;
1046 sf.AddrStack.Offset = pContext->Esp;
1047 sf.AddrFrame.Offset = pContext->Ebp;
1048 dwMachineType = IMAGE_FILE_MACHINE_I386;
1049#elif defined(_M_X64)
1050 sf.AddrPC.Offset = pContext->Rip;
1051 sf.AddrStack.Offset = pContext->Rsp;
1052 sf.AddrFrame.Offset = pContext->Rbp;
1053 dwMachineType = IMAGE_FILE_MACHINE_AMD64;
1054#elif defined(_M_ARM64)
1055 sf.AddrPC.Offset = pContext->Pc;
1056 sf.AddrStack.Offset = pContext->Sp;
1057 sf.AddrFrame.Offset = pContext->Fp;
1058 dwMachineType = IMAGE_FILE_MACHINE_ARM64;
1064 if (!StackWalkEx(dwMachineType,
1066 pThreadHandle !=
nullptr ? pThreadHandle : GetCurrentThread(),
1070 SymFunctionTableAccess64,
1073 SYM_STKWALK_DEFAULT))
1075 if (0 == sf.AddrFrame.Offset)
1078 Log(_T(
"%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1079#elif defined(_M_X64) || defined(_M_ARM64)
1080 Log(_T(
"%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1083 DWORD64 symDisplacement = 0;
1086 bool isInline = sf.InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE && sf.InlineFrameContext & 0x200;
1088 Log(_T(
"[inline] "));
1095 sf.InlineFrameContext,
1099 Log(_T(
"%h" PRSTRc "+%I64X"), sip.si.Name, symDisplacement);
1105 DWORD_PTR offset = 0;
1110 Log(_T(
"%04X:%08X %s"), section, offset, szModule);
1111#elif defined(_M_X64) || defined(_M_ARM64)
1112 Log(_T(
"%04X:%016I64X %s"), section, offset, szModule);
1117 IMAGEHLP_LINE64 lineInfo = {
sizeof(IMAGEHLP_LINE64) };
1118 DWORD dwLineDisplacement;
1120 &dwLineDisplacement, &lineInfo))
1122 Log(_T(
" %" PRSTRc " line %u"), lineInfo.FileName, lineInfo.LineNumber);
1128 if (bWriteVariables && !isInline)
1131 IMAGEHLP_STACK_FRAME imagehlpStackFrame;
1132 imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
1133 SymSetContext(
m_process, &imagehlpStackFrame,
nullptr);
1368 if (pSym->Tag == SymTagFunction)
1371 DWORD_PTR pVariable = pSym->Address;
1374 if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_FRAMERELATIVE
1375 || (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE && pSym->Register ==
CV_ALLREG_VFRAME))
1377 pVariable += pCtx->
sf->AddrFrame.Offset;
1379 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE)
1385 pVariable += *registerValue;
1387 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
1390 if (!registerVariableStorage)
1393 pVariable =
reinterpret_cast<DWORD_PTR
>(&*registerVariableStorage);
1403 if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
1405 else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
1411 DumpTypeIndex(pSym->ModBase, pSym->TypeIndex, pVariable, bHandled, pSym->Name,
"",
false,
true);
1423 if (pSym->Name[0] !=
'\0')
1427 FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable,
sizeof(buffer));
1456 if (!SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
1461 WCHAR * pwszTypeName;
1462 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_SYMNAME,
1466 if (wcscmp(pwszTypeName, L
"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
1468 LocalFree(pwszTypeName);
1473 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1480 wcstombs(buffer, pwszTypeName,
sizeof(buffer));
1482 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1487 else if (buffer[0] !=
'\0')
1490 LocalFree(pwszTypeName);
1492 else if (
Name !=
nullptr &&
Name[0] !=
'\0')
1498 if (typeTag == SymTagBaseClass)
1506 case SymTagPointerType:
1507 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1509 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1513 SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
1515 char addressStr[40];
1516 memset(addressStr, 0,
sizeof(addressStr));
1531 logChildren =
false;
1534 if (address == 0 || address == DWORD_PTR(-1))
1535 logChildren =
false;
1537 DumpTypeIndex(modBase, innerTypeID, address, bHandled,
Name, addressStr,
false, logChildren);
1547 else if (address == DWORD_PTR(-1))
1553 SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);
1561 else if (address == 0)
1563 else if (address == DWORD_PTR(-1))
1572 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1575 if (!SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
1578 switch (innerTypeTag)
1582 logChildren =
false;
1584 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1586 case SymTagPointerType:
1587 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1590 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1592 case SymTagArrayType:
1594 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1601 case SymTagArrayType:
1602 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1608 offset, bHandled,
Name,
"",
false,
false);
1611 std::string firstElementValue = std::move(
m_symbolDetails.top().Value);
1613 DWORD elementsCount;
1614 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
1616 char countStr[11] = { };
1619 suffix.append(countStr, std::to_chars(std::begin(countStr), std::end(countStr), elementsCount).ptr - std::begin(countStr));
1635 SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);
1642 FormatOutputValue(buffer, basicType, length, (PVOID)offset,
sizeof(buffer), elementsCount);
1648 bool elementHandled =
false;
1652 if (firstElementValue.empty())
1654 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1655 firstElementValue = buffer;
1657 arrayElement.
Value = std::move(firstElementValue);
1661 DumpTypeIndex(modBase, innerTypeID, offset + length * index, elementHandled,
"",
"",
false,
false);
1662 if (!elementHandled)
1664 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1665 arrayElement.
Value = buffer;
1669 arrayElement.
Prefix.clear();
1670 arrayElement.
Type.clear();
1671 arrayElement.
Suffix.resize(3);
1672 arrayElement.
Suffix[0] =
'[';
1673 arrayElement.
Suffix[1] =
'0' + index;
1674 arrayElement.
Suffix[2] =
']';
1675 arrayElement.
Name.clear();
1684 case SymTagBaseType:
1693 DWORD dwChildrenCount = 0;
1694 SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
1696 if (!dwChildrenCount)
1702 TI_FINDCHILDREN_PARAMS* children =
static_cast<TI_FINDCHILDREN_PARAMS*
>(alloca(
sizeof(TI_FINDCHILDREN_PARAMS) +
sizeof(ULONG) * (dwChildrenCount - 1)));
1703 children->Count = dwChildrenCount;
1704 children->Start = 0;
1707 if (!SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_FINDCHILDREN,
1714 for (
unsigned i = 0; i < dwChildrenCount; i++)
1717 SymGetTypeInfo(
m_process, modBase, children->ChildId[i], TI_GET_SYMTAG, &symTag);
1719 if (symTag == SymTagFunction ||
1720 symTag == SymTagEnum ||
1721 symTag == SymTagTypedef ||
1722 symTag == SymTagVTable)
1727 SymGetTypeInfo(
m_process, modBase, children->ChildId[i], TI_GET_DATAKIND, &dataKind);
1745 DWORD dwMemberOffset;
1746 SymGetTypeInfo(
m_process, modBase, children->ChildId[i],
1747 TI_GET_OFFSET, &dwMemberOffset);
1750 DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
1753 children->ChildId[i],
1754 dwFinalOffset, bHandled2,
"",
"",
true,
true);
1765 SymGetTypeInfo(
m_process, modBase, children->ChildId[i],
1766 TI_GET_TYPEID, &typeId);
1770 SymGetTypeInfo(
m_process, modBase, typeId, TI_GET_LENGTH, &length);
1773 FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset,
sizeof(buffer));
1788size_t countOverride)
1797 if (countOverride != 0)
1798 length = countOverride;
1800 length = strlen((
char*)pAddress);
1802 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s...\"", (
int)(
bufferSize - 6), (
char*)pAddress);
1804 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s\"", (
int)length, (
char*)pAddress);
1809 std::string* value =
static_cast<std::string*
>(pAddress);
1811 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%.*s...\"", (
int)(
bufferSize - 6), value->c_str());
1813 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"\"%s\"", value->c_str());
1819 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", *(PBYTE)pAddress);
1820 else if (length == 2)
1821 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%X", *(PWORD)pAddress);
1822 else if (length == 4)
1825 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%f", *(PFLOAT)pAddress);
1827 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%lX", *(PDWORD)pAddress);
1829 else if (length == 8)
1833 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%f",
1834 *(
double *)pAddress);
1837 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"0x%llX",
1838 *(DWORD64*)pAddress);
1842 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%p", pAddress);
1847 __except (EXCEPTION_EXECUTE_HANDLER)
1849 pszCurrBuffer += snprintf(pszCurrBuffer,
bufferSize,
"%p <Unable to read memory>", pAddress);