diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index 53a9398..f518e01 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -48,6 +48,8 @@ ULONG getModuleSize( ULONG64 baseOffset ); std::string getModuleSymbolFileName( ULONG64 baseOffset ); ULONG getModuleTimeStamp( ULONG64 baseOffset ); ULONG getModuleCheckSum( ULONG64 baseOffset ); +bool isModuleUnloaded( ULONG64 baseOffset ); +bool isModuleUserMode( ULONG64 baseOffset ); std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value ); void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow ); diff --git a/pykd/module.cpp b/pykd/module.cpp index 8e3aa55..656f4af 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -27,10 +27,7 @@ Module::Module(const std::string &moduleName ) { m_base = findModuleBase( moduleName ); m_name = moduleName; - m_imageName = getModuleImageName( m_base ); - m_timeDataStamp = getModuleTimeStamp( m_base ); - m_checkSum = getModuleCheckSum( m_base ); - m_size = getModuleSize( m_base ); + completeConstruct(); } ///////////////////////////////////////////////////////////////////////////////////// @@ -39,10 +36,19 @@ Module::Module(ULONG64 offset ) { m_base = findModuleBase( addr64(offset) ); m_name = getModuleName( m_base ); + completeConstruct(); +} + +///////////////////////////////////////////////////////////////////////////////////// + +void Module::completeConstruct() +{ m_imageName = getModuleImageName( m_base ); m_timeDataStamp = getModuleTimeStamp( m_base ); m_checkSum = getModuleCheckSum( m_base ); m_size = getModuleSize( m_base ); + m_unloaded = isModuleUnloaded( m_base ); + m_userMode = isModuleUserMode( m_base ); } ///////////////////////////////////////////////////////////////////////////////////// @@ -176,7 +182,8 @@ std::string Module::print() prepareSymbolFile(); sstr << "Module: " << m_name << std::endl; - sstr << "Start: " << std::hex << m_base << " End: " << getEnd() << " Size: " << m_size << std::endl; + sstr << "Start: " << std::hex << m_base << " End: " << getEnd() << " Size: " << m_size; + sstr << (m_unloaded ? ", UNLOADED!" : "") << std::endl; sstr << "Image: " << m_imageName << std::endl; if ( m_symSession ) sstr << "Symbols: " << m_symSession->getSymbolFileName() << std::endl; diff --git a/pykd/module.h b/pykd/module.h index 42a0ace..3140b09 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -80,6 +80,14 @@ public: return m_timeDataStamp; } + bool isUnloaded() const { + return m_unloaded; + } + + bool isUserMode() const { + return m_userMode; + } + TypeInfoPtr getTypeByName( const std::string &typeName ) { return TypeInfo::getTypeInfo( boost::static_pointer_cast<Symbol>( getSymScope() ), typeName); } @@ -119,6 +127,7 @@ public: python::tuple getVersion(); private: + void completeConstruct(); // call from ctor ULONG64 prepareVa(ULONG64 addr); @@ -140,6 +149,8 @@ private: ULONG m_size; ULONG m_timeDataStamp; ULONG m_checkSum; + bool m_unloaded; + bool m_userMode; SymbolSessionPtr m_symSession; }; diff --git a/pykd/python/pymod.cpp b/pykd/python/pymod.cpp index da91adc..e913fc8 100644 --- a/pykd/python/pymod.cpp +++ b/pykd/python/pymod.cpp @@ -403,10 +403,14 @@ BOOST_PYTHON_MODULE( pykd ) "Return list of tuple ( symbolname, offset )" ) ) .def("enumTypes", &Module::enumTypes, Module_enumTypes( python::args("mask"), "Return list of type's names" )) - .def("checksum",&Module::getCheckSum, + .def("checksum", &Module::getCheckSum, "Return a image file checksum: IMAGE_OPTIONAL_HEADER.CheckSum" ) - .def("timestamp",&Module::getTimeDataStamp, + .def("timestamp", &Module::getTimeDataStamp, "Return a low 32 bits of the time stamp of the image: IMAGE_FILE_HEADER.TimeDateStamp" ) + .def("unloaded", &Module::isUnloaded, + "Returns a flag that the module was unloaded") + .def("um", &Module::isUserMode, + "Returns a flag that the module is a user-mode module") .def("queryVersion", &Module::queryVersion, "Return string from the module's version resources" ) .def("getVersion", &Module::getVersion, diff --git a/pykd/win/dbgmod.cpp b/pykd/win/dbgmod.cpp index 72ba3f1..1a3c898 100644 --- a/pykd/win/dbgmod.cpp +++ b/pykd/win/dbgmod.cpp @@ -24,7 +24,7 @@ ULONG64 findModuleBase( const std::string &moduleName ) hres = g_dbgEng->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &base ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); + throw DbgException( "IDebugSymbol::GetModuleByModuleName", hres ); return base; } @@ -41,7 +41,7 @@ ULONG64 findModuleBase( ULONG64 offset ) hres = g_dbgEng->symbols->GetModuleByOffset( offset, 0, &moduleIndex, &base ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleByOffset failed" ); + throw DbgException( "IDebugSymbol::GetModuleByOffset", hres ); return base; } @@ -85,7 +85,7 @@ std::string getModuleNameImpl( ULONG64 baseOffset ) NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); + throw DbgException( "IDebugSymbol::GetModuleNameString", hres ); return std::string( moduleName ); } @@ -117,7 +117,7 @@ std::string getModuleImageName( ULONG64 baseOffset ) NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); + throw DbgException( "IDebugSymbol::GetModuleNameString", hres ); return std::string( imageName ); } @@ -133,7 +133,7 @@ ULONG getModuleSizeImpl( ULONG64 baseOffset ) hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + throw DbgException( "IDebugSymbol::GetModuleParameters", hres ); return moduleParam.Size; } @@ -168,7 +168,7 @@ std::string getModuleSymbolFileName( ULONG64 baseOffset ) NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); + throw DbgException( "IDebugAdvanced2::GetSymbolInformation", hres ); if (!*moduleInfo.LoadedPdbName) { @@ -177,7 +177,7 @@ std::string getModuleSymbolFileName( ULONG64 baseOffset ) hres = g_dbgEng->symbols->ReloadWide( sstr.str().c_str() ); if ( FAILED( hres ) ) - throw DbgException("IDebugSymbols::Reload failed" ); + throw DbgException("IDebugSymbols::Reload", hres ); hres = g_dbgEng->advanced->GetSymbolInformation( DEBUG_SYMINFO_IMAGEHLP_MODULEW64, @@ -191,7 +191,7 @@ std::string getModuleSymbolFileName( ULONG64 baseOffset ) NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" ); + throw DbgException( "IDebugAdvanced2::GetSymbolInformation", hres ); } char pdbName[ 256 ]; @@ -211,7 +211,7 @@ ULONG getModuleTimeStampImpl( ULONG64 baseOffset ) hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + throw DbgException( "IDebugSymbol::GetModuleParameters", hres ); return moduleParam.TimeDateStamp; } @@ -236,7 +236,7 @@ ULONG getModuleCheckSumImpl( ULONG64 baseOffset ) hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + throw DbgException( "IDebugSymbol::GetModuleParameters", hres ); return moduleParam.Checksum; } @@ -252,6 +252,36 @@ ULONG getModuleCheckSum( ULONG64 baseOffset ) /////////////////////////////////////////////////////////////////////////////// +namespace { + +ULONG getModuleFlags(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", hres ); + + return moduleParam.Flags; +} + +} + +bool isModuleUnloaded( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + return !!(getModuleFlags(baseOffset) & DEBUG_MODULE_UNLOADED); +} + +bool isModuleUserMode( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + return !!(getModuleFlags(baseOffset) & DEBUG_MODULE_USER_MODE); +} + +/////////////////////////////////////////////////////////////////////////////// + void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow ) { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); @@ -269,7 +299,7 @@ void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorL NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation", hres ); majorHigh = HIWORD(fileInfo.dwFileVersionMS); majorLow = LOWORD(fileInfo.dwFileVersionMS); @@ -301,7 +331,7 @@ std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value ) &codePagesSize ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation", hres ); size_t codePageNum = codePagesSize / sizeof(LANGANDCODEPAGE); @@ -316,7 +346,7 @@ std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value ) NULL ); if ( FAILED( hres ) ) - throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" ); + throw DbgException( "IDebugSymbol2::GetModuleVersionInformation", hres ); ULONG productNameLength = 0; diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index 44b6e30..b0535e8 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -12,26 +12,30 @@ class ModuleTest( unittest.TestCase ): def testCtor( self ): self.assertEqual( target.module.name(), pykd.module(target.module.begin() ).name() ) self.assertEqual( target.module.name(), pykd.module(target.module.name() ).name() ) - + + def testMiscellaneous( self ): + self.assertFalse( target.module.unloaded() ) + self.assertTrue( target.module.um() ) + def testName( self ): self.assertEqual( target.moduleName, target.module.name() ) - + def testSize( self ): self.assertNotEqual( 0, target.module.size() ) self.assertTrue( pykd.isValid( target.module.begin() + target.module.size() - 1) ) - + def testBegin( self ): self.assertNotEqual( 0, target.module.begin() ) self.assertEqual( target.module.begin(), target.module ) self.assertEqual( target.module.begin() + 100, target.module + 100 ) - + def testEnd( self ): self.assertEqual( target.module.size(), target.module.end() - target.module.begin() ) self.assertTrue( pykd.isValid( target.module.end() - 1) ) - + def testPdb( self ): self.assertNotEqual( "", target.module.symfile() ) - + def testImage( self ): self.assertEqual( target.module.name() + ".exe", target.module.image() )