/* ==================================================================== * 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 /////////////////////////////////////////////////////////////////////// // a few helper template 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; } }