diff --git a/pykd/dbgexcept.h b/pykd/dbgexcept.h index fd7c8e8..846dd4f 100644 --- a/pykd/dbgexcept.h +++ b/pykd/dbgexcept.h @@ -5,6 +5,32 @@ namespace pykd { + +///////////////////////////////////////////////////////////////////////////////// + +class PyException +{ +public: + + PyException( PyObject* pyObj, const std::string &desc ) : + m_typeObj( pyObj ), + m_desc( desc ) + {} + + static + void + exceptionTranslate(const PyException &e ) { + PyErr_SetString( e.m_typeObj, e.m_desc.c_str() ); + } + +private: + + PyObject* m_typeObj; + + std::string m_desc; + +}; + ///////////////////////////////////////////////////////////////////////////////// class DbgException : public std::exception diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 210e29e..836ac12 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -386,7 +386,9 @@ BOOST_PYTHON_MODULE( pykd ) "Return field of structure as an object attribute" ) .def("__getattr__", &TypedVar::getField, "Return field of structure as an object attribute" ) - .def( "__str__", &TypedVar::print ); + .def( "__str__", &TypedVar::print ) + .def("__len__", &TypedVar::getElementCount ) + .def("__getitem__", &TypedVar::getElementByIndex ); python::class_("module", "Class representing executable module", python::no_init ) .def("begin", &pykd::Module::getBase, @@ -625,6 +627,9 @@ BOOST_PYTHON_MODULE( pykd ) // exception: + // wrapper for standart python exceptions + python::register_exception_translator( &PyException::exceptionTranslate ); + // base exception python::class_ dbgExceptionClass( "BaseException", "Pykd base exception class", diff --git a/pykd/intbase.h b/pykd/intbase.h index 890420c..961ae2d 100644 --- a/pykd/intbase.h +++ b/pykd/intbase.h @@ -36,7 +36,11 @@ public: std::stringstream ss; ss << std::hex << getValue(); return ss.str(); - } + } + + template + bool operator!=(T const& rhs) + { return getValue() == rhs } template intBase& operator+=(T const& rhs) diff --git a/pykd/typedvar.cpp b/pykd/typedvar.cpp index c14fe1b..e47eb24 100644 --- a/pykd/typedvar.cpp +++ b/pykd/typedvar.cpp @@ -7,6 +7,41 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////////// +TypedVarPtr TypedVar::getTypedVar( IDebugClient4 *client, const TypeInfoPtr& typeInfo, ULONG64 offset ) +{ + TypedVarPtr tv; + + if ( typeInfo->isBasicType() ) + { + tv.reset( new BasicTypedVar( client, typeInfo, offset) ); + return tv; + } + + if ( typeInfo->isPointer() ) + { + tv.reset( new PtrTypedVar( client, typeInfo, offset ) ); + return tv; + } + + if ( typeInfo->isArray() ) + { + tv.reset( new ArrayTypedVar( client, typeInfo, offset ) ); + return tv; + } + + if ( typeInfo->isUserDefined() ) + { + tv.reset( new TypedVar( client, typeInfo, offset ) ); + return tv; + } + + throw DbgException( "can not get field" ); + + return tv; +} + +/////////////////////////////////////////////////////////////////////////////////// + TypedVar::TypedVar ( IDebugClient4 *client, const TypeInfoPtr& typeInfo, ULONG64 offset ) : DbgObject( client ), m_typeInfo( typeInfo ), @@ -46,6 +81,12 @@ TypedVar::getField( const std::string &fieldName ) return tv; } + if ( fieldType->isArray() ) + { + tv.reset( new ArrayTypedVar( m_client, fieldType, m_offset + fieldType->getOffset() ) ); + return tv; + } + if ( fieldType->isUserDefined() ) { tv.reset( new TypedVar( m_client, fieldType, m_offset + fieldType->getOffset() ) ); diff --git a/pykd/typedvar.h b/pykd/typedvar.h index 03d4abe..e381672 100644 --- a/pykd/typedvar.h +++ b/pykd/typedvar.h @@ -3,6 +3,7 @@ #include "typeinfo.h" #include "intbase.h" #include "dbgobj.h" +#include "dbgexcept.h" namespace pykd { @@ -17,6 +18,8 @@ class TypedVar : public intBase, protected DbgObject { public: + static TypedVarPtr getTypedVar( IDebugClient4 *client, const TypeInfoPtr& typeInfo, ULONG64 offset ); + TypedVar ( const TypeInfoPtr& typeInfo, ULONG64 offset ); @@ -45,6 +48,14 @@ public: return "TypeVar"; } + virtual ULONG getElementCount() { + throw PyException( PyExc_TypeError, "object has no len()" ); + } + + virtual TypedVarPtr getElementByIndex( ULONG index ) { + throw PyException( PyExc_TypeError, "object is unsubscriptable"); + } + protected: virtual ULONG64 getValue() const { @@ -106,4 +117,29 @@ public: /////////////////////////////////////////////////////////////////////////////////// +class ArrayTypedVar: public TypedVar { + +public: + + ArrayTypedVar ( IDebugClient4 *client, const TypeInfoPtr& typeInfo, ULONG64 offset ) : TypedVar(client, typeInfo, offset){} + + virtual ULONG getElementCount() { + return m_typeInfo->getCount(); + } + + virtual TypedVarPtr getElementByIndex( ULONG index ) { + + if ( index > m_typeInfo->getCount() ) + { + throw PyException( PyExc_IndexError, "Index out of range" ); + } + + TypeInfoPtr elementType = m_typeInfo->getElementType(); + + return TypedVar::getTypedVar( m_client, elementType, m_offset + elementType->getSize()*index ); + } +}; + +/////////////////////////////////////////////////////////////////////////////////// + } // namespace pykd diff --git a/pykd/typeinfo.h b/pykd/typeinfo.h index 95e7a93..4350f19 100644 --- a/pykd/typeinfo.h +++ b/pykd/typeinfo.h @@ -45,10 +45,22 @@ public: return false; } + virtual bool isArray() { + return false; + } + virtual bool isUserDefined() { return false; } + virtual ULONG getCount() { + throw DbgException( "there is no element" ); + } + + virtual TypeInfoPtr getElementType() { + throw DbgException( "there is no element" ); + } + ULONG getOffset() { return m_offset; } @@ -199,6 +211,19 @@ public: throw DbgException( "there is no such field" ); } + virtual bool isArray() { + return true; + } + + virtual ULONG getCount() { + return m_count; + } + + virtual TypeInfoPtr getElementType() { + return m_derefType; + } + + private: TypeInfoPtr m_derefType; diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 5869c0c..012bb46 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -52,8 +52,8 @@ if __name__ == "__main__": target.module.reload(); suite = getTestSuite() - #suite = getTestSuite( "memtest.MemoryTest.testPtrRead" ) + #suite = getTestSuite( "typedvar.TypedVarTest" ) unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( suite ) - #a = raw_input("\npress return\n") \ No newline at end of file + a = raw_input("\npress return\n") \ No newline at end of file diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 635c6cd..12c841f 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -19,8 +19,8 @@ class TypedVarTest( unittest.TestCase ): def testGetSize( self ): tv1 = target.module.typedVar( "structTest", target.module.g_structTest ) self.assertEqual( 20, tv1.sizeof() ) - #tv2 = target.module.typedVar( "structTest[2]", target.module.g_testArray ) - #self.assertEqual( tv1.sizeof()*2, tv2.sizeof() ) + tv2 = target.module.typedVar( "structTest[2]", target.module.g_testArray ) + self.assertEqual( tv1.sizeof()*2, tv2.sizeof() ) def testByAddress( self ): tv1 = target.module.typedVar( "structTest", target.module.g_structTest ) @@ -46,3 +46,10 @@ class TypedVarTest( unittest.TestCase ): self.assertEqual( 0, tv.m_field0.offset() ) self.assertEqual( 4, tv.m_field1.offset() ) self.assertEqual( 16, tv.m_field4.offset() ) + + def testArrayField(self): + tv = target.module.typedVar( "g_struct3" ) + self.assertEqual( 2, len(tv.m_arrayField) ) + self.assertEqual( 0, tv.m_arrayField[0] ) + self.assertEqual( 2, tv.m_arrayField[1] ) + self.assertEqual( 3, tv.m_noArrayField ) diff --git a/test/targetapp/targetapp.cpp b/test/targetapp/targetapp.cpp index c3c21c3..ccf5408 100644 --- a/test/targetapp/targetapp.cpp +++ b/test/targetapp/targetapp.cpp @@ -95,6 +95,13 @@ struct struct2 { int m_field; }; +struct struct3 { + int m_arrayField[2]; + int m_noArrayField; +}; + +struct3 g_struct3 = { { 0, 2 }, 3 }; + __int64 g_bigValue = 0x8080808080808080; void FuncWithName0() @@ -126,6 +133,7 @@ void FuncWithName0() std::cout << intMatrix[1][1]; std::cout << strArray[0]; std::cout << (*ptrIntMatrix)[0][1]; + std::cout << g_struct3.m_noArrayField; } void FuncWithName1(int a)