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 @@ ...@@ -97,6 +97,9 @@
crashFile.open(crashName.toLatin1(),std::ios::out | std::ios::app); crashFile.open(crashName.toLatin1(),std::ios::out | std::ios::app);
crashFile << szText; crashFile << szText;
crashFile.close(); crashFile.close();
// Write crash dump to console as well
StackWalker::OnOutput(szText);
} }
}; };
#endif #endif
......
/********************************************************************** /**********************************************************************
* *
* StackWalker.cpp * StackWalker.cpp
* http://stackwalker.codeplex.com/ * https://github.com/JochenKalmbach/StackWalker
*
* Old location: http://stackwalker.codeplex.com/
* *
* *
* History: * History:
...@@ -239,15 +241,9 @@ DWORD64 ...@@ -239,15 +241,9 @@ DWORD64
static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
{ {
if (strlen(szSrc) < nMaxDestSize) if (nMaxDestSize <= 0) return;
{ strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
strcpy_s(szDest, nMaxDestSize, szSrc); 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!)
}
else
{
strncpy_s(szDest, nMaxDestSize, szSrc, nMaxDestSize);
szDest[nMaxDestSize-1] = 0;
}
} // MyStrCpy } // MyStrCpy
// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') // Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
...@@ -662,7 +658,7 @@ private: ...@@ -662,7 +658,7 @@ private:
return FALSE; return FALSE;
} }
hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE)); hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
tt = (char*) malloc(sizeof(char) * TTBUFLEN); tt = (char*) malloc(sizeof(char) * TTBUFLEN);
tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
...@@ -680,10 +676,10 @@ private: ...@@ -680,10 +676,10 @@ private:
goto cleanup; goto cleanup;
} }
for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ ) for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ )
{ {
// base address, size // base address, size
pGMI(hProcess, hMods[i], &mi, sizeof mi ); pGMI(hProcess, hMods[i], &mi, sizeof(mi));
// image file name // image file name
tt[0] = 0; tt[0] = 0;
pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
...@@ -824,7 +820,7 @@ public: ...@@ -824,7 +820,7 @@ public:
static bool s_useV3Version = true; static bool s_useV3Version = true;
if (s_useV3Version) 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... // only copy as much memory as is reserved...
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
...@@ -838,7 +834,7 @@ public: ...@@ -838,7 +834,7 @@ public:
// could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
memcpy(pData, pModuleInfo, 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... // only copy as much memory as is reserved...
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
...@@ -1038,15 +1034,26 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro ...@@ -1038,15 +1034,26 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro
if (context == NULL) if (context == NULL)
{ {
// If no context is provided, capture the context // 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()) 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 else
{ {
SuspendThread(hThread); SuspendThread(hThread);
memset(&c, 0, sizeof(CONTEXT)); memset(&c, 0, sizeof(CONTEXT));
c.ContextFlags = USED_CONTEXT_FLAGS; 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) if (GetThreadContext(hThread, &c) == FALSE)
{ {
ResumeThread(hThread); ResumeThread(hThread);
...@@ -1204,7 +1211,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro ...@@ -1204,7 +1211,7 @@ BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadPro
csEntry.symTypeString = "Virtual"; csEntry.symTypeString = "Virtual";
break; break;
default: default:
//_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType ); //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );
csEntry.symTypeString = NULL; csEntry.symTypeString = NULL;
break; break;
} }
...@@ -1271,22 +1278,31 @@ BOOL __stdcall StackWalker::myReadProcMem( ...@@ -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) void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
{ {
CHAR buffer[STACKWALK_MAX_NAMELEN]; CHAR buffer[STACKWALK_MAX_NAMELEN];
size_t maxLen = STACKWALK_MAX_NAMELEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
if (fileVersion == 0) 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 else
{ {
DWORD v4 = (DWORD) (fileVersion & 0xFFFF); DWORD v4 = (DWORD) (fileVersion & 0xFFFF);
DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF); DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF);
DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF); DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF);
DWORD v1 = (DWORD) ((fileVersion>>48) & 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); OnOutput(buffer);
} }
void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
{ {
CHAR buffer[STACKWALK_MAX_NAMELEN]; 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 ( (eType != lastEntry) && (entry.offset != 0) )
{ {
if (entry.name[0] == 0) if (entry.name[0] == 0)
...@@ -1300,10 +1316,10 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent ...@@ -1300,10 +1316,10 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent
MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
if (entry.moduleName[0] == 0) if (entry.moduleName[0] == 0)
MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); 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 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; buffer[STACKWALK_MAX_NAMELEN-1] = 0;
OnOutput(buffer); OnOutput(buffer);
} }
...@@ -1312,14 +1328,24 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent ...@@ -1312,14 +1328,24 @@ void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &ent
void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
{ {
CHAR buffer[STACKWALK_MAX_NAMELEN]; 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); OnOutput(buffer);
} }
void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
{ {
CHAR buffer[STACKWALK_MAX_NAMELEN]; 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); OnOutput(buffer);
// Also display the OS-version // Also display the OS-version
#if _MSC_VER <= 1200 #if _MSC_VER <= 1200
...@@ -1328,22 +1354,31 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser ...@@ -1328,22 +1354,31 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser
ver.dwOSVersionInfoSize = sizeof(ver); ver.dwOSVersionInfoSize = sizeof(ver);
if (GetVersionExA(&ver) != FALSE) 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.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion); ver.szCSDVersion);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer); OnOutput(buffer);
} }
#else #else
OSVERSIONINFOEXA ver; OSVERSIONINFOEXA ver;
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
ver.dwOSVersionInfoSize = sizeof(ver); ver.dwOSVersionInfoSize = sizeof(ver);
#if _MSC_VER >= 1900
#pragma warning(push)
#pragma warning(disable: 4996)
#endif
if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) 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.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
OnOutput(buffer); OnOutput(buffer);
} }
#if _MSC_VER >= 1900
#pragma warning(pop)
#endif
#endif #endif
} }
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#include <windows.h> #include <windows.h>
#if _MSC_VER >= 1900
#pragma warning(disable : 4091)
#endif
// special defines for VC5/6 (if no actual PSDK is installed): // special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300 #if _MSC_VER < 1300
typedef unsigned __int64 DWORD64, *PDWORD64; typedef unsigned __int64 DWORD64, *PDWORD64;
...@@ -51,10 +55,6 @@ typedef unsigned long SIZE_T, *PSIZE_T; ...@@ -51,10 +55,6 @@ typedef unsigned long SIZE_T, *PSIZE_T;
class StackWalkerInternal; // forward class StackWalkerInternal; // forward
class StackWalker class StackWalker
{ {
private:
// copy ops are private to prevent copying
StackWalker(const StackWalker&); // no implementation
StackWalker& operator=(const StackWalker&); // no implementation
public: public:
typedef enum StackWalkOptions typedef enum StackWalkOptions
{ {
...@@ -181,7 +181,7 @@ protected: ...@@ -181,7 +181,7 @@ protected:
#ifdef CURRENT_THREAD_VIA_EXCEPTION #ifdef CURRENT_THREAD_VIA_EXCEPTION
// TODO: The following is not a "good" implementation, // TODO: The following is not a "good" implementation,
// because the callstack is only valid in the "__except" block... // 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 { \ do { \
memset(&c, 0, sizeof(CONTEXT)); \ memset(&c, 0, sizeof(CONTEXT)); \
EXCEPTION_POINTERS *pExp = NULL; \ EXCEPTION_POINTERS *pExp = NULL; \
...@@ -194,7 +194,7 @@ protected: ...@@ -194,7 +194,7 @@ protected:
} while(0); } while(0);
#else #else
// The following should be enough for walking the callstack... // The following should be enough for walking the callstack...
#define GET_CURRENT_CONTEXT(c, contextFlags) \ #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do { \ do { \
memset(&c, 0, sizeof(CONTEXT)); \ memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \ c.ContextFlags = contextFlags; \
...@@ -209,7 +209,7 @@ protected: ...@@ -209,7 +209,7 @@ protected:
#else #else
// The following is defined for x86 (XP and higher), x64 and IA64: // 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 { \ do { \
memset(&c, 0, sizeof(CONTEXT)); \ memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \ 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