diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000000..178814df73c --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,10 @@ +# top-most EditorConfig file +root = true + +# 4 space indentation +[*.{cpp,h,hpp}] +indent_style = space +indent_size = 4 + +# newline ending every file +insert_final_newline = true diff --git a/src/xrCore/Debug/MiniDump.cpp b/src/xrCore/Debug/MiniDump.cpp index 3cd4bf3075d..1c8204ba9dc 100644 --- a/src/xrCore/Debug/MiniDump.cpp +++ b/src/xrCore/Debug/MiniDump.cpp @@ -7,7 +7,6 @@ Copyright (c) 1997-2001 John Robbins -- All rights reserved. #pragma warning(push) #pragma warning(disable : 4091) // 'typedef ': ignored on left of '' when no variable is declared #include "MiniDump.h" -#include "StackTrace.h" #pragma warning(pop) #include diff --git a/src/xrCore/Debug/StackTrace.cpp b/src/xrCore/Debug/StackTrace.cpp deleted file mode 100644 index e8ed966cf83..00000000000 --- a/src/xrCore/Debug/StackTrace.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/*---------------------------------------------------------------------- -"Debugging Applications" (Microsoft Press) -Copyright (c) 1997-2000 John Robbins -- All rights reserved. -----------------------------------------------------------------------*/ - -#include "stdafx.h" -#pragma warning(push) -#pragma warning(disable : 4091) // 'typedef ': ignored on left of '' when no variable is declared -#include "StackTrace.h" -#include "SymbolEngine.h" -#include "MiniDump.h" -#pragma warning(pop) -#include -#pragma comment(lib, "psapi.lib") - -/*////////////////////////////////////////////////////////////////////// -File Scope Defines -//////////////////////////////////////////////////////////////////////*/ -// The maximum symbol size handled in the module -#define MAX_SYM_SIZE 256 -#define BUFF_SIZE 1024 -#define SYM_BUFF_SIZE 512 - -/*////////////////////////////////////////////////////////////////////// -File Scope Global Variables -//////////////////////////////////////////////////////////////////////*/ - -// The original unhandled exception filter -static LPTOP_LEVEL_EXCEPTION_FILTER g_pfnOrigFilt = NULL; - -// The array of modules to limit crash handler to -static HMODULE* g_ahMod = NULL; -// The size, in items, of g_ahMod -static UINT g_uiModCount = 0; - -// The static buffer returned by various functions. This buffer -// allows data to be transferred without using the stack. -static TCHAR g_szBuff[BUFF_SIZE]; - -// The static symbol lookup buffer -static BYTE g_stSymbol[SYM_BUFF_SIZE]; - -// The static source file and line number structure -static IMAGEHLP_LINE g_stLine; - -// The stack frame used in walking the stack -static STACKFRAME g_stFrame; - -// The flag indicating that the symbol engine has been initialized -static BOOL g_bSymEngInit = FALSE; - -// The flag indicating that microsoft symbol server will be used -// static BOOL g_SymServerLookup = TRUE; - -/*////////////////////////////////////////////////////////////////////// -File Scope Function Declarations -//////////////////////////////////////////////////////////////////////*/ - -// The internal function that does all the stack walking -LPCTSTR __stdcall InternalGetStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs); - -// Initializes the symbol engine if needed -void InitializeSymbolEngine(void); - -// Cleans up the symbol engine if needed -void DeinitializeSymbolEngine(void); - -/*////////////////////////////////////////////////////////////////////// -Crash Handler Function Implementation -//////////////////////////////////////////////////////////////////////*/ - -LPCTSTR __stdcall GetFirstStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs) -{ - // All the error checking is in the InternalGetStackTraceString - // function. - - // Initialize the STACKFRAME structure. - ZeroMemory(&g_stFrame, sizeof(STACKFRAME)); - -#if defined(XR_X64) - g_stFrame.AddrPC.Offset = pExPtrs->ContextRecord->Rip; - g_stFrame.AddrPC.Mode = AddrModeFlat; - g_stFrame.AddrReturn.Offset = 0; - g_stFrame.AddrReturn.Mode = AddrModeFlat; - g_stFrame.AddrStack.Offset = pExPtrs->ContextRecord->Rsp; - g_stFrame.AddrStack.Mode = AddrModeFlat; - g_stFrame.AddrFrame.Offset = pExPtrs->ContextRecord->Rbp; - g_stFrame.AddrFrame.Mode = AddrModeFlat; -#elif defined(XR_X86) - g_stFrame.AddrPC.Offset = pExPtrs->ContextRecord->Eip; - g_stFrame.AddrPC.Mode = AddrModeFlat; - g_stFrame.AddrStack.Offset = pExPtrs->ContextRecord->Esp; - g_stFrame.AddrStack.Mode = AddrModeFlat; - g_stFrame.AddrFrame.Offset = pExPtrs->ContextRecord->Ebp; - g_stFrame.AddrFrame.Mode = AddrModeFlat; -#else - g_stFrame.AddrPC.Offset = (DWORD)pExPtrs->ContextRecord->Fir; - g_stFrame.AddrPC.Mode = AddrModeFlat; - g_stFrame.AddrReturn.Offset = (DWORD)pExPtrs->ContextRecord->IntRa; - g_stFrame.AddrReturn.Mode = AddrModeFlat; - g_stFrame.AddrStack.Offset = (DWORD)pExPtrs->ContextRecord->IntSp; - g_stFrame.AddrStack.Mode = AddrModeFlat; - g_stFrame.AddrFrame.Offset = (DWORD)pExPtrs->ContextRecord->IntFp; - g_stFrame.AddrFrame.Mode = AddrModeFlat; -#endif - - return InternalGetStackTraceString(dwOpts, pExPtrs); -} - -LPCTSTR __stdcall GetNextStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs) -{ - // All error checking is in InternalGetStackTraceString. - // Assume that GetFirstStackTraceString has already initialized the - // stack frame information. - return InternalGetStackTraceString(dwOpts, pExPtrs); -} - -#ifndef XR_X64 -BOOL __stdcall ReadCurrentProcessMemory(HANDLE, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) -#else -BOOL __stdcall ReadCurrentProcessMemory(HANDLE, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, SIZE_T* lpNumberOfBytesRead) -#endif -{ - return ReadProcessMemory(GetCurrentProcess(), lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead); -} - -// The internal function that does all the stack walking -LPCTSTR __stdcall InternalGetStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs) -{ - // ASSERT(IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS)) == FALSE); - if (IsBadReadPtr(pExPtrs, sizeof(EXCEPTION_POINTERS)) == TRUE) - { - SetLastError(ERROR_INVALID_ADDRESS); - // TRACE0("GetStackTraceString - invalid pExPtrs!\n"); - return NULL; - } - - // The value that is returned - LPCTSTR szRet; - // A temporary variable for all to use. This variable saves - // stack space. - DWORD dwTemp; - // The module base address. I look this up right after the stack - // walk to ensure that the module is valid. - DWORD dwModBase; - - HANDLE hProcess = (HANDLE)GetCurrentProcessId(); - - __try - { - // Initialize the symbol engine in case it isn't initialized. - InitializeSymbolEngine(); - -#ifdef _WIN64 -#define CH_MACHINE IMAGE_FILE_MACHINE_IA64 -#else -#define CH_MACHINE IMAGE_FILE_MACHINE_I386 -#endif - // Note: If the source file and line number functions are used, - // StackWalk can cause an access violation. - BOOL bSWRet = StackWalk(CH_MACHINE, hProcess, GetCurrentThread(), &g_stFrame, pExPtrs->ContextRecord, - (PREAD_PROCESS_MEMORY_ROUTINE)ReadCurrentProcessMemory, SymFunctionTableAccess, SymGetModuleBase, NULL); - - if ((bSWRet == FALSE) || (g_stFrame.AddrFrame.Offset == 0)) - { - szRet = NULL; - __leave; - } - - // Before I get too carried away and start calculating - // everything, I need to double-check that the address returned - // by StackWalk really exists. I've seen cases in which - // StackWalk returns TRUE but the address doesn't belong to - // a module in the process. - dwModBase = SymGetModuleBase(hProcess, g_stFrame.AddrPC.Offset); - if (dwModBase == 0) - { - szRet = NULL; - __leave; - } - - int iCurr = 0; - -// At a minimum, put in the address. -#ifdef _WIN64 - iCurr += wsprintf(g_szBuff + iCurr, _T("0x%016I64X"), g_stFrame.AddrPC.Offset); -#else - // iCurr += wsprintf(g_szBuff + iCurr, _T("%04X:%08I64X"), pExPtrs->ContextRecord->SegCs, - // g_stFrame.AddrPC.Offset); - iCurr += wsprintf(g_szBuff + iCurr, _T("%04X:%08X"), pExPtrs->ContextRecord->SegCs, g_stFrame.AddrPC.Offset); -#endif - - // Output the parameters? - if ((dwOpts & GSTSO_PARAMS) == GSTSO_PARAMS) - { - iCurr += wsprintf(g_szBuff + iCurr, -#ifdef _WIN64 - _T(" (0x%016I64X 0x%016I64X 0x%016I64X 0x%016I64X)"), -#else - //_T(" (0x%08I64X 0x%08I64X 0x%08I64X 0x%08I64X)"), - _T(" (0x%08X 0x%08X 0x%08X 0x%08X)"), -#endif - g_stFrame.Params[0], g_stFrame.Params[1], g_stFrame.Params[2], g_stFrame.Params[3]); - } - // Output the module name. - if ((dwOpts & GSTSO_MODULE) == GSTSO_MODULE) - { - iCurr += wsprintf(g_szBuff + iCurr, _T(" ")); - // ASSERT(iCurr < (BUFF_SIZE - MAX_PATH)); - iCurr += GetModuleBaseName(GetCurrentProcess(), (HINSTANCE)dwModBase, g_szBuff + iCurr, BUFF_SIZE - iCurr); - } - - // ASSERT(iCurr < (BUFF_SIZE - MAX_PATH)); - DWORD_PTR dwDisp; - // Output the symbol name? - if ((dwOpts & GSTSO_SYMBOL) == GSTSO_SYMBOL) - { - // Start looking up the exception address. - PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol; - ZeroMemory(pSym, SYM_BUFF_SIZE); - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); - pSym->MaxNameLength = SYM_BUFF_SIZE - sizeof(IMAGEHLP_SYMBOL); - - if (SymGetSymFromAddr(hProcess, g_stFrame.AddrPC.Offset, &dwDisp, pSym) == TRUE) - { - iCurr += wsprintf(g_szBuff + iCurr, _T(", ")); - // Copy no more symbol information than there's room for. - dwTemp = lstrlen(pSym->Name); - if (dwTemp > (DWORD)(BUFF_SIZE - iCurr - (MAX_SYM_SIZE + 50))) - { - lstrcpyn(g_szBuff + iCurr, pSym->Name, BUFF_SIZE - iCurr - 1); - // Gotta leave now - szRet = g_szBuff; - __leave; - } - else - { - if (dwDisp > 0) - { - // iCurr += wsprintf(g_szBuff + iCurr, _T("%s() + %I64d byte(s)"), pSym->Name, dwDisp); - iCurr += wsprintf(g_szBuff + iCurr, _T("%s() + %d byte(s)"), pSym->Name, dwDisp); - } - else - { - iCurr += wsprintf(g_szBuff + iCurr, _T("%s"), pSym->Name); - } - } - } - else - { - // If the symbol wasn't found, the source file and line - // number won't be found either, so leave now. - szRet = g_szBuff; - __leave; - } - } - - // ASSERT(iCurr < (BUFF_SIZE - MAX_PATH)); - - // Output the source file and line number information? - if ((dwOpts & GSTSO_SRCLINE) == GSTSO_SRCLINE) - { - ZeroMemory(&g_stLine, sizeof(IMAGEHLP_LINE)); - g_stLine.SizeOfStruct = sizeof(IMAGEHLP_LINE); - - if (SymGetLineFromAddr(hProcess, g_stFrame.AddrPC.Offset, (PDWORD)&dwDisp, &g_stLine) == TRUE) - { - iCurr += wsprintf(g_szBuff + iCurr, _T(", ")); - - // Copy no more of the source file and line number - // information than there's room for. - dwTemp = lstrlen(g_stLine.FileName); - if (dwTemp > (DWORD)(BUFF_SIZE - iCurr - (MAX_PATH + 50))) - { - lstrcpyn(g_szBuff + iCurr, g_stLine.FileName, BUFF_SIZE - iCurr - 1); - // Gotta leave now - szRet = g_szBuff; - __leave; - } - else - { - if (dwDisp > 0) - { - iCurr += wsprintf(g_szBuff + iCurr, _T("%s, line %d + %d byte(s)"), g_stLine.FileName, - g_stLine.LineNumber, dwDisp); - } - else - { - iCurr += wsprintf(g_szBuff + iCurr, _T("%s, line %d"), g_stLine.FileName, g_stLine.LineNumber); - } - } - } - } - szRet = g_szBuff; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - // int err = GetLastError(); - // char buf[1024]; - // sprintf(buf, "error %d", err); - // MessageBoxA(0, buf, "Flux Engine", 0); - // ASSERT(!"Crashed in InternalGetStackTraceString"); - szRet = NULL; - } - return szRet; -} - -BOOL __stdcall GetFirstStackTraceStringVB(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs, LPTSTR szBuff, UINT uiSize) -{ - // ASSERT(IsBadWritePtr(szBuff, uiSize) == FALSE); - if (IsBadWritePtr(szBuff, uiSize) == TRUE) - { - return FALSE; - } - - LPCTSTR szRet; - - __try - { - szRet = GetFirstStackTraceString(dwOpts, pExPtrs); - if (NULL == szRet) - { - __leave; - } - lstrcpyn(szBuff, szRet, std::min((UINT)lstrlen(szRet) + 1, uiSize)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - szRet = NULL; - } - return szRet != NULL; -} - -BOOL __stdcall GetNextStackTraceStringVB(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs, LPTSTR szBuff, UINT uiSize) -{ - // ASSERT(IsBadWritePtr(szBuff, uiSize) == FALSE); - if (IsBadWritePtr(szBuff, uiSize) == TRUE) - { - return FALSE; - } - LPCTSTR szRet; - __try - { - szRet = GetNextStackTraceString(dwOpts, pExPtrs); - if (NULL == szRet) - { - __leave; - } - lstrcpyn(szBuff, szRet, std::min((UINT)lstrlen(szRet) + 1, uiSize)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - szRet = NULL; - } - return szRet != NULL; -} - -// Initializes the symbol engine if needed -void InitializeSymbolEngine(void) -{ - // static char const ms_symsrv[] = "http://msdl.microsoft.com/download/symbols"; - if (!g_bSymEngInit) - { - // Set up the symbol engine. - DWORD dwOpts = SymGetOptions(); - // Turn on line loading and deferred loading. - SymSetOptions(dwOpts | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); - - HANDLE hProcess = (HANDLE)GetCurrentProcessId(); - SymInitialize(hProcess, NULL, TRUE); - // if (g_SymServerLookup) - //{ - // SymSetSearchPath(hProcess, ms_symsrv); - //} - - g_bSymEngInit = TRUE; - } -} - -// Cleans up the symbol engine if needed -void DeinitializeSymbolEngine(void) -{ - if (g_bSymEngInit) - { - SymCleanup((HANDLE)GetCurrentProcessId()); - g_bSymEngInit = FALSE; - } -} diff --git a/src/xrCore/Debug/StackTrace.h b/src/xrCore/Debug/StackTrace.h deleted file mode 100644 index 6e8a2eea1be..00000000000 --- a/src/xrCore/Debug/StackTrace.h +++ /dev/null @@ -1,77 +0,0 @@ -/*---------------------------------------------------------------------- -"Debugging Applications" (Microsoft Press) -Copyright (c) 1997-2000 John Robbins -- All rights reserved. -----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -/*////////////////////////////////////////////////////////////////////// -Type Definitions -//////////////////////////////////////////////////////////////////////*/ -// The type for the filter function called by the Crash Handler API. -typedef LONG(__stdcall* PFNCHFILTFN)(EXCEPTION_POINTERS* pExPtrs); - -/*////////////////////////////////////////////////////////////////////// -Crash Handler Function Definitions -//////////////////////////////////////////////////////////////////////*/ - -/*---------------------------------------------------------------------- -FUNCTION : GetFirstStackTraceString -GetNextStackTraceString -DISCUSSION : -These functions allow you to get the stack trace information for a -crash. Call GetFirstStackTraceString and then GetNextStackTraceString -to get the entire stack trace for a crash. -The options GSTSO_PARAMS, GSTSO_MODULE, GSTSO_SYMBOL, and -GSTSO_SRCLINE, appear in that order in the string. -PARAMETERS : -dwOpts - The options flags "Or" the following options together. -0 - Just put the PC address in the string. -GSTSO_PARAMS - Include the possible params. -GSTSO_MODULE - Include the module name as well. -GSTSO_SYMBOL - Include the symbol name of the stack -address. -GSTSO_SRCLINE - Include source and line info of the -stack address. -pExtPtrs - The exception pointers passed to the crash handler -function. -RETURNS : -!NULL - The requested stack trace string. -NULL - There was a problem. -----------------------------------------------------------------------*/ -#define GSTSO_PARAMS 0x01 -#define GSTSO_MODULE 0x02 -#define GSTSO_SYMBOL 0x04 -#define GSTSO_SRCLINE 0x08 -LPCTSTR __stdcall GetFirstStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs); -LPCTSTR __stdcall GetNextStackTraceString(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs); - -/*---------------------------------------------------------------------- -FUNCTION : GetFirstStackTraceStringVB -GetNextStackTraceStringVB -DISCUSSION : -The VB wrappers on GetFirstStackTraceString and -GetNextStackTraceString since VB cannot handle returning a string from -a DLL call. -PARAMETERS : -dwOpts - The options flags "Or" the following options together. -0 - Just put the PC address in the string. -GSTSO_PARAMS - Include the possible params. -GSTSO_MODULE - Include the module name as well. -GSTSO_SYMBOL - Include the symbol name the stack -address. -GSTSO_SRCLINE - Include source and line info for the -address. -pExtPtrs - The exception pointers passed to the crash handler -function. -szBuff - The output buffer. -uiSize - The size of the output buffer. -RETURNS : -TRUE - The string was copied into szBuff. -FALSE - There was a problem. -----------------------------------------------------------------------*/ -BOOL __stdcall GetFirstStackTraceStringVB(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs, LPTSTR szBuff, UINT uiSize); -BOOL __stdcall GetNextStackTraceStringVB(DWORD dwOpts, EXCEPTION_POINTERS* pExPtrs, LPTSTR szBuff, UINT uiSize); diff --git a/src/xrCore/Debug/SymbolEngine.h b/src/xrCore/Debug/SymbolEngine.h deleted file mode 100644 index 43ca6554cf7..00000000000 --- a/src/xrCore/Debug/SymbolEngine.h +++ /dev/null @@ -1,264 +0,0 @@ -/*---------------------------------------------------------------------- -"Debugging Applications" (Microsoft Press) -Copyright (c) 1997-2000 John Robbins -- All rights reserved. ------------------------------------------------------------------------- -This class is a paper-thin layer around the DBGHELP.DLL symbol engine. - -This class wraps only those functions that take the unique -HANDLE value. Other DBGHELP.DLL symbol engine functions are global in -scope, so I didn’t wrap them with this class. -----------------------------------------------------------------------*/ - -#pragma once - -#include -#include - -// Include these in case the user forgets to link against them. -#pragma comment(lib, "dbghelp.lib") -#pragma comment(lib, "version.lib") - -// The great Bugslayer idea of creating wrapper classes on structures -// that have size fields came from fellow MSJ columnist, Paul DiLascia. -// Thanks, Paul! - -// I didn’t wrap IMAGEHLP_SYMBOL because that is a variable-size -// structure. - -// The IMAGEHLP_MODULE wrapper class -struct CImageHlp_Module : public IMAGEHLP_MODULE -{ - CImageHlp_Module() - { - memset(this, NULL, sizeof(IMAGEHLP_MODULE)); - SizeOfStruct = sizeof(IMAGEHLP_MODULE); - } -}; - -// The IMAGEHLP_LINE wrapper class -struct CImageHlp_Line : public IMAGEHLP_LINE -{ - CImageHlp_Line() - { - memset(this, NULL, sizeof(IMAGEHLP_LINE)); - SizeOfStruct = sizeof(IMAGEHLP_LINE); - } -}; - -// The symbol engine class -class SymbolEngine -{ - /*---------------------------------------------------------------------- - Public Construction and Destruction - ----------------------------------------------------------------------*/ -public: - // To use this class, call the SymInitialize member function to - // initialize the symbol engine and then use the other member - // functions in place of their corresponding DBGHELP.DLL functions. - SymbolEngine(void) {} - virtual ~SymbolEngine(void) {} - /*---------------------------------------------------------------------- - Public Helper Information Functions - ----------------------------------------------------------------------*/ -public: - // Returns the file version of DBGHELP.DLL being used. - // To convert the return values into a readable format: - // wsprintf(szVer , - // _T("%d.%02d.%d.%d"), - // HIWORD(dwMS) , - // LOWORD(dwMS) , - // HIWORD(dwLS) , - // LOWORD(dwLS) ); - // szVer will contain a string like: 5.00.1878.1 - BOOL GetDbgHelpVersion(DWORD& dwMS, DWORD& dwLS) { return GetInMemoryFileVersion(_T("DBGHELP.DLL"), dwMS, dwLS); } - // Returns the file version of the PDB reading DLLs - BOOL GetPDBReaderVersion(DWORD& dwMS, DWORD& dwLS) - { - // First try MSDBI.DLL. - if (GetInMemoryFileVersion(_T("MSDBI.DLL"), dwMS, dwLS) == TRUE) - { - return TRUE; - } - else if (GetInMemoryFileVersion(_T("MSPDB60.DLL" ), dwMS, dwLS) == TRUE) - { - return TRUE; - } - // Just fall down to MSPDB50.DLL. - return GetInMemoryFileVersion(_T("MSPDB50.DLL"), dwMS, dwLS); - } - - // The worker function used by the previous two functions - BOOL GetInMemoryFileVersion(LPCTSTR szFile, DWORD& dwMS, DWORD& dwLS) - { - HMODULE hInstIH = GetModuleHandle(szFile); - - // Get the full filename of the loaded version. - TCHAR szImageHlp[MAX_PATH]; - GetModuleFileName(hInstIH, szImageHlp, MAX_PATH); - - dwMS = 0; - dwLS = 0; - - // Get the version information size. - DWORD dwVerInfoHandle; - DWORD dwVerSize; - - dwVerSize = GetFileVersionInfoSize(szImageHlp, &dwVerInfoHandle); - if (dwVerSize == 0) - return false; - - // Got the version size, now get the version information. - LPVOID lpData = (LPVOID) new TCHAR[dwVerSize]; - if (GetFileVersionInfo(szImageHlp, dwVerInfoHandle, dwVerSize, lpData) == false) - { - delete[] lpData; - return false; - } - - VS_FIXEDFILEINFO* lpVerInfo; - UINT uiLen; - BOOL bRet = VerQueryValue(lpData, _T("\\"), (LPVOID*)&lpVerInfo, &uiLen); - if (bRet) - { - dwMS = lpVerInfo->dwFileVersionMS; - dwLS = lpVerInfo->dwFileVersionLS; - } - - delete[] lpData; - return bRet; - } - - /*---------------------------------------------------------------------- - Public Initialization and Cleanup - ----------------------------------------------------------------------*/ -public: - BOOL SymInitialize(IN HANDLE hProcess, IN LPSTR UserSearchPath, IN BOOL fInvadeProcess) - { - m_hProcess = hProcess; - return ::SymInitialize(hProcess, UserSearchPath, fInvadeProcess); - } - - BOOL SymCleanup() { return ::SymCleanup(m_hProcess); } - /*---------------------------------------------------------------------- - Public Module Manipulation - ----------------------------------------------------------------------*/ -public: - BOOL SymEnumerateModules(IN PSYM_ENUMMODULES_CALLBACK EnumModulesCallback, IN PVOID UserContext) - { - return ::SymEnumerateModules(m_hProcess, EnumModulesCallback, UserContext); - } - - BOOL SymLoadModule(IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD BaseOfDll, IN DWORD SizeOfDll) - { - return ::SymLoadModule(m_hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll); - } - - BOOL EnumerateLoadedModules(IN PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback, IN PVOID UserContext) - { - return ::EnumerateLoadedModules(m_hProcess, EnumLoadedModulesCallback, UserContext); - } - - BOOL SymUnloadModule(IN DWORD BaseOfDll) { return ::SymUnloadModule(m_hProcess, BaseOfDll); } - BOOL SymGetModuleInfo(IN DWORD dwAddr, OUT PIMAGEHLP_MODULE ModuleInfo) - { - return ::SymGetModuleInfo(m_hProcess, dwAddr, ModuleInfo); - } - - DWORD SymGetModuleBase(IN DWORD dwAddr) { return ::SymGetModuleBase(m_hProcess, dwAddr); } - /*---------------------------------------------------------------------- - Public Symbol Manipulation - ----------------------------------------------------------------------*/ -public: - BOOL SymEnumerateSymbols(IN DWORD BaseOfDll, IN PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, IN PVOID UserContext) - { - return ::SymEnumerateSymbols(m_hProcess, BaseOfDll, EnumSymbolsCallback, UserContext); - } - - BOOL SymGetSymFromAddr(IN DWORD dwAddr, OUT PDWORD_PTR pdwDisplacement, OUT PIMAGEHLP_SYMBOL Symbol) - { - return ::SymGetSymFromAddr(m_hProcess, dwAddr, pdwDisplacement, Symbol); - } - - BOOL SymGetSymFromName(IN LPSTR Name, OUT PIMAGEHLP_SYMBOL Symbol) - { - return ::SymGetSymFromName(m_hProcess, Name, Symbol); - } - - BOOL SymGetSymNext(IN OUT PIMAGEHLP_SYMBOL Symbol) { return ::SymGetSymNext(m_hProcess, Symbol); } - BOOL SymGetSymPrev(IN OUT PIMAGEHLP_SYMBOL Symbol) { return ::SymGetSymPrev(m_hProcess, Symbol); } - /*---------------------------------------------------------------------- - Public Source Line Manipulation - ----------------------------------------------------------------------*/ -public: - BOOL SymGetLineFromAddr(IN DWORD dwAddr, OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE Line) - { -#ifdef DO_NOT_WORK_AROUND_SRCLINE_BUG - // Just pass along the values returned by the main function. - return ::SymGetLineFromAddr(m_hProcess, dwAddr, pdwDisplacement, Line); - -#else - // The problem is that the symbol engine finds only those source - // line addresses (after the first lookup) that fall exactly on - // a zero displacement. I’ll walk backward 100 bytes to - // find the line and return the proper displacement. - DWORD dwTempDis = 0; - while (::SymGetLineFromAddr(m_hProcess, dwAddr - dwTempDis, pdwDisplacement, Line) == false) - { - dwTempDis += 1; - if (100 == dwTempDis) - { - return FALSE; - } - } - // I found it and the source line information is correct, so - // change the displacement if I had to search backward to find - // the source line. - if (dwTempDis != 0) - { - *pdwDisplacement = dwTempDis; - } - return TRUE; -#endif // DO_NOT_WORK_AROUND_SRCLINE_BUG - } - - BOOL SymGetLineFromName(IN LPSTR ModuleName, IN LPSTR FileName, IN DWORD dwLineNumber, OUT PLONG plDisplacement, - IN OUT PIMAGEHLP_LINE Line) - { - return ::SymGetLineFromName(m_hProcess, ModuleName, FileName, dwLineNumber, plDisplacement, Line); - } - - BOOL SymGetLineNext(IN OUT PIMAGEHLP_LINE Line) { return ::SymGetLineNext(m_hProcess, Line); } - BOOL SymGetLinePrev(IN OUT PIMAGEHLP_LINE Line) { return ::SymGetLinePrev(m_hProcess, Line); } - BOOL SymMatchFileName(IN LPSTR FileName, IN LPSTR Match, OUT LPSTR* FileNameStop, OUT LPSTR* MatchStop) - { - return ::SymMatchFileName(FileName, Match, FileNameStop, MatchStop); - } - - /*---------------------------------------------------------------------- - Public Miscellaneous Members - ----------------------------------------------------------------------*/ -public: - LPVOID SymFunctionTableAccess(DWORD AddrBase) { return ::SymFunctionTableAccess(m_hProcess, AddrBase); } - BOOL SymGetSearchPath(OUT LPSTR SearchPath, IN DWORD SearchPathLength) - { - return ::SymGetSearchPath(m_hProcess, SearchPath, SearchPathLength); - } - - BOOL SymSetSearchPath(IN LPSTR SearchPath) { return ::SymSetSearchPath(m_hProcess, SearchPath); } -#ifdef XR_X64 - BOOL SymRegisterCallback(IN PSYMBOL_REGISTERED_CALLBACK CallbackFunction, IN ULONG64 UserContext) -#else - BOOL SymRegisterCallback(IN PSYMBOL_REGISTERED_CALLBACK CallbackFunction, IN PVOID UserContext) -#endif - { - return ::SymRegisterCallback(m_hProcess, CallbackFunction, UserContext); - } - /*---------------------------------------------------------------------- - Protected Data Members - ----------------------------------------------------------------------*/ -protected: - // The unique value that will be used for this instance of the - // symbol engine. This value doesn’t have to be an actual - // process value, just a unique value. - HANDLE m_hProcess; -}; diff --git a/src/xrCore/Threading/ScopeLock.h b/src/xrCore/Threading/ScopeLock.h new file mode 100644 index 00000000000..2594fc6ed57 --- /dev/null +++ b/src/xrCore/Threading/ScopeLock.h @@ -0,0 +1,27 @@ +#pragma once + +#include "Common/Noncopyable.hpp" +#include "Threading/Lock.hpp" +#include "xrDebug.h" + +class ScopeLock : Noncopyable +{ +public: + ScopeLock(Lock *SyncObject); + ~ScopeLock(); + +private: + Lock *syncObject; +}; + +ScopeLock::ScopeLock(Lock *SyncObject) : syncObject(SyncObject) +{ + VERIFY(syncObject); + + syncObject->Enter(); +} + +ScopeLock::~ScopeLock() +{ + syncObject->Leave(); +} diff --git a/src/xrCore/xrCore.vcxproj b/src/xrCore/xrCore.vcxproj index 9f12182d0f0..5fd13c37444 100644 --- a/src/xrCore/xrCore.vcxproj +++ b/src/xrCore/xrCore.vcxproj @@ -102,7 +102,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -117,7 +117,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -130,7 +130,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -145,7 +145,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -158,7 +158,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -173,7 +173,7 @@ _USRDLL;XRCORE_EXPORTS;CRYPTO_BUILD;%(PreprocessorDefinitions) - PowrProf.lib;%(AdditionalDependencies) + PowrProf.lib;DbgHelp.lib;%(AdditionalDependencies) for /r "$(xrSdkDir)binaries/$(PlatformShortName)" %%f in (*.dll *.pdb) do @xcopy /Q /D "%%f" "$(OutDir)" @@ -198,7 +198,6 @@ - @@ -315,8 +314,6 @@ CppHeader - - @@ -357,6 +354,7 @@ + diff --git a/src/xrCore/xrCore.vcxproj.filters b/src/xrCore/xrCore.vcxproj.filters index 8b01f1e0c20..2e16cbd915f 100644 --- a/src/xrCore/xrCore.vcxproj.filters +++ b/src/xrCore/xrCore.vcxproj.filters @@ -273,9 +273,6 @@ Debug core - - Debug core - XML @@ -629,12 +626,6 @@ Debug core - - Debug core - - - Debug core - Common @@ -677,6 +668,9 @@ Memory + + Threading + diff --git a/src/xrCore/xrDebug.cpp b/src/xrCore/xrDebug.cpp index 9719be7a91c..d9757633b57 100644 --- a/src/xrCore/xrDebug.cpp +++ b/src/xrCore/xrDebug.cpp @@ -4,10 +4,10 @@ #include "xrDebug.h" #include "os_clipboard.h" #include "Debug/dxerr.h" -#include "xrCore/Threading/Lock.hpp" +#include "Threading/ScopeLock.h" + #pragma warning(push) #pragma warning(disable : 4091) // 'typedef ': ignored on left of '' when no variable is declared -#include "Debug/StackTrace.h" #include "Debug/MiniDump.h" #pragma warning(pop) #include @@ -45,9 +45,16 @@ static BOOL bException = FALSE; #define USE_OWN_MINI_DUMP #endif +#if defined XR_X64 +# define MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64 +#elif defined XR_X86 +# define MACHINE_TYPE IMAGE_FILE_MACHINE_I386 +#else +# error CPU architecture is not supported. +#endif + namespace { - ICN void* GetInstructionPtr() { #ifdef _MSC_VER @@ -70,63 +77,185 @@ xrDebug::CrashHandler xrDebug::OnCrash = nullptr; xrDebug::DialogHandler xrDebug::OnDialog = nullptr; string_path xrDebug::BugReportFile; bool xrDebug::ErrorAfterDialog = false; -StackTraceInfo xrDebug::StackTrace = {}; -void xrDebug::SetBugReportFile(const char* fileName) { strcpy_s(BugReportFile, fileName); } -void xrDebug::LogStackTrace(const char* header) +bool xrDebug::symEngineInitialized = false; +Lock xrDebug::dbgHelpLock; + +void xrDebug::SetBugReportFile(const char *fileName) { strcpy_s(BugReportFile, fileName); } + +bool xrDebug::GetNextStackFrameString(LPSTACKFRAME stackFrame, PCONTEXT threadCtx, xr_string &frameStr) { - if (!shared_str_initialized) - return; - StackTrace.Count = BuildStackTrace(StackTrace.Frames, StackTrace.Capacity, StackTrace.LineCapacity); - Msg("%s", header); - for (size_t i = 1; i < StackTrace.Count; i++) - Msg("%s", StackTrace[i]); + BOOL result = StackWalk(MACHINE_TYPE, GetCurrentProcess(), GetCurrentThread(), stackFrame, threadCtx, nullptr, + SymFunctionTableAccess, SymGetModuleBase, nullptr); + + if (result == FALSE || stackFrame->AddrPC.Offset == 0) + { + return false; + } + + frameStr.clear(); + string512 formatBuff; + + /// + /// Module name + /// + HINSTANCE hModule = (HINSTANCE)SymGetModuleBase(GetCurrentProcess(), stackFrame->AddrPC.Offset); + if (hModule && GetModuleFileName(hModule, formatBuff, _countof(formatBuff))) + { + frameStr.append(formatBuff); + } + + /// + /// Address + /// + xr_sprintf(formatBuff, _countof(formatBuff), " at %p", stackFrame->AddrPC.Offset); + frameStr.append(formatBuff); + + /// + /// Function info + /// + BYTE arrSymBuffer[512]; + ZeroMemory(arrSymBuffer, sizeof(arrSymBuffer)); + PIMAGEHLP_SYMBOL functionInfo = reinterpret_cast(arrSymBuffer); + functionInfo->SizeOfStruct = sizeof(*functionInfo); + functionInfo->MaxNameLength = sizeof(arrSymBuffer) - sizeof(*functionInfo) + 1; + DWORD_PTR dwFunctionOffset; + + result = SymGetSymFromAddr(GetCurrentProcess(), stackFrame->AddrPC.Offset, &dwFunctionOffset, functionInfo); + + if (result) + { + if (dwFunctionOffset) + { + xr_sprintf(formatBuff, _countof(formatBuff), " %s() + %Iu byte(s)", functionInfo->Name, dwFunctionOffset); + } + else + { + xr_sprintf(formatBuff, _countof(formatBuff), " %s()", functionInfo->Name); + } + frameStr.append(formatBuff); + } + + /// + /// Source info + /// + DWORD dwLineOffset; + IMAGEHLP_LINE sourceInfo = {}; + sourceInfo.SizeOfStruct = sizeof(sourceInfo); + + result = SymGetLineFromAddr(GetCurrentProcess(), stackFrame->AddrPC.Offset, &dwLineOffset, &sourceInfo); + + if (result) + { + if (dwLineOffset) + { + xr_sprintf(formatBuff, _countof(formatBuff), " in %s line %u + %u byte(s)", sourceInfo.FileName, + sourceInfo.LineNumber, dwLineOffset); + } + else + { + xr_sprintf(formatBuff, _countof(formatBuff), " in %s line %u", sourceInfo.FileName, sourceInfo.LineNumber); + } + frameStr.append(formatBuff); + } + + return true; +} + +bool xrDebug::InitializeSymbolEngine() +{ + if (!symEngineInitialized) + { + DWORD dwOptions = SymGetOptions(); + SymSetOptions(dwOptions | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + + if (SymInitialize(GetCurrentProcess(), nullptr, TRUE)) + { + symEngineInitialized = true; + } + } + + return symEngineInitialized; } -size_t xrDebug::BuildStackTrace(char* buffer, size_t capacity, size_t lineCapacity) +void xrDebug::DeinitializeSymbolEngine(void) { - // XXX: add support for x86_64 - CONTEXT context; - EXCEPTION_POINTERS ex_ptrs; - void* ebp; - context.ContextFlags = CONTEXT_FULL; - if (GetThreadContext(GetCurrentThread(), &context)) + if (symEngineInitialized) { -#if defined(XR_X64) - context.Rip = (DWORD64)GetInstructionPtr(); - context.Rbp = (DWORD64)&ebp; - context.Rsp = (DWORD64)&context; -#elif defined(XR_X86) - context.Eip = (DWORD)GetInstructionPtr(); - context.Ebp = (DWORD)&ebp; - context.Esp = (DWORD)&context; + SymCleanup(GetCurrentProcess()); + + symEngineInitialized = false; + } +} + +xr_vector xrDebug::BuildStackTrace(PCONTEXT threadCtx, u16 maxFramesCount) +{ + ScopeLock Lock(&dbgHelpLock); + + SStringVec traceResult; + STACKFRAME stackFrame = {}; + xr_string frameStr; + + if (!InitializeSymbolEngine()) + { + Msg("[xrDebug::BuildStackTrace]InitializeSymbolEngine failed with error: %d", GetLastError()); + return traceResult; + } + + traceResult.reserve(maxFramesCount); + +#if defined XR_X64 + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrPC.Offset = threadCtx->Rip; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = threadCtx->Rsp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = threadCtx->Rbp; +#elif defined XR_X86 + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrPC.Offset = threadCtx->Eip; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = threadCtx->Esp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = threadCtx->Ebp; +#else +# error CPU architecture is not supported. #endif - ex_ptrs.ContextRecord = &context; - ex_ptrs.ExceptionRecord = 0; - return BuildStackTrace(&ex_ptrs, buffer, capacity, lineCapacity); + + while (GetNextStackFrameString(&stackFrame, threadCtx, frameStr) && traceResult.size() <= maxFramesCount) + { + traceResult.push_back(frameStr); } - return 0; + + DeinitializeSymbolEngine(); + + return traceResult; } -size_t xrDebug::BuildStackTrace(EXCEPTION_POINTERS* exPtrs, char* buffer, size_t capacity, size_t lineCapacity) +SStringVec xrDebug::BuildStackTrace(u16 maxFramesCount) { - memset(buffer, 0, capacity*lineCapacity); - auto flags = GSTSO_MODULE | GSTSO_SYMBOL | GSTSO_SRCLINE; - auto traceDump = GetFirstStackTraceString(flags, exPtrs); - int frameCount = 0; - while (traceDump) + CONTEXT currentThreadCtx = {}; + + RtlCaptureContext(¤tThreadCtx); /// GetThreadContext cann't be used on the current thread + currentThreadCtx.ContextFlags = CONTEXT_FULL; + + return BuildStackTrace(¤tThreadCtx, maxFramesCount); +} + +void xrDebug::LogStackTrace(const char *header) +{ + SStringVec stackTrace = BuildStackTrace(); + Msg("%s", header); + for (const auto &frame : stackTrace) { - lstrcpy(buffer + frameCount * lineCapacity, traceDump); - frameCount++; - traceDump = GetNextStackTraceString(flags, exPtrs); + Msg("%s", frame.c_str()); } - return frameCount; } -void xrDebug::GatherInfo(char* assertionInfo, const ErrorLocation& loc, const char* expr, const char* desc, - const char* arg1, const char* arg2) +void xrDebug::GatherInfo(char *assertionInfo, const ErrorLocation &loc, const char *expr, const char *desc, + const char *arg1, const char *arg2) { - char* buffer = assertionInfo; + char *buffer = assertionInfo; if (!expr) expr = ""; bool extendedDesc = desc && strchr(desc, '\n'); @@ -174,13 +303,13 @@ void xrDebug::GatherInfo(char* assertionInfo, const ErrorLocation& loc, const ch #ifdef USE_OWN_ERROR_MESSAGE_WINDOW buffer += sprintf(buffer, "stack trace:\n\n"); #endif // USE_OWN_ERROR_MESSAGE_WINDOW - BuildStackTrace(StackTrace.Frames, StackTrace.Capacity, StackTrace.LineCapacity); - for (size_t i = 2; i < StackTrace.Count; i++) + xr_vector stackTrace = BuildStackTrace(); + for (size_t i = 2; i < stackTrace.size(); i++) { if (shared_str_initialized) - Log(StackTrace[i]); + Log(stackTrace[i].c_str()); #ifdef USE_OWN_ERROR_MESSAGE_WINDOW - buffer += sprintf(buffer, "%s\n", StackTrace[i]); + buffer += sprintf(buffer, "%s\n", stackTrace[i].c_str()); #endif // USE_OWN_ERROR_MESSAGE_WINDOW } if (shared_str_initialized) @@ -188,7 +317,7 @@ void xrDebug::GatherInfo(char* assertionInfo, const ErrorLocation& loc, const ch os_clipboard::copy_to_clipboard(assertionInfo); } -void xrDebug::Fatal(const ErrorLocation& loc, const char* format, ...) +void xrDebug::Fatal(const ErrorLocation &loc, const char *format, ...) { string1024 desc; va_list args; @@ -199,14 +328,14 @@ void xrDebug::Fatal(const ErrorLocation& loc, const char* format, ...) Fail(ignoreAlways, loc, nullptr, "fatal error", desc); } -void xrDebug::Fail( - bool& ignoreAlways, const ErrorLocation& loc, const char* expr, long hresult, const char* arg1, const char* arg2) +void xrDebug::Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, long hresult, const char *arg1, + const char *arg2) { Fail(ignoreAlways, loc, expr, xrDebug::ErrorToString(hresult), arg1, arg2); } -void xrDebug::Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* expr, const char* desc, const char* arg1, - const char* arg2) +void xrDebug::Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, const char *desc, const char *arg1, + const char *arg2) { #ifdef PROFILE_CRITICAL_SECTIONS static Lock lock(MUTEX_PROFILE_ID(xrDebug::Backend)); @@ -263,13 +392,13 @@ void xrDebug::Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* exp lock.Leave(); } -void xrDebug::Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* expr, const std::string& desc, - const char* arg1, const char* arg2) +void xrDebug::Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, const std::string &desc, + const char *arg1, const char *arg2) { Fail(ignoreAlways, loc, expr, desc.c_str(), arg1, arg2); } -void xrDebug::DoExit(const std::string& message) +void xrDebug::DoExit(const std::string &message) { FlushLog(); MessageBox(NULL, message.c_str(), "Error", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); @@ -278,7 +407,7 @@ void xrDebug::DoExit(const std::string& message) LPCSTR xrDebug::ErrorToString(long code) { - const char* result = nullptr; + const char *result = nullptr; static string1024 descStorage; DXGetErrorDescription(code, descStorage, sizeof(descStorage)); if (!result) @@ -346,7 +475,7 @@ void WINAPI xrDebug::PreErrorHandler(INT_PTR) BT_SaveSnapshot(nullptr); } -void xrDebug::SetupExceptionHandler(const bool& dedicated) +void xrDebug::SetupExceptionHandler(const bool &dedicated) { // disable 'appname has stopped working' popup dialog UINT prevMode = SetErrorMode(SEM_NOGPFAULTERRORBOX); @@ -386,7 +515,7 @@ void xrDebug::SetupExceptionHandler(const bool& dedicated) #endif // USE_BUG_TRAP #ifdef USE_OWN_MINI_DUMP -void xrDebug::SaveMiniDump(EXCEPTION_POINTERS* exPtrs) +void xrDebug::SaveMiniDump(EXCEPTION_POINTERS *exPtrs) { string64 dateStr; timestamp(dateStr); @@ -407,7 +536,7 @@ void xrDebug::SaveMiniDump(EXCEPTION_POINTERS* exPtrs) } #endif -void xrDebug::FormatLastError(char* buffer, const size_t& bufferSize) +void xrDebug::FormatLastError(char *buffer, const size_t &bufferSize) { int lastErr = GetLastError(); if (lastErr == ERROR_SUCCESS) @@ -415,7 +544,7 @@ void xrDebug::FormatLastError(char* buffer, const size_t& bufferSize) *buffer = 0; return; } - void* msg = nullptr; + void *msg = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, lastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, nullptr); // XXX nitrocaster: check buffer overflow @@ -423,25 +552,25 @@ void xrDebug::FormatLastError(char* buffer, const size_t& bufferSize) LocalFree(msg); } -LONG WINAPI xrDebug::UnhandledFilter(EXCEPTION_POINTERS* exPtrs) +LONG WINAPI xrDebug::UnhandledFilter(EXCEPTION_POINTERS *exPtrs) { string256 errMsg; FormatLastError(errMsg, sizeof(errMsg)); if (!ErrorAfterDialog && !strstr(GetCommandLine(), "-no_call_stack_assert")) { CONTEXT save = *exPtrs->ContextRecord; - StackTrace.Count = BuildStackTrace(exPtrs, StackTrace.Frames, StackTrace.Capacity, StackTrace.LineCapacity); + xr_vector stackTrace = BuildStackTrace(exPtrs->ContextRecord, 1024); *exPtrs->ContextRecord = save; if (shared_str_initialized) Msg("stack trace:\n"); if (!IsDebuggerPresent()) os_clipboard::copy_to_clipboard("stack trace:\r\n\r\n"); string4096 buffer; - for (size_t i = 0; i < StackTrace.Count; i++) + for (size_t i = 0; i < stackTrace.size(); i++) { if (shared_str_initialized) - Log(StackTrace[i]); - sprintf(buffer, "%s\r\n", StackTrace[i]); + Log(stackTrace[i].c_str()); + sprintf(buffer, "%s\r\n", stackTrace[i].c_str()); #ifdef DEBUG if (!IsDebuggerPresent()) os_clipboard::update_clipboard(buffer); @@ -498,14 +627,14 @@ void _terminate() } #endif // USE_BUG_TRAP -static void handler_base(const char* reason) +static void handler_base(const char *reason) { bool ignoreAlways = false; xrDebug::Fail(ignoreAlways, DEBUG_INFO, nullptr, reason, nullptr, nullptr); } -static void invalid_parameter_handler( - const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t reserved) +static void invalid_parameter_handler(const wchar_t *expression, const wchar_t *function, const wchar_t *file, + unsigned int line, uintptr_t reserved) { bool ignoreAlways = false; string4096 mbExpression; @@ -544,7 +673,7 @@ void xrDebug::OnThreadSpawn() #ifdef USE_BUG_TRAP BT_SetTerminate(); #else -// std::set_terminate(_terminate); + // std::set_terminate(_terminate); #endif _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); signal(SIGABRT, abort_handler); @@ -562,7 +691,7 @@ void xrDebug::OnThreadSpawn() #endif } -void xrDebug::Initialize(const bool& dedicated) +void xrDebug::Initialize(const bool &dedicated) { *BugReportFile = 0; OnThreadSpawn(); diff --git a/src/xrCore/xrDebug.h b/src/xrCore/xrDebug.h index 89fe84483b0..7dbdb9de4d5 100644 --- a/src/xrCore/xrDebug.h +++ b/src/xrCore/xrDebug.h @@ -1,16 +1,15 @@ #pragma once #include "xrCore/_types.h" -#include +#include "xrCommon/xr_string.h" +#include "xrCommon/xr_vector.h" +#include "Threading/Lock.hpp" -struct StackTraceInfo -{ - static const size_t Capacity = 100; - static const size_t LineCapacity = 256; - char Frames[Capacity * LineCapacity]; - size_t Count; +#include - char* operator[](size_t i) { return Frames + i * LineCapacity; } -}; +#pragma warning(push) +#pragma warning(disable : 4091) /// 'typedef ': ignored on left of '' when no variable is declared +#include +#pragma warning(pop) class ErrorLocation { @@ -19,14 +18,14 @@ class ErrorLocation int Line = -1; const char* Function = nullptr; - ErrorLocation(const char* file, int line, const char* function) + ErrorLocation(const char* file, int line, const char *function) { File = file; Line = line; Function = function; } - ErrorLocation& operator=(const ErrorLocation& rhs) + ErrorLocation& operator=(const ErrorLocation &rhs) { File = rhs.File; Line = rhs.Line; @@ -38,10 +37,10 @@ class ErrorLocation class XRCORE_API xrDebug { public: - using OutOfMemoryCallbackFunc = void (*)(); - using CrashHandler = void (*)(); - using DialogHandler = void (*)(bool); - using UnhandledExceptionFilter = LONG(WINAPI*)(EXCEPTION_POINTERS* exPtrs); + using OutOfMemoryCallbackFunc = void(*)(); + using CrashHandler = void(*)(); + using DialogHandler = void(*)(bool); + using UnhandledExceptionFilter = LONG(WINAPI*)(EXCEPTION_POINTERS *exPtrs); private: static UnhandledExceptionFilter PrevFilter; @@ -50,7 +49,6 @@ class XRCORE_API xrDebug static DialogHandler OnDialog; static string_path BugReportFile; static bool ErrorAfterDialog; - static StackTraceInfo StackTrace; public: xrDebug() = delete; @@ -64,31 +62,36 @@ class XRCORE_API xrDebug static DialogHandler GetDialogHandler() { return OnDialog; } static void SetDialogHandler(DialogHandler handler) { OnDialog = handler; } static const char* ErrorToString(long code); - static void SetBugReportFile(const char* fileName); - static void LogStackTrace(const char* header); - static size_t BuildStackTrace(char* buffer, size_t capacity, size_t lineCapacity); - static void GatherInfo(char* assertionInfo, const ErrorLocation& loc, const char* expr, const char* desc, - const char* arg1 = nullptr, const char* arg2 = nullptr); - static void Fatal(const ErrorLocation& loc, const char* format, ...); - static void Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* expr, long hresult, - const char* arg1 = nullptr, const char* arg2 = nullptr); - static void Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* expr, - const char* desc = "assertion failed", const char* arg1 = nullptr, const char* arg2 = nullptr); - static void Fail(bool& ignoreAlways, const ErrorLocation& loc, const char* expr, const std::string& desc, - const char* arg1 = nullptr, const char* arg2 = nullptr); - static void DoExit(const std::string& message); + static void SetBugReportFile(const char *fileName); + static void GatherInfo(char *assertionInfo, const ErrorLocation &loc, const char *expr, const char *desc, + const char *arg1 = nullptr, const char *arg2 = nullptr); + static void Fatal(const ErrorLocation &loc, const char *format, ...); + static void Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, long hresult, + const char *arg1 = nullptr, const char *arg2 = nullptr); + static void Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, + const char *desc = "assertion failed", const char *arg1 = nullptr, const char *arg2 = nullptr); + static void Fail(bool &ignoreAlways, const ErrorLocation &loc, const char *expr, const std::string &desc, + const char *arg1 = nullptr, const char *arg2 = nullptr); + static void DoExit(const std::string &message); + static void LogStackTrace(const char *header); + static xr_vector BuildStackTrace(u16 maxFramesCount = 512); private: - static void FormatLastError(char* buffer, const size_t& bufferSize); - static size_t BuildStackTrace(EXCEPTION_POINTERS* exPtrs, char* buffer, size_t capacity, size_t lineCapacity); - static void SetupExceptionHandler(const bool& dedicated); - static LONG WINAPI UnhandledFilter(EXCEPTION_POINTERS* exPtrs); + static bool symEngineInitialized; + static Lock dbgHelpLock; + static void FormatLastError(char *buffer, const size_t &bufferSize); + static void SetupExceptionHandler(const bool &dedicated); + static LONG WINAPI UnhandledFilter(EXCEPTION_POINTERS *exPtrs); static void WINAPI PreErrorHandler(INT_PTR); - static void SaveMiniDump(EXCEPTION_POINTERS* exPtrs); + static void SaveMiniDump(EXCEPTION_POINTERS *exPtrs); + static xr_vector BuildStackTrace(PCONTEXT threadCtx, u16 maxFramesCount); + static bool GetNextStackFrameString(LPSTACKFRAME stackFrame, PCONTEXT threadCtx, xr_string &frameStr); + static bool InitializeSymbolEngine(); + static void DeinitializeSymbolEngine(void); }; // for debug purposes only -inline std::string make_string(const char* format, ...) +inline std::string make_string(const char *format, ...) { va_list args; va_start(args, format);