From e585187b248f48b3c6e9247b49fa07c6565d65e5 Mon Sep 17 00:00:00 2001 From: maximius Date: Sat, 17 Oct 2009 15:51:44 -0700 Subject: *Backed out changeset 3be01fb200a5 --HG-- branch : trunk --- src/shared/WheatyExceptionReport.cpp | 131 +++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'src/shared/WheatyExceptionReport.cpp') diff --git a/src/shared/WheatyExceptionReport.cpp b/src/shared/WheatyExceptionReport.cpp index 9c537a20949..f2fd9b0f2e7 100644 --- a/src/shared/WheatyExceptionReport.cpp +++ b/src/shared/WheatyExceptionReport.cpp @@ -18,6 +18,7 @@ #include "revision.h" #define CrashFolder _T("Crashes") //#pragma comment(linker, "/defaultlib:dbghelp.lib") + inline LPTSTR ErrorMessage(DWORD dw) { LPVOID lpMsgBuf; @@ -31,7 +32,9 @@ inline LPTSTR ErrorMessage(DWORD dw) 0, NULL); return (LPTSTR)lpMsgBuf; } + //============================== Global Variables ============================= + // // Declare the static variables of the WheatyExceptionReport class // @@ -39,15 +42,19 @@ TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH]; LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter; HANDLE WheatyExceptionReport::m_hReportFile; HANDLE WheatyExceptionReport::m_hProcess; + // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; + //============================== Class Methods ============================= + WheatyExceptionReport::WheatyExceptionReport() // Constructor { // Install the unhandled exception filter function m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); m_hProcess = GetCurrentProcess(); } + //============ // Destructor //============ @@ -56,6 +63,7 @@ WheatyExceptionReport::~WheatyExceptionReport() if (m_previousFilter) SetUnhandledExceptionFilter(m_previousFilter); } + //=========================================================== // Entry point where control comes on an unhandled exception //=========================================================== @@ -69,6 +77,7 @@ PEXCEPTION_POINTERS pExceptionInfo) return 0; pos[0] = '\0'; ++pos; + TCHAR crash_folder_path[MAX_PATH]; sprintf(crash_folder_path, "%s\\%s", module_folder_name, CrashFolder); if (!CreateDirectory(crash_folder_path, NULL)) @@ -76,10 +85,12 @@ PEXCEPTION_POINTERS pExceptionInfo) if (GetLastError() != ERROR_ALREADY_EXISTS) return 0; } + SYSTEMTIME systime; GetLocalTime(&systime); sprintf(m_szLogFileName, "%s\\%s_[%u-%u_%u-%u-%u].txt", crash_folder_path, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); + m_hReportFile = CreateFile(m_szLogFileName, GENERIC_WRITE, 0, @@ -87,22 +98,28 @@ PEXCEPTION_POINTERS pExceptionInfo) OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0); + if (m_hReportFile) { SetFilePointer(m_hReportFile, 0, 0, FILE_END); + GenerateExceptionReport(pExceptionInfo); + CloseHandle(m_hReportFile); m_hReportFile = 0; } + if (m_previousFilter) return m_previousFilter(pExceptionInfo); else return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/; } + BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount) { if (!sProcessorName) return FALSE; + HKEY hKey; LONG lRet; lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), @@ -124,6 +141,7 @@ BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxco _tcsncpy(sProcessorName, psz, maxcount); return TRUE; } + BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) { // Try calling GetVersionEx using the OSVERSIONINFOEX structure. @@ -155,6 +173,7 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax); if (osvi.dwMajorVersion <= 4) _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax); + // Test for specific product on Windows NT 4.0 SP6 and later. if (bOsVersionInfoEx) { @@ -247,6 +266,7 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) { HKEY hKey; LONG lRet; + // Test for SP6 versus SP6a. lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); if (lRet == ERROR_SUCCESS) @@ -280,12 +300,15 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) _tcsncat(szVersion, wszTmp, cntMax); break; } + return TRUE; } + void WheatyExceptionReport::PrintSystemInfo() { SYSTEM_INFO SystemInfo; ::GetSystemInfo(&SystemInfo); + MEMORYSTATUS MemoryStatus; MemoryStatus.dwLength = sizeof (MEMORYSTATUS); ::GlobalMemoryStatus(&MemoryStatus); @@ -297,24 +320,29 @@ void WheatyExceptionReport::PrintSystemInfo() else _tprintf(_T("*** Hardware ***\r\nProcessor: \r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); + if (_GetWindowsVersion(sString, countof(sString))) _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString); else _tprintf(_T("\r\n*** Operation System:\r\n\r\n")); } + //=========================================================================== void WheatyExceptionReport::printTracesForAllThreads() { HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32; + DWORD dwOwnerPID = GetCurrentProcessId(); m_hProcess = GetCurrentProcess(); // Take a snapshot of all running threads hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) return; + // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32); + // Retrieve information about the first thread, // and exit if unsuccessful if (!Thread32First(hThreadSnap, &te32)) @@ -323,6 +351,7 @@ void WheatyExceptionReport::printTracesForAllThreads() // snapshot object! return; } + // Now walk the thread list of the system, // and display information about each thread // associated with the specified process @@ -340,9 +369,12 @@ void WheatyExceptionReport::printTracesForAllThreads() CloseHandle(threadHandle); } } while(Thread32Next(hThreadSnap, &te32)); + // Don't forget to clean up the snapshot object. CloseHandle(hThreadSnap); } + + //=========================================================================== // Open the report file, and write the desired information to it. Called by // WheatyUnhandledExceptionFilter @@ -352,16 +384,19 @@ PEXCEPTION_POINTERS pExceptionInfo) { SYSTEMTIME systime; GetLocalTime(&systime); + // Start out with a banner _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + PrintSystemInfo(); // First print information about the type of fault _tprintf(_T("\r\n//=====================================================\r\n")); _tprintf(_T("Exception code: %08X %s\r\n"), pExceptionRecord->ExceptionCode, GetExceptionString(pExceptionRecord->ExceptionCode)); + // Now print information about where the fault occured TCHAR szFaultingModule[MAX_PATH]; DWORD section; @@ -370,6 +405,7 @@ PEXCEPTION_POINTERS pExceptionInfo) szFaultingModule, sizeof(szFaultingModule), section, offset); + #ifdef _M_IX86 _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), pExceptionRecord->ExceptionAddress, @@ -380,13 +416,17 @@ PEXCEPTION_POINTERS pExceptionInfo) pExceptionRecord->ExceptionAddress, section, offset, szFaultingModule); #endif + PCONTEXT pCtx = pExceptionInfo->ContextRecord; + // Show the registers #ifdef _M_IX86 // X86 Only! _tprintf(_T("\r\nRegisters:\r\n")); + _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") ,pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi); + _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), pCtx->SegSs, pCtx->Esp, pCtx->Ebp); @@ -394,6 +434,7 @@ PEXCEPTION_POINTERS pExceptionInfo) pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); #endif + #ifdef _M_X64 _tprintf(_T("\r\nRegisters:\r\n")); _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") @@ -407,30 +448,42 @@ PEXCEPTION_POINTERS pExceptionInfo) pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); #endif + SymSetOptions(SYMOPT_DEFERRED_LOADS); + // Initialize DbgHelp if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) { _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), ErrorMessage(GetLastError())); } + CONTEXT trashableContext = *pCtx; + WriteStackDetails(&trashableContext, false, NULL); printTracesForAllThreads(); + // #ifdef _M_IX86 // X86 Only! + _tprintf(_T("========================\r\n")); _tprintf(_T("Local Variables And Parameters\r\n")); + trashableContext = *pCtx; WriteStackDetails(&trashableContext, true, NULL); + _tprintf(_T("========================\r\n")); _tprintf(_T("Global Variables\r\n")); + SymEnumSymbols(GetCurrentProcess(), (DWORD64)GetModuleHandle(szFaultingModule), 0, EnumerateSymbolsCallback, 0); // #endif // X86 Only! + SymCleanup(GetCurrentProcess()); + _tprintf(_T("\r\n")); } + //====================================================================== // Given an exception code, returns a pointer to a static string with a // description of the exception @@ -438,6 +491,7 @@ PEXCEPTION_POINTERS pExceptionInfo) LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) { #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x); + switch (dwCode) { EXCEPTION(ACCESS_VIOLATION) @@ -463,14 +517,19 @@ LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) EXCEPTION(GUARD_PAGE) EXCEPTION(INVALID_HANDLE) } + // If not one of the "known" exceptions, try to get the string // from NTDLL.DLL's message table. + static TCHAR szBuffer[512] = { 0 }; + FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(_T("NTDLL.DLL")), dwCode, 0, szBuffer, sizeof(szBuffer), 0); + return szBuffer; } + //============================================================================= // Given a linear address, locates the module, section, and offset containing // that address. @@ -482,17 +541,25 @@ BOOL WheatyExceptionReport::GetLogicalAddress( PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset) { MEMORY_BASIC_INFORMATION mbi; + if (!VirtualQuery(addr, &mbi, sizeof(mbi))) return FALSE; + DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase; + if (!GetModuleFileName((HMODULE)hMod, szModule, len)) return FALSE; + // Point to the DOS header in memory PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; + // From the DOS header, find the NT (PE) header PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew)); + PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr); + DWORD_PTR rva = (DWORD_PTR)addr - hMod; // RVA is offset from module load address + // Iterate through the section table, looking for the one that encompasses // the linear address. for (unsigned i = 0; @@ -502,6 +569,7 @@ PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset) DWORD_PTR sectionStart = pSection->VirtualAddress; DWORD_PTR sectionEnd = sectionStart + DWORD_PTR(max(pSection->SizeOfRawData, pSection->Misc.VirtualSize)); + // Is the address in this section??? if ((rva >= sectionStart) && (rva <= sectionEnd)) { @@ -513,8 +581,10 @@ PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset) return TRUE; } } + return FALSE; // Should never get here! } + // It contains SYMBOL_INFO structure plus additional // space for the name of the symbol struct CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE @@ -525,6 +595,7 @@ struct CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE si.MaxNameLen = sizeof(name); } }; + //============================================================ // Walks the stack, and writes the results to the report file //============================================================ @@ -533,11 +604,15 @@ PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle) // true if local/params should be output { _tprintf(_T("\r\nCall stack:\r\n")); + _tprintf(_T("Address Frame Function SourceFile\r\n")); + DWORD dwMachineType = 0; // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag + STACKFRAME64 sf; memset(&sf, 0, sizeof(sf)); + #ifdef _M_IX86 // Initialize the STACKFRAME structure for the first call. This is only // necessary for Intel CPUs, and isn't mentioned in the documentation. @@ -547,8 +622,10 @@ bool bWriteVariables, HANDLE pThreadHandle) sf.AddrStack.Mode = AddrModeFlat; sf.AddrFrame.Offset = pContext->Ebp; sf.AddrFrame.Mode = AddrModeFlat; + dwMachineType = IMAGE_FILE_MACHINE_I386; #endif + #ifdef _M_X64 sf.AddrPC.Offset = pContext->Rip; sf.AddrPC.Mode = AddrModeFlat; @@ -558,6 +635,7 @@ bool bWriteVariables, HANDLE pThreadHandle) sf.AddrFrame.Mode = AddrModeFlat; dwMachineType = IMAGE_FILE_MACHINE_AMD64; #endif + while (1) { // Get the next stack frame @@ -579,8 +657,10 @@ bool bWriteVariables, HANDLE pThreadHandle) #ifdef _M_X64 _tprintf(_T("%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); #endif + DWORD64 symDisplacement = 0; // Displacement of the input address, // relative to the start of the symbol + // Get the name of the function for this stack frame entry CSymbolInfoPackage sip; if (SymFromAddr( @@ -590,12 +670,14 @@ bool bWriteVariables, HANDLE pThreadHandle) &sip.si)) // Address of the SYMBOL_INFO structure (inside "sip" object) { _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement); + } else // No symbol found. Print out the logical address instead. { TCHAR szModule[MAX_PATH] = _T(""); DWORD section = 0; DWORD_PTR offset = 0; + GetLogicalAddress((PVOID)sf.AddrPC.Offset, szModule, sizeof(szModule), section, offset); #ifdef _M_IX86 @@ -605,6 +687,7 @@ bool bWriteVariables, HANDLE pThreadHandle) _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule); #endif } + // Get the source line for this stack frame entry IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE) }; DWORD dwLineDisplacement; @@ -613,7 +696,9 @@ bool bWriteVariables, HANDLE pThreadHandle) { _tprintf(_T(" %s line %u"),lineInfo.FileName,lineInfo.LineNumber); } + _tprintf(_T("\r\n")); + // Write out the variables, if desired if (bWriteVariables) { @@ -621,22 +706,29 @@ bool bWriteVariables, HANDLE pThreadHandle) IMAGEHLP_STACK_FRAME imagehlpStackFrame; imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; SymSetContext(m_hProcess, &imagehlpStackFrame, 0); + // Enumerate the locals/parameters SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf); + _tprintf(_T("\r\n")); } } + } + ////////////////////////////////////////////////////////////////////////////// // The function invoked by SymEnumSymbols ////////////////////////////////////////////////////////////////////////////// + BOOL CALLBACK WheatyExceptionReport::EnumerateSymbolsCallback( PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext) { + char szBuffer[2048]; + __try { if (FormatSymbolValue(pSymInfo, (STACKFRAME*)UserContext, @@ -647,8 +739,10 @@ PVOID UserContext) { _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name); } + return TRUE; } + ////////////////////////////////////////////////////////////////////////////// // Given a SYMBOL_INFO representing a particular variable, displays its // contents. If it's a user defined type, display the members and their @@ -661,15 +755,19 @@ char * pszBuffer, unsigned cbBuffer) { char * pszCurrBuffer = pszBuffer; + // Indicate if the variable is a local or parameter if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter "); else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) pszCurrBuffer += sprintf(pszCurrBuffer, "Local "); + // If it's a function, don't do anything. if (pSym->Tag == 5) // SymTagFunction from CVCONST.H from the DIA SDK return false; + DWORD_PTR pVariable = 0; // Will point to the variable's data in memory + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE) { // if (pSym->Register == 8) // EBP is the value 8 (in DBGHELP 5.1) @@ -688,11 +786,13 @@ unsigned cbBuffer) { pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable } + // Determine if the variable is a user defined type (UDT). IF so, bHandled // will return true. bool bHandled; pszCurrBuffer = DumpTypeIndex(pszCurrBuffer,pSym->ModBase, pSym->TypeIndex, 0, pVariable, bHandled, pSym->Name); + if (!bHandled) { // The symbol wasn't a UDT, so do basic, stupid formatting of the @@ -700,13 +800,17 @@ unsigned cbBuffer) // DWORD. BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + // Emit the variable name pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name); + pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size, (PVOID)pVariable); } + return true; } + ////////////////////////////////////////////////////////////////////////////// // If it's a user defined type (UDT), recurse through its members until we're // at fundamental types. When he hit fundamental types, return @@ -722,6 +826,7 @@ bool & bHandled, char* Name) { bHandled = false; + // Get the name of the symbol. This will either be a Type name (if a UDT), // or the structure member name. WCHAR * pwszTypeName; @@ -731,12 +836,15 @@ char* Name) pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); LocalFree(pwszTypeName); } + // Determine how many children this type has. DWORD dwChildrenCount = 0; SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount); + if (!dwChildrenCount) // If no children, we're done return pszCurrBuffer; + // Prepare to get an array of "TypeIds", representing each of the children. // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a // TI_FINDCHILDREN_PARAMS struct has. Use derivation to accomplish this. @@ -745,29 +853,36 @@ char* Name) ULONG MoreChildIds[1024]; FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);} } children; + children.Count = dwChildrenCount; children.Start= 0; + // Get the array of TypeIds, one for each child type if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN, &children)) { return pszCurrBuffer; } + // Append a line feed pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + // Iterate through each of the children for (unsigned i = 0; i < dwChildrenCount; i++) { // Add appropriate indentation level (since this routine is recursive) for (unsigned j = 0; j <= nestingLevel+1; j++) pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + // Recurse for each of the child types bool bHandled2; BasicType basicType = GetBasicType(children.ChildId[i], modBase); pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, children.ChildId[i], nestingLevel+1, offset, bHandled2, ""/*Name */); + // If the child wasn't a UDT, format it appropriately if (!bHandled2) { @@ -775,30 +890,38 @@ char* Name) DWORD dwMemberOffset; SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_OFFSET, &dwMemberOffset); + // Get the real "TypeId" of the child. We need this for the // SymGetTypeInfo(TI_GET_TYPEID) call below. DWORD typeId; SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_TYPEID, &typeId); + // Get the size of the child member ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH,&length); + // Calculate the address of the member DWORD_PTR dwFinalOffset = offset + dwMemberOffset; + // BasicType basicType = GetBasicType(children.ChildId[i], modBase); // // pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // // Emit the variable name // pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", Name); + pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)dwFinalOffset); + pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); } } + bHandled = true; return pszCurrBuffer; } + char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, @@ -840,8 +963,10 @@ PVOID pAddress) pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", *(DWORD64*)pAddress); } + return pszCurrBuffer; } + BasicType WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) { @@ -851,6 +976,7 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) { return basicType; } + // Get the real "TypeId" of the child. We need this for the // SymGetTypeInfo(TI_GET_TYPEID) call below. DWORD typeId; @@ -862,8 +988,10 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) return basicType; } } + return btNoType; } + //============================================================================ // Helper function that writes to the report file, and allows the user to use // printf style formating @@ -874,10 +1002,13 @@ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) int retValue; DWORD cbWritten; va_list argptr; + va_start(argptr, format); retValue = vsprintf(szBuff, format, argptr); va_end(argptr); + WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + return retValue; } -- cgit v1.2.3