diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 5871675..e6ad6ae 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -13,6 +13,8 @@ #include "dbgpath.h" #include "dbgcmd.h" #include "dbgevent.h" +#include "typeinfo.h" +#include "typedvar.h" using namespace pykd; @@ -125,6 +127,19 @@ BOOST_PYTHON_MODULE( pykd ) .def( "field", &pykd::TypeInfo::getField ) .def( "__getattr__", &pykd::TypeInfo::getField ); + python::class_<pykd::TypedVar>("typedVar", + "Class of non-primitive type object, child class of typeClass. Data from target is copied into object instance", + python::no_init ) + .def("getAddress", &pykd::TypedVar::getAddress, + "Return virtual address" ) + .def("sizeof", &pykd::TypedVar::getSize, + "Return size of a variable in the target memory" ); + //.def("data", &pykd::TypedVar::data, + // "Return raw string object with data stream" ); + //.def("__getattr__", &pykd::TypedVar::getFieldWrap, + // "Return field of structure as an object attribute" ); + + python::class_<pykd::Module>("module", "Class representing executable module", python::no_init ) .def("begin", &pykd::Module::getBase, "Return start address of the module" ) @@ -146,6 +161,10 @@ BOOST_PYTHON_MODULE( pykd ) "Return rva of the symbol" ) .def("type", &pykd::Module::getTypeByName, "Return typeInfo class by type name" ) + .def("typedVar", &pykd::Module::getTypedVarByAddr, + "Return a typedVar class instance" ) + .def("typedVar",&pykd::Module::getTypedVarByName, + "Return a typedVar class instance" ) .def("__getattr__", &pykd::Module::getSymbol, "Return address of the symbol" ); diff --git a/pykd/module.cpp b/pykd/module.cpp index c35ad13..4345908 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -153,14 +153,27 @@ Module::reloadSymbols() /////////////////////////////////////////////////////////////////////////////////// TypeInfo -Module::getTypeByName( const std::string typeName ) +Module::getTypeByName( const std::string &typeName ) { - pyDia::SymbolPtr typeSym = m_dia->getChildByName( typeName ); + return TypeInfo( m_dia, typeName ); +} - if ( typeSym->getSymTag() == SymTagData ) - return TypeInfo( typeSym->getType() ); - else - return TypeInfo( typeSym ); +/////////////////////////////////////////////////////////////////////////////////// + +TypedVar +Module::getTypedVarByAddr( const std::string &typeName, ULONG64 addr ) +{ + return TypedVar( TypeInfo( m_dia, typeName ), addr ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +TypedVar +Module::getTypedVarByName( const std::string &symName ) +{ + pyDia::SymbolPtr typeSym = m_dia->getChildByName( symName ); + + return TypedVar( TypeInfo( typeSym->getType() ), typeSym->getRva() + m_base ); } /////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/module.h b/pykd/module.h index 07532f6..cc67dc1 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -5,6 +5,7 @@ #include "dbgobj.h" #include "diawrapper.h" #include "typeinfo.h" +#include "typedvar.h" namespace pykd { @@ -66,7 +67,11 @@ public: return sym->getRva(); } - TypeInfo getTypeByName( const std::string typeName ); + TypeInfo getTypeByName( const std::string &typeName ); + + TypedVar getTypedVarByAddr( const std::string &typeName, ULONG64 addr ); + + TypedVar getTypedVarByName( const std::string &symName ); private: diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index d1538d5..6012948 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -437,6 +437,10 @@ /> </FileConfiguration> </File> + <File + RelativePath=".\typeinfo.cpp" + > + </File> </Filter> <Filter Name="Header Files" @@ -499,6 +503,10 @@ RelativePath=".\stdafx.h" > </File> + <File + RelativePath=".\typedvar.h" + > + </File> <File RelativePath=".\typeinfo.h" > diff --git a/pykd/typedvar.h b/pykd/typedvar.h new file mode 100644 index 0000000..92016f3 --- /dev/null +++ b/pykd/typedvar.h @@ -0,0 +1,35 @@ +#pragma once + +#include "typeinfo.h" + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////////// + +class TypedVar { + +public: + + TypedVar ( const TypeInfo& typeInfo, ULONG64 offset ) : + m_typeInfo( typeInfo ), + m_offset( offset ) + {} + + ULONG64 getAddress() const { + return m_offset; + } + + ULONG getSize() { + return m_typeInfo.getSize(); + } + +private: + + TypeInfo m_typeInfo; + + ULONG64 m_offset; +}; + +/////////////////////////////////////////////////////////////////////////////////// + +}; // namespace pykd diff --git a/pykd/typeinfo.cpp b/pykd/typeinfo.cpp new file mode 100644 index 0000000..87256b0 --- /dev/null +++ b/pykd/typeinfo.cpp @@ -0,0 +1,61 @@ +#include "stdafx.h" + +#include "typeinfo.h" + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////////// + +TypeInfo::TypeInfo( pyDia::GlobalScopePtr &diaScope, const std::string &symName ) : + m_offset( 0 ) +{ + pyDia::SymbolPtr typeSym = diaScope->getChildByName( symName ); + + if ( typeSym->getSymTag() == SymTagData ) + { + m_dia = typeSym->getType(); + } + else + { + m_dia = typeSym; + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +std::string +TypeInfo::getName() +{ + std::stringstream sstr; + + pyDia::SymbolPtr diaptr = m_dia; + + int symtag = diaptr->getSymTag(); + + while( symtag == SymTagArrayType || symtag == SymTagPointerType ) + { + if ( symtag == SymTagArrayType ) + { + sstr << '[' << diaptr->getCount() << ']'; + } + else + { + sstr << '*'; + } + + diaptr = diaptr->getType(); + symtag = diaptr->getSymTag(); + } + + std::string typeName = symtag == SymTagBaseType ? + diaptr->getBasicTypeName( diaptr->getBaseType() ) : + diaptr->getName(); + + typeName += sstr.str(); + + return typeName; +}; + +/////////////////////////////////////////////////////////////////////////////////// + +}; // end namespace pykd \ No newline at end of file diff --git a/pykd/typeinfo.h b/pykd/typeinfo.h index 04bd248..c1dd14c 100644 --- a/pykd/typeinfo.h +++ b/pykd/typeinfo.h @@ -1,6 +1,7 @@ #pragma once -#include "dbgobj.h" +#include <string> + #include "diawrapper.h" namespace pykd { @@ -11,10 +12,12 @@ class TypeInfo { public: - TypeInfo( pyDia::SymbolPtr dia ) : - m_dia( dia ), - m_offset( 0 ) - {} + TypeInfo( pyDia::GlobalScopePtr &diaScope, const std::string &symName ); + + TypeInfo( pyDia::SymbolPtr &diaType ) : + m_offset( 0 ), + m_dia( diaType ) + {} TypeInfo getField( const std::string &fieldName ) { @@ -25,20 +28,16 @@ public: } std::string - getName() { - return m_dia->isBasicType() ? - m_dia->getBasicTypeName( m_dia->getBaseType() ) : - m_dia->getName(); - } + getName(); ULONG getOffset() { return m_offset; } - ULONG64 + ULONG getSize() { - return m_dia->getSize(); + return (ULONG)m_dia->getSize(); } private: @@ -50,4 +49,4 @@ private: /////////////////////////////////////////////////////////////////////////////////// -}; // namespace pykd \ No newline at end of file +}; // namespace pykd diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index ff3a026..08ffa24 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -19,6 +19,7 @@ import diatest import dbgcmd import clienttest import eventtest +import typedvar def getTestSuite( singleName = "" ): if singleName == "": @@ -27,6 +28,7 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ), unittest.TestLoader().loadTestsFromTestCase( diatest.DiaTest ), unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ), + unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ), unittest.TestLoader().loadTestsFromTestCase( dbgcmd.DbgcmdTest ), unittest.TestLoader().loadTestsFromTestCase( clienttest.DbgClientTest ), unittest.TestLoader().loadTestsFromTestCase( eventtest.EventTest ) @@ -48,5 +50,6 @@ if __name__ == "__main__": target.module.reload(); suite = getTestSuite() + #suite = getTestSuite( "typedvar.TypedVarTest.testCtor" ) unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( suite ) diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py new file mode 100644 index 0000000..08b4d42 --- /dev/null +++ b/test/scripts/typedvar.py @@ -0,0 +1,29 @@ +# +# +# + +import unittest +import target +import pykd + +class TypedVarTest( unittest.TestCase ): + + def testCtor( self ): + try: pykd.typedVar() + except RuntimeError: pass + + try: pykd.typedVar( "structTest", target.module.g_structTest ) + except RuntimeError: pass + + tv = target.module.typedVar( "structTest", target.module.g_structTest ) + tv = target.module.typedVar( "g_structTest" ) + + def testGetAddress( self ): + tv = target.module.typedVar( "structTest", target.module.g_structTest ) + self.assertEqual( tv.getAddress(), target.module.g_structTest ) + + def testGetSize( self ): + tv1 = target.module.typedVar( "structTest", target.module.g_structTest ) + self.assertEqual( 16, tv1.sizeof() ) + #tv2 = target.module.typedVar( "structTest[]", target.module.g_testArray ) + #self.assertEqual( tv1.sizeof()*2, tv2.sizeof() ) diff --git a/test/scripts/typeinfo.py b/test/scripts/typeinfo.py index 76b02aa..3053c76 100644 --- a/test/scripts/typeinfo.py +++ b/test/scripts/typeinfo.py @@ -28,17 +28,25 @@ class TypeInfoTest( unittest.TestCase ): def testName( self ): ti1 = target.module.type( "classChild" ) self.assertEqual( "classChild", ti1.name() ) - self.assertEqual( "Int", ti1.m_childField.name() ) + self.assertEqual( "Int", ti1.m_childField.name() ) self.assertEqual( "structTest", ti1.m_childField3.name() ) + self.assertEqual( "structTest", target.module.type("g_structTest").name() ) + + def testArrayName( self ): + self.assertEqual( "structTest[2]", target.module.type("g_testArray").name() ) + + def testPtrName( self ): + self.assertEqual( "structTest*", target.module.type("g_structTestPtr").name() ) + self.assertEqual( "structTest**", target.module.type("g_structTestPtrPtr").name() ) def testOffset( self ): ti1 = target.module.type( "structTest" ) self.assertEqual( 0, ti1.m_field0.offset() ) self.assertEqual( 4, ti1.m_field1.offset() ) - self.assertEqual( 12, ti1.m_field2.offset() ) - self.assertEqual( 14, ti1.m_field3.offset() ) + self.assertEqual( 12, ti1.m_field2.offset() ) + self.assertEqual( 14, ti1.m_field3.offset() ) def testSize( self ): ti1 = target.module.type( "structTest" ) - self.assertEqual( 16, ti1.size() ) + self.assertEqual( 16, ti1.size() ) diff --git a/test/targetapp/targetapp.cpp b/test/targetapp/targetapp.cpp index 57bea03..b0bd603 100644 --- a/test/targetapp/targetapp.cpp +++ b/test/targetapp/targetapp.cpp @@ -46,7 +46,12 @@ struct structTest { USHORT m_field3; }; -structTest g_structTest = { 0, 500, true, 1 }; +structTest g_structTest = { 0, 500, true, 1 }; + +structTest g_testArray[2] = { { 0, 500, true, 1 }, { 2, 1500, false, 1 } }; + +structTest *g_structTestPtr = &g_structTest; +structTest **g_structTestPtrPtr = &g_structTestPtr; class classChild : public classBase { public: @@ -79,6 +84,9 @@ void FuncWithName0() std::cout << g_ulonglongValue; std::cout << g_structTest.m_field0; + std::cout << g_testArray[1].m_field3; + std::cout << g_structTestPtr->m_field3; + std::cout << (*g_structTestPtrPtr)->m_field3; } void FuncWithName1(int a) diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj index 6784c0e..c15aa01 100644 --- a/test/targetapp/targetapp.vcproj +++ b/test/targetapp/targetapp.vcproj @@ -436,6 +436,10 @@ RelativePath="..\scripts\target.py" > </File> + <File + RelativePath="..\scripts\typedvar.py" + > + </File> <File RelativePath="..\scripts\typeinfo.py" >