diff --git a/pykd/dbgclient.cpp b/pykd/dbgclient.cpp index ba96444..e792676 100644 --- a/pykd/dbgclient.cpp +++ b/pykd/dbgclient.cpp @@ -295,7 +295,12 @@ void DebugClient::waitForEvent() } while( false ); if ( FAILED( hres ) ) + { + if (E_UNEXPECTED == hres) + throw WaitEventException(); + throw DbgException( "IDebugControl::WaitForEvent failed" ); + } } void waitForEvent() @@ -317,6 +322,8 @@ ULONG DebugClient::ptrSize() return S_OK == hres ? 8 : 4; } +/////////////////////////////////////////////////////////////////////////////////// + ULONG ptrSize() { return g_dbgClient->ptrSize(); diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h index cb6db3a..507ced2 100644 --- a/pykd/dbgclient.h +++ b/pykd/dbgclient.h @@ -222,6 +222,10 @@ public: return m_symSymbols->removeByMask(moduleName, symName); } + SynSymbolsPtr getSynSymbols() { + return m_symSymbols; + } + private: template<typename T> diff --git a/pykd/dbgevent.cpp b/pykd/dbgevent.cpp index bf26aa4..0644d59 100644 --- a/pykd/dbgevent.cpp +++ b/pykd/dbgevent.cpp @@ -177,25 +177,8 @@ HRESULT EventHandler::LoadModule( __in ULONG TimeDateStamp ) { - //PyThread_StateSave pyThreadSave( m_parentClient->getThreadState() ); - - //return onLoadModule( module ); - - //std::auto_ptr<OutputReader> silentMode( new OutputReader(dbgExt->client) ); - - //ULONG64 moduleBase; - //ULONG moduleSize; - //std::string moduleName; - // - //queryModuleParams(BaseOffset, moduleName, moduleBase, moduleSize); - //dbgModuleClass module(moduleName, moduleBase, moduleSize); - //silentMode.reset(); - - //PyThread_StateSave pyThreadSave; - //return onLoadModule( module ); - - return S_OK; - + PyThread_StateSave pyThreadSave( m_parentClient->getThreadState() ); + return onLoadModule( m_parentClient->loadModuleByOffset(BaseOffset) ); } /////////////////////////////////////////////////////////////////////////////////// @@ -205,19 +188,9 @@ HRESULT EventHandler::UnloadModule( __in ULONG64 BaseOffset ) { - //std::auto_ptr<OutputReader> silentMode( new OutputReader(dbgExt->client) ); - - //ULONG64 moduleBase; - //ULONG moduleSize; - //std::string moduleName; - // - //queryModuleParams(BaseOffset, moduleName, moduleBase, moduleSize); - //dbgModuleClass module(moduleName, moduleBase, moduleSize); - //silentMode.reset(); - - //PyThread_StateSave pyThreadSave; - //return onUnloadModule( module ); - return S_OK; + PyThread_StateSave pyThreadSave( m_parentClient->getThreadState() ); + BaseOffset = m_parentClient->addr64(BaseOffset); + return onUnloadModule( BaseOffset ); } /////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgevent.h b/pykd/dbgevent.h index aaacaf4..d20a127 100644 --- a/pykd/dbgevent.h +++ b/pykd/dbgevent.h @@ -75,7 +75,7 @@ protected: virtual ULONG onLoadModule(const Module &/* module */) = 0; - virtual ULONG onUnloadModule(const Module &/* module */) = 0; + virtual ULONG onUnloadModule(ULONG64 /*modBase*/) = 0; virtual ULONG onChangeSessionStatus( ULONG status ) = 0; @@ -113,8 +113,8 @@ public: return handler<const Module&>("onLoadModule", module ); } - ULONG onUnloadModule(const Module &module) { - return handler<const Module&>("onUnloadModule", module ); + ULONG onUnloadModule(ULONG64 modBase) { + return handler<ULONG64>("onUnloadModule", modBase ); } ULONG onChangeSessionStatus( ULONG status ) { diff --git a/pykd/dbgexcept.cpp b/pykd/dbgexcept.cpp index d557cd4..f2494a6 100644 --- a/pykd/dbgexcept.cpp +++ b/pykd/dbgexcept.cpp @@ -7,6 +7,7 @@ namespace pykd { PyObject *DbgException::baseExceptTypeObject = NULL; PyObject *MemoryException::memoryExceptionTypeObject = NULL; +PyObject *WaitEventException::waitEventExceptTypeObject = NULL; ///////////////////////////////////////////////////////////////////////////////// @@ -36,6 +37,16 @@ std::string buildExceptDesc(PCSTR routineName, HRESULT hres) return sstream.str(); } +///////////////////////////////////////////////////////////////////////////////// + +void WaitEventException::exceptionTranslate( const WaitEventException &e ) +{ + python::object pyExcept(e); + + PyErr_SetObject( waitEventExceptTypeObject, pyExcept.ptr() ); +} + + ///////////////////////////////////////////////////////////////////////////////// }; // end namespace pykd diff --git a/pykd/dbgexcept.h b/pykd/dbgexcept.h index f5033ea..078394d 100644 --- a/pykd/dbgexcept.h +++ b/pykd/dbgexcept.h @@ -116,6 +116,25 @@ private: std::string buildExceptDesc(PCSTR routineName, HRESULT hres); +/////////////////////////////////////////////////////////////////////////////////// + +class WaitEventException : public DbgException +{ +public: + WaitEventException() + : DbgException( "None of the targets could generate events" ) + { + } + + static void exceptionTranslate(const WaitEventException &e); + + static void setTypeObject(PyObject *p) { + waitEventExceptTypeObject = p; + } +private: + static PyObject *waitEventExceptTypeObject; +}; + /////////////////////////////////////////////////////////////////////////////////// }; // namespace pykd diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index ad7cfce..61258ba 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -448,10 +448,10 @@ BOOST_PYTHON_MODULE( pykd ) "Detailed information: http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx \n" "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ) .def( "onLoadModule", &pykd::EventHandlerWrap::onLoadModule, - "Load module event. Parameter is instance of dbgModuleClass.\n" + "Load module event. Parameter is instance of module.\n" "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ) .def( "onUnloadModule", &pykd::EventHandlerWrap::onUnloadModule, - "Unload module event. Parameter is instance of dbgModuleClass.\n" + "Unload module event. Parameter is base address of unloaded module.\n" "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ); python::class_<Disasm>("disasm", "Class disassemble a processor instructions" ) @@ -662,6 +662,15 @@ BOOST_PYTHON_MODULE( pykd ) python::register_exception_translator<pykd::MemoryException>( &pykd::MemoryException::exceptionTranslate ); + // Wait debug event exception + python::class_<WaitEventException, python::bases<DbgException> > waitEventException( + "WaitEventException", "Debug interface access exception", python::no_init); + waitEventException + _DECL_BASE_EXCEPT_STR; + WaitEventException::setTypeObject( waitEventException.ptr() ); + python::register_exception_translator<WaitEventException>( + &WaitEventException::exceptionTranslate ); + DEF_PY_CONST_ULONG( DEBUG_CLASS_UNINITIALIZED ); DEF_PY_CONST_ULONG( DEBUG_CLASS_KERNEL ); DEF_PY_CONST_ULONG( DEBUG_CLASS_USER_WINDOWS ); diff --git a/test/scripts/ehloadtest.py b/test/scripts/ehloadtest.py new file mode 100644 index 0000000..2a0915f --- /dev/null +++ b/test/scripts/ehloadtest.py @@ -0,0 +1,51 @@ +"""Debug events handler: test [un-]load modules notification""" + +import unittest +import target +import pykd +import fnmatch + +class ModuleLoadHandler(pykd.eventHandler): + """Track load/unload module implementation""" + def __init__(self, client, moduleMask): + pykd.eventHandler.__init__(self, client) + + self.moduleMask = moduleMask.lower() + + self.wasLoad = 0 + self.wasUnload = False + + def onLoadModule(self, module): + """Load module handler""" + + if ( fnmatch.fnmatch(module.name().lower(), self.moduleMask) ): + self.wasLoad = module.begin() + + return pykd.DEBUG_STATUS_NO_CHANGE + + def onUnloadModule(self, modBase): + """Unload module handler""" + + if ( self.wasLoad and (self.wasLoad == modBase) ): + self.wasUnload = True + + return pykd.DEBUG_STATUS_NO_CHANGE + +class EhLoadTest(unittest.TestCase): + """Unit tests of [un-]load modules notification""" + + def testLoadUnload(self): + """Start new process and track loading and unloading modules""" + testClient = pykd.createDbgClient() + testClient.startProcess( target.appPath + " -testLoadUnload" ) + + modLoadHandler = ModuleLoadHandler( testClient, "*Iphlpapi*" ) + try: + while True: + testClient.go() + except pykd.WaitEventException: + pass + + self.assertTrue(modLoadHandler.wasLoad) + self.assertTrue(modLoadHandler.wasUnload) + diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 5b78d8d..9d58449 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -23,6 +23,7 @@ import typedvar import memtest import intbase import synsymtest +import ehloadtest def getTestSuite( singleName = "" ): if singleName == "": @@ -37,7 +38,8 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( eventtest.EventTest ), unittest.TestLoader().loadTestsFromTestCase( memtest.MemoryTest ), unittest.TestLoader().loadTestsFromTestCase( intbase.IntBaseTest ), - unittest.TestLoader().loadTestsFromTestCase( synsymtest.SynSymTest ) + unittest.TestLoader().loadTestsFromTestCase( synsymtest.SynSymTest ), + unittest.TestLoader().loadTestsFromTestCase( ehloadtest.EhLoadTest ) ] ) else: return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) ) @@ -45,12 +47,12 @@ def getTestSuite( singleName = "" ): if __name__ == "__main__": - targetAppPath = sys.argv[1] + target.appPath = sys.argv[1] - target.moduleName = os.path.splitext(os.path.basename(targetAppPath))[0] - print "\nTest module: %s" % targetAppPath + target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0] + print "\nTest module: %s" % target.appPath - pykd.startProcess( targetAppPath ) + pykd.startProcess( target.appPath ) target.module = pykd.loadModule( target.moduleName ) target.module.reload(); diff --git a/test/scripts/target.py b/test/scripts/target.py index 8d64d02..2fcf817 100644 --- a/test/scripts/target.py +++ b/test/scripts/target.py @@ -4,4 +4,5 @@ module = None moduleName = None -dbgext = None \ No newline at end of file +dbgext = None +appPath = None diff --git a/test/targetapp/targetapp.cpp b/test/targetapp/targetapp.cpp index 75723ed..7231543 100644 --- a/test/targetapp/targetapp.cpp +++ b/test/targetapp/targetapp.cpp @@ -159,6 +159,7 @@ void FuncWithName1(int a) int doLoadUnload() { + __debugbreak(); HMODULE hmod = ::LoadLibrary( _T("iphlpapi.dll") ); if (hmod) ::FreeLibrary(hmod); @@ -172,6 +173,9 @@ int _tmain(int argc, _TCHAR* argv[]) { try { + // Let test scripts to execute + __debugbreak(); + if (2 == argc) { // run with parameters @@ -179,8 +183,6 @@ int _tmain(int argc, _TCHAR* argv[]) return doLoadUnload(); } - // Let test scripts to execute - __debugbreak(); __debugbreak(); __debugbreak(); __debugbreak(); diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj index 03cd77b..b147454 100644 --- a/test/targetapp/targetapp.vcproj +++ b/test/targetapp/targetapp.vcproj @@ -416,6 +416,10 @@ RelativePath="..\scripts\diatest.py" > </File> + <File + RelativePath="..\scripts\ehloadtest.py" + > + </File> <File RelativePath="..\scripts\eventtest.py" >