72 m_tempPathBuffer(static_cast<TCHAR*>(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, m_tempPathBufferChars * sizeof(TCHAR)))),
73 m_previousFilter(SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter)),
74 m_previousCrtHandler(_set_invalid_parameter_handler(WheatyCrtHandler)),
75 m_reportFile(nullptr),
77 m_process(GetCurrentProcess()),
78 m_alreadyCrashed(false),
79 m_alreadyCrashedLock(SRWLOCK_INIT),
80 RtlGetVersion((pRtlGetVersion)GetProcAddress(GetModuleHandle(_T(
"ntdll.dll")),
"RtlGetVersion"))
82 if (!IsDebuggerPresent())
84 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
85 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
86 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
87 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
90 if (std::exchange(g_WheatyExceptionReport,
this) !=
nullptr)
91 throw std::logic_error(
"Only one instance of WheatyExceptionReport can exist");
120 AcquireSRWLockExclusive(&m_alreadyCrashedLock);
121 auto guard = Trinity::make_unique_ptr_with_deleter<&ReleaseSRWLockExclusive>(&m_alreadyCrashedLock);
123 if (m_alreadyCrashed)
124 return EXCEPTION_EXECUTE_HANDLER;
126 m_alreadyCrashed =
true;
128 auto prepareCrashFolder = [
this]<
typename Char>(Char
const* path) -> TCHAR*
133 std::basic_string_view<Char> processPath = path;
135 auto filenameSeparator = processPath.rfind(
'\\');
136 if (filenameSeparator == std::basic_string_view<Char>::npos)
139 std::basic_string_view<Char> processName = processPath.substr(filenameSeparator + 1);
140 if (processName.empty())
143 processPath.remove_suffix(processName.length());
145 TCHAR* buffer = m_tempPathBuffer;
148 if constexpr (std::is_same_v<wchar_t, Char>)
153 if (!CreateDirectory(m_tempPathBuffer,
nullptr) && GetLastError() != ERROR_ALREADY_EXISTS)
157 GetLocalTime(&systime);
160 if constexpr (std::is_same_v<wchar_t, Char>)
161 buffer += _stprintf_s(buffer, m_tempPathBufferChars - (buffer - m_tempPathBuffer), _T(
"\\%" PRSTRc "_%.*" PRSTRw "_[%u_%u_%u_%u_%u_%u]."),
164 buffer += _stprintf_s(buffer, m_tempPathBufferChars - (buffer - m_tempPathBuffer), _T(
"\\%" PRSTRc "_%.*" PRSTRc "_[%u_%u_%u_%u_%u_%u]."),
170 TCHAR* crashPath =
nullptr;
173 if (
char const* processName = _pgmptr)
174 crashPath = prepareCrashFolder(processName);
175 else if (
wchar_t const* wprocessName = _wpgmptr)
176 crashPath = prepareCrashFolder(wprocessName);
181 _tcscpy_s(crashPath, m_tempPathBufferChars - (crashPath - m_tempPathBuffer), _T(
"dmp"));
182 m_dumpFile = CreateFile(m_tempPathBuffer,
187 FILE_FLAG_WRITE_THROUGH,
190 if (m_dumpFile && m_dumpFile != INVALID_HANDLE_VALUE)
192 MINIDUMP_EXCEPTION_INFORMATION info;
193 info.ClientPointers = FALSE;
194 info.ExceptionPointers = pExceptionInfo;
195 info.ThreadId = GetCurrentThreadId();
197 MINIDUMP_USER_STREAM additionalStream = {};
198 MINIDUMP_USER_STREAM_INFORMATION additionalStreamInfo = {};
200 if (pExceptionInfo->ExceptionRecord->ExceptionCode ==
EXCEPTION_ASSERTION_FAILURE && pExceptionInfo->ExceptionRecord->NumberParameters > 0)
202 additionalStream.Type = CommentStreamA;
203 additionalStream.Buffer =
reinterpret_cast<PVOID
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0]);
204 additionalStream.BufferSize = strlen(
reinterpret_cast<char const*
>(pExceptionInfo->ExceptionRecord->ExceptionInformation[0])) + 1;
206 additionalStreamInfo.UserStreamArray = &additionalStream;
207 additionalStreamInfo.UserStreamCount = 1;
210 MiniDumpWriteDump(m_process, GetCurrentProcessId(),
211 m_dumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, &additionalStreamInfo,
nullptr);
213 CloseHandle(m_dumpFile);
216 _tcscpy_s(crashPath, m_tempPathBufferChars - (crashPath - m_tempPathBuffer), _T(
"txt"));
217 m_reportFile = _tfopen(m_tempPathBuffer, _T(
"wb"));
221 GenerateExceptionReport(pExceptionInfo);
223 fclose(m_reportFile);
224 m_reportFile =
nullptr;
227 if (m_previousFilter)
228 return m_previousFilter(pExceptionInfo);
230 return EXCEPTION_EXECUTE_HANDLER;
276 *szVersion = _T(
'\0');
283 RTL_OSVERSIONINFOEXW osvi = { };
284 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOEXW);
285 NTSTATUS bVersionEx =
RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);
286 if (FAILED(bVersionEx))
288 osvi.dwOSVersionInfoSize =
sizeof(RTL_OSVERSIONINFOW);
293 TCHAR szCSDVersion[256];
294 ToTchar(osvi.szCSDVersion, szCSDVersion);
297 switch (osvi.dwPlatformId)
300 case VER_PLATFORM_WIN32_NT:
303 BYTE suiteMask = osvi.wReserved[0];
304 BYTE productType = osvi.wReserved[1];
306 WORD suiteMask = osvi.wSuiteMask;
307 BYTE productType = osvi.wProductType;
311 if (osvi.dwMajorVersion == 10)
313 if (productType == VER_NT_WORKSTATION)
314 _tcsncat(szVersion, _T(
"Windows 10 "), cntMax);
316 _tcsncat(szVersion, _T(
"Windows Server 2016 "), cntMax);
318 else if (osvi.dwMajorVersion == 6)
320 if (productType == VER_NT_WORKSTATION)
322 if (osvi.dwMinorVersion == 3)
323 _tcsncat(szVersion, _T(
"Windows 8.1 "), cntMax);
324 else if (osvi.dwMinorVersion == 2)
325 _tcsncat(szVersion, _T(
"Windows 8 "), cntMax);
326 else if (osvi.dwMinorVersion == 1)
327 _tcsncat(szVersion, _T(
"Windows 7 "), cntMax);
329 _tcsncat(szVersion, _T(
"Windows Vista "), cntMax);
331 else if (osvi.dwMinorVersion == 3)
332 _tcsncat(szVersion, _T(
"Windows Server 2012 R2 "), cntMax);
333 else if (osvi.dwMinorVersion == 2)
334 _tcsncat(szVersion, _T(
"Windows Server 2012 "), cntMax);
335 else if (osvi.dwMinorVersion == 1)
336 _tcsncat(szVersion, _T(
"Windows Server 2008 R2 "), cntMax);
338 _tcsncat(szVersion, _T(
"Windows Server 2008 "), cntMax);
340 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
341 _tcsncat(szVersion, _T(
"Microsoft Windows Server 2003 "), cntMax);
342 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
343 _tcsncat(szVersion, _T(
"Microsoft Windows XP "), cntMax);
344 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
345 _tcsncat(szVersion, _T(
"Microsoft Windows 2000 "), cntMax);
346 else if (osvi.dwMajorVersion <= 4)
347 _tcsncat(szVersion, _T(
"Microsoft Windows NT "), cntMax);
353 if (productType == VER_NT_WORKSTATION)
355 if (osvi.dwMajorVersion == 4)
356 _tcsncat(szVersion, _T(
"Workstation 4.0 "), cntMax);
357 else if (suiteMask & VER_SUITE_PERSONAL)
358 _tcsncat(szVersion, _T(
"Home Edition "), cntMax);
359 else if (suiteMask & VER_SUITE_EMBEDDEDNT)
360 _tcsncat(szVersion, _T(
"Embedded "), cntMax);
362 _tcsncat(szVersion, _T(
"Professional "), cntMax);
365 else if (productType == VER_NT_SERVER)
367 if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
369 if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
370 _tcsncat(szVersion, _T(
"Essentials "), cntMax);
371 else if (suiteMask & VER_SUITE_DATACENTER)
372 _tcsncat(szVersion, _T(
"Datacenter "), cntMax);
373 else if (suiteMask & VER_SUITE_ENTERPRISE)
374 _tcsncat(szVersion, _T(
"Enterprise "), cntMax);
376 _tcsncat(szVersion, _T(
"Standard "), cntMax);
378 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
380 if (suiteMask & VER_SUITE_DATACENTER)
381 _tcsncat(szVersion, _T(
"Datacenter Edition "), cntMax);
382 else if (suiteMask & VER_SUITE_ENTERPRISE)
383 _tcsncat(szVersion, _T(
"Enterprise Edition "), cntMax);
384 else if (suiteMask == VER_SUITE_BLADE)
385 _tcsncat(szVersion, _T(
"Web Edition "), cntMax);
387 _tcsncat(szVersion, _T(
"Standard Edition "), cntMax);
389 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
391 if (suiteMask & VER_SUITE_DATACENTER)
392 _tcsncat(szVersion, _T(
"Datacenter Server "), cntMax);
393 else if (suiteMask & VER_SUITE_ENTERPRISE)
394 _tcsncat(szVersion, _T(
"Advanced Server "), cntMax);
396 _tcsncat(szVersion, _T(
"Server "), cntMax);
400 if (suiteMask & VER_SUITE_ENTERPRISE)
401 _tcsncat(szVersion, _T(
"Server 4.0, Enterprise Edition "), cntMax);
403 _tcsncat(szVersion, _T(
"Server 4.0 "), cntMax);
409 if (osvi.dwMajorVersion == 4 && _tcsicmp(szCSDVersion, _T(
"Service Pack 6")) == 0)
415 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey);
416 if (lRet == ERROR_SUCCESS)
418 _stprintf_s(wszTmp, _T(
"Service Pack 6a (Version %d.%d, Build %d)"),
419 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
420 _tcsncat(szVersion, wszTmp, cntMax);
424 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
425 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
426 _tcsncat(szVersion, wszTmp, cntMax);
432 if (!_tcslen(szCSDVersion))
433 _stprintf_s(wszTmp, _T(
"(Version %d.%d, Build %d)"),
434 osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
436 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
437 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
438 _tcsncat(szVersion, wszTmp, cntMax);
443 _stprintf_s(wszTmp, _T(
"%s (Version %d.%d, Build %d)"),
444 szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
445 _tcsncat(szVersion, wszTmp, cntMax);
462 HRESULT hres = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
470 hres = CoInitializeSecurity(
475 RPC_C_AUTHN_LEVEL_DEFAULT,
476 RPC_C_IMP_LEVEL_IMPERSONATE,
489 IWbemLocator* tmp =
nullptr;
490 HRESULT hres = CoCreateInstance(
493 CLSCTX_INPROC_SERVER,
495 reinterpret_cast<LPVOID*
>(&tmp));
497 return SUCCEEDED(hres) ? tmp :
nullptr;
509 IWbemServices* tmp =
nullptr;
510 HRESULT hres = loc->ConnectServer(
511 bstr_t(L
"ROOT\\CIMV2"),
515 WBEM_FLAG_CONNECT_USE_MAX_WAIT,
521 return SUCCEEDED(hres) ? tmp :
nullptr;
529 hres = CoSetProxyBlanket(
534 RPC_C_AUTHN_LEVEL_CALL,
535 RPC_C_IMP_LEVEL_IMPERSONATE,
549 IEnumWbemClassObject* tmp =
nullptr;
550 HRESULT hres = svc->ExecQuery(
552 bstr_t(
"SELECT Caption, CSDVersion FROM Win32_OperatingSystem"),
553 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
557 return SUCCEEDED(hres) ? tmp :
nullptr;
567 auto [fields, rows] = [&]
569 IWbemClassObject* fields =
nullptr;
571 HRESULT hres = queryResult->Next(WBEM_INFINITE, 1, &fields, &rows);
573 return SUCCEEDED(hres) && rows
574 ? std::pair(wbem_class_object_ptr(fields), rows)
575 : std::pair(wbem_class_object_ptr(), ULONG(0));
578 if (!fields || !rows)
583 fields->Get(L
"Caption", 0, &field,
nullptr,
nullptr);
584 TCHAR buf[256] = { };
586 _tcsncat(szVersion, buf, cntMax);
587 VariantClear(&field);
589 fields->Get(L
"CSDVersion", 0, &field,
nullptr,
nullptr);
590 if (field.vt == VT_BSTR)
592 _tcsncat(szVersion, _T(
" "), cntMax);
593 memset(buf, 0,
sizeof(buf));
596 _tcsncat(szVersion, buf, cntMax);
598 VariantClear(&field);
635 DWORD dwOwnerPID = GetProcessId(
m_process);
636 DWORD dwCurrentTID = GetCurrentThreadId();
638 HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
639 if (hThreadSnap == INVALID_HANDLE_VALUE)
643 te32.dwSize =
sizeof(THREADENTRY32);
647 if (!Thread32First(hThreadSnap, &te32))
649 CloseHandle(hThreadSnap);
659 if (te32.th32OwnerProcessID == dwOwnerPID && te32.th32ThreadID != dwCurrentTID)
662 context.ContextFlags = 0xffffffff;
663 HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
false, te32.th32ThreadID);
666 if (GetThreadContext(threadHandle, &context))
668 CloseHandle(threadHandle);
671 }
while (Thread32Next(hThreadSnap, &te32));
674 CloseHandle(hThreadSnap);
682PEXCEPTION_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;
940PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset)
942 MEMORY_BASIC_INFORMATION mbi;
944 if (!VirtualQuery(addr, &mbi,
sizeof(mbi)))
947 DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
952 if (!GetModuleFileName((HMODULE)hMod, szModule, len))
956 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
959 PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
961 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
963 DWORD_PTR rva = (DWORD_PTR)addr - hMod;
968 i < pNtHdr->FileHeader.NumberOfSections;
971 DWORD_PTR sectionStart = pSection->VirtualAddress;
972 DWORD_PTR sectionEnd = sectionStart
973 + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
976 if ((rva >= sectionStart) && (rva <= sectionEnd))
982 offset = rva - sectionStart;
1022bool bWriteVariables, HANDLE pThreadHandle)
1024 Log(_T(
"\r\nCall stack:\r\n"));
1026 Log(_T(
"Address Frame Function SourceFile\r\n"));
1028 DWORD dwMachineType = 0;
1031 STACKFRAME_EX sf = {};
1032 sf.StackFrameSize =
sizeof(sf);
1035 sf.AddrPC.Mode = AddrModeFlat;
1036 sf.AddrStack.Mode = AddrModeFlat;
1037 sf.AddrFrame.Mode = AddrModeFlat;
1040 sf.AddrPC.Offset = pContext->Eip;
1041 sf.AddrStack.Offset = pContext->Esp;
1042 sf.AddrFrame.Offset = pContext->Ebp;
1043 dwMachineType = IMAGE_FILE_MACHINE_I386;
1044#elif defined(_M_X64)
1045 sf.AddrPC.Offset = pContext->Rip;
1046 sf.AddrStack.Offset = pContext->Rsp;
1047 sf.AddrFrame.Offset = pContext->Rbp;
1048 dwMachineType = IMAGE_FILE_MACHINE_AMD64;
1049#elif defined(_M_ARM64)
1050 sf.AddrPC.Offset = pContext->Pc;
1051 sf.AddrStack.Offset = pContext->Sp;
1052 sf.AddrFrame.Offset = pContext->Fp;
1053 dwMachineType = IMAGE_FILE_MACHINE_ARM64;
1059 if (!StackWalkEx(dwMachineType,
1065 SymFunctionTableAccess64,
1068 SYM_STKWALK_DEFAULT))
1070 if (0 == sf.AddrFrame.Offset)
1073 Log(_T(
"%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1074#elif defined(_M_X64) || defined(_M_ARM64)
1075 Log(_T(
"%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
1078 DWORD64 symDisplacement = 0;
1081 bool isInline = sf.InlineFrameContext != INLINE_FRAME_CONTEXT_IGNORE && sf.InlineFrameContext & 0x200;
1083 Log(_T(
"[inline] "));
1090 sf.InlineFrameContext,
1094 Log(_T(
"%h" PRSTRc "+%I64X"), sip.si.Name, symDisplacement);
1100 DWORD_PTR offset = 0;
1105 Log(_T(
"%04X:%08X %s"), section, offset, szModule);
1106#elif defined(_M_X64) || defined(_M_ARM64)
1107 Log(_T(
"%04X:%016I64X %s"), section, offset, szModule);
1112 IMAGEHLP_LINE64 lineInfo = {
sizeof(IMAGEHLP_LINE64) };
1113 DWORD dwLineDisplacement;
1115 &dwLineDisplacement, &lineInfo))
1117 Log(_T(
" %" PRSTRc " line %u"), lineInfo.FileName, lineInfo.LineNumber);
1123 if (bWriteVariables && !isInline)
1126 IMAGEHLP_STACK_FRAME imagehlpStackFrame;
1127 imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
1128 SymSetContext(
m_process, &imagehlpStackFrame,
nullptr);
1442 if (!SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
1447 WCHAR * pwszTypeName;
1448 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_SYMNAME,
1452 if (wcscmp(pwszTypeName, L
"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
1454 LocalFree(pwszTypeName);
1459 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1466 wcstombs(buffer, pwszTypeName,
sizeof(buffer));
1468 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1473 else if (buffer[0] !=
'\0')
1476 LocalFree(pwszTypeName);
1478 else if (
Name !=
nullptr &&
Name[0] !=
'\0')
1493 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1495 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1499 SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
1501 char addressStr[40];
1502 memset(addressStr, 0,
sizeof(addressStr));
1510 DWORD_PTR address = DereferenceUnsafePointer<DWORD_PTR>(
reinterpret_cast<LPCVOID
>(offset)).value_or(DWORD_PTR(-1));
1517 logChildren =
false;
1520 if (address == 0 || address == DWORD_PTR(-1))
1521 logChildren =
false;
1523 DumpTypeIndex(modBase, innerTypeID, address, bHandled,
Name, addressStr,
false, logChildren);
1533 else if (address == DWORD_PTR(-1))
1539 SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);
1547 else if (address == 0)
1549 else if (address == DWORD_PTR(-1))
1558 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1561 if (!SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
1564 switch (innerTypeTag)
1568 logChildren =
false;
1570 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1573 if (
Name !=
nullptr &&
Name[0] !=
'\0')
1576 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1580 offset, bHandled,
m_symbolDetails.top().Name.c_str(),
"",
false, logChildren);
1588 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1594 offset, bHandled,
Name,
"",
false,
false);
1597 std::string firstElementValue = std::move(
m_symbolDetails.top().Value);
1599 DWORD elementsCount;
1600 if (SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
1602 char countStr[11] = { };
1605 suffix.append(countStr, std::to_chars(std::begin(countStr), std::end(countStr), elementsCount).ptr - std::begin(countStr));
1621 SymGetTypeInfo(
m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);
1628 FormatOutputValue(buffer, basicType, length, (PVOID)offset,
sizeof(buffer), elementsCount);
1634 bool elementHandled =
false;
1638 if (firstElementValue.empty())
1640 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1641 firstElementValue = buffer;
1643 arrayElement.
Value = std::move(firstElementValue);
1647 DumpTypeIndex(modBase, innerTypeID, offset + length * index, elementHandled,
"",
"",
false,
false);
1648 if (!elementHandled)
1650 FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index),
sizeof(buffer));
1651 arrayElement.
Value = buffer;
1655 arrayElement.
Prefix.clear();
1656 arrayElement.
Type.clear();
1657 arrayElement.
Suffix.resize(3);
1658 arrayElement.
Suffix[0] =
'[';
1659 arrayElement.
Suffix[1] =
'0' + index;
1660 arrayElement.
Suffix[2] =
']';
1661 arrayElement.
Name.clear();
1679 DWORD dwChildrenCount = 0;
1680 SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
1682 if (!dwChildrenCount)
1688 TI_FINDCHILDREN_PARAMS* children =
static_cast<TI_FINDCHILDREN_PARAMS*
>(alloca(
sizeof(TI_FINDCHILDREN_PARAMS) +
sizeof(ULONG) * (dwChildrenCount - 1)));
1689 children->Count = dwChildrenCount;
1690 children->Start = 0;
1693 if (!SymGetTypeInfo(
m_process, modBase, dwTypeIndex, TI_FINDCHILDREN,
1700 for (
unsigned i = 0; i < dwChildrenCount; i++)
1703 SymGetTypeInfo(
m_process, modBase, children->ChildId[i], TI_GET_SYMTAG, &symTag);
1713 SymGetTypeInfo(
m_process, modBase, children->ChildId[i], TI_GET_DATAKIND, &dataKind);
1731 DWORD dwMemberOffset;
1732 SymGetTypeInfo(
m_process, modBase, children->ChildId[i],
1733 TI_GET_OFFSET, &dwMemberOffset);
1736 DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
1739 children->ChildId[i],
1740 dwFinalOffset, bHandled2,
"",
"",
true,
true);
1751 SymGetTypeInfo(
m_process, modBase, children->ChildId[i],
1752 TI_GET_TYPEID, &typeId);
1756 SymGetTypeInfo(
m_process, modBase, typeId, TI_GET_LENGTH, &length);
1759 FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset,
sizeof(buffer), 1);
1783size_t countOverride)
1790 if (countOverride != 0)
1792 *pszCurrBuffer =
'"';
1797 strcpy(pszCurrBuffer +
bufferSize - 5,
"...\"");
1803 if (ReadProcessMemory(
m_process, pAddress, pszCurrBuffer + 1, countOverride,
nullptr))
1805 strcpy(pszCurrBuffer + 1 + countOverride,
"\"");
1810 (void)snprintf(pszCurrBuffer,
bufferSize,
"%p <Unable to read memory>", pAddress);
1814 *pszCurrBuffer =
'"';
1818 Optional<char> character = DereferenceUnsafePointer<char>(
static_cast<char const*
>(pAddress) + i - 1);
1821 (void)snprintf(pszCurrBuffer,
bufferSize,
"%p <Unable to read memory>", pAddress);
1824 *(pszCurrBuffer + i) = *character;
1831 strcpy(pszCurrBuffer +
bufferSize - 6,
"...");
1834 *(pszCurrBuffer + i) =
'"';
1835 *(pszCurrBuffer + i + 1) =
'\0';
1841 alignas(std::string) std::array<
char,
sizeof(std::string)> rawBytes = { };
1842 if (ReadProcessMemory(
m_process, pAddress, rawBytes.data(), rawBytes.size(),
nullptr))
1844 std::string
const* value =
reinterpret_cast<std::string const*
>(rawBytes.data());
1846 *pszCurrBuffer =
'"';
1849 if (ReadProcessMemory(
m_process, value->data(), pszCurrBuffer + 1,
bufferSize - 6,
nullptr))
1851 strcpy(pszCurrBuffer +
bufferSize - 6,
"...\"");
1857 if (ReadProcessMemory(
m_process, value->data(), pszCurrBuffer + 1, value->length(),
nullptr))
1859 strcpy(pszCurrBuffer + 1 + value->length(),
"\"");
1865 (void)snprintf(pszCurrBuffer,
bufferSize,
"%p <Unable to read memory>", pAddress);
1872 FormatOutputValueNumeric<BYTE>(pszCurrBuffer,
bufferSize,
"0x%X", pAddress);
1873 else if (length == 2)
1874 FormatOutputValueNumeric<WORD>(pszCurrBuffer,
bufferSize,
"0x%X", pAddress);
1875 else if (length == 4)
1878 FormatOutputValueNumeric<float>(pszCurrBuffer,
bufferSize,
"%f", pAddress);
1880 FormatOutputValueNumeric<DWORD>(pszCurrBuffer,
bufferSize,
"0x%lX", pAddress);
1882 else if (length == 8)
1885 FormatOutputValueNumeric<double>(pszCurrBuffer,
bufferSize,
"%f", pAddress);
1887 FormatOutputValueNumeric<DWORD64>(pszCurrBuffer,
bufferSize,
"0x%llX", pAddress);
1890 (
void)snprintf(pszCurrBuffer,
bufferSize,
"%p", pAddress);