added: evalExpr routine ( Evaluate C++ expression with typed information )

This commit is contained in:
ussrhero 2018-12-29 02:01:52 +03:00
parent 23c1376112
commit fc90ccc846
12 changed files with 98 additions and 27 deletions

@ -1 +1 @@
Subproject commit f27cdbdaef5f68e6704d24beb208921a0a66da4b Subproject commit 809848cf36172dd3fe4c5781b9009d6bd49ca4c1

View File

@ -2,7 +2,7 @@
#define PYKD_VERSION_MAJOR 0 #define PYKD_VERSION_MAJOR 0
#define PYKD_VERSION_MINOR 3 #define PYKD_VERSION_MINOR 3
#define PYKD_VERSION_SUBVERSION 4 #define PYKD_VERSION_SUBVERSION 4
#define PYKD_VERSION_BUILDNO 2 #define PYKD_VERSION_BUILDNO 3
#define __VER_STR2__(x) #x #define __VER_STR2__(x) #x
#define __VER_STR1__(x) __VER_STR2__(x) #define __VER_STR1__(x) __VER_STR2__(x)

View File

@ -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( getTypeFromSource_, pykd::getTypeFromSource, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromPdb_, pykd::getTypeInfoProviderFromPdb, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromPdb_, pykd::getTypeInfoProviderFromPdb, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromSource_, pykd::getTypeInfoProviderFromSource, 1, 2); BOOST_PYTHON_FUNCTION_OVERLOADS( getTypeInfoProviderFromSource_, pykd::getTypeInfoProviderFromSource, 1, 2);
BOOST_PYTHON_FUNCTION_OVERLOADS(evalExpr_, pykd::evalExpr, 1, 3);
namespace pykd { namespace pykd {
@ -432,6 +433,9 @@ void pykd_init()
"Create typeInfo provider from C/C++ source code") ); "Create typeInfo provider from C/C++ source code") );
python::def( "getTypeInfoProviderFromPdb", &pykd::getTypeInfoProviderFromPdb, getTypeInfoProviderFromPdb_( python::args("filePath", "baseOffset"), python::def( "getTypeInfoProviderFromPdb", &pykd::getTypeInfoProviderFromPdb, getTypeInfoProviderFromPdb_( python::args("filePath", "baseOffset"),
"Create typeInfo provider from pdb file") ); "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 // CPU registers
python::def( "reg", pykd::getRegisterByName, python::def( "reg", pykd::getRegisterByName,

View File

@ -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<std::wstring, kdlib::TypedValue> > scopeList;
for (auto i = 0; i < python::len(scope); ++i)
{
auto key = scope.keys()[i];
std::wstring varName = python::extract<std::wstring>(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<kdlib::TypedVarPtr> getTypedVar(value);
if (getTypedVar.check())
return getTypedVar();
return NumVariantAdaptor::convertToVariant(value);
}
///////////////////////////////////////////////////////////////////////////////
} // namespace pykd } // namespace pykd

View File

@ -7,6 +7,7 @@
namespace python = boost::python; namespace python = boost::python;
#include "kdlib/typedvar.h" #include "kdlib/typedvar.h"
#include "kdlib/typeinfo.h"
#include "stladaptor.h" #include "stladaptor.h"
#include "pythreadstate.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 } // end namespace pykd

View File

@ -291,7 +291,6 @@ python::object callTypedVar(kdlib::TypedVarPtr& funcobj, python::tuple& args)
continue; continue;
} }
if ( python::extract<int>(args[i]).check() ) if ( python::extract<int>(args[i]).check() )
{ {
kdlib::NumVariant var= NumVariantAdaptor::convertToVariant(args[i]); kdlib::NumVariant var= NumVariantAdaptor::convertToVariant(args[i]);

View File

@ -411,9 +411,4 @@ struct BaseTypesEnum {
static kdlib::TypeInfoPtr getDouble() { return pykd::getTypeInfoByName(L"Double"); } static kdlib::TypeInfoPtr getDouble() { return pykd::getTypeInfoByName(L"Double"); }
}; };
} // end namespace pykd } // end namespace pykd

View File

@ -14,12 +14,12 @@ class NumVariantAdaptor : public kdlib::NumConvertable
public: public:
static kdlib::NumVariant NumVariantAdaptor::convertToVariant( const python::object &obj) static kdlib::NumVariant convertToVariant(const python::object &obj)
{ {
kdlib::NumVariant var; kdlib::NumVariant var;
python::extract<kdlib::NumConvertable> getNumVar(obj); python::extract<kdlib::NumConvertable> getNumVar(obj);
if ( getNumVar.check() ) if (getNumVar.check())
{ {
var = getNumVar(); var = getNumVar();
return var; return var;
@ -49,23 +49,27 @@ public:
} }
#endif #endif
if (_PyLong_Sign(obj.ptr()) >= 0) if (PyLong_Check(obj.ptr()))
{ {
if (_PyLong_NumBits(obj.ptr()) > 64) if (_PyLong_Sign(obj.ptr()) >= 0)
throw pykd::OverflowException("int too big to convert"); {
if (_PyLong_NumBits(obj.ptr()) > 64)
throw pykd::OverflowException("int too big to convert");
var.setULongLong(PyLong_AsUnsignedLongLong(obj.ptr())); var.setULongLong(PyLong_AsUnsignedLongLong(obj.ptr()));
} }
else else
{ {
if (_PyLong_NumBits(obj.ptr()) > 63) if (_PyLong_NumBits(obj.ptr()) > 63)
throw pykd::OverflowException("int too big to convert"); throw pykd::OverflowException("int too big to convert");
var.setLongLong(PyLong_AsLongLong(obj.ptr())); var.setLongLong(PyLong_AsLongLong(obj.ptr()));
}
return var;
} }
throw kdlib::TypeException(L"failed convert argument");
return var;
} }
static python::object NumVariantAdaptor::convertToPython( const kdlib::NumVariant& var ) static python::object NumVariantAdaptor::convertToPython( const kdlib::NumVariant& var )

View File

@ -8,7 +8,7 @@ import sys
_name = "pykd" _name = "pykd"
_desc = "python windbg extension" _desc = "python windbg extension"
_version = '0.3.4.1' _version = '0.3.4.2'
def getReleaseSrc(): def getReleaseSrc():
return 'Release_%d.%d' % sys.version_info[0:2] return 'Release_%d.%d' % sys.version_info[0:2]

View File

@ -91,7 +91,7 @@ if __name__ == "__main__":
target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0] 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() )
#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 try: input = raw_input
except NameError: pass except NameError: pass

View File

@ -444,3 +444,26 @@ class TypedVarTest( unittest.TestCase ):
self.assertFalse(hasattr(var, "noexisit")) self.assertFalse(hasattr(var, "noexisit"))
self.assertRaises(AttributeError, getattr, *(var, "noexists")) self.assertRaises(AttributeError, getattr, *(var, "noexists"))
self.assertRaises(AttributeError, setattr, *(var, "noexists", 0)) 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()) )

View File

@ -164,10 +164,10 @@ class TypeInfoTest( unittest.TestCase ):
self.assertEqual( "structTest", ti.deref().name() ) self.assertEqual( "structTest", ti.deref().name() )
ti = pykd.typeInfo("structTest[2]") ti = pykd.typeInfo("structTest[2]")
self.assertRaises( pykd.TypeException, ti.deref ); self.assertEqual( "structTest", ti.deref().name() )
ti = target.module.type("classChild") ti = target.module.type("classChild")
self.assertRaises( pykd.TypeException, ti.deref ); self.assertRaises( pykd.TypeException, ti.deref )
def testNestedStruct( self ): def testNestedStruct( self ):
ti = target.module.type("structWithNested") ti = target.module.type("structWithNested")