diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 2002243..ce981f1 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -876,6 +876,7 @@ void pykd_init() "Return FixedFileInfo" ) .def("__getattr__", ModuleAdapter::getSymbolVaAttr, "Return address of the symbol" ) + .def("__contains__", ModuleAdapter::isContainedSymbol) .def( "__str__", &ModuleAdapter::print ); python::class_<kdlib::TypeInfo, kdlib::TypeInfoPtr, python::bases<kdlib::NumConvertable>, boost::noncopyable >("typeInfo", "Class representing typeInfo", python::no_init ) @@ -971,6 +972,7 @@ void pykd_init() .def( "__getitem__", TypeInfoAdapter::getElementByIndex ) .def( "__getitem__", TypeInfoAdapter::getElementByKey ) .def( "__dir__", TypeInfoAdapter::getElementDir ) + .def("__contains__", TypeInfoAdapter::isContainedField) #if PY_VERSION_HEX >= 0x03000000 .def("__bool__", TypeInfoAdapter::isZero ) #else @@ -1044,7 +1046,7 @@ void pykd_init() .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 ) + .def("__contains__", TypedVarAdapter::isContainedField) #if PY_VERSION_HEX >= 0x03000000 .def("__bool__", TypedVarAdapter::isNotZero) #else diff --git a/pykd/pymodule.cpp b/pykd/pymodule.cpp index 1965f6b..56d08d5 100644 --- a/pykd/pymodule.cpp +++ b/pykd/pymodule.cpp @@ -103,6 +103,15 @@ python::list ModuleAdapter::enumTypes(kdlib::Module& module, const std::wstring /////////////////////////////////////////////////////////////////////////////// +bool ModuleAdapter::isContainedSymbol(kdlib::ModulePtr& module, const std::wstring& symbolName) +{ + if (!module->enumSymbols(symbolName).empty()) + return true; + + return !module->enumTypes(symbolName).empty(); +} + +/////////////////////////////////////////////////////////////////////////////// std::wstring ModuleAdapter::findSymbol( kdlib::Module& module, kdlib::MEMOFFSET_64 offset, bool showDisplacement ) { diff --git a/pykd/pymodule.h b/pykd/pymodule.h index 33fec8d..fe86987 100644 --- a/pykd/pymodule.h +++ b/pykd/pymodule.h @@ -198,6 +198,7 @@ struct ModuleAdapter : public kdlib::Module static python::list getTypedVarArrayByTypeName( kdlib::Module& module, kdlib::MEMOFFSET_64 offset, const std::wstring &typeName, size_t number ); + static bool isContainedSymbol(kdlib::ModulePtr& module, const std::wstring& symbolName); }; } // end namespace pykd diff --git a/pykd/pytypedvar.cpp b/pykd/pytypedvar.cpp index ade8587..7bc3240 100644 --- a/pykd/pytypedvar.cpp +++ b/pykd/pytypedvar.cpp @@ -138,6 +138,22 @@ python::list TypedVarAdapter::getFields( kdlib::TypedVar& typedVar ) /////////////////////////////////////////////////////////////////////////////// +bool TypedVarAdapter::isContainedField(kdlib::TypedVarPtr& typedVar, const std::wstring& fieldName) +{ + AutoRestorePyState pystate; + + for (size_t i = 0; i < typedVar->getElementCount(); ++i) + { + std::wstring name = typedVar->getElementName(i); + if (name == fieldName) + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + python::list TypedVarAdapter::getElementsDir(kdlib::TypedVar& typedVar) { std::list<std::wstring> lst; @@ -306,28 +322,40 @@ void TypedVarAdapter::setFieldByKey(kdlib::TypedVar& typedVar, const std::wstrin /////////////////////////////////////////////////////////////////////////////// -kdlib::TypedVarPtr evalExpr(const std::string expression, python::dict& scope, kdlib::TypeInfoProviderPtr& typeInfoProvider ) +class PyScope : public kdlib::Scope { - std::list < std::pair<std::wstring, kdlib::TypedValue> > scopeList; +public: - for (auto i = 0; i < python::len(scope); ++i) + kdlib::TypedValue get(const std::wstring& varName) const override { - 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&) - { } + return getTypdedValueFromPyObj(m_scope[varName]); } - AutoRestorePyState pystate; + virtual bool find(const std::wstring& varName, kdlib::TypedValue& value) const override + { + if (!m_scope.contains(varName)) + return false; - if (!scopeList.empty() ) - return kdlib::evalExpr(expression, makeScope(scopeList), typeInfoProvider).get(); + value = getTypdedValueFromPyObj(m_scope[varName]); + + return true; + } + + PyScope(const python::object& scope) : + m_scope(scope) + {} + +private: + + python::object m_scope; +}; + +kdlib::TypedVarPtr evalExpr(const std::string expression, python::object& scope, kdlib::TypeInfoProviderPtr& typeInfoProvider ) +{ + if (scope) + { + return kdlib::evalExpr(expression, kdlib::ScopePtr(new PyScope(scope)), typeInfoProvider).get(); + } return kdlib::evalExpr(expression).get(); } diff --git a/pykd/pytypedvar.h b/pykd/pytypedvar.h index a1e4c97..1e20cf8 100644 --- a/pykd/pytypedvar.h +++ b/pykd/pytypedvar.h @@ -228,11 +228,13 @@ struct TypedVarAdapter { { return new TypedVarIterator(typedVar); } + + static bool isContainedField(kdlib::TypedVarPtr& typedVar, const std::wstring& fieldName); }; kdlib::TypedValue getTypdedValueFromPyObj(const python::object& value); -kdlib::TypedVarPtr evalExpr(const std::string expression, python::dict& scope = python::dict(), kdlib::TypeInfoProviderPtr& typeInfoProvider = kdlib::getDefaultTypeInfoProvider()); +kdlib::TypedVarPtr evalExpr(const std::string expression, python::object& scope = python::object(), kdlib::TypeInfoProviderPtr& typeInfoProvider = kdlib::getDefaultTypeInfoProvider()); } // end namespace pykd diff --git a/pykd/pytypeinfo.cpp b/pykd/pytypeinfo.cpp index 27c2c97..c38d22f 100644 --- a/pykd/pytypeinfo.cpp +++ b/pykd/pytypeinfo.cpp @@ -103,6 +103,21 @@ python::list TypeInfoAdapter::getFields( kdlib::TypeInfo &typeInfo ) return pylst; } +bool TypeInfoAdapter::isContainedField(kdlib::TypeInfoPtr& typeInfo, const std::wstring& fieldName) +{ + + AutoRestorePyState pystate; + + for (size_t i = 0; i < typeInfo->getElementCount(); ++i) + { + std::wstring name = typeInfo->getElementName(i); + if (name == fieldName) + return true; + } + + return false; +} + python::list TypeInfoAdapter::getMethods(kdlib::TypeInfo &typeInfo) { typedef boost::tuple<std::wstring, kdlib::TypeInfoPtr> FieldTuple; diff --git a/pykd/pytypeinfo.h b/pykd/pytypeinfo.h index 6b672e8..ab4adda 100644 --- a/pykd/pytypeinfo.h +++ b/pykd/pytypeinfo.h @@ -334,6 +334,8 @@ struct TypeInfoAdapter : public kdlib::TypeInfo { return false; } + static bool isContainedField(kdlib::TypeInfoPtr& typedVar, const std::wstring& fieldName); + }; diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index a76c6c3..efd1c00 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -139,4 +139,9 @@ class ModuleTest( unittest.TestCase ): def testModuleList(self): self.assertTrue( [] != pykd.getModulesList() ) + def testContain(self): + self.assertTrue("voidPtr" in target.module) + self.assertTrue("structTest" in target.module) + self.assertFalse("NotExist" in target.module) + self.assertRaises(Exception, lambda md : 2 in md, target.module) diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index f5bb1bf..cd4572f 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -443,7 +443,6 @@ 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") ) @@ -459,11 +458,21 @@ class TypedVarTest( unittest.TestCase ): 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()) ) + def testEvalExprScopeStruct(self): + var = pykd.typedVar("g_structTest1") + self.assertEqual(var.m_field1, pykd.evalExpr("m_field1", var)) + self.assertEqual(var.m_field4.deref().m_field1, pykd.evalExpr("m_field4->m_field1", var)) + + def testContain(self): + var = pykd.typedVar("g_structTest") + self.assertTrue("m_field1" in var) + self.assertFalse("NotExist" in var) + self.assertRaises(Exception, lambda var : 2 in var, var) + diff --git a/test/scripts/typeinfo.py b/test/scripts/typeinfo.py index a0f26eb..eae9ba3 100644 --- a/test/scripts/typeinfo.py +++ b/test/scripts/typeinfo.py @@ -351,7 +351,6 @@ class TypeInfoTest( unittest.TestCase ): self.assertEqual( classChild.baseClassOffset(0), classChild.baseClassOffset('classBase1')) self.assertEqual(classChild.baseClassOffset(1), classChild.baseClassOffset('classBase2')) - def testPdbTypeProvider(self): pdb = target.module.symfile() typeProvider = pykd.getTypeInfoProviderFromPdb(pdb) @@ -362,6 +361,9 @@ class TypeInfoTest( unittest.TestCase ): def testScopeName(self): self.assertEqual( target.module.name(), pykd.typeInfo( "structTest" ).scopeName() ) self.assertEqual( target.module.name(), pykd.typeInfo( "structWithNested::Nested" ).scopeName() ) - - - + + def testContain(self): + ti = target.module.type( "structTest" ) + self.assertTrue("m_field1" in ti) + self.assertFalse("NotExist" in ti) + self.assertRaises(Exception, lambda t : 2 in t, ti)