diff options
| author | StormBytePP <stormbyte@gmail.com> | 2015-08-19 19:02:10 +0200 |
|---|---|---|
| committer | StormBytePP <stormbyte@gmail.com> | 2015-08-21 17:52:42 +0200 |
| commit | 1d2aafd39bcb79a67357d198ce9b2345642fdd39 (patch) | |
| tree | c32cf1c3717625c60da59c82ba5a4fca2530119a /src/server/shared/Debugging | |
| parent | 172293acee1607727ebd8070ab3e1390590d02a8 (diff) | |
Core/Build: Merge common library and move database out of shared
Diffstat (limited to 'src/server/shared/Debugging')
| -rw-r--r-- | src/server/shared/Debugging/Errors.cpp | 75 | ||||
| -rw-r--r-- | src/server/shared/Debugging/Errors.h | 58 | ||||
| -rw-r--r-- | src/server/shared/Debugging/WheatyExceptionReport.cpp | 1423 | ||||
| -rw-r--r-- | src/server/shared/Debugging/WheatyExceptionReport.h | 210 |
4 files changed, 0 insertions, 1766 deletions
diff --git a/src/server/shared/Debugging/Errors.cpp b/src/server/shared/Debugging/Errors.cpp deleted file mode 100644 index cebd9d4cf2f..00000000000 --- a/src/server/shared/Debugging/Errors.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "Errors.h" - -#include <cstdio> -#include <cstdlib> -#include <thread> -#include <cstdarg> - -namespace Trinity { - -void Assert(char const* file, int line, char const* function, char const* message) -{ - fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", - file, line, function, message); - *((volatile int*)NULL) = 0; - exit(1); -} - -void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) -{ - va_list args; - va_start(args, format); - - fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s ", file, line, function, message); - vfprintf(stderr, format, args); - fprintf(stderr, "\n"); - fflush(stderr); - - va_end(args); - *((volatile int*)NULL) = 0; - exit(1); -} - -void Fatal(char const* file, int line, char const* function, char const* message) -{ - fprintf(stderr, "\n%s:%i in %s FATAL ERROR:\n %s\n", - file, line, function, message); - - std::this_thread::sleep_for(std::chrono::seconds(10)); - *((volatile int*)NULL) = 0; - exit(1); -} - -void Error(char const* file, int line, char const* function, char const* message) -{ - fprintf(stderr, "\n%s:%i in %s ERROR:\n %s\n", - file, line, function, message); - *((volatile int*)NULL) = 0; - exit(1); -} - -void Warning(char const* file, int line, char const* function, char const* message) -{ - fprintf(stderr, "\n%s:%i in %s WARNING:\n %s\n", - file, line, function, message); -} - -} // namespace Trinity diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h deleted file mode 100644 index 4d4624b63dd..00000000000 --- a/src/server/shared/Debugging/Errors.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef TRINITYCORE_ERRORS_H -#define TRINITYCORE_ERRORS_H - -#include "Define.h" - -namespace Trinity -{ - DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; - DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) ATTR_NORETURN ATTR_PRINTF(5, 6); - - DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; - - DECLSPEC_NORETURN void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; - - void Warning(char const* file, int line, char const* function, char const* message); - -} // namespace Trinity - -#if COMPILER == COMPILER_MICROSOFT -#define ASSERT_BEGIN __pragma(warning(push)) __pragma(warning(disable: 4127)) -#define ASSERT_END __pragma(warning(pop)) -#else -#define ASSERT_BEGIN -#define ASSERT_END -#endif - -#define WPAssert(cond, ...) ASSERT_BEGIN do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond, ##__VA_ARGS__); } while(0) ASSERT_END -#define WPFatal(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END -#define WPError(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END -#define WPWarning(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END - -#define ASSERT WPAssert - -template <typename T> inline T* ASSERT_NOTNULL(T* pointer) -{ - ASSERT(pointer); - return pointer; -} - -#endif diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp deleted file mode 100644 index 7cf109b4070..00000000000 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ /dev/null @@ -1,1423 +0,0 @@ -//========================================== -// Matt Pietrek -// MSDN Magazine, 2002 -// FILE: WheatyExceptionReport.CPP -//========================================== -#include "CompilerDefs.h" - -#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__) -#define WIN32_LEAN_AND_MEAN -#pragma warning(disable:4996) -#pragma warning(disable:4312) -#pragma warning(disable:4311) -#include <windows.h> -#include <tlhelp32.h> -#include <stdio.h> -#include <tchar.h> -#define _NO_CVCONST_H -#include <dbghelp.h> - -#include "WheatyExceptionReport.h" - -#include "Common.h" -#include "GitRevision.h" - -#define CrashFolder _T("Crashes") -#pragma comment(linker, "/DEFAULTLIB:dbghelp.lib") - -inline LPTSTR ErrorMessage(DWORD dw) -{ - LPVOID lpMsgBuf; - DWORD formatResult = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, - 0, NULL); - if (formatResult != 0) - return (LPTSTR)lpMsgBuf; - else - { - LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30); - sprintf(msgBuf, "Unknown error: %u", dw); - return msgBuf; - } - -} - -//============================== Global Variables ============================= - -// -// Declare the static variables of the WheatyExceptionReport class -// -TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH]; -TCHAR WheatyExceptionReport::m_szDumpFileName[MAX_PATH]; -LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter; -HANDLE WheatyExceptionReport::m_hReportFile; -HANDLE WheatyExceptionReport::m_hDumpFile; -HANDLE WheatyExceptionReport::m_hProcess; -SymbolPairs WheatyExceptionReport::symbols; -std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; -bool WheatyExceptionReport::stackOverflowException; -bool WheatyExceptionReport::alreadyCrashed; -std::mutex WheatyExceptionReport::alreadyCrashedLock; - -// 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(); - stackOverflowException = false; - alreadyCrashed = false; - if (!IsDebuggerPresent()) - { - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); - } -} - -//============ -// Destructor -//============ -WheatyExceptionReport::~WheatyExceptionReport() -{ - if (m_previousFilter) - SetUnhandledExceptionFilter(m_previousFilter); - ClearSymbols(); -} - -//=========================================================== -// Entry point where control comes on an unhandled exception -//=========================================================== -LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter( -PEXCEPTION_POINTERS pExceptionInfo) -{ - std::unique_lock<std::mutex> guard(alreadyCrashedLock); - // Handle only 1 exception in the whole process lifetime - if (alreadyCrashed) - return EXCEPTION_EXECUTE_HANDLER; - - alreadyCrashed = true; - - if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - stackOverflowException = true; - - TCHAR module_folder_name[MAX_PATH]; - GetModuleFileName(0, module_folder_name, MAX_PATH); - TCHAR* pos = _tcsrchr(module_folder_name, '\\'); - if (!pos) - 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)) - { - if (GetLastError() != ERROR_ALREADY_EXISTS) - return 0; - } - - SYSTEMTIME systime; - GetLocalTime(&systime); - sprintf(m_szDumpFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].dmp", - crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); - - sprintf(m_szLogFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].txt", - crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); - - m_hDumpFile = CreateFile(m_szDumpFileName, - GENERIC_WRITE, - 0, - 0, - OPEN_ALWAYS, - FILE_FLAG_WRITE_THROUGH, - 0); - - m_hReportFile = CreateFile(m_szLogFileName, - GENERIC_WRITE, - 0, - 0, - OPEN_ALWAYS, - FILE_FLAG_WRITE_THROUGH, - 0); - - if (m_hDumpFile) - { - MINIDUMP_EXCEPTION_INFORMATION info; - info.ClientPointers = FALSE; - info.ExceptionPointers = pExceptionInfo; - info.ThreadId = GetCurrentThreadId(); - - MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), - m_hDumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, 0, 0); - - CloseHandle(m_hDumpFile); - } - - 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"), - 0, KEY_QUERY_VALUE, &hKey); - if (lRet != ERROR_SUCCESS) - return FALSE; - TCHAR szTmp[2048]; - DWORD cntBytes = sizeof(szTmp); - lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, NULL, - (LPBYTE)szTmp, &cntBytes); - if (lRet != ERROR_SUCCESS) - return FALSE; - ::RegCloseKey(hKey); - sProcessorName[0] = '\0'; - // Skip spaces - TCHAR* psz = szTmp; - while (iswspace(*psz)) - ++psz; - _tcsncpy(sProcessorName, psz, maxcount); - return TRUE; -} - -BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) -{ - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - // If that fails, try using the OSVERSIONINFO structure. - OSVERSIONINFOEX osvi = { 0 }; - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - BOOL bOsVersionInfoEx; - bOsVersionInfoEx = ::GetVersionEx((LPOSVERSIONINFO)(&osvi)); - if (!bOsVersionInfoEx) - { - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (!::GetVersionEx((OSVERSIONINFO*)&osvi)) - return FALSE; - } - *szVersion = _T('\0'); - TCHAR wszTmp[128]; - switch (osvi.dwPlatformId) - { - // Windows NT product family. - case VER_PLATFORM_WIN32_NT: - { - #if WINVER < 0x0500 - BYTE suiteMask = osvi.wReserved[0]; - BYTE productType = osvi.wReserved[1]; - #else - WORD suiteMask = osvi.wSuiteMask; - BYTE productType = osvi.wProductType; - #endif // WINVER < 0x0500 - - // Test for the specific product family. - if (osvi.dwMajorVersion == 6) - { - if (productType == VER_NT_WORKSTATION) - { - if (osvi.dwMinorVersion == 2) - _tcsncat(szVersion, _T("Windows 8 "), cntMax); - else if (osvi.dwMinorVersion == 1) - _tcsncat(szVersion, _T("Windows 7 "), cntMax); - else - _tcsncat(szVersion, _T("Windows Vista "), cntMax); - } - else if (osvi.dwMinorVersion == 2) - _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax); - else if (osvi.dwMinorVersion == 1) - _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax); - else - _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax); - } - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) - _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax); - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) - _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax); - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) - _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax); - else 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) - { - // Test for the workstation type. - if (productType == VER_NT_WORKSTATION) - { - if (osvi.dwMajorVersion == 4) - _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); - else if (suiteMask & VER_SUITE_PERSONAL) - _tcsncat(szVersion, _T("Home Edition "), cntMax); - else if (suiteMask & VER_SUITE_EMBEDDEDNT) - _tcsncat(szVersion, _T("Embedded "), cntMax); - else - _tcsncat(szVersion, _T("Professional "), cntMax); - } - // Test for the server type. - else if (productType == VER_NT_SERVER) - { - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) - { - if (suiteMask & VER_SUITE_DATACENTER) - _tcsncat(szVersion, _T("Datacenter Edition "), cntMax); - else if (suiteMask & VER_SUITE_ENTERPRISE) - _tcsncat(szVersion, _T("Enterprise Edition "), cntMax); - else if (suiteMask == VER_SUITE_BLADE) - _tcsncat(szVersion, _T("Web Edition "), cntMax); - else - _tcsncat(szVersion, _T("Standard Edition "), cntMax); - } - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) - { - if (suiteMask & VER_SUITE_DATACENTER) - _tcsncat(szVersion, _T("Datacenter Server "), cntMax); - else if (suiteMask & VER_SUITE_ENTERPRISE) - _tcsncat(szVersion, _T("Advanced Server "), cntMax); - else - _tcsncat(szVersion, _T("Server "), cntMax); - } - else // Windows NT 4.0 - { - if (suiteMask & VER_SUITE_ENTERPRISE) - _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax); - else - _tcsncat(szVersion, _T("Server 4.0 "), cntMax); - } - } - } - - // Display service pack (if any) and build number. - if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) - { - 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) - { - _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); - } - else // Windows NT 4.0 prior to SP6a - { - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); - } - ::RegCloseKey(hKey); - } - else // Windows NT 3.51 and earlier or Windows 2000 and later - { - if (!_tcslen(osvi.szCSDVersion)) - _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - else - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); - } - break; - } - default: - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); - break; - } - - return TRUE; -} - -void WheatyExceptionReport::PrintSystemInfo() -{ - SYSTEM_INFO SystemInfo; - ::GetSystemInfo(&SystemInfo); - - MEMORYSTATUS MemoryStatus; - MemoryStatus.dwLength = sizeof (MEMORYSTATUS); - ::GlobalMemoryStatus(&MemoryStatus); - TCHAR sString[1024]; - _tprintf(_T("//=====================================================\r\n")); - if (_GetProcessorName(sString, countof(sString))) - _tprintf(_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"), - sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); - else - _tprintf(_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"), - 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<unknown>\r\n")); -} - -//=========================================================================== -void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables) -{ - THREADENTRY32 te32; - - DWORD dwOwnerPID = GetCurrentProcessId(); - m_hProcess = GetCurrentProcess(); - // Take a snapshot of all running threads - HANDLE 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)) - { - CloseHandle(hThreadSnap); // Must clean up the - // snapshot object! - return; - } - - // Now walk the thread list of the system, - // and display information about each thread - // associated with the specified process - do - { - if (te32.th32OwnerProcessID == dwOwnerPID) - { - CONTEXT context; - context.ContextFlags = 0xffffffff; - HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, false, te32.th32ThreadID); - if (threadHandle) - { - if (GetThreadContext(threadHandle, &context)) - WriteStackDetails(&context, bWriteVariables, threadHandle); - 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 -//=========================================================================== -void WheatyExceptionReport::GenerateExceptionReport( -PEXCEPTION_POINTERS pExceptionInfo) -{ - __try - { - SYSTEMTIME systime; - GetLocalTime(&systime); - - // Start out with a banner - _tprintf(_T("Revision: %s\r\n"), GitRevision::GetFullVersion()); - _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; - DWORD_PTR offset; - GetLogicalAddress(pExceptionRecord->ExceptionAddress, - szFaultingModule, - sizeof(szFaultingModule), - section, offset); - -#ifdef _M_IX86 - _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); -#endif -#ifdef _M_X64 - _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), - 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); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - 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") - _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") - , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, - pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); - _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); - _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), - pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - 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(false); - - // #ifdef _M_IX86 // X86 Only! - - _tprintf(_T("========================\r\n")); - _tprintf(_T("Local Variables And Parameters\r\n")); - - trashableContext = *pCtx; - WriteStackDetails(&trashableContext, true, NULL); - printTracesForAllThreads(true); - - /*_tprintf(_T("========================\r\n")); - _tprintf(_T("Global Variables\r\n")); - - SymEnumSymbols(GetCurrentProcess(), - (UINT_PTR)GetModuleHandle(szFaultingModule), - 0, EnumerateSymbolsCallback, 0);*/ - // #endif // X86 Only! - - SymCleanup(GetCurrentProcess()); - - _tprintf(_T("\r\n")); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - _tprintf(_T("Error writing the crash log\r\n")); - } -} - -//====================================================================== -// Given an exception code, returns a pointer to a static string with a -// description of the exception -//====================================================================== -LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) -{ - #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x); - - switch (dwCode) - { - EXCEPTION(ACCESS_VIOLATION) - EXCEPTION(DATATYPE_MISALIGNMENT) - EXCEPTION(BREAKPOINT) - EXCEPTION(SINGLE_STEP) - EXCEPTION(ARRAY_BOUNDS_EXCEEDED) - EXCEPTION(FLT_DENORMAL_OPERAND) - EXCEPTION(FLT_DIVIDE_BY_ZERO) - EXCEPTION(FLT_INEXACT_RESULT) - EXCEPTION(FLT_INVALID_OPERATION) - EXCEPTION(FLT_OVERFLOW) - EXCEPTION(FLT_STACK_CHECK) - EXCEPTION(FLT_UNDERFLOW) - EXCEPTION(INT_DIVIDE_BY_ZERO) - EXCEPTION(INT_OVERFLOW) - EXCEPTION(PRIV_INSTRUCTION) - EXCEPTION(IN_PAGE_ERROR) - EXCEPTION(ILLEGAL_INSTRUCTION) - EXCEPTION(NONCONTINUABLE_EXCEPTION) - EXCEPTION(STACK_OVERFLOW) - EXCEPTION(INVALID_DISPOSITION) - EXCEPTION(GUARD_PAGE) - EXCEPTION(INVALID_HANDLE) - } - - // 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. -// -// Note: the szModule paramater buffer is an output buffer of length specified -// by the len parameter (in characters!) -//============================================================================= -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 (!hMod) - return FALSE; - - 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; - i < pNtHdr->FileHeader.NumberOfSections; - i++, pSection++) - { - DWORD_PTR sectionStart = pSection->VirtualAddress; - DWORD_PTR sectionEnd = sectionStart - + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize)); - - // Is the address in this section??? - if ((rva >= sectionStart) && (rva <= sectionEnd)) - { - // Yes, address is in the section. Calculate section and offset, - // and store in the "section" & "offset" params, which were - // passed by reference. - section = i+1; - offset = rva - sectionStart; - 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 -{ - CSymbolInfoPackage() - { - si.SizeOfStruct = sizeof(SYMBOL_INFO); - si.MaxNameLen = sizeof(name); - } -}; - -//============================================================ -// Walks the stack, and writes the results to the report file -//============================================================ -void WheatyExceptionReport::WriteStackDetails( -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. - sf.AddrPC.Offset = pContext->Eip; - sf.AddrPC.Mode = AddrModeFlat; - sf.AddrStack.Offset = pContext->Esp; - 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; - sf.AddrStack.Offset = pContext->Rsp; - sf.AddrStack.Mode = AddrModeFlat; - sf.AddrFrame.Offset = pContext->Rbp; - sf.AddrFrame.Mode = AddrModeFlat; - dwMachineType = IMAGE_FILE_MACHINE_AMD64; -#endif - - for (;;) - { - // Get the next stack frame - if (! StackWalk64(dwMachineType, - m_hProcess, - pThreadHandle != NULL ? pThreadHandle : GetCurrentThread(), - &sf, - pContext, - 0, - SymFunctionTableAccess64, - SymGetModuleBase64, - 0)) - break; - if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure - break; // the frame is OK. Bail if not. -#ifdef _M_IX86 - _tprintf(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); -#endif -#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( - m_hProcess, // Process handle of the current process - sf.AddrPC.Offset, // Symbol address - &symDisplacement, // Address of the variable that will receive the displacement - &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 - _tprintf(_T("%04X:%08X %s"), section, offset, szModule); -#endif -#ifdef _M_X64 - _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule); -#endif - } - - // Get the source line for this stack frame entry - IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) }; - DWORD dwLineDisplacement; - if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, - &dwLineDisplacement, &lineInfo)) - { - _tprintf(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber); - } - - _tprintf(_T("\r\n")); - - // Write out the variables, if desired - if (bWriteVariables) - { - // Use SymSetContext to get just the locals/params for this frame - 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[WER_LARGE_BUFFER_SIZE]; - memset(szBuffer, 0, sizeof(szBuffer)); - - __try - { - ClearSymbols(); - if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, - szBuffer, sizeof(szBuffer))) - _tprintf(_T("%s"), szBuffer); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); - if (szBuffer[0] != '\0') - _tprintf(_T("%s"), szBuffer); - } - - 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 -// values. -////////////////////////////////////////////////////////////////////////////// -bool WheatyExceptionReport::FormatSymbolValue( -PSYMBOL_INFO pSym, -STACKFRAME64 * sf, -char * pszBuffer, -unsigned /*cbBuffer*/) -{ - char * pszCurrBuffer = pszBuffer; - - // If it's a function, don't do anything. - if (pSym->Tag == SymTagFunction) // 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) - { // This may change!!! -#ifdef _M_IX86 - pVariable = sf->AddrFrame.Offset; -#elif _M_X64 - pVariable = sf->AddrStack.Offset; -#endif - pVariable += (DWORD_PTR)pSym->Address; - } - // else - // return false; - } - else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER) - return false; // Don't try to report register variable - else - { - pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable - } - - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); - - // Indicate if the variable is a local or parameter - if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) - symbolDetails.top().Prefix = "Parameter "; - else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) - symbolDetails.top().Prefix = "Local "; - - // 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, "", false, true); - - if (!bHandled) - { - // The symbol wasn't a UDT, so do basic, stupid formatting of the - // variable. Based on the size, we're assuming it's a char, WORD, or - // DWORD. - BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); - if (symbolDetails.top().Type.empty()) - symbolDetails.top().Type = rgBaseType[basicType]; - - // Emit the variable name - if (pSym->Name[0] != '\0') - symbolDetails.top().Name = pSym->Name; - - char buffer[50]; - FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer)); - symbolDetails.top().Value = buffer; - } - - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); - 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 -// bHandled = false, so that FormatSymbolValue() will format them. -////////////////////////////////////////////////////////////////////////////// -char * WheatyExceptionReport::DumpTypeIndex( -char * pszCurrBuffer, -DWORD64 modBase, -DWORD dwTypeIndex, -unsigned nestingLevel, -DWORD_PTR offset, -bool & bHandled, -const char* Name, -char* /*suffix*/, -bool newSymbol, -bool logChildren) -{ - bHandled = false; - - if (newSymbol) - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); - - DWORD typeTag; - if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) - return pszCurrBuffer; - - // Get the name of the symbol. This will either be a Type name (if a UDT), - // or the structure member name. - WCHAR * pwszTypeName; - if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME, - &pwszTypeName)) - { - // handle special cases - if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0) - { - LocalFree(pwszTypeName); - symbolDetails.top().Type = "std::string"; - char buffer[50]; - FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer)); - symbolDetails.top().Value = buffer; - if (Name != NULL && Name[0] != '\0') - symbolDetails.top().Name = Name; - bHandled = true; - return pszCurrBuffer; - } - - char buffer[200]; - wcstombs(buffer, pwszTypeName, sizeof(buffer)); - buffer[199] = '\0'; - if (Name != NULL && Name[0] != '\0') - { - symbolDetails.top().Type = buffer; - symbolDetails.top().Name = Name; - } - else if (buffer[0] != '\0') - symbolDetails.top().Name = buffer; - - LocalFree(pwszTypeName); - } - else if (Name != NULL && Name[0] != '\0') - symbolDetails.top().Name = Name; - - if (!StoreSymbol(dwTypeIndex, offset)) - { - // Skip printing address and base class if it has been printed already - if (typeTag == SymTagBaseClass) - bHandled = true; - return pszCurrBuffer; - } - - DWORD innerTypeID; - switch (typeTag) - { - case SymTagPointerType: - if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) - { - if (Name != NULL && Name[0] != '\0') - symbolDetails.top().Name = Name; - - BOOL isReference; - SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); - - char addressStr[40]; - memset(addressStr, 0, sizeof(addressStr)); - - if (isReference) - symbolDetails.top().Suffix += "&"; - else - symbolDetails.top().Suffix += "*"; - - // Try to dereference the pointer in a try/except block since it might be invalid - DWORD_PTR address = DereferenceUnsafePointer(offset); - - char buffer[50]; - FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); - symbolDetails.top().Value = buffer; - - if (nestingLevel >= WER_MAX_NESTING_LEVEL) - logChildren = false; - - // no need to log any children since the address is invalid anyway - if (address == NULL || address == DWORD_PTR(-1)) - logChildren = false; - - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - address, bHandled, Name, addressStr, false, logChildren); - - if (!bHandled) - { - BasicType basicType = GetBasicType(dwTypeIndex, modBase); - if (symbolDetails.top().Type.empty()) - symbolDetails.top().Type = rgBaseType[basicType]; - - if (address == NULL) - symbolDetails.top().Value = "NULL"; - else if (address == DWORD_PTR(-1)) - symbolDetails.top().Value = "<Unable to read memory>"; - else - { - // Get the size of the child member - ULONG64 length; - SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); - char buffer2[50]; - FormatOutputValue(buffer2, basicType, length, (PVOID)address, sizeof(buffer)); - symbolDetails.top().Value = buffer2; - } - bHandled = true; - return pszCurrBuffer; - } - else if (address == NULL) - symbolDetails.top().Value = "NULL"; - else if (address == DWORD_PTR(-1)) - { - symbolDetails.top().Value = "<Unable to read memory>"; - bHandled = true; - return pszCurrBuffer; - } - } - break; - case SymTagData: - if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) - { - DWORD innerTypeTag; - if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) - break; - - switch (innerTypeTag) - { - case SymTagUDT: - if (nestingLevel >= WER_MAX_NESTING_LEVEL) - logChildren = false; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); - break; - case SymTagPointerType: - if (Name != NULL && Name[0] != '\0') - symbolDetails.top().Name = Name; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); - break; - case SymTagArrayType: - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); - break; - default: - break; - } - } - break; - case SymTagArrayType: - if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) - { - symbolDetails.top().HasChildren = true; - - BasicType basicType = btNoType; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, Name, "", false, false); - - // Set Value back to an empty string since the Array object itself has no value, only its elements have - symbolDetails.top().Value.clear(); - - DWORD elementsCount; - if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) - symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]"; - else - symbolDetails.top().Suffix += "[<unknown count>]"; - - if (!bHandled) - { - basicType = GetBasicType(dwTypeIndex, modBase); - if (symbolDetails.top().Type.empty()) - symbolDetails.top().Type = rgBaseType[basicType]; - bHandled = true; - } - - // Get the size of the child member - ULONG64 length; - SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); - - char buffer[50]; - switch (basicType) - { - case btChar: - case btStdString: - FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer), elementsCount); - symbolDetails.top().Value = buffer; - break; - default: - for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) - { - pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); - symbolDetails.top().Suffix += "[" + std::to_string(index) + "]"; - FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); - symbolDetails.top().Value = buffer; - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); - } - break; - } - - return pszCurrBuffer; - } - break; - case SymTagBaseType: - break; - case SymTagEnum: - return pszCurrBuffer; - default: - break; - } - - // 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. - struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS - { - ULONG MoreChildIds[1024*2]; - 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; - } - - // Iterate through each of the children - for (unsigned i = 0; i < dwChildrenCount; i++) - { - DWORD symTag; - SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); - - if (symTag == SymTagFunction || - symTag == SymTagEnum || - symTag == SymTagTypedef || - symTag == SymTagVTable) - continue; - - // Ignore static fields - DWORD dataKind; - SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind); - if (dataKind == DataIsStaticLocal || - dataKind == DataIsGlobal || - dataKind == DataIsStaticMember) - continue; - - - symbolDetails.top().HasChildren = true; - if (!logChildren) - { - bHandled = false; - return pszCurrBuffer; - } - - // Recurse for each of the child types - bool bHandled2; - BasicType basicType = GetBasicType(children.ChildId[i], modBase); - - // Get the offset of the child member, relative to its parent - DWORD dwMemberOffset; - SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], - TI_GET_OFFSET, &dwMemberOffset); - - // Calculate the address of the member - DWORD_PTR dwFinalOffset = offset + dwMemberOffset; - - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, - children.ChildId[i], nestingLevel+1, - dwFinalOffset, bHandled2, ""/*Name */, "", true, true); - - // If the child wasn't a UDT, format it appropriately - if (!bHandled2) - { - if (symbolDetails.top().Type.empty()) - symbolDetails.top().Type = rgBaseType[basicType]; - - // 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); - - char buffer[50]; - FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer)); - symbolDetails.top().Value = buffer; - } - - pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); - } - - bHandled = true; - return pszCurrBuffer; -} - -void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, -BasicType basicType, -DWORD64 length, -PVOID pAddress, -size_t bufferSize, -size_t countOverride) -{ - __try - { - switch (basicType) - { - case btChar: - { - // Special case handling for char[] type - if (countOverride != 0) - length = countOverride; - else - length = strlen((char*)pAddress); - if (length > bufferSize - 6) - pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), (char*)pAddress); - else - pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", (DWORD)length, (char*)pAddress); - break; - } - case btStdString: - { - std::string* value = static_cast<std::string*>(pAddress); - if (value->length() > bufferSize - 6) - pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), value->c_str()); - else - pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str()); - break; - } - default: - // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) - if (length == 1) - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress); - else if (length == 2) - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress); - else if (length == 4) - { - if (basicType == btFloat) - pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress); - else - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress); - } - else if (length == 8) - { - if (basicType == btFloat) - { - pszCurrBuffer += sprintf(pszCurrBuffer, "%f", - *(double *)pAddress); - } - else - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", - *(DWORD64*)pAddress); - } - else - { - #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64)pAddress); - #else - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (DWORD)pAddress); - #endif - } - break; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { -#if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64)pAddress); -#else - pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (DWORD)pAddress); -#endif - } -} - -BasicType -WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) -{ - BasicType basicType; - if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, - TI_GET_BASETYPE, &basicType)) - { - return basicType; - } - - // Get the real "TypeId" of the child. We need this for the - // SymGetTypeInfo(TI_GET_TYPEID) call below. - DWORD typeId; - if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId)) - { - if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE, - &basicType)) - { - return basicType; - } - } - - return btNoType; -} - -DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) -{ - __try - { - return *(PDWORD_PTR)address; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return DWORD_PTR(-1); - } -} - -//============================================================================ -// Helper function that writes to the report file, and allows the user to use -// printf style formating -//============================================================================ -int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) -{ - int retValue; - va_list argptr; - va_start(argptr, format); - if (stackOverflowException) - { - retValue = heapprintf(format, argptr); - va_end(argptr); - } - else - { - retValue = stackprintf(format, argptr); - va_end(argptr); - } - - return retValue; -} - -int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr) -{ - int retValue; - DWORD cbWritten; - - TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; - retValue = vsprintf(szBuff, format, argptr); - WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); - - return retValue; -} - -int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr) -{ - int retValue; - DWORD cbWritten; - TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE); - retValue = vsprintf(szBuff, format, argptr); - WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); - free(szBuff); - - return retValue; -} - -bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset) -{ - return symbols.insert(SymbolPair(type, offset)).second; -} - -void WheatyExceptionReport::ClearSymbols() -{ - symbols.clear(); - while (!symbolDetails.empty()) - symbolDetails.pop(); -} - -char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer) -{ - // Log current symbol and then add another to the stack to keep the hierarchy format - pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); - symbolDetails.emplace(); - return pszCurrBuffer; -} - -char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer) -{ - pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); - symbolDetails.pop(); - return pszCurrBuffer; -} - -char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer) -{ - if (symbolDetails.empty()) - return pszCurrBuffer; - - // Don't log anything if has been logged already or if it's empty - if (symbolDetails.top().Logged || symbolDetails.top().empty()) - return pszCurrBuffer; - - // Add appropriate indentation level (since this routine is recursive) - for (size_t i = 0; i < symbolDetails.size(); i++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); - - pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str()); - - return pszCurrBuffer; -} - -#endif // _WIN32 diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h deleted file mode 100644 index 8c2479d5232..00000000000 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ /dev/null @@ -1,210 +0,0 @@ -#ifndef _WHEATYEXCEPTIONREPORT_ -#define _WHEATYEXCEPTIONREPORT_ - -#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__) - -#include <dbghelp.h> -#include <set> -#include <stdlib.h> -#include <stack> -#include <mutex> -#define countof _countof - -#define WER_MAX_ARRAY_ELEMENTS_COUNT 10 -#define WER_MAX_NESTING_LEVEL 5 -#define WER_LARGE_BUFFER_SIZE 1024 * 128 - -enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK -{ - btNoType = 0, - btVoid = 1, - btChar = 2, - btWChar = 3, - btInt = 6, - btUInt = 7, - btFloat = 8, - btBCD = 9, - btBool = 10, - btLong = 13, - btULong = 14, - btCurrency = 25, - btDate = 26, - btVariant = 27, - btComplex = 28, - btBit = 29, - btBSTR = 30, - btHresult = 31, - - // Custom types - btStdString = 101 -}; - -enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK -{ - DataIsUnknown, - DataIsLocal, - DataIsStaticLocal, - DataIsParam, - DataIsObjectPtr, - DataIsFileStatic, - DataIsGlobal, - DataIsMember, - DataIsStaticMember, - DataIsConstant -}; - -const char* const rgBaseType[] = -{ - "<user defined>", // btNoType = 0, - "void", // btVoid = 1, - "char",//char* // btChar = 2, - "wchar_t*", // btWChar = 3, - "signed char", - "unsigned char", - "int", // btInt = 6, - "unsigned int", // btUInt = 7, - "float", // btFloat = 8, - "<BCD>", // btBCD = 9, - "bool", // btBool = 10, - "short", - "unsigned short", - "long", // btLong = 13, - "unsigned long", // btULong = 14, - "int8", - "int16", - "int32", - "int64", - "int128", - "uint8", - "uint16", - "uint32", - "uint64", - "uint128", - "<currency>", // btCurrency = 25, - "<date>", // btDate = 26, - "VARIANT", // btVariant = 27, - "<complex>", // btComplex = 28, - "<bit>", // btBit = 29, - "BSTR", // btBSTR = 30, - "HRESULT" // btHresult = 31 -}; - -struct SymbolPair -{ - SymbolPair(DWORD type, DWORD_PTR offset) - { - _type = type; - _offset = offset; - } - - bool operator<(const SymbolPair& other) const - { - return _offset < other._offset || - (_offset == other._offset && _type < other._type); - } - - DWORD _type; - DWORD_PTR _offset; -}; -typedef std::set<SymbolPair> SymbolPairs; - -struct SymbolDetail -{ - SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {} - - std::string ToString() - { - Logged = true; - std::string formatted = Prefix + Type + Suffix; - if (!Name.empty()) - { - if (!formatted.empty()) - formatted += " "; - formatted += Name; - } - if (!Value.empty()) - formatted += " = " + Value; - return formatted; - } - - bool empty() const - { - return Value.empty() && !HasChildren; - } - - std::string Prefix; - std::string Type; - std::string Suffix; - std::string Name; - std::string Value; - bool Logged; - bool HasChildren; -}; - -class WheatyExceptionReport -{ - public: - - WheatyExceptionReport(); - ~WheatyExceptionReport(); - - // entry point where control comes on an unhandled exception - static LONG WINAPI WheatyUnhandledExceptionFilter( - PEXCEPTION_POINTERS pExceptionInfo); - - static void printTracesForAllThreads(bool); - private: - // where report info is extracted and generated - static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo); - static void PrintSystemInfo(); - static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax); - static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount); - - // Helper functions - static LPTSTR GetExceptionString(DWORD dwCode); - static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, - DWORD& section, DWORD_PTR& offset); - - static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle); - - static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID); - - static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); - - static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool); - - static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0); - - static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); - static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); - - static int __cdecl _tprintf(const TCHAR * format, ...); - static int __cdecl stackprintf(const TCHAR * format, va_list argptr); - static int __cdecl heapprintf(const TCHAR * format, va_list argptr); - - static bool StoreSymbol(DWORD type , DWORD_PTR offset); - static void ClearSymbols(); - - // Variables used by the class - static TCHAR m_szLogFileName[MAX_PATH]; - static TCHAR m_szDumpFileName[MAX_PATH]; - static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter; - static HANDLE m_hReportFile; - static HANDLE m_hDumpFile; - static HANDLE m_hProcess; - static SymbolPairs symbols; - static std::stack<SymbolDetail> symbolDetails; - static bool stackOverflowException; - static bool alreadyCrashed; - static std::mutex alreadyCrashedLock; - - static char* PushSymbolDetail(char* pszCurrBuffer); - static char* PopSymbolDetail(char* pszCurrBuffer); - static char* PrintSymbolDetail(char* pszCurrBuffer); - -}; - -extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class -#endif // _WIN32 -#endif // _WHEATYEXCEPTIONREPORT_ - |
