Skip to content

Instantly share code, notes, and snippets.

@thennequin
Last active May 2, 2018 13:38
Show Gist options
  • Save thennequin/82482546483aa7fa7661 to your computer and use it in GitHub Desktop.
Save thennequin/82482546483aa7fa7661 to your computer and use it in GitHub Desktop.
StackWatcher for Windows
#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;
}
}
#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