diff --git a/pykd/dbgclient.cpp b/pykd/dbgclient.cpp index c25584b..f25aa89 100644 --- a/pykd/dbgclient.cpp +++ b/pykd/dbgclient.cpp @@ -439,38 +439,68 @@ void terminateProcess() static const boost::regex moduleSymMatch("^(?:([^!]*)!)?([^!]+)$"); -TypedVarPtr DebugClient::getTypedVarByName( const std::string &varName ) +void DebugClient::splitSymName( const std::string &fullName, std::string &moduleName, std::string &symbolName ) { boost::cmatch matchResult; - if ( !boost::regex_match( varName.c_str(), matchResult, moduleSymMatch ) ) + if ( !boost::regex_match( fullName.c_str(), matchResult, moduleSymMatch ) ) { std::stringstream sstr; - sstr << "invalid symbol name: " << varName; + sstr << "invalid symbol name: " << fullName; throw SymbolException( sstr.str() ); } - std::string symName = std::string( matchResult[2].first, matchResult[2].second ); + symbolName = std::string( matchResult[2].first, matchResult[2].second ); if ( matchResult[1].matched ) { - Module module = loadModuleByName( std::string( matchResult[1].first, matchResult[1].second ) ); + moduleName = std::string( matchResult[1].first, matchResult[1].second ); - return module.getTypedVarByName( symName ); + return; } HRESULT hres; ULONG64 base; - hres = m_symbols->GetSymbolModule( ( std::string("!") + symName ).c_str(), &base ); + hres = m_symbols->GetSymbolModule( ( std::string("!") + symbolName ).c_str(), &base ); if ( FAILED( hres ) ) { std::stringstream sstr; - sstr << "failed to find module for symbol: " << symName; + sstr << "failed to find module for symbol: " << symbolName; throw SymbolException( sstr.str() ); } - Module module = loadModuleByOffset( base ); + char nameBuffer[0x100]; + + hres = + m_symbols->GetModuleNameString( + DEBUG_MODNAME_MODULE, + DEBUG_ANY_ID, + base, + nameBuffer, + sizeof(nameBuffer), + NULL ); + + if ( FAILED( hres ) ) + { + std::stringstream sstr; + sstr << "failed to find module for symbol: " << symbolName; + throw SymbolException( sstr.str() ); + } + + moduleName = std::string( nameBuffer ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +TypedVarPtr DebugClient::getTypedVarByName( const std::string &varName ) +{ + std::string moduleName; + std::string symName; + + splitSymName( varName, moduleName, symName ); + + Module module = loadModuleByName( moduleName ); return module.getTypedVarByName( symName ); } @@ -479,39 +509,143 @@ TypedVarPtr DebugClient::getTypedVarByName( const std::string &varName ) TypedVarPtr DebugClient::getTypedVarByTypeName( const std::string &typeName, ULONG64 addr ) { - boost::cmatch matchResult; + addr = addr64( addr ); - if ( !boost::regex_match( typeName.c_str(), matchResult, moduleSymMatch ) ) - { - std::stringstream sstr; - sstr << "invalid symbol name: " << typeName; - throw SymbolException( sstr.str() ); - } + std::string moduleName; + std::string symName; - std::string symName = std::string( matchResult[2].first, matchResult[2].second ); + splitSymName( typeName, moduleName, symName ); - if ( matchResult[1].matched ) - { - Module module = loadModuleByName( std::string( matchResult[1].first, matchResult[1].second ) ); - - return module.getTypedVarByTypeName( symName, addr ); - } - - HRESULT hres; - ULONG64 base; - - hres = m_symbols->GetSymbolModule( ( std::string("!") + symName ).c_str(), &base ); - if ( FAILED( hres ) ) - { - std::stringstream sstr; - sstr << "failed to find module for symbol: " << symName; - throw SymbolException( sstr.str() ); - } - - Module module = loadModuleByOffset( base ); + Module module = loadModuleByName( moduleName ); return module.getTypedVarByTypeName( symName, addr ); +} +/////////////////////////////////////////////////////////////////////////////////// + +TypedVarPtr DebugClient::containingRecordByName( ULONG64 addr, const std::string &typeName, const std::string &fieldName ) +{ + addr = addr64( addr ); + + std::string moduleName; + std::string symName; + + splitSymName( typeName, moduleName, symName ); + + Module module = loadModuleByName( moduleName ); + + return module.containingRecordByName( addr, symName, fieldName ); +} + +TypedVarPtr containingRecordByName( ULONG64 addr, const std::string &typeName, const std::string &fieldName ) +{ + return g_dbgClient->containingRecordByName( addr, typeName, fieldName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +TypedVarPtr DebugClient::containingRecordByType( ULONG64 addr, const TypeInfoPtr &typeInfo, const std::string &fieldName ) +{ + addr = addr64(addr); + + TypeInfoPtr fieldTypeInfo = typeInfo->getField( fieldName ); + + VarDataPtr varData = VarDataMemory::factory( m_dataSpaces, addr - fieldTypeInfo->getOffset() ); + + return TypedVar::getTypedVar( m_client, typeInfo, varData ); +} + +TypedVarPtr containingRecordByType( ULONG64 addr, const TypeInfoPtr &typeInfo, const std::string &fieldName ) +{ + return g_dbgClient->containingRecordByType( addr, typeInfo, fieldName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +python::list DebugClient::getTypedVarListByType( ULONG64 listHeadAddress, const TypeInfoPtr &typeInfo, const std::string &listEntryName )\ +{ + python::list lst; + + listHeadAddress = addr64( listHeadAddress ); + + ULONG64 entryAddress = 0; + + TypeInfoPtr fieldTypeInfo = typeInfo->getField( listEntryName ); + + if ( fieldTypeInfo->getName() == ( typeInfo->getName() + "*" ) ) + { + for( entryAddress = ptrPtr( listHeadAddress ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress + fieldTypeInfo->getOffset() ) ) + lst.append( getTypedVarByTypeInfo( typeInfo, entryAddress ) ); + } + else + { + for( entryAddress = ptrPtr( listHeadAddress ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress ) ) + lst.append( containingRecordByType( entryAddress, typeInfo, listEntryName ) ); + } + + return lst; +} + +python::list getTypedVarListByType( ULONG64 listHeadAddress, const TypeInfoPtr &typeInfo, const std::string &listEntryName ) +{ + return g_dbgClient->getTypedVarListByType( listHeadAddress, typeInfo, listEntryName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +python::list DebugClient::getTypedVarListByTypeName( ULONG64 listHeadAddress, const std::string &typeName, const std::string &listEntryName ) +{ + std::string moduleName; + std::string symName; + + splitSymName( typeName, moduleName, symName ); + + Module module = loadModuleByName( moduleName ); + + return module.getTypedVarListByTypeName( listHeadAddress, symName, listEntryName ); +} + +python::list getTypedVarListByTypeName( ULONG64 listHeadAddress, const std::string &typeName, const std::string &listEntryName ) +{ + return g_dbgClient->getTypedVarListByTypeName( listHeadAddress, typeName, listEntryName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +python::list DebugClient::getTypedVarArrayByType( ULONG64 address, const TypeInfoPtr &typeInfo, ULONG number ) +{ + address = addr64(address); + + python::list lst; + + for( ULONG i = 0; i < number; ++i ) + lst.append( getTypedVarByTypeInfo( typeInfo, address + i * typeInfo->getSize() ) ); + + return lst; +} + +python::list getTypedVarArrayByType( ULONG64 address, const TypeInfoPtr &typeInfo, ULONG number ) +{ + return g_dbgClient->getTypedVarArrayByType( address, typeInfo, number ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +python::list DebugClient::getTypedVarArrayByTypeName( ULONG64 addr, const std::string &typeName, ULONG number ) +{ + std::string moduleName; + std::string symName; + + splitSymName( typeName, moduleName, symName ); + + Module module = loadModuleByName( moduleName ); + + return module.getTypedVarArrayByTypeName( addr, symName, number ); +} + +python::list getTypedVarArrayByTypeName( ULONG64 addr, const std::string &typeName, ULONG number ) +{ + return g_dbgClient->getTypedVarArrayByTypeName( addr, typeName, number ); } /////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h index 4877d0a..9b8d0bc 100644 --- a/pykd/dbgclient.h +++ b/pykd/dbgclient.h @@ -325,6 +325,8 @@ public: void removeBp(BPOINT_ID Id); void removeAllBp(); + void splitSymName( const std::string &fullName, std::string &moduleName, std::string &symbolName ); + TypedVarPtr getTypedVarByName( const std::string &varName ); TypedVarPtr getTypedVarByTypeName( const std::string &typeName, ULONG64 addr ); @@ -332,7 +334,21 @@ public: TypedVarPtr getTypedVarByTypeInfo( const TypeInfoPtr &typeInfo, ULONG64 addr ) { return TypedVar::getTypedVar( m_client, typeInfo, VarDataMemory::factory(m_dataSpaces, addr) ); } - + + TypedVarPtr containingRecordByName( ULONG64 addr, const std::string &typeName, const std::string &fieldName ); + + TypedVarPtr containingRecordByType( ULONG64 addr, const TypeInfoPtr &typeInfo, const std::string &fieldName ); + + + python::list getTypedVarListByTypeName( ULONG64 listHeadAddres, const std::string &typeName, const std::string &listEntryName ); + + python::list getTypedVarListByType( ULONG64 listHeadAddres, const TypeInfoPtr &typeInfo, const std::string &listEntryName ); + + python::list getTypedVarArrayByTypeName( ULONG64 addr, const std::string &typeName, ULONG number ); + + python::list getTypedVarArrayByType( ULONG64 addr, const TypeInfoPtr &typeInfo, ULONG number ); + + private: template python::list @@ -388,6 +404,18 @@ void terminateProcess(); void waitForEvent(); +TypedVarPtr containingRecordByName( ULONG64 addr, const std::string &typeName, const std::string &fieldName ); + +TypedVarPtr containingRecordByType( ULONG64 addr, const TypeInfoPtr &typeInfo, const std::string &fieldName ); + +python::list getTypedVarListByTypeName( ULONG64 listHeadAddres, const std::string &typeName, const std::string &listEntryName ); + +python::list getTypedVarListByType( ULONG64 listHeadAddres, const TypeInfoPtr &typeInfo, const std::string &listEntryName ); + +python::list getTypedVarArrayByTypeName( ULONG64 addr, const std::string &typeName, ULONG number ); + +python::list getTypedVarArrayByType( ULONG64 addr, const TypeInfoPtr &typeInfo, ULONG number ); + ///////////////////////////////////////////////////////////////////////////////// // Synthetic symbols global finctions: diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 55ae0f2..6ec0839 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -304,6 +304,20 @@ BOOST_PYTHON_MODULE( pykd ) "Return symbol path" ) .def( "trace", &DebugClient::changeDebuggerStatus, "Change debugger status to DEBUG_STATUS_STEP_INTO" ) + .def("typedVarList", &DebugClient::getTypedVarListByTypeName, + "Return a list of the typedVar class instances. Each item represents an item of the linked list in the target memory" ) + .def("typedVarList", &DebugClient::getTypedVarListByType, + "Return a list of the typedVar class instances. Each item represents an item of the linked list in the target memory" ) + .def("typedVarArray", &DebugClient::getTypedVarArrayByTypeName, + "Return a list of the typedVar class instances. Each item represents an item of the counted array in the target memory" ) + .def("typedVarArray", &DebugClient::getTypedVarArrayByType, + "Return a list of the typedVar class instances. Each item represents an item of the counted array in the target memory" ) + .def("containingRecord", &DebugClient::containingRecordByName, + "Return instance of the typedVar class. It's value are loaded from the target memory." + "The start address is calculated by the same method as the standard macro CONTAINING_RECORD does" ) + .def("containingRecord", &DebugClient::containingRecordByType, + "Return instance of the typedVar class. It's value are loaded from the target memory." + "The start address is calculated by the same method as the standard macro CONTAINING_RECORD does" ) .def( "waitForEvent", &DebugClient::waitForEvent, "Wait for events that breaks into the debugger" ) .def( "wrmsr", &DebugClient::setMSR, @@ -491,6 +505,20 @@ BOOST_PYTHON_MODULE( pykd ) "Set MSR value" ); python::def( "trace", &changeDebuggerStatus, "Change debugger status to DEBUG_STATUS_STEP_INTO" ); + python::def("typedVarList", &getTypedVarListByTypeName, + "Return a list of the typedVar class instances. Each item represents an item of the linked list in the target memory" ); + python::def("typedVarList", &getTypedVarListByType, + "Return a list of the typedVar class instances. Each item represents an item of the linked list in the target memory" ); + python::def("typedVarArray", &getTypedVarArrayByTypeName, + "Return a list of the typedVar class instances. Each item represents an item of the counted array in the target memory" ); + python::def("typedVarArray", &getTypedVarArrayByType, + "Return a list of the typedVar class instances. Each item represents an item of the counted array in the target memory" ); + python::def("containingRecord", &containingRecordByName, + "Return instance of the typedVar class. It's value are loaded from the target memory." + "The start address is calculated by the same method as the standard macro CONTAINING_RECORD does" ); + python::def("containingRecord", &containingRecordByType, + "Return instance of the typedVar class. It's value are loaded from the target memory." + "The start address is calculated by the same method as the standard macro CONTAINING_RECORD does" ); python::def( "waitForEvent", &waitForEvent, "Wait for events that breaks into the debugger" ); python::def( "getNumberProcessors", &getNumberProcessors, diff --git a/pykd/module.cpp b/pykd/module.cpp index d80d50d..49de94b 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -347,12 +347,12 @@ python::list Module::getTypedVarListByType( ULONG64 listHeadAddress, const TypeI if ( fieldTypeInfo->getName() == ( typeInfo->getName() + "*" ) ) { - for( entryAddress = ptrPtr( listHeadAddress ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress + fieldTypeInfo->getOffset() ) ) + for( entryAddress = ptrPtr( listHeadAddress, m_dataSpaces ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress + fieldTypeInfo->getOffset() ) ) lst.append( getTypedVarByType( typeInfo, entryAddress ) ); } else { - for( entryAddress = ptrPtr( listHeadAddress ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress ) ) + for( entryAddress = ptrPtr( listHeadAddress, m_dataSpaces ); addr64(entryAddress) != listHeadAddress && entryAddress != NULL; entryAddress = ptrPtr( entryAddress ) ) lst.append( containingRecordByType( entryAddress, typeInfo, listEntryName ) ); } diff --git a/test/scripts/basetest.py b/test/scripts/basetest.py index b336049..297f2bb 100644 --- a/test/scripts/basetest.py +++ b/test/scripts/basetest.py @@ -17,6 +17,7 @@ class BaseTest( unittest.TestCase ): self.assertTrue( hasattr(pykd, 'addr64') ) self.assertTrue( hasattr(pykd, 'breakin') ) self.assertTrue( hasattr(pykd, 'compareMemory') ) + self.assertTrue( hasattr(pykd, 'containingRecord') ) self.assertTrue( hasattr(pykd, 'dbgCommand') ) self.assertTrue( hasattr(pykd, 'dprint') ) self.assertTrue( hasattr(pykd, 'dprintln') ) @@ -76,6 +77,8 @@ class BaseTest( unittest.TestCase ): self.assertTrue( hasattr(pykd, 'startProcess') ) self.assertTrue( hasattr(pykd, 'step') ) self.assertTrue( hasattr(pykd, 'symbolsPath') ) + self.assertTrue( hasattr(pykd, 'typedVarArray') ) + self.assertTrue( hasattr(pykd, 'typedVarList') ) self.assertTrue( hasattr(pykd, 'trace') ) self.assertTrue( hasattr(pykd, 'wrmsr') ) @@ -95,7 +98,6 @@ class BaseTest( unittest.TestCase ): def testOldRemovedApi( self ): """ Branch test: old API 0.0.x what should be removed """ - self.assertFalse( hasattr(pykd, 'containingRecord') ) self.assertFalse( hasattr(pykd, 'dbgModuleClass') ) self.assertFalse( hasattr(pykd, 'dbgStackFrameClass') ) self.assertFalse( hasattr(pykd, 'debugEvent') ) @@ -104,8 +106,6 @@ class BaseTest( unittest.TestCase ): self.assertFalse( hasattr(pykd, 'loadPtrs') ) self.assertFalse( hasattr(pykd, 'reloadModule') ) self.assertFalse( hasattr(pykd, 'sizeof') ) - self.assertFalse( hasattr(pykd, 'typedVarArray') ) - self.assertFalse( hasattr(pykd, 'typedVarList') ) self.assertFalse( hasattr(pykd, 'windbgIn') ) self.assertFalse( hasattr(pykd, 'windbgOut') ) self.assertFalse( hasattr(pykd, 'bp') ) diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 4833bd4..23f7644 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -125,6 +125,11 @@ class TypedVarTest( unittest.TestCase ): self.assertEqual( 3, len( tvl ) ) self.assertEqual( [1000,2000,3000], [ tv.m_someBaseFiled2 for tv in tvl ] ) self.assertEqual( [1001,2001,3001], [ tv.m_childFiled1 for tv in tvl ] ) + + tvl1 = target.module.typedVarList( target.module.g_listHead, "listStruct", "listEntry" ) + tvl2 = pykd.typedVarList( target.module.g_listHead, target.moduleName + "!listStruct", "listEntry" ) + self.assertEqual( tvl1, tvl2 ) + def testTypedVarArray(self): tvl = target.module.typedVarArray( target.module.g_testArray, "structTest", 2 ) @@ -137,6 +142,10 @@ class TypedVarTest( unittest.TestCase ): self.assertEqual( 1, tvl[0].m_field3 ) self.assertEqual( 0, tvl[1].m_field4 ) + tvl1 = target.module.typedVarArray( target.module.g_testArray, "structTest", 2 ) + tvl2 = pykd.typedVarArray( target.module.g_testArray, target.moduleName + "!structTest", 2 ) + self.assertEqual( tvl1, tvl2 ) + def testEqual(self): tv1 = target.module.typedVar("g_structTest") tv2 = target.module.typedVar("intMatrix")