From fc90ccc8467fbc5490c338b0e98febe5bab6ba06 Mon Sep 17 00:00:00 2001 From: ussrhero Date: Sat, 29 Dec 2018 02:01:52 +0300 Subject: [PATCH] added: evalExpr routine ( Evaluate C++ expression with typed information ) --- kdlibcpp | 2 +- pykd/pykdver.h | 2 +- pykd/pymod.cpp | 4 ++++ pykd/pytypedvar.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ pykd/pytypedvar.h | 6 ++++++ pykd/pytypeinfo.cpp | 1 - pykd/pytypeinfo.h | 5 ----- pykd/variant.h | 34 +++++++++++++++++++--------------- setup/setup.py | 2 +- test/scripts/pykdtest.py | 2 +- test/scripts/typedvar.py | 23 +++++++++++++++++++++++ test/scripts/typeinfo.py | 4 ++-- 12 files changed, 98 insertions(+), 27 deletions(-) diff --git a/kdlibcpp b/kdlibcpp index f27cdbd..809848c 160000 --- a/kdlibcpp +++ b/kdlibcpp @@ -1 +1 @@ -Subproject commit f27cdbdaef5f68e6704d24beb208921a0a66da4b +Subproject commit 809848cf36172dd3fe4c5781b9009d6bd49ca4c1 diff --git a/pykd/pykdver.h b/pykd/pykdver.h index b2566d7..e7391bc 100644 --- a/pykd/pykdver.h +++ b/pykd/pykdver.h @@ -2,7 +2,7 @@ #define PYKD_VERSION_MAJOR 0 #define PYKD_VERSION_MINOR 3 #define PYKD_VERSION_SUBVERSION 4 -#define PYKD_VERSION_BUILDNO 2 +#define PYKD_VERSION_BUILDNO 3 #define __VER_STR2__(x) #x #define __VER_STR1__(x) __VER_STR2__(x) diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 92c4f9b..2002243 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -104,6 +104,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( TypeInfo_ptrTo, TypeInfoAdapter::ptrTo, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeFromSource_, pykd::getTypeFromSource, 2, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromPdb_, pykd::getTypeInfoProviderFromPdb, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromSource_, pykd::getTypeInfoProviderFromSource, 1, 2); +BOOST_PYTHON_FUNCTION_OVERLOADS(evalExpr_, pykd::evalExpr, 1, 3); namespace pykd { @@ -432,6 +433,9 @@ void pykd_init() "Create typeInfo provider from C/C++ source code") ); python::def( "getTypeInfoProviderFromPdb", &pykd::getTypeInfoProviderFromPdb, getTypeInfoProviderFromPdb_( python::args("filePath", "baseOffset"), "Create typeInfo provider from pdb file") ); + python::def("evalExpr", &pykd::evalExpr, evalExpr_(python::args("expression", "scope", "typeProvider"), + "Evaluate C++ expression with typed information")); + // CPU registers python::def( "reg", pykd::getRegisterByName, diff --git a/pykd/pytypedvar.cpp b/pykd/pytypedvar.cpp index b653701..ade8587 100644 --- a/pykd/pytypedvar.cpp +++ b/pykd/pytypedvar.cpp @@ -306,5 +306,45 @@ void TypedVarAdapter::setFieldByKey(kdlib::TypedVar& typedVar, const std::wstrin /////////////////////////////////////////////////////////////////////////////// +kdlib::TypedVarPtr evalExpr(const std::string expression, python::dict& scope, kdlib::TypeInfoProviderPtr& typeInfoProvider ) +{ + std::list < std::pair > scopeList; + + for (auto i = 0; i < python::len(scope); ++i) + { + auto key = scope.keys()[i]; + + std::wstring varName = python::extract(key); + + try + { + scopeList.push_back(std::make_pair(varName, getTypdedValueFromPyObj(scope[key]))); + } + catch (kdlib::DbgException&) + { } + } + + AutoRestorePyState pystate; + + if (!scopeList.empty() ) + return kdlib::evalExpr(expression, makeScope(scopeList), typeInfoProvider).get(); + + return kdlib::evalExpr(expression).get(); +} + +/////////////////////////////////////////////////////////////////////////////// + +kdlib::TypedValue getTypdedValueFromPyObj(const python::object& value) +{ + python::extract getTypedVar(value); + if (getTypedVar.check()) + return getTypedVar(); + + return NumVariantAdaptor::convertToVariant(value); +} + +/////////////////////////////////////////////////////////////////////////////// + + } // namespace pykd diff --git a/pykd/pytypedvar.h b/pykd/pytypedvar.h index 7c32ca0..a1e4c97 100644 --- a/pykd/pytypedvar.h +++ b/pykd/pytypedvar.h @@ -7,6 +7,7 @@ namespace python = boost::python; #include "kdlib/typedvar.h" +#include "kdlib/typeinfo.h" #include "stladaptor.h" #include "pythreadstate.h" @@ -229,4 +230,9 @@ struct TypedVarAdapter { } }; +kdlib::TypedValue getTypdedValueFromPyObj(const python::object& value); + +kdlib::TypedVarPtr evalExpr(const std::string expression, python::dict& scope = python::dict(), kdlib::TypeInfoProviderPtr& typeInfoProvider = kdlib::getDefaultTypeInfoProvider()); + + } // end namespace pykd diff --git a/pykd/pytypeinfo.cpp b/pykd/pytypeinfo.cpp index 96bbb5a..27c2c97 100644 --- a/pykd/pytypeinfo.cpp +++ b/pykd/pytypeinfo.cpp @@ -291,7 +291,6 @@ python::object callTypedVar(kdlib::TypedVarPtr& funcobj, python::tuple& args) continue; } - if ( python::extract(args[i]).check() ) { kdlib::NumVariant var= NumVariantAdaptor::convertToVariant(args[i]); diff --git a/pykd/pytypeinfo.h b/pykd/pytypeinfo.h index e908f08..6b672e8 100644 --- a/pykd/pytypeinfo.h +++ b/pykd/pytypeinfo.h @@ -411,9 +411,4 @@ struct BaseTypesEnum { static kdlib::TypeInfoPtr getDouble() { return pykd::getTypeInfoByName(L"Double"); } }; - - - - - } // end namespace pykd diff --git a/pykd/variant.h b/pykd/variant.h index fd625df..3bfeef2 100644 --- a/pykd/variant.h +++ b/pykd/variant.h @@ -14,12 +14,12 @@ class NumVariantAdaptor : public kdlib::NumConvertable public: - static kdlib::NumVariant NumVariantAdaptor::convertToVariant( const python::object &obj) - { + static kdlib::NumVariant convertToVariant(const python::object &obj) + { kdlib::NumVariant var; python::extract getNumVar(obj); - if ( getNumVar.check() ) + if (getNumVar.check()) { var = getNumVar(); return var; @@ -49,23 +49,27 @@ public: } #endif - if (_PyLong_Sign(obj.ptr()) >= 0) + if (PyLong_Check(obj.ptr())) { - if (_PyLong_NumBits(obj.ptr()) > 64) - throw pykd::OverflowException("int too big to convert"); + if (_PyLong_Sign(obj.ptr()) >= 0) + { + if (_PyLong_NumBits(obj.ptr()) > 64) + throw pykd::OverflowException("int too big to convert"); - var.setULongLong(PyLong_AsUnsignedLongLong(obj.ptr())); - } - else - { - if (_PyLong_NumBits(obj.ptr()) > 63) - throw pykd::OverflowException("int too big to convert"); + var.setULongLong(PyLong_AsUnsignedLongLong(obj.ptr())); + } + else + { + if (_PyLong_NumBits(obj.ptr()) > 63) + throw pykd::OverflowException("int too big to convert"); - var.setLongLong(PyLong_AsLongLong(obj.ptr())); + var.setLongLong(PyLong_AsLongLong(obj.ptr())); + } + + return var; } - - return var; + throw kdlib::TypeException(L"failed convert argument"); } static python::object NumVariantAdaptor::convertToPython( const kdlib::NumVariant& var ) diff --git a/setup/setup.py b/setup/setup.py index a605a7d..f8e03f1 100644 --- a/setup/setup.py +++ b/setup/setup.py @@ -8,7 +8,7 @@ import sys _name = "pykd" _desc = "python windbg extension" -_version = '0.3.4.1' +_version = '0.3.4.2' def getReleaseSrc(): return 'Release_%d.%d' % sys.version_info[0:2] diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 0a99658..2ed3b67 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -91,7 +91,7 @@ if __name__ == "__main__": target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0] unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( getTestSuite() ) - #unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( getTestSuite("typedvar.TypedVarTest.testAttr") ) + #unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( getTestSuite("typedvar.TypedVarTest.testEvalExprScopeLong") ) try: input = raw_input except NameError: pass diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 88ec80a..f5bb1bf 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -444,3 +444,26 @@ class TypedVarTest( unittest.TestCase ): self.assertFalse(hasattr(var, "noexisit")) self.assertRaises(AttributeError, getattr, *(var, "noexists")) self.assertRaises(AttributeError, setattr, *(var, "noexists", 0)) + + def testEvalExpr(self): + self.assertEqual( 2+2, pykd.evalExpr("2+2") ) + self.assertEqual( target.module.typedVar("g_structTest").m_field1, pykd.evalExpr("g_structTest.m_field1") ) + self.assertEqual( target.module.typedVar("g_testArray")[1].m_field3, pykd.evalExpr("(g_testArray + 1)->m_field3") ) + + def testEvalExprScope(self): + + v1 = target.module.typedVar( "ulongVar" ) + v2 = target.module.typedVar( "g_structTest" ) + + scope = { "v1" : v1, "v2" : v2 } + self.assertEqual( v1 + v2.m_field1, pykd.evalExpr("v1 + v2.m_field1", scope) ) + + def testEvalExprScopeLong(self): + + v1 = 100 + v2 = -500 + scope = { "v1" : v1, "v2" : v2 } + self.assertEqual( v1 + v2, pykd.evalExpr("v1 + v2", scope) ) + self.assertEqual( v1 * v2, pykd.evalExpr("v1 * v2", locals()) ) + + diff --git a/test/scripts/typeinfo.py b/test/scripts/typeinfo.py index 34b864d..a0f26eb 100644 --- a/test/scripts/typeinfo.py +++ b/test/scripts/typeinfo.py @@ -164,10 +164,10 @@ class TypeInfoTest( unittest.TestCase ): self.assertEqual( "structTest", ti.deref().name() ) ti = pykd.typeInfo("structTest[2]") - self.assertRaises( pykd.TypeException, ti.deref ); + self.assertEqual( "structTest", ti.deref().name() ) ti = target.module.type("classChild") - self.assertRaises( pykd.TypeException, ti.deref ); + self.assertRaises( pykd.TypeException, ti.deref ) def testNestedStruct( self ): ti = target.module.type("structWithNested")