diff --git a/pykd/dbgexcept.h b/pykd/dbgexcept.h index 9948597..0956622 100644 --- a/pykd/dbgexcept.h +++ b/pykd/dbgexcept.h @@ -25,6 +25,13 @@ public: {} }; +class StopIteration : public std::exception +{ +public: + + StopIteration(const char* desc) : std::exception(desc) + {} +}; template< class TExcept > struct exceptPyType{ @@ -111,6 +118,12 @@ inline void pykdExceptionTranslate(const std::exception &e) return; } + if (typeid(e).hash_code() == typeid(StopIteration).hash_code()) + { + PyErr_SetString(PyExc_StopIteration, e.what()); + return; + } + } inline void registerExceptions() @@ -125,6 +138,7 @@ inline void registerExceptions() python::register_exception_translator<kdlib::DbgException>( &dbgExceptionTranslate ); python::register_exception_translator<OverflowException>( &pykdExceptionTranslate ); python::register_exception_translator<AttributeException>(&pykdExceptionTranslate); + python::register_exception_translator<StopIteration>(&pykdExceptionTranslate); } ///////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index f9eb93f..aa903a9 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -928,6 +928,11 @@ BOOST_PYTHON_MODULE( pykd ) #endif ; + python::class_<TypedVarIterator>("typedVarIterator", "iterator for typedVar array", python::no_init) + .def("__iter__", &TypedVarIterator::self) + .def("next", &TypedVarIterator::next) + ; + python::class_<kdlib::TypedVar, kdlib::TypedVarPtr, python::bases<kdlib::NumBehavior>, boost::noncopyable >("typedVar", "Class of non-primitive type object, child class of typeClass. Data from target is copied into object instance", python::no_init ) .def("__init__", python::make_constructor(pykd::getTypedVarByName) ) @@ -982,6 +987,7 @@ BOOST_PYTHON_MODULE( pykd ) .def("__setitem__", TypedVarAdapter::setElementByIndex ) .def("__dir__", TypedVarAdapter::getElementsDir) .def("__call__", python::raw_function(pykd::callFunctionByVar, 0) ) + .def("__iter__", TypedVarAdapter::getArrayIter, python::return_value_policy<python::manage_new_object>()) //.def("__getitem__", &kdlib::TypedVar::getElementByIndexPtr ) #if PY_VERSION_HEX >= 0x03000000 .def("__bool__", TypedVarAdapter::isNotZero) diff --git a/pykd/pytypedvar.h b/pykd/pytypedvar.h index 9c8b21f..e9c6578 100644 --- a/pykd/pytypedvar.h +++ b/pykd/pytypedvar.h @@ -51,6 +51,36 @@ inline kdlib::TypedVarPtr containingRecordByType( kdlib::MEMOFFSET_64 offset, kd } +class TypedVarIterator { + +public: + + TypedVarIterator(kdlib::TypedVarPtr& var) : m_var(var), m_pos(0) + {} + + static python::object self(const python::object& obj) + { + return obj; + } + + kdlib::TypedVarPtr next() + { + AutoRestorePyState pystate; + if (m_pos==m_var->getElementCount()) + throw StopIteration("No more data."); + + return m_var->getElement(m_pos++); + } + + +private: + + size_t m_pos; + + kdlib::TypedVarPtr m_var; +}; + + struct TypedVarAdapter { @@ -188,6 +218,11 @@ struct TypedVarAdapter { } static python::list getRawBytes(kdlib::TypedVar& typedVar); + + static TypedVarIterator* getArrayIter(kdlib::TypedVarPtr& typedVar) + { + return new TypedVarIterator(typedVar); + } }; } // end namespace pykd diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 0a3abe1..43ed55d 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -110,6 +110,11 @@ class TypedVarTest( unittest.TestCase ): self.assertNotEqual( 0, tv.m_noArrayField ) tv.m_arrayField[len(tv.m_arrayField)] + def testArrayIteration(self): + tv = target.module.typedVar( "g_structWithArray" ) + self.assertEqual([0, 2], [x for x in tv.m_arrayField]) + + #def testArrayFieldSlice(self): # tv = target.module.typedVar( "g_structWithArray" ) # self.assertEqual( [ 0, 2 ], tv.m_arrayField[0:2] )