aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared/Debugging
diff options
context:
space:
mode:
authorStormBytePP <stormbyte@gmail.com>2015-08-19 19:02:10 +0200
committerStormBytePP <stormbyte@gmail.com>2015-08-21 17:52:42 +0200
commit1d2aafd39bcb79a67357d198ce9b2345642fdd39 (patch)
treec32cf1c3717625c60da59c82ba5a4fca2530119a /src/server/shared/Debugging
parent172293acee1607727ebd8070ab3e1390590d02a8 (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.cpp75
-rw-r--r--src/server/shared/Debugging/Errors.h58
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp1423
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h210
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_
-