Last active
May 2, 2018 13:38
-
-
Save thennequin/82482546483aa7fa7661 to your computer and use it in GitHub Desktop.
StackWatcher for Windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
#include <dbghelp.h> | |
#include <stdlib.h> | |
#pragma comment(lib, "dbghelp.lib") // for "VerQueryValue" | |
#pragma comment(lib, "version.lib") // for "VerQueryValue" | |
#pragma warning(disable:4826) | |
#pragma warning(disable:4127) | |
#include "StackWatcher.h" | |
namespace StackWatcher | |
{ | |
static const uint16 c_BufferSize = 16384; | |
static char s_sBuffer[c_BufferSize]; | |
void Init() | |
{ | |
DWORD symOptions = SymGetOptions(); | |
//symOptions |= SYMOPT_DEBUG; | |
symOptions |= SYMOPT_LOAD_LINES; | |
//symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; | |
symOptions |= SYMOPT_DEFERRED_LOADS; | |
SymSetOptions( symOptions ); | |
if ((SymInitialize( | |
GetCurrentProcess(), | |
NULL, | |
TRUE)) == FALSE) | |
{ | |
printf("SymInitialize returned error : %X\n", GetLastError()); | |
//return FALSE; | |
//DebugBreak(); | |
} | |
} | |
void get( CallStackFrame* pFrame, uint16 iSkip, void* pContext ) | |
{ | |
uint16 iMaxDepth = SW_CALLSTACK_MAX_DEPTH; | |
pFrame->m_iStackSize = 0; | |
memset(&pFrame->m_iStackAddr, 0, sizeof(uint32) * iMaxDepth); | |
addrint* pCurrentAddr; | |
int index = -iSkip; // Ignore first stacks entries | |
CONTEXT oContext; | |
if (pContext == NULL) | |
{ | |
RtlCaptureContext(&oContext); | |
pContext = &oContext; | |
} | |
DWORD iMachineType; | |
STACKFRAME64 oFrame; | |
ZeroMemory(&oFrame, sizeof(oFrame)); | |
oFrame.AddrPC.Mode = AddrModeFlat; | |
oFrame.AddrFrame.Mode = AddrModeFlat; | |
oFrame.AddrStack.Mode = AddrModeFlat; | |
#ifdef _M_X64 | |
oFrame.AddrPC.Offset = pContext->Rip; | |
oFrame.AddrFrame.Offset = pContext->Rbp; | |
oFrame.AddrStack.Offset = pContext->Rsp; | |
iMachineType = IMAGE_FILE_MACHINE_AMD64; | |
#else | |
oFrame.AddrPC.Offset = pContext->Eip; | |
oFrame.AddrPC.Offset = pContext->Ebp; | |
oFrame.AddrPC.Offset = pContext->Esp; | |
iMachineType = IMAGE_FILE_MACHINE_I386; | |
#endif | |
while(index < iMaxDepth) | |
{ | |
if (StackWalk64(iMachineType, | |
GetCurrentProcess(), | |
GetCurrentThread(), | |
&oFrame, | |
pContext, | |
NULL, | |
SymFunctionTableAccess64, | |
SymGetModuleBase64, | |
NULL)) | |
{ | |
if (index >= 0) | |
{ | |
pFrame->m_iStackAddr[index] = oFrame.AddrPC.Offset; | |
} | |
++index; | |
} | |
else | |
{ | |
break; | |
} | |
} | |
pFrame->m_iStackSize = index; | |
} | |
struct SYMBOL_INFOW_NAME : SYMBOL_INFOW | |
{ | |
char _name[512]; | |
}; | |
struct IMAGEHLP_LINE_NAME : IMAGEHLP_LINE | |
{ | |
char _name[512]; | |
}; | |
const char* getReadableCallStackFromFrame( CallStackFrame& oFrame ) | |
{ | |
strcpy_s(s_sBuffer, c_BufferSize, ""); | |
char sTmp[4096]; | |
char sSymbolName[1024]; | |
char sModuleName[1024]; | |
DWORD displacement = 0; | |
DWORD64 displacement64 = 0; | |
HANDLE process = GetCurrentProcess(); | |
for (int i=0; i < oFrame.m_iStackSize && oFrame.m_iStackAddr[i] != 0; ++i) | |
{ | |
DWORD64 addr = ( DWORD64 )( oFrame.m_iStackAddr[i] ); | |
addr = ( DWORD64 )( oFrame.m_iStackAddr[i] ); | |
SYMBOL_INFOW_NAME symbol; | |
symbol.MaxNameLen = 512; | |
symbol.SizeOfStruct = sizeof(SYMBOL_INFOW); | |
if (SymFromAddrW( process, addr , &displacement64, (PSYMBOL_INFOW)&symbol)) | |
{ | |
wcstombs( sSymbolName, symbol.Name, 1024 ); | |
}else{ | |
strcpy_s( sSymbolName, 1024, "?" ); | |
} | |
IMAGEHLP_MODULE64 moduleInfo ; | |
moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); | |
if (SymGetModuleInfo64( process, addr, &moduleInfo )) | |
{ | |
//wcstombs( sModuleName, moduleInfo.ModuleName, 1024 ); | |
strcpy_s( sModuleName, 1024, moduleInfo.ModuleName ); | |
}else{ | |
strcpy_s( sModuleName, 1024, "?" ); | |
} | |
IMAGEHLP_LINE_NAME line; | |
line.SizeOfStruct = sizeof(IMAGEHLP_LINE_NAME); | |
if ( SymGetLineFromAddr( process, addr, &displacement, &line ) ) | |
{ | |
sprintf_s(sTmp, 4096, " %s(%i) : (0x%08x) %s!%s\n", line.FileName, line.LineNumber, (DWORD32)addr, sModuleName, sSymbolName); | |
}else{ | |
sprintf_s(sTmp, 4096, " (0x%08x) %s!%s\n", (DWORD32)addr, sModuleName, sSymbolName); | |
} | |
strcat_s(s_sBuffer, c_BufferSize, sTmp); | |
} | |
strcat_s(s_sBuffer, c_BufferSize, "\n"); | |
return s_sBuffer; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#define SW_CALLSTACK_MAX_DEPTH 32 | |
namespace StackWatcher | |
{ | |
typedef unsigned __int16 uint16; | |
typedef unsigned __int32 uint32; | |
#ifdef __WIN64__ | |
typedef unsigned __int64 addrint; | |
#else | |
typedef unsigned __int32 addrint; | |
#endif | |
struct CallStackFrame | |
{ | |
uint16 m_iStackSize; | |
addrint m_iStackAddr[SW_CALLSTACK_MAX_DEPTH]; | |
}; | |
void Init(); | |
void get( CallStackFrame* pFrame, uint16 iSkip = 0, void* pContext ); | |
const char* getReadableCallStackFromFrame( CallStackFrame& oFrame ); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment