From d3b5f99a204061d1cb9a6e8c5d27382c5a6d9814 Mon Sep 17 00:00:00 2001 From: "SND\\ussrhero_cp" Date: Sun, 23 Apr 2017 15:34:46 +0000 Subject: [PATCH] [0.3.x] reworked : typedVar can change python byte sequences git-svn-id: https://pykd.svn.codeplex.com/svn@91219 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/pydataaccess.h | 314 +++++++++++++++++++++++++++++++++++++++ pykd/pytypedvar.cpp | 84 +++++++---- pykd/pytypedvar.h | 14 +- pykd/variant.h | 8 +- test/scripts/typedvar.py | 34 +++-- 5 files changed, 400 insertions(+), 54 deletions(-) create mode 100644 pykd/pydataaccess.h diff --git a/pykd/pydataaccess.h b/pykd/pydataaccess.h new file mode 100644 index 0000000..cb7cdd0 --- /dev/null +++ b/pykd/pydataaccess.h @@ -0,0 +1,314 @@ +#pragma once + + +#include "boost/python/object.hpp" +#include "boost/python/wrapper.hpp" + +#include "kdlib/dataaccessor.h" +#include "kdlib/exceptions.h" + +#include "pythreadstate.h" + +namespace python = boost::python; + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////// + +using kdlib::ImplementException; + +/////////////////////////////////////////////////////////////////////////////// + +class PythonObjectAccessor : public kdlib::DataAccessor +{ + +public: + + PythonObjectAccessor(python::object& obj, size_t pos = 0) : m_object(obj) + { + m_pystate = PyThreadState_Get(); + m_startPos = pos; + } + +public: + + virtual size_t getLength() const { + AutoSavePythonState pystate(&m_pystate); + return python::len(m_object); + } + + virtual unsigned char readByte(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeByte(unsigned char value, size_t pos=0) { + writeValue(value,pos); + } + + virtual char readSignByte(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeSignByte(char value, size_t pos=0) { + writeValue(value,pos); + } + + virtual unsigned short readWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeWord(unsigned short value, size_t pos=0) { + writeValue(value,pos); + } + + virtual short readSignWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeSignWord(short value, size_t pos=0) { + writeValue(value,pos); + } + + virtual unsigned long readDWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeDWord(unsigned long value, size_t pos=0) { + writeValue(value,pos); + } + + virtual long readSignDWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeSignDWord(long value, size_t pos=0) { + writeValue(value,pos); + } + + virtual unsigned long long readQWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeQWord(unsigned long long value, size_t pos=0) { + writeValue(value,pos); + } + + virtual long long readSignQWord(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeSignQWord(long long value, size_t pos=0) { + writeValue(value,pos); + } + + virtual float readFloat(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeFloat(float value, size_t pos=0) { + writeValue(value,pos); + } + + virtual double readDouble(size_t pos=0) const { + return readValue(pos); + } + + virtual void writeDouble(double value, size_t pos=0) { + writeValue(value,pos); + } + + virtual void readBytes( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeBytes( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + void readWords( std::vector& dataRange, size_t count, size_t pos) const { + readValues(dataRange, count, pos); + } + + virtual void writeWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readDWords( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeDWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readQWords( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeQWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readSignBytes( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeSignBytes( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readSignWords( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeSignWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readSignDWords( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeSignDWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange, pos); + } + + virtual void readSignQWords( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeSignQWords( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange,pos); + } + + virtual void readFloats( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeFloats( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange, pos); + } + + virtual void readDoubles( std::vector& dataRange, size_t count, size_t pos=0) const { + readValues(dataRange, count, pos); + } + + virtual void writeDoubles( const std::vector& dataRange, size_t pos=0) { + writeValues(dataRange, pos); + } + + virtual kdlib::DataAccessorPtr copy( size_t startOffset = 0, size_t length = 0 ) { + AutoSavePythonState pystate(&m_pystate); + return kdlib::DataAccessorPtr( new PythonObjectAccessor(m_object, startOffset) ); + } + + virtual std::wstring getLocationAsStr() const { + return L"python byte sequance"; + } + + virtual kdlib::MEMOFFSET_64 getAddress() const { + throw kdlib::DbgException("python accessor error"); + } + + virtual kdlib::VarStorage getStorageType() const { + throw kdlib::DbgException("python accessor error"); + } + + virtual std::wstring getRegisterName() const { + throw kdlib::DbgException("python accessor error"); + } + +private: + + python::object m_object; + + mutable PyThreadState* m_pystate; + + size_t m_startPos; + + template + T readValue(size_t pos) const + { + AutoSavePythonState pystate(&m_pystate); + try + { + return readValueUnsafe(pos); + } + catch( python::error_already_set const & ) + {} + + throw kdlib::DbgException("python accessor error"); + } + + template + T readValueUnsafe(size_t pos) const + { + unsigned long long value = 0; + for ( size_t i = sizeof(T); i > 0; --i) + value = ( value << 8 ) + python::extract(m_object[m_startPos + pos*sizeof(T) + i - 1])(); + + return *reinterpret_cast(&value); + } + + template + void writeValue(T value, size_t pos) + { + AutoSavePythonState pystate(&m_pystate); + try + { + writeValueUnsafe(value,pos); + return; + } + catch( python::error_already_set const & ) + {} + + throw kdlib::DbgException("python accessor error"); + } + + template + void writeValueUnsafe(T value, size_t pos) + { + unsigned long long val = *reinterpret_cast(&value); + for ( size_t i = 0; i < sizeof(T); ++i ) + m_object[m_startPos + pos*sizeof(T) + i] = static_cast( ( val >> (8*i)) & 0xFF ); + } + + template + void readValues( std::vector& dataRange, size_t count, size_t pos) const + { + AutoSavePythonState pystate(&m_pystate); + try + { + dataRange.resize(count); + for ( size_t i = 0; i < count; ++i ) + dataRange[i] = readValueUnsafe(pos + i); + return; + } + catch( python::error_already_set const & ) + {} + + throw kdlib::DbgException("python accessor error"); + } + + template + void writeValues( const std::vector& dataRange, size_t pos) + { + AutoSavePythonState pystate(&m_pystate); + try + { + for ( size_t i = 0; i < dataRange.size(); ++i ) + writeValueUnsafe(dataRange[i], pos + i ); + return; + } + catch( python::error_already_set const & ) + {} + + throw kdlib::DbgException("python accessor error"); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// + + +} diff --git a/pykd/pytypedvar.cpp b/pykd/pytypedvar.cpp index c9823f1..936bcaa 100644 --- a/pykd/pytypedvar.cpp +++ b/pykd/pytypedvar.cpp @@ -3,6 +3,10 @@ #include "pytypedvar.h" #include "kdlib/exceptions.h" +#include "pytypeinfo.h" +#include "pydataaccess.h" + + namespace pykd { /////////////////////////////////////////////////////////////////////////////// @@ -17,15 +21,10 @@ kdlib::TypedVarPtr getTypedVarByTypeName(const std::wstring &name, python::objec return kdlib::loadTypedVar( name, offset ); } - std::vector byteArray; + kdlib::DataAccessorPtr dataAceesor( new PythonObjectAccessor(dataStorage) ); - for (int i = 0; i < python::len(dataStorage); ++i) - { - byteArray.push_back( python::extract(dataStorage[i]) ); - } - AutoRestorePyState pystate; - return kdlib::loadTypedVar( name, kdlib::getCacheAccessor(byteArray) ); + return kdlib::loadTypedVar(name, dataAceesor ); } /////////////////////////////////////////////////////////////////////////////// @@ -40,15 +39,10 @@ kdlib::TypedVarPtr getTypedVarByTypeInfo( const kdlib::TypeInfoPtr &typeInfo, py return kdlib::loadTypedVar(typeInfo, offset ); } - std::vector byteArray; + kdlib::DataAccessorPtr dataAceesor( new PythonObjectAccessor(dataStorage) ); - for (int i = 0; i < python::len(dataStorage); ++i) - { - byteArray.push_back( python::extract(dataStorage[i]) ); - } - AutoRestorePyState pystate; - return kdlib::loadTypedVar(typeInfo, kdlib::getCacheAccessor(byteArray) ); + return kdlib::loadTypedVar(typeInfo, dataAceesor ); } /////////////////////////////////////////////////////////////////////////////// @@ -198,23 +192,6 @@ kdlib::TypedVarPtr TypedVarAdapter::getFieldAttr(kdlib::TypedVar& typedVar, cons throw AttributeException(std::string(_bstr_t(sstr.str().c_str())).c_str()); } -/////////////////////////////////////////////////////////////////////////////// - -void TypedVarAdapter::setFieldAttr(kdlib::TypedVar& typedVar, const std::wstring &name, NumVariantAdaptor& var) -{ - try - { - AutoRestorePyState pystate; - typedVar.setElement(name, var); - return; - } - catch (kdlib::TypeException&) - {} - - std::wstringstream sstr; - sstr << L"typed var has no field " << L'\'' << name << L'\''; - throw AttributeException(std::string(_bstr_t(sstr.str().c_str())).c_str()); -} /////////////////////////////////////////////////////////////////////////////// @@ -236,5 +213,50 @@ python::list TypedVarAdapter::getRawBytes(kdlib::TypedVar& typedVar) /////////////////////////////////////////////////////////////////////////////// +void TypedVarAdapter::setField(kdlib::TypedVar& typedVar, const std::wstring &name, python::object& object) +{ + + kdlib::TypedValue value = NumVariantAdaptor::convertToVariant(object); + + { + AutoRestorePyState pystate; + typedVar.setElement(name, value); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void TypedVarAdapter::setElementByIndex(kdlib::TypedVar& typedVar, long index, python::object& object) +{ + kdlib::TypedValue value = NumVariantAdaptor::convertToVariant(object); + + { + AutoRestorePyState pystate; + typedVar.setElement(index, value); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void TypedVarAdapter::setFieldAttr(kdlib::TypedVar& typedVar, const std::wstring &name, python::object& object) +{ + kdlib::TypedValue value = NumVariantAdaptor::convertToVariant(object); + + try + { + AutoRestorePyState pystate; + typedVar.setElement(name, value); + return; + } + catch (kdlib::TypeException&) + {} + + std::wstringstream sstr; + sstr << L"typed var has no field " << L'\'' << name << L'\''; + throw AttributeException(std::string(_bstr_t(sstr.str().c_str())).c_str()); +} + +/////////////////////////////////////////////////////////////////////////////// + } // namesapce pykd diff --git a/pykd/pytypedvar.h b/pykd/pytypedvar.h index dfe2559..9c8b21f 100644 --- a/pykd/pytypedvar.h +++ b/pykd/pytypedvar.h @@ -110,15 +110,11 @@ struct TypedVarAdapter { return typedVar.getElement( name ); } - static void setField(kdlib::TypedVar& typedVar, const std::wstring &name, NumVariantAdaptor& var) - { - AutoRestorePyState pystate; - typedVar.setElement(name, var); - } + static void setField(kdlib::TypedVar& typedVar, const std::wstring &name, python::object& object); static kdlib::TypedVarPtr getFieldAttr(kdlib::TypedVar& typedVar, const std::wstring &name); - static void setFieldAttr(kdlib::TypedVar& typedVar, const std::wstring &name, NumVariantAdaptor& var); + static void setFieldAttr(kdlib::TypedVar& typedVar, const std::wstring &name, python::object& object); static size_t getElementCount( kdlib::TypedVar& typedVar ) { @@ -138,11 +134,7 @@ struct TypedVarAdapter { return typedVar.getElement( index ); } - static void setElementByIndex(kdlib::TypedVar& typedVar, long index, NumVariantAdaptor& var) - { - AutoRestorePyState pystate; - typedVar.setElement(index, var); - } + static void setElementByIndex(kdlib::TypedVar& typedVar, long index, python::object& object); static kdlib::TypedVarPtr getMethodByName(kdlib::TypedVar& typedVar, const std::wstring &name, const std::wstring &prototype = L"") { diff --git a/pykd/variant.h b/pykd/variant.h index f158220..a40ef5a 100644 --- a/pykd/variant.h +++ b/pykd/variant.h @@ -5,6 +5,7 @@ #include "kdlib/variant.h" #include "kdlib/exceptions.h" #include "dbgexcept.h" +#include "pythreadstate.h" namespace pykd { @@ -122,7 +123,12 @@ public: static python::object NumVariantAdaptor::convertToPython( kdlib::NumBehavior& num ) { - kdlib::NumVariant var = kdlib::NumVariant( num ); + kdlib::NumVariant var; + + { + AutoRestorePyState pystate; + var = kdlib::NumVariant( num ); + } return convertToPython( var ); } diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 76c1303..0a3abe1 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -305,12 +305,12 @@ class TypedVarTest( unittest.TestCase ): for field in tv.fields(): str( field ) - def testDeadlockList(self): - lst = [] - entry = pykd.typedVar("deadlockEntry").flink - for i in range( 0, 100000 ): - lst.append(entry) - entry = entry.deref().flink + #def testDeadlockList(self): + # lst = [] + # entry = pykd.typedVar("deadlockEntry").flink + # for i in xrange( 0, 100000 ): + # lst.append(entry) + # entry = entry.deref().flink def testHresult(self): tv = pykd.typedVar( "g_atlException" ) @@ -427,9 +427,21 @@ class TypedVarTest( unittest.TestCase ): self.assertEqual( [ 0x55, 0x55, 0, 0], target.module.typedVar( "ulongConst" ).rawBytes() ) def testSetField(self): - var = target.module.typedVar("structTest", [0x55] * 20 ) - var.setField("m_field2", 0xAA) - var.m_field3 == 0xAAAA - self.assertEqual( 0xAAAA, var.m_filed3) + byteseq = [0x55] * 20 + var = target.module.typedVar("structTest", byteseq) + var.setField("m_field1", 0xFF000000000000AA) + self.assertEqual( [0xAA, 0, 0, 0, 0, 0, 0, 0xFF], byteseq[4:12] ) + var.m_field3 = 0xAAAA + self.assertEqual( 0xAAAA, var.m_field3) + self.assertEqual( 0xAAAA, var.field("m_field3") ) - \ No newline at end of file + + def testAttr(self): + var = target.module.typedVar("structTest", [0x55] * 20 ) + self.assertTrue(hasattr(var, "m_field3")) + setattr(var, "m_field1", 11) + self.assertEqual(11, getattr(var, "m_field1")) + + self.assertFalse(hasattr(var, "noexisit")) + self.assertRaises(AttributeError, getattr, *(var, "noexists")) + self.assertRaises(AttributeError, setattr, *(var, "noexists", 0))