diff --git a/pykd/dbgeventcb.cpp b/pykd/dbgeventcb.cpp index 0e9a8b7..32df821 100644 --- a/pykd/dbgeventcb.cpp +++ b/pykd/dbgeventcb.cpp @@ -7,6 +7,7 @@ #include "dbgmodule.h" #include "dbgsynsym.h" #include "dbgcmd.h" +#include "dbgmodevent.h" /////////////////////////////////////////////////////////////////////////////////// @@ -51,7 +52,11 @@ HRESULT DbgEventCallbacksManager::GetInterestMask( __out PULONG Mask ) { - *Mask = DEBUG_EVENT_CHANGE_SYMBOL_STATE | DEBUG_EVENT_BREAKPOINT; + *Mask = + DEBUG_EVENT_CHANGE_SYMBOL_STATE | + DEBUG_EVENT_BREAKPOINT | + DEBUG_EVENT_LOAD_MODULE | + DEBUG_EVENT_UNLOAD_MODULE; return S_OK; } @@ -66,27 +71,25 @@ HRESULT DbgEventCallbacksManager::ChangeSymbolState( { if (Argument) { - DEBUG_MODULE_PARAMETERS dbgModuleParameters={}; - + DEBUG_MODULE_PARAMETERS dbgModuleParameters; HRESULT hres = dbgExt->symbols3->GetModuleParameters( 1, &Argument, 0, &dbgModuleParameters); - + if (SUCCEEDED(hres)) { ModuleInfo moduleInfo(dbgModuleParameters); - restoreSyntheticSymbolForModule(moduleInfo); - } - - return S_OK; + } + + return S_OK; } //// f.e. is case ".reload /f image.exe", if for image.exe no symbols restoreSyntheticSymbolForAllModules(); - + return S_OK; } @@ -100,7 +103,45 @@ HRESULT DbgEventCallbacksManager::Breakpoint( ) { return dbgBreakpointClass::onBreakpointEvnet( bp ); -} +} /////////////////////////////////////////////////////////////////////////////////// +HRESULT DbgEventCallbacksManager::LoadModule( + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCSTR ModuleName, + __in PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp +) +{ + try + { + return moduleEvents::onLoadModule(BaseOffset); + } + catch (std::exception &) + { + } + return DEBUG_STATUS_NO_CHANGE; +} + +/////////////////////////////////////////////////////////////////////////////////// + +HRESULT DbgEventCallbacksManager::UnloadModule( + __in PCSTR ImageBaseName, + __in ULONG64 BaseOffset +) +{ + try + { + return moduleEvents::onUnloadModule(BaseOffset); + } + catch (std::exception &) + { + } + return DEBUG_STATUS_NO_CHANGE; +} + +/////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgeventcb.h b/pykd/dbgeventcb.h index 89ae44c..35ba683 100644 --- a/pykd/dbgeventcb.h +++ b/pykd/dbgeventcb.h @@ -25,19 +25,33 @@ private: STDMETHOD(GetInterestMask)( __out PULONG Mask - ); + ); STDMETHOD(ChangeSymbolState)( __in ULONG Flags, __in ULONG64 Argument ); - + STDMETHOD(Breakpoint)( __in PDEBUG_BREAKPOINT Bp ); - + + STDMETHOD(LoadModule)( + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCSTR ModuleName, + __in PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp + ); + + STDMETHOD(UnloadModule)( + __in PCSTR ImageBaseName, + __in ULONG64 BaseOffset + ); + private: - IDebugClient *m_debugClient; }; diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 0f257c1..3dd6ca5 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -28,6 +28,7 @@ #include "dbgprocess.h" #include "dbgsynsym.h" #include "dbgclient.h" +#include "dbgmodevent.h" ////////////////////////////////////////////////////////////////////////////// @@ -221,7 +222,7 @@ BOOST_PYTHON_MODULE( pykd ) boost::python::class_( "dbgModuleClass", "Class representing module in the target memory" ) .def("begin", &dbgModuleClass::getBegin, - "Return start address of the module" ) + "Return start address of the module" ) .def("end", &dbgModuleClass::getEnd, "Return end address of the module" ) .def("size", &dbgModuleClass::getSize, @@ -249,7 +250,7 @@ BOOST_PYTHON_MODULE( pykd ) "Return address of the symbol" ) .def("__str__", &dbgModuleClass::print, "Return a nice string represention of the dbgModuleClass" ); - + boost::python::class_( "ext", "windbg extension wrapper", @@ -275,7 +276,7 @@ BOOST_PYTHON_MODULE( pykd ) boost::python::class_( "windbgOut", "windbgOut" ) .def( "write", &dbgOut::write ); boost::python::class_( "windbgIn", "windbgIn" ) - .def( "readline", &dbgIn::readline ); + .def( "readline", &dbgIn::readline ); boost::python::class_( "bp", "Class representing breakpoint", boost::python::init( boost::python::args("offset", "callback"), @@ -287,6 +288,15 @@ BOOST_PYTHON_MODULE( pykd ) .def( "__str__", &dbgBreakpointClass::print, "Return a nice string represention of the breakpoint class" ); + boost::python::class_( "modEvents", + "Class for processing of events: loading and unloading modules" ) + .def( "onLoad", &moduleEvents::onLoad, &moduleEventsWrap::onLoadDef, + "Load module event. Parameter is instance of dbgModuleClass. " + "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ) + .def( "onUnload", &moduleEvents::onUnload, &moduleEventsWrap::onUnloadDef, + "Unload module event. Parameter is instance of dbgModuleClass. " + "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ); + // debug status _DEF_PY_CONST(DEBUG_STATUS_NO_CHANGE); _DEF_PY_CONST(DEBUG_STATUS_GO); diff --git a/pykd/dbgmodevent.cpp b/pykd/dbgmodevent.cpp new file mode 100644 index 0000000..0195dfa --- /dev/null +++ b/pykd/dbgmodevent.cpp @@ -0,0 +1,108 @@ +///////////////////////////////////////////////////////////////////////////////// +// Load/Unload module events +///////////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "dbgeng.h" + +#include "dbgmodule.h" +#include "dbgmodevent.h" + +///////////////////////////////////////////////////////////////////////////////// + +moduleEvents::modCallbacksColl moduleEvents::modCallbacks; +moduleEvents::modCallbacksLock moduleEvents::modCallbacksMtx; + +///////////////////////////////////////////////////////////////////////////////// + +moduleEvents::moduleEvents() +{ + modCallbacksScopedLock lock(modCallbacksMtx); + modCallbacks.insert(this); +} + +///////////////////////////////////////////////////////////////////////////////// + +moduleEvents::~moduleEvents() +{ + modCallbacksScopedLock lock(modCallbacksMtx); + modCallbacks.erase(this); +} + +///////////////////////////////////////////////////////////////////////////////// + +ULONG moduleEvents::onLoadModule(__in ULONG64 addr) +{ + modCallbacksScopedLock lock(modCallbacksMtx); + if (modCallbacks.empty()) + return DEBUG_STATUS_NO_CHANGE; + + ULONG64 moduleBase; + ULONG moduleSize; + std::string moduleName; + queryModuleParams(addr, moduleName, moduleBase, moduleSize); + dbgModuleClass module(moduleName, moduleBase, moduleSize); + + modCallbacksColl::iterator itCallback = modCallbacks.begin(); + while (itCallback != modCallbacks.end()) + { + const ULONG retValue = (*itCallback)->onLoad(module); + if (DEBUG_STATUS_NO_CHANGE != retValue) + return retValue; + + ++itCallback; + } + return DEBUG_STATUS_NO_CHANGE; +} + +///////////////////////////////////////////////////////////////////////////////// + +ULONG moduleEvents::onUnloadModule(__in ULONG64 addr) +{ + modCallbacksScopedLock lock(modCallbacksMtx); + if (modCallbacks.empty()) + return DEBUG_STATUS_NO_CHANGE; + + ULONG64 moduleBase; + ULONG moduleSize; + std::string moduleName; + queryModuleParams(addr, moduleName, moduleBase, moduleSize); + dbgModuleClass module(moduleName, moduleBase, moduleSize); + + modCallbacksColl::iterator itCallback = modCallbacks.begin(); + while (itCallback != modCallbacks.end()) + { + const ULONG retValue = (*itCallback)->onUnload(module); + if (DEBUG_STATUS_NO_CHANGE != retValue) + return retValue; + + ++itCallback; + } + return DEBUG_STATUS_NO_CHANGE; +} + +///////////////////////////////////////////////////////////////////////////////// + +ULONG moduleEventsWrap::onLoad( + const dbgModuleClass &module +) +{ + if (boost::python::override override = get_override("onLoad")) + return override(module); + + return moduleEvents::onLoad(module); +} + +///////////////////////////////////////////////////////////////////////////////// + +ULONG moduleEventsWrap::onUnload( + const dbgModuleClass &module +) +{ + if (boost::python::override override = get_override("onUnload")) + return override(module); + + return moduleEvents::onUnload(module); +} + +///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgmodevent.h b/pykd/dbgmodevent.h new file mode 100644 index 0000000..70aff00 --- /dev/null +++ b/pykd/dbgmodevent.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////////// +// Load/Unload module events +///////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +interface moduleEvents +{ + moduleEvents(); + virtual ~moduleEvents(); + + virtual ULONG onLoad(const dbgModuleClass &/* module */) + { + return DEBUG_STATUS_NO_CHANGE; + } + virtual ULONG onUnload(const dbgModuleClass &/* module */) + { + return DEBUG_STATUS_NO_CHANGE; + } + + static ULONG onLoadModule(__in ULONG64 addr); + static ULONG onUnloadModule(__in ULONG64 addr); + +private: + + typedef std::set modCallbacksColl; + static modCallbacksColl modCallbacks; + + typedef boost::interprocess::interprocess_recursive_mutex modCallbacksLock; + static modCallbacksLock modCallbacksMtx; + typedef boost::interprocess::scoped_lock modCallbacksScopedLock; +}; + +// python wrapper for moduleEvents +struct moduleEventsWrap : moduleEvents, boost::python::wrapper +{ + ULONG onLoad(const dbgModuleClass &module); + ULONG onLoadDef(const dbgModuleClass &module) + { + return moduleEvents::onLoad(module); + } + + ULONG onUnload(const dbgModuleClass &module); + ULONG onUnloadDef(const dbgModuleClass &module) + { + return moduleEvents::onUnload(module); + } +}; + +///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgmodule.cpp b/pykd/dbgmodule.cpp index c6a94b2..3d04876 100644 --- a/pykd/dbgmodule.cpp +++ b/pykd/dbgmodule.cpp @@ -47,61 +47,82 @@ loadModule( const std::string &moduleName ) ///////////////////////////////////////////////////////////////////////////////// +void queryModuleParams( + __in ULONG64 addr, + __out std::string &name, + __out ULONG64 &base, + __out ULONG &size +) +{ + addr = addr64( addr ); + + ULONG moduleIndex; + HRESULT hres = + dbgExt->symbols->GetModuleByOffset( addr, 0, &moduleIndex, &base); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByOffset failed" ); + + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + hres = dbgExt->symbols->GetModuleParameters( 1, &base, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + size = moduleParam.Size; + + ULONG moduleNameChars = 0; + dbgExt->symbols->GetModuleNames( + moduleIndex, + 0, + NULL, + 0, + NULL, + NULL, + 0, + &moduleNameChars, + NULL, + 0, + NULL ); + name.resize(moduleNameChars + 1); + hres = dbgExt->symbols->GetModuleNames( + moduleIndex, + 0, + NULL, + 0, + NULL, + &name[0], + (ULONG)name.size(), + NULL, + NULL, + 0, + NULL ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleNames failed" ); +} + +///////////////////////////////////////////////////////////////////////////////// + boost::python::object findModule( ULONG64 addr ) { - HRESULT hres; - - addr = addr64( addr ); - try { - - ULONG moduleIndex; - ULONG64 moduleBase; - hres = dbgExt->symbols->GetModuleByOffset( addr, 0, &moduleIndex, &moduleBase ); - - if ( FAILED( hres ) ) - { - return boost::python::object(); - } - - DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; - hres = dbgExt->symbols->GetModuleParameters( 1, &moduleBase, 0, &moduleParam ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); - - char moduleName[0x100]; - - hres = - dbgExt->symbols->GetModuleNames( - moduleIndex, - 0, - NULL, - 0, - NULL, - moduleName, - sizeof( moduleName ), - NULL, - NULL, - 0, - NULL ); - - if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleNames failed" ); - - return boost::python::object( dbgModuleClass( moduleName, moduleBase, moduleParam.Size ) ); - + ULONG64 moduleBase; + ULONG moduleSize; + std::string moduleName; + queryModuleParams(addr, moduleName, moduleBase, moduleSize); + return + boost::python::object( + dbgModuleClass( moduleName, moduleBase, moduleSize ) + ); } - catch( std::exception &e ) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); - } - catch(...) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); - } - - return boost::python::object(); + catch( std::exception &e ) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); + } + catch(...) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); + } + + return boost::python::object(); } ///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgmodule.h b/pykd/dbgmodule.h index ae51356..92d9002 100644 --- a/pykd/dbgmodule.h +++ b/pykd/dbgmodule.h @@ -162,6 +162,14 @@ private: boost::python::object loadModule( const std::string &moduleName ); +// query module parameters (for construct dbgModuleClass) by virtual address +// error : DbgException exception +void queryModuleParams( + __in ULONG64 addr, + __out std::string &name, + __out ULONG64 &base, + __out ULONG &size +); boost::python::object findModule( ULONG64 addr ); diff --git a/pykd/pykd.vcproj b/pykd/pykd.vcproj index 87b3ebe..4867e86 100644 --- a/pykd/pykd.vcproj +++ b/pykd/pykd.vcproj @@ -376,6 +376,10 @@ RelativePath=".\dbgmem.cpp" > + + @@ -494,6 +498,10 @@ RelativePath=".\dbgmem.h" > + + diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index c5baab8..874f944 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -78,7 +78,6 @@ GenerateDebugInformation="true" SubSystem="2" TargetMachine="1" - Profile="true" /> + + @@ -485,6 +487,10 @@ RelativePath=".\dbgmem.h" > + + diff --git a/samples/goLoad.py b/samples/goLoad.py new file mode 100644 index 0000000..b76fb4b --- /dev/null +++ b/samples/goLoad.py @@ -0,0 +1,26 @@ +""" +Wait (execute) for load target module +""" + +from pykd import * +import fnmatch +import sys + +class modLoad(modEvents): + def __init__(self, mask): + modEvents.__init__(self) + self.mask = mask + + def onLoad(self, module): + if fnmatch.fnmatch( module.name(), self.mask ): + return DEBUG_STATUS_BREAK + return DEBUG_STATUS_NO_CHANGE + +if __name__ == "__main__": + if len(sys.argv) == 2: + loadHandler = modLoad( sys.argv[1] ) + go() + else: + dprintln( "Wait (execute) for load target module\nInvalid command line" ) + dprintln( "Using" + sys.argv[0] + " " ) + dprintln( "\tMOD_FILE_NAME - name of target module with wildcard" )