From 342792bc915200dca5bff43e20783efad6fc861b Mon Sep 17 00:00:00 2001 From: "SND\\EreTIk_cp" Date: Thu, 28 Mar 2013 18:28:42 +0000 Subject: [PATCH] [0.2.x] workitem 11665 fixed: work with modules moved to separate module, add load/unload symbols debug events, work with symbol cache moved to separate module git-svn-id: https://pykd.svn.codeplex.com/svn@83100 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/dbgengine.h | 2 + pykd/eventhandler.h | 9 + pykd/module.cpp | 24 +-- pykd/module.h | 34 ---- pykd/pykd_2008.vcproj | 14 +- pykd/python/pymod.cpp | 10 +- pykd/symsessioncache.cpp | 193 +++++++++++++++++++++ pykd/symsessioncache.h | 59 +++++++ pykd/win/dbgeng.cpp | 337 ++++-------------------------------- pykd/win/dbgeng.h | 11 +- pykd/win/dbgmod.cpp | 359 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 691 insertions(+), 361 deletions(-) create mode 100644 pykd/symsessioncache.cpp create mode 100644 pykd/symsessioncache.h create mode 100644 pykd/win/dbgmod.cpp diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index fb0a65d..53a9398 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -110,6 +110,8 @@ struct DEBUG_EVENT_CALLBACK { virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; + virtual void onSymbolsLoaded(ULONG64 modBase) = 0; + virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) = 0; }; enum EVENT_TYPE { diff --git a/pykd/eventhandler.h b/pykd/eventhandler.h index b8be6d3..bd3c82d 100644 --- a/pykd/eventhandler.h +++ b/pykd/eventhandler.h @@ -27,6 +27,8 @@ private: virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; + virtual void onSymbolsLoaded(ULONG64 modBase) = 0; + virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) = 0; }; ////////////////////////////////////////////////////////////////////////////////// @@ -57,6 +59,13 @@ public: void_handler("onExecutionStatusChange", executionStatus ); } + virtual void onSymbolsLoaded(ULONG64 modBase) { + void_handler("onSymbolsLoaded", modBase); + } + + virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) { + void_handler("onSymbolsUnloaded", modBase); + } private: diff --git a/pykd/module.cpp b/pykd/module.cpp index b773794..8e3aa55 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -3,15 +3,12 @@ #include "module.h" #include "dbgexcept.h" #include "vardata.h" +#include "symsessioncache.h" namespace pykd { /////////////////////////////////////////////////////////////////////////////////// -Module::SymbolSessionCache Module::m_symSessionCache; - -/////////////////////////////////////////////////////////////////////////////////// - ModulePtr Module::loadModuleByName( const std::string &moduleName ) { return ModulePtr( new Module( moduleName ) ); @@ -55,11 +52,9 @@ SymbolSessionPtr& Module::getSymSession() if (m_symSession) return m_symSession; - SymbolMapKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; - SymbolSessionCache::iterator found = m_symSessionCache.find( cacheKey ); - if ( found != m_symSessionCache.end() ) + SymCacheModuleKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; + if ( findSymCacheEntry( cacheKey, m_symSession ) ) { - m_symSession = found->second; if ( !m_symSession ) throw SymbolException( "failed to load symbol file" ); @@ -71,7 +66,7 @@ SymbolSessionPtr& Module::getSymSession() m_symSession = loadSymbolFile( m_base, m_imageName); if (m_symSession) { - m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); + insertSymCacheEntry( m_base, cacheKey, m_symSession ); return m_symSession; } } @@ -90,7 +85,7 @@ SymbolSessionPtr& Module::getSymSession() if (m_symSession) { - m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); + insertSymCacheEntry( m_base, cacheKey, m_symSession ); return m_symSession; } } @@ -102,15 +97,14 @@ SymbolSessionPtr& Module::getSymSession() m_symSession = loadSymbolFromExports(m_base); if (m_symSession) { - m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); + insertSymCacheEntry( m_base, cacheKey, m_symSession ); return m_symSession; } } catch(const DbgException&) {} - m_symSessionCache.insert( std::make_pair( cacheKey, SymbolSessionPtr() ) ); - + insertSymCacheEntry( m_base, cacheKey, SymbolSessionPtr() ); throw SymbolException( "failed to load symbol file" ); } @@ -137,8 +131,8 @@ SymbolPtr Module::getSymScope() void Module::reloadSymbols() { - SymbolMapKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; - m_symSessionCache.erase( cacheKey ); + SymCacheModuleKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; + eraseSymCacheEntry( cacheKey ); m_symSession.reset(); getSymSession(); diff --git a/pykd/module.h b/pykd/module.h index 4830d07..42a0ace 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -24,40 +24,6 @@ public: static ModulePtr loadModuleByOffset( ULONG64 offset ); -private: - - struct SymbolMapKey{ - std::string name; - ULONG size; - ULONG timeStamp; - ULONG checkSum; - - bool operator < ( const SymbolMapKey& key ) const - { - if ( name < key.name ) - return true; - if ( name > key.name ) - return false; - - if ( size < key.size ) - return true; - if ( size > key.size ) - return false; - - if ( timeStamp < key.timeStamp ) - return true; - if ( timeStamp > key.timeStamp ) - return false; - - return checkSum < key.checkSum; - } - }; - - typedef std::map SymbolSessionCache; - static SymbolSessionCache m_symSessionCache; - - SymbolSessionPtr getFromCache(); - public: Module(const std::string &name ); diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index ddfa5c4..a9afee0 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -1,7 +1,7 @@ + + @@ -527,6 +531,10 @@ RelativePath=".\symengine.h" > + + @@ -581,6 +589,10 @@ RelativePath=".\win\dbgio.h" > + + diff --git a/pykd/python/pymod.cpp b/pykd/python/pymod.cpp index 4fa0d29..e8883ff 100644 --- a/pykd/python/pymod.cpp +++ b/pykd/python/pymod.cpp @@ -611,9 +611,15 @@ BOOST_PYTHON_MODULE( pykd ) .def( "onException", &EventHandlerWrap::OnException, "Triggered exception event. Parameter - exceptionInfo\n" "For ignore event method must return eventResult.noChange" ) - .def( "onExecutionStatusChange", &EventHandlerWrap::onExecutionStatusChange, + .def( "onExecutionStatusChange", &EventHandlerWrap::onExecutionStatusChange, "Triggered execution status changed. Parameter - execution status.\n" - "There is no return value" ); + "There is no return value" ) + .def( "onSymbolsLoaded", &EventHandlerWrap::onSymbolsLoaded, + "Triggered debug symbols loaded. Parameter - module base\n" + "There is no return value") + .def( "onSymbolsUnloaded", &EventHandlerWrap::onSymbolsUnloaded, + "Triggered debug symbols unloaded. Parameter - module base or 0 (all modules)\n" + "There is no return value"); // wrapper for standart python exceptions python::register_exception_translator( &PyException::exceptionTranslate ); diff --git a/pykd/symsessioncache.cpp b/pykd/symsessioncache.cpp new file mode 100644 index 0000000..d7d0dfa --- /dev/null +++ b/pykd/symsessioncache.cpp @@ -0,0 +1,193 @@ +// +// Cache of loaded executable module symbols: +// Map: module -> symbol session +// + +#include "stdafx.h" +#include "dbgengine.h" +#include "symsessioncache.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace pykd { + +///////////////////////////////////////////////////////////////////////////////////// + +class Impl : protected DEBUG_EVENT_CALLBACK { +public: + Impl(); + ~Impl(); + + bool find(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession); + + void insert(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession); + + void erase(const SymCacheModuleKey &cacheKey); + + void clear(); + +protected: + + // DEBUG_EVENT_CALLBACK: + virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG ) { + return DebugCallbackNoChange; + } + virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64, const std::string & ) { + return DebugCallbackNoChange; + } + virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64, const std::string & ); + virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr ) { + return DebugCallbackNoChange; + } + virtual void onExecutionStatusChange( ULONG ) { + } + virtual void onSymbolsLoaded(ULONG64 modBase) { + } + virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL); + +private: + typedef std::map< ULONG64, SymCacheModuleKey > Base2Key; + Base2Key m_base2Key; + boost::recursive_mutex m_base2KeyLock; + + typedef std::map< SymCacheModuleKey, SymbolSessionPtr > Key2Sym; + Key2Sym m_key2Sym; + boost::recursive_mutex m_key2SymLock; +}; + +///////////////////////////////////////////////////////////////////////////////////// + +Impl::Impl() +{ + eventRegisterCallbacks(this); +} + +///////////////////////////////////////////////////////////////////////////////////// + +Impl::~Impl() +{ + eventRemoveCallbacks(this); +} + +///////////////////////////////////////////////////////////////////////////////////// + +DEBUG_CALLBACK_RESULT Impl::OnModuleUnload( ULONG64 modBase, const std::string & ) +{ + boost::recursive_mutex::scoped_lock l(m_base2KeyLock); + if (modBase) + m_base2Key.erase(modBase); + else + m_base2Key.clear(); + return DebugCallbackNoChange; +} + +///////////////////////////////////////////////////////////////////////////////////// + +void Impl::onSymbolsUnloaded(ULONG64 modBase) +{ + if (!modBase) + { + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + m_key2Sym.clear(); + return; + } + + SymCacheModuleKey cacheKey; + { + boost::recursive_mutex::scoped_lock l(m_base2KeyLock); + Base2Key::const_iterator it = m_base2Key.find(modBase); + if (it == m_base2Key.end()) + return; + cacheKey = it->second; + } + + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + m_key2Sym.erase(cacheKey); +} + +///////////////////////////////////////////////////////////////////////////////////// + +namespace +{ + +Impl &getImpl() +{ + // contruct after DebugEngine + static Impl g_Impl; + return g_Impl; +} + +} + +///////////////////////////////////////////////////////////////////////////////////// + +bool findSymCacheEntry(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession) +{ + return getImpl().find(cacheKey, symSession); +} + +bool Impl::find(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession) +{ + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + Key2Sym::const_iterator it = m_key2Sym.find(cacheKey); + if (it == m_key2Sym.end()) + { + symSession.reset(); + return false; + } + + symSession = it->second; + return true; +} + +///////////////////////////////////////////////////////////////////////////////////// + +void insertSymCacheEntry(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession) +{ + return getImpl().insert(modBase, cacheKey, symSession); +} + +void Impl::insert(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession) +{ + { + boost::recursive_mutex::scoped_lock l(m_base2KeyLock); + m_base2Key[modBase] = cacheKey; + } + + { + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + m_key2Sym[cacheKey] = symSession; + } +} + +///////////////////////////////////////////////////////////////////////////////////// + +void eraseSymCacheEntry(const SymCacheModuleKey &cacheKey) +{ + return getImpl().erase(cacheKey); +} + +void Impl::erase(const SymCacheModuleKey &cacheKey) +{ + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + m_key2Sym.erase(cacheKey); +} + +///////////////////////////////////////////////////////////////////////////////////// + +void clearSymCache() +{ + return getImpl().clear(); +} + +void Impl::clear() +{ + boost::recursive_mutex::scoped_lock l(m_key2SymLock); + m_key2Sym.clear(); +} + +///////////////////////////////////////////////////////////////////////////////////// + +} // namespace pykd + +////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/symsessioncache.h b/pykd/symsessioncache.h new file mode 100644 index 0000000..876e15e --- /dev/null +++ b/pykd/symsessioncache.h @@ -0,0 +1,59 @@ +// +// Cache of loaded executable module symbols: +// Map: module -> symbol session +// + +#pragma once + +//////////////////////////////////////////////////////////////////////////////// + +#include "symengine.h" + +//////////////////////////////////////////////////////////////////////////////// + +namespace pykd { + +//////////////////////////////////////////////////////////////////////////////// + +struct SymCacheModuleKey { + std::string name; + ULONG size; + ULONG timeStamp; + ULONG checkSum; + + bool operator < ( const SymCacheModuleKey& key ) const + { + if ( name < key.name ) + return true; + if ( name > key.name ) + return false; + + if ( size < key.size ) + return true; + if ( size > key.size ) + return false; + + if ( timeStamp < key.timeStamp ) + return true; + if ( timeStamp > key.timeStamp ) + return false; + + return checkSum < key.checkSum; + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +bool findSymCacheEntry(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession); + +void insertSymCacheEntry(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession); + +void eraseSymCacheEntry(const SymCacheModuleKey &cacheKey); + +void clearSymCache(); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace pykd + +//////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/win/dbgeng.cpp b/pykd/win/dbgeng.cpp index 04e4b22..696f6fd 100644 --- a/pykd/win/dbgeng.cpp +++ b/pykd/win/dbgeng.cpp @@ -1,12 +1,12 @@ #include "stdafx.h" #include -#include #include "win/dbgeng.h" #include "win/dbgio.h" #include "dbgexcept.h" #include "eventhandler.h" +#include "symengine.h" namespace pykd { @@ -346,7 +346,7 @@ ULONG64 evaluate( const std::wstring &expression ) if ( remainderIndex == expression.length() ) value = debugValue.I32; - } + } return value; } @@ -370,310 +370,6 @@ std::string debugCommand( const std::wstring &command ) /////////////////////////////////////////////////////////////////////////////// -ULONG64 findModuleBase( const std::string &moduleName ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - ULONG64 base; - - hres = g_dbgEng->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &base ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); - - return base; -} - -/////////////////////////////////////////////////////////////////////////////////// - -ULONG64 findModuleBase( ULONG64 offset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - ULONG64 base; - ULONG moduleIndex; - - hres = g_dbgEng->symbols->GetModuleByOffset( offset, 0, &moduleIndex, &base ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleByOffset failed" ); - - return base; -} - -/////////////////////////////////////////////////////////////////////////////////// - -ULONG64 findModuleBySymbol( const std::string &symbolName ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - ULONG64 base; - - hres = g_dbgEng->symbols->GetSymbolModule( ( std::string("!") + symbolName ).c_str(), &base ); - if ( FAILED( hres ) ) - { - std::stringstream sstr; - sstr << "failed to find module for symbol: " << symbolName; - throw SymbolException( sstr.str() ); - } - - return base; -} - -/////////////////////////////////////////////////////////////////////////////////// - -std::string getModuleName( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - - char moduleName[0x100]; - - hres = g_dbgEng->symbols->GetModuleNameString( - DEBUG_MODNAME_MODULE, - DEBUG_ANY_ID, - baseOffset, - moduleName, - sizeof( moduleName ), - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); - - return std::string( moduleName ); -} - -/////////////////////////////////////////////////////////////////////////////////// - -std::string getModuleImageName( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - char imageName[0x100]; - - hres = g_dbgEng->symbols->GetModuleNameString( - DEBUG_MODNAME_IMAGE, - DEBUG_ANY_ID, - baseOffset, - imageName, - sizeof( imageName ), - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); - - return std::string( imageName ); -} - -/////////////////////////////////////////////////////////////////////////////////// - -ULONG getModuleSize( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; - - hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); - - return moduleParam.Size; -} - -/////////////////////////////////////////////////////////////////////////////////// - -std::string getModuleSymbolFileName( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - IMAGEHLP_MODULEW64 moduleInfo = {}; - - hres = g_dbgEng->advanced->GetSymbolInformation( - DEBUG_SYMINFO_IMAGEHLP_MODULEW64, - baseOffset, - 0, - &moduleInfo, - sizeof(moduleInfo), - NULL, - NULL, - 0, - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); - - if (!*moduleInfo.LoadedPdbName) - { - std::wstringstream sstr; - sstr << L"/f \"" << moduleInfo.ImageName << L"\""; - - hres = g_dbgEng->symbols->ReloadWide( sstr.str().c_str() ); - if ( FAILED( hres ) ) - throw DbgException("IDebugSymbols::Reload failed" ); - - hres = g_dbgEng->advanced->GetSymbolInformation( - DEBUG_SYMINFO_IMAGEHLP_MODULEW64, - baseOffset, - 0, - &moduleInfo, - sizeof(moduleInfo), - NULL, - NULL, - 0, - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); - } - - char pdbName[ 256 ]; - WideCharToMultiByte( CP_ACP, 0, moduleInfo.LoadedPdbName, 256, pdbName, 256, NULL, NULL ); - - return std::string( pdbName ); -} - -/////////////////////////////////////////////////////////////////////////////////// - -ULONG getModuleTimeStamp( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; - - hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); - - return moduleParam.TimeDateStamp; -} - -/////////////////////////////////////////////////////////////////////////////////// - -ULONG getModuleCheckSum( ULONG64 baseOffset ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; - - hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); - - return moduleParam.Checksum; -} - -/////////////////////////////////////////////////////////////////////////////// - -void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - VS_FIXEDFILEINFO fileInfo={}; - - HRESULT hres; - - hres = g_dbgEng->symbols->GetModuleVersionInformation( - DEBUG_ANY_ID, - baseOffset, - "\\", - (PVOID)&fileInfo, - sizeof(fileInfo), - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); - - majorHigh = HIWORD(fileInfo.dwFileVersionMS); - majorLow = LOWORD(fileInfo.dwFileVersionMS); - minorHigh = HIWORD(fileInfo.dwFileVersionLS); - minorLow = LOWORD(fileInfo.dwFileVersionLS); -} - -/////////////////////////////////////////////////////////////////////////////// - -std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value ) -{ - struct LANGANDCODEPAGE { - WORD wLanguage; - WORD wCodePage; - }; - - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - - ULONG codePagesSize = 0; - - hres = g_dbgEng->symbols->GetModuleVersionInformation( - DEBUG_ANY_ID, - baseOffset, - "\\VarFileInfo\\Translation", - NULL, - 0, - &codePagesSize ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); - - size_t codePageNum = codePagesSize / sizeof(LANGANDCODEPAGE); - - std::vector codePages(codePageNum); - - hres = g_dbgEng->symbols->GetModuleVersionInformation( - DEBUG_ANY_ID, - baseOffset, - "\\VarFileInfo\\Translation", - &codePages[0], - codePagesSize, - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); - - ULONG productNameLength = 0; - - std::stringstream sstr; - sstr << "\\StringFileInfo\\" << std::hex - << std::setw(4) << std::setfill('0') << codePages[0].wLanguage - << std::setw(4) << std::setfill('0') << codePages[0].wCodePage - << "\\" << value; - - ULONG valueLength; - - g_dbgEng->symbols->GetModuleVersionInformation( - DEBUG_ANY_ID, - baseOffset, - sstr.str().c_str(), - NULL, - 0, - &valueLength ); - - std::vector valueStr(valueLength); - - hres = g_dbgEng->symbols->GetModuleVersionInformation( - DEBUG_ANY_ID, - baseOffset, - sstr.str().c_str(), - &valueStr[0], - valueLength, - NULL ); - - if ( hres == S_OK ) - return std::string( &valueStr[0] ); - - return ""; - -} - -/////////////////////////////////////////////////////////////////////////////// - ULONG ptrSize() { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); @@ -1543,6 +1239,35 @@ HRESULT STDMETHODCALLTYPE DebugEngine::ChangeEngineState( /////////////////////////////////////////////////////////////////////////////// +HRESULT STDMETHODCALLTYPE DebugEngine::ChangeSymbolState( + __in ULONG Flags, + __in ULONG64 Argument ) +{ + HandlerList::iterator it; + + if (Flags & DEBUG_CSS_LOADS) + { + for ( it = m_handlers.begin(); it != m_handlers.end(); ++it ) + { + PyThread_StateSave pyThreadSave( it->pystate ); + it->callback->onSymbolsLoaded( Argument ); + } + } + + if (Flags & DEBUG_CSS_UNLOADS) + { + for ( it = m_handlers.begin(); it != m_handlers.end(); ++it ) + { + PyThread_StateSave pyThreadSave( it->pystate ); + it->callback->onSymbolsUnloaded( Argument ); + } + } + + return S_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + HRESULT STDMETHODCALLTYPE DebugEngine::StartInput( __in ULONG BufferSize ) { diff --git a/pykd/win/dbgeng.h b/pykd/win/dbgeng.h index 4f55fd6..66d35de 100644 --- a/pykd/win/dbgeng.h +++ b/pykd/win/dbgeng.h @@ -4,6 +4,7 @@ #include "dbgexcept.h" #include "pyaux.h" #include "eventhandler.h" +#include "symsessioncache.h" #include #include @@ -15,7 +16,6 @@ namespace pykd { class DebugEngine : private DebugBaseEventCallbacks, private IDebugInputCallbacks { public: - struct DbgEngBind { CComQIPtr client; @@ -78,6 +78,7 @@ public: *Mask |= DEBUG_EVENT_UNLOAD_MODULE; *Mask |= DEBUG_EVENT_EXCEPTION; *Mask |= DEBUG_EVENT_CHANGE_ENGINE_STATE; + *Mask |= DEBUG_EVENT_CHANGE_SYMBOL_STATE; return S_OK; } @@ -106,6 +107,10 @@ public: __in ULONG Flags, __in ULONG64 Argument ); + STDMETHOD(ChangeSymbolState)( + __in ULONG Flags, + __in ULONG64 Argument ); + STDMETHOD(StartInput)( __in ULONG BufferSize ); @@ -117,12 +122,12 @@ public: void registerCallbacks( const DEBUG_EVENT_CALLBACK *callbacks ); void removeCallbacks( const DEBUG_EVENT_CALLBACK *callbacks ); + DebugEngine() : previousExecutionStatus( DebugStatusNoChange ) {} private: - std::auto_ptr m_bind; struct DebugEventContext @@ -150,4 +155,4 @@ extern DebugEngine g_dbgEng; ///////////////////////////////////////////////////////////////////////////////// -}; \ No newline at end of file +}; diff --git a/pykd/win/dbgmod.cpp b/pykd/win/dbgmod.cpp new file mode 100644 index 0000000..72ba3f1 --- /dev/null +++ b/pykd/win/dbgmod.cpp @@ -0,0 +1,359 @@ +// +// Work with modules +// + +/////////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "dbgeng.h" + +#include + +/////////////////////////////////////////////////////////////////////////////// + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////// + +ULONG64 findModuleBase( const std::string &moduleName ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + ULONG64 base; + + hres = g_dbgEng->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &base ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); + + return base; +} + +/////////////////////////////////////////////////////////////////////////////////// + +ULONG64 findModuleBase( ULONG64 offset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + ULONG64 base; + ULONG moduleIndex; + + hres = g_dbgEng->symbols->GetModuleByOffset( offset, 0, &moduleIndex, &base ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByOffset failed" ); + + return base; +} + +/////////////////////////////////////////////////////////////////////////////////// + +ULONG64 findModuleBySymbol( const std::string &symbolName ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + ULONG64 base; + + hres = g_dbgEng->symbols->GetSymbolModule( ( std::string("!") + symbolName ).c_str(), &base ); + if ( FAILED( hres ) ) + { + std::stringstream sstr; + sstr << "failed to find module for symbol: " << symbolName; + throw SymbolException( sstr.str() ); + } + + return base; +} + +/////////////////////////////////////////////////////////////////////////////////// + +namespace { + +std::string getModuleNameImpl( ULONG64 baseOffset ) +{ + HRESULT hres; + + char moduleName[0x100]; + + hres = g_dbgEng->symbols->GetModuleNameString( + DEBUG_MODNAME_MODULE, + DEBUG_ANY_ID, + baseOffset, + moduleName, + sizeof( moduleName ), + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); + + return std::string( moduleName ); +} + +} + +std::string getModuleName( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + return getModuleNameImpl( baseOffset ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +std::string getModuleImageName( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + char imageName[0x100]; + + hres = g_dbgEng->symbols->GetModuleNameString( + DEBUG_MODNAME_IMAGE, + DEBUG_ANY_ID, + baseOffset, + imageName, + sizeof( imageName ), + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); + + return std::string( imageName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +namespace { + +ULONG getModuleSizeImpl( ULONG64 baseOffset ) +{ + HRESULT hres; + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + + hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + return moduleParam.Size; +} + +} + +ULONG getModuleSize( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + return getModuleSizeImpl( baseOffset ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +std::string getModuleSymbolFileName( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + IMAGEHLP_MODULEW64 moduleInfo = {}; + + hres = g_dbgEng->advanced->GetSymbolInformation( + DEBUG_SYMINFO_IMAGEHLP_MODULEW64, + baseOffset, + 0, + &moduleInfo, + sizeof(moduleInfo), + NULL, + NULL, + 0, + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); + + if (!*moduleInfo.LoadedPdbName) + { + std::wstringstream sstr; + sstr << L"/f \"" << moduleInfo.ImageName << L"\""; + + hres = g_dbgEng->symbols->ReloadWide( sstr.str().c_str() ); + if ( FAILED( hres ) ) + throw DbgException("IDebugSymbols::Reload failed" ); + + hres = g_dbgEng->advanced->GetSymbolInformation( + DEBUG_SYMINFO_IMAGEHLP_MODULEW64, + baseOffset, + 0, + &moduleInfo, + sizeof(moduleInfo), + NULL, + NULL, + 0, + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); + } + + char pdbName[ 256 ]; + WideCharToMultiByte( CP_ACP, 0, moduleInfo.LoadedPdbName, 256, pdbName, 256, NULL, NULL ); + + return std::string( pdbName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +namespace{ + +ULONG getModuleTimeStampImpl( ULONG64 baseOffset ) +{ + HRESULT hres; + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + + hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + return moduleParam.TimeDateStamp; +} + +} + +ULONG getModuleTimeStamp( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + return getModuleTimeStampImpl( baseOffset ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +namespace { + +ULONG getModuleCheckSumImpl( ULONG64 baseOffset ) +{ + HRESULT hres; + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + + hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + return moduleParam.Checksum; +} + +} + +ULONG getModuleCheckSum( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + return getModuleCheckSumImpl( baseOffset ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + VS_FIXEDFILEINFO fileInfo={}; + + HRESULT hres; + + hres = g_dbgEng->symbols->GetModuleVersionInformation( + DEBUG_ANY_ID, + baseOffset, + "\\", + (PVOID)&fileInfo, + sizeof(fileInfo), + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + + majorHigh = HIWORD(fileInfo.dwFileVersionMS); + majorLow = LOWORD(fileInfo.dwFileVersionMS); + minorHigh = HIWORD(fileInfo.dwFileVersionLS); + minorLow = LOWORD(fileInfo.dwFileVersionLS); +} + +/////////////////////////////////////////////////////////////////////////////// + +std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value ) +{ + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + }; + + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + + ULONG codePagesSize = 0; + + hres = g_dbgEng->symbols->GetModuleVersionInformation( + DEBUG_ANY_ID, + baseOffset, + "\\VarFileInfo\\Translation", + NULL, + 0, + &codePagesSize ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + + size_t codePageNum = codePagesSize / sizeof(LANGANDCODEPAGE); + + std::vector codePages(codePageNum); + + hres = g_dbgEng->symbols->GetModuleVersionInformation( + DEBUG_ANY_ID, + baseOffset, + "\\VarFileInfo\\Translation", + &codePages[0], + codePagesSize, + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + + ULONG productNameLength = 0; + + std::stringstream sstr; + sstr << "\\StringFileInfo\\" << std::hex + << std::setw(4) << std::setfill('0') << codePages[0].wLanguage + << std::setw(4) << std::setfill('0') << codePages[0].wCodePage + << "\\" << value; + + ULONG valueLength; + + g_dbgEng->symbols->GetModuleVersionInformation( + DEBUG_ANY_ID, + baseOffset, + sstr.str().c_str(), + NULL, + 0, + &valueLength ); + + std::vector valueStr(valueLength); + + hres = g_dbgEng->symbols->GetModuleVersionInformation( + DEBUG_ANY_ID, + baseOffset, + sstr.str().c_str(), + &valueStr[0], + valueLength, + NULL ); + + if ( hres == S_OK ) + return std::string( &valueStr[0] ); + + return ""; +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace pykd + +///////////////////////////////////////////////////////////////////////////////