/* ====================================================================
* Copyright (c) 2003-2006, Martin Hauner
* http://subcommander.tigris.org
*
* Subcommander is licensed as described in the file doc/COPYING, which
* you should have received as part of this distribution.
* ====================================================================
*/
// sc
#include "Stackwalk.h"
// sys
#include <dbghelp.h>
///////////////////////////////////////////////////////////////////////
// a few helper
template<typename T> static void clear( T &t )
{
memset( &t, 0, sizeof(T) );
}
const long SyminfoSizeName = 256;
typedef struct _SW_SYMBOL_INFO : IMAGEHLP_SYMBOL64
{
char _name[SyminfoSizeName];
} SW_SYMBOL_INFO;
static void init( SW_SYMBOL_INFO &si, DWORD64 addr )
{
clear(si);
si.Address = addr;
si.SizeOfStruct = sizeof(SW_SYMBOL_INFO);
si.MaxNameLength = SyminfoSizeName;
}
static void init( IMAGEHLP_MODULE64& mi )
{
clear(mi);
mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
}
static void init( IMAGEHLP_LINE64& li )
{
clear(li);
li.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
}
static void init( STACKFRAME64& sf, CONTEXT& c )
{
clear(sf);
// x86
sf.AddrPC.Offset = c.Eip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrFrame.Offset = c.Ebp;
sf.AddrFrame.Mode = AddrModeFlat;
sf.AddrStack.Offset = c.Esp;
sf.AddrStack.Mode = AddrModeFlat;
}
static BOOL CALLBACK ReadProcessMemoryProc( HANDLE hProcess, DWORD64 lpBaseAddress,
PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead )
{
return ReadProcessMemory( GetCurrentProcess(), (LPCVOID)lpBaseAddress, lpBuffer,
nSize, lpNumberOfBytesRead );
}
static bool StackWalk( STACKFRAME64* sf, CONTEXT* c )
{
return StackWalk64( IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
sf, c, ReadProcessMemoryProc, SymFunctionTableAccess64, SymGetModuleBase64, 0 )
== TRUE;
}
static bool GetSymFromAddr( DWORD64 addr, SW_SYMBOL_INFO &si, DWORD64 *disp )
{
return SymGetSymFromAddr64( GetCurrentProcess(), addr, disp, (PIMAGEHLP_SYMBOL64)&si )
== TRUE;
}
static bool GetModuleFromAddr( DWORD64 addr, IMAGEHLP_MODULE64& mi )
{
DWORD64 baseAddr = SymGetModuleBase64( GetCurrentProcess(), addr );
return SymGetModuleInfo64( GetCurrentProcess(), baseAddr, &mi ) == TRUE;
}
static bool GetLineFromAddr( DWORD64 addr, IMAGEHLP_LINE64 &li, DWORD *disp )
{
return SymGetLineFromAddr64( GetCurrentProcess(), addr, disp, &li ) == TRUE;
}
///////////////////////////////////////////////////////////////////////
Stackwalk::Stackwalk( EXCEPTION_POINTERS* pExp ) : _exp(pExp)
{
}
void Stackwalk::walk()
{
try
{
STACKFRAME64 csf; // current stack frame
CONTEXT ctxt = *_exp->ContextRecord; // copy the context
// initialize the current stackframe.
init( csf, ctxt );
// walk the stack...
bool success = true;
while(success)
{
success = StackWalk( &csf, &ctxt );
if( success )
{
Stackframe frame;
frame._addr = csf.AddrPC.Offset;
frame._addrSeg = ctxt.SegCs;
fillModuleInfo( frame );
fillSymbolInfo( frame );
fillLineInfo( frame );
_frames.push_back(frame);
}
}
}
catch(...)
{
Stackframe frame;
frame._error = true;
_frames.push_back(frame);
}
}
const Stackframes& Stackwalk::getFrames() const
{
return _frames;
}
void Stackwalk::fillLineInfo( Stackframe& f )
{
IMAGEHLP_LINE64 li;
init(li);
DWORD dispLine = 0;
bool b = GetLineFromAddr( f._addr, li, &dispLine );
if( b )
{
f._line = true;
f._fileName = li.FileName;
f._lineNr = li.LineNumber;
f._lineDisp = dispLine;
}
else
{
f._line = false;
}
}
void Stackwalk::fillModuleInfo( Stackframe& f )
{
IMAGEHLP_MODULE64 mi;
init(mi);
bool b = GetModuleFromAddr( f._addr, mi );
if( b )
{
f._module = true;
f._moduleName = mi.ModuleName;
}
else
{
f._module = false;
}
}
void Stackwalk::fillSymbolInfo( Stackframe& f )
{
SW_SYMBOL_INFO si;
init(si,f._addr);
DWORD64 disp = 0;
bool b = GetSymFromAddr( f._addr, si, &disp );
if( b )
{
f._symbol = true;
f._symbolName = si.Name;
f._symbolDisp = disp;
}
else
{
f._symbol = false;
}
}
syntax highlighted by Code2HTML, v. 0.9.1