Commit 67711d01 authored by Jan Möbius's avatar Jan Möbius

- Updated Stackwalker

- Log to Crashdump file and console for StackWalker
parent ef806d5b
......@@ -97,6 +97,9 @@
crashFile.open(crashName.toLatin1(),std::ios::out | std::ios::app);
crashFile << szText;
crashFile.close();
// Write crash dump to console as well
StackWalker::OnOutput(szText);
}
};
#endif
......
/**********************************************************************
*
* StackWalker.cpp
* http://stackwalker.codeplex.com/
* https://github.com/JochenKalmbach/StackWalker
*
* Old location: http://stackwalker.codeplex.com/
*
*
* History:
......@@ -239,15 +241,9 @@ DWORD64
static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
{
if (strlen(szSrc) < nMaxDestSize)
{
strcpy_s(szDest, nMaxDestSize, szSrc);
}
else
{
strncpy_s(szDest, nMaxDestSize, szSrc, nMaxDestSize);
szDest[nMaxDestSize-1] = 0;
}
if (nMaxDestSize <= 0) return;
strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
szDest[nMaxDestSize-1] = 0; // INFO: _TRUNCATE will ensure that it is nul-terminated; but with older compilers (<1400) it uses "strncpy" and this does not!)
} // MyStrCpy
// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
......@@ -662,7 +658,7 @@ private:
return FALSE;
}
hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
tt = (char*) malloc(sizeof(char) * TTBUFLEN);
tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
......@@ -680,10 +676,10 @@ private:
goto cleanup;
}
for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )
for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ )
{
// base address, size
pGMI(hProcess, hMods[i], &mi, sizeof mi );
pGMI(hProcess, hMods[i], &mi, sizeof(mi));
// image file name
tt[0] = 0;
pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
......@@ -824,7 +820,7 @@ public:
static bool s_useV3Version = true;
if (s_useV3Version)
{
if (this->pSGMI(hProcess, baseAddr, reinterpret_cast<IMAGEHLP_MODULE64_V3*>(pData) ) != FALSE)
if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
{
// only copy as much memory as is reserved...
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
......@@ -838,7 +834,7 @@ public:
// could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
if (this->pSGMI(hProcess, baseAddr, reinterpret_cast<IMAGEHLP_MODULE64_V3*>(pData) ) != FALSE)
if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
{
// only copy as much memory as is reserved...
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
......@@ -1038,15 +1034,26 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro
if (context == NULL)
{
// If no context is provided, capture the context
// See: https://stackwalker.codeplex.com/discussions/446958
#if _WIN32_WINNT <= 0x0501
// If we need to support XP, we need to use the "old way", because "GetThreadId" is not available!
if (hThread == GetCurrentThread())
#else
if (GetThreadId(hThread) == GetCurrentThreadId())
#endif
{
GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);
GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
}
else
{
SuspendThread(hThread);
memset(&c, 0, sizeof(CONTEXT));
c.ContextFlags = USED_CONTEXT_FLAGS;
// TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture...
// This does only work if we are x64 and the target process is x64 or x86;
// It cannnot work, if this process is x64 and the target process is x64... this is not supported...
// See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html
if (GetThreadContext(hThread, &c) == FALSE)
{
ResumeThread(hThread);
......@@ -1204,7 +1211,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro
csEntry.symTypeString = "Virtual";
break;
default:
//_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
//_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );
csEntry.symTypeString = NULL;
break;
}
......@@ -1271,22 +1278,31 @@ BOOL __stdcall StackWalker::myReadProcMem(
void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
size_t maxLen = STACKWALK_MAX_NAMELEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
if (fileVersion == 0)
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);
_snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID)baseAddr, size, result, symType, pdbName);
else
{
DWORD v4 = (DWORD) (fileVersion & 0xFFFF);
DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF);
DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF);
DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF);
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
_snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
}
buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NUL terminated
OnOutput(buffer);
}
void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
size_t maxLen = STACKWALK_MAX_NAMELEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
if ( (eType != lastEntry) && (entry.offset != 0) )
{
if (entry.name[0] == 0)
......@@ -1300,10 +1316,10 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent
MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
if (entry.moduleName[0] == 0)
MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
_snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
}
else
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
_snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
buffer[STACKWALK_MAX_NAMELEN-1] = 0;
OnOutput(buffer);
}
......@@ -1312,14 +1328,24 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent
void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
size_t maxLen = STACKWALK_MAX_NAMELEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
_snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer);
}
void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
size_t maxLen = STACKWALK_MAX_NAMELEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
_snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer);
// Also display the OS-version
#if _MSC_VER <= 1200
......@@ -1328,22 +1354,31 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser
ver.dwOSVersionInfoSize = sizeof(ver);
if (GetVersionExA(&ver) != FALSE)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer);
}
#else
OSVERSIONINFOEXA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
ver.dwOSVersionInfoSize = sizeof(ver);
#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable: 4996)
#endif
if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
{
_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer);
}
#if _MSC_VER >= 1900
#pragma warning(pop)
#endif
#endif
}
......
......@@ -38,6 +38,10 @@
#include <windows.h>
#if _MSC_VER >= 1900
#pragma warning(disable : 4091)
#endif
// special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300
typedef unsigned __int64 DWORD64, *PDWORD64;
......@@ -51,10 +55,6 @@ typedef unsigned long SIZE_T, *PSIZE_T;
class StackWalkerInternal; // forward
class StackWalker
{
private:
// copy ops are private to prevent copying
StackWalker(const StackWalker&); // no implementation
StackWalker& operator=(const StackWalker&); // no implementation
public:
typedef enum StackWalkOptions
{
......@@ -181,7 +181,7 @@ protected:
#ifdef CURRENT_THREAD_VIA_EXCEPTION
// TODO: The following is not a "good" implementation,
// because the callstack is only valid in the "__except" block...
#define GET_CURRENT_CONTEXT(c, contextFlags) \
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
EXCEPTION_POINTERS *pExp = NULL; \
......@@ -194,7 +194,7 @@ protected:
} while(0);
#else
// The following should be enough for walking the callstack...
#define GET_CURRENT_CONTEXT(c, contextFlags) \
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
......@@ -209,7 +209,7 @@ protected:
#else
// The following is defined for x86 (XP and higher), x64 and IA64:
#define GET_CURRENT_CONTEXT(c, contextFlags) \
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment