From 5dc822ab1b5302e9cc1c0eb254962ce4ea484fcd Mon Sep 17 00:00:00 2001 From: "SND\\kernelnet_cp" Date: Mon, 17 Jun 2013 14:21:11 +0000 Subject: [PATCH] [0.3.x] updated : test git-svn-id: https://pykd.svn.codeplex.com/svn@84081 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/breakpoint.cpp | 122 ++++++++++++++++++++++++++ pykd/breakpoint.h | 33 +++++++ pykd/dbgengine.cpp | 24 +++-- pykd/dbgengine.h | 6 +- pykd/pykd.vcxproj | 2 + pykd/pykd.vcxproj.filters | 6 ++ pykd/pymod.cpp | 48 +++++----- test/scripts/diatest.py | 179 -------------------------------------- test/scripts/pykdtest.py | 7 +- test/scripts/typedvar.py | 2 +- 10 files changed, 219 insertions(+), 210 deletions(-) create mode 100644 pykd/breakpoint.cpp create mode 100644 pykd/breakpoint.h delete mode 100644 test/scripts/diatest.py diff --git a/pykd/breakpoint.cpp b/pykd/breakpoint.cpp new file mode 100644 index 0000000..39540e7 --- /dev/null +++ b/pykd/breakpoint.cpp @@ -0,0 +1,122 @@ +#include "stdafx.h" + +#include "kdlib\eventhandler.h" + +#include "breakpoint.h" +#include "dbgexcept.h" + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////// + +class SoftwareBreakpoint : public Breakpoint +{ +public: + + SoftwareBreakpoint( kdlib::MEMOFFSET_64 offset ) { + m_id = kdlib::softwareBreakPointSet( offset ); + } + + ~SoftwareBreakpoint() { + kdlib::breakPointRemove( m_id ); + } + +private: + + kdlib::BREAKPOINT_ID m_id; + +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SoftwareBreakpointWithCallback : public Breakpoint, private kdlib::EventHandler +{ +public: + + SoftwareBreakpointWithCallback( kdlib::MEMOFFSET_64 offset, python::object &callback ) + { + m_pystate = PyThreadState_Get(); + m_callback = callback; + m_id = kdlib::softwareBreakPointSet( offset ); + } + + ~SoftwareBreakpointWithCallback() + { + try { + kdlib::breakPointRemove( m_id ); + } catch( kdlib::DbgException& ) + { } + } + +private: + + virtual kdlib::DebugCallbackResult onBreakpoint( kdlib::BREAKPOINT_ID bpId ) + { + + kdlib::DebugCallbackResult result; + + if ( bpId != m_id ) + return kdlib::DebugCallbackNoChange; + + PyEval_RestoreThread( m_pystate ); + + try { + + do { + + python::object resObj = m_callback( bpId ); + + if ( resObj.is_none() ) + { + result = kdlib::DebugCallbackNoChange; + break; + } + + int retVal = python::extract( resObj ); + + if ( retVal >= kdlib::DebugCallbackMax ) + { + result = kdlib::DebugCallbackBreak; + break; + } + + result = kdlib::DebugCallbackResult(retVal); + + } while( FALSE ); + + } + catch (const python::error_already_set &) + { + printException(); + result = kdlib::DebugCallbackBreak; + } + + m_pystate = PyEval_SaveThread(); + + return result; + } + + kdlib::BREAKPOINT_ID m_id; + python::object m_callback; + PyThreadState* m_pystate; + +}; + +/////////////////////////////////////////////////////////////////////////////// + +BreakpointPtr Breakpoint::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback ) +{ + if ( callback ) + { + return BreakpointPtr( new SoftwareBreakpointWithCallback( offset, callback ) ); + } + else + { + return BreakpointPtr( new SoftwareBreakpoint(offset) ); + } +} + +/////////////////////////////////////////////////////////////////////////////// + + +} // end namespace pykd diff --git a/pykd/breakpoint.h b/pykd/breakpoint.h new file mode 100644 index 0000000..8c57897 --- /dev/null +++ b/pykd/breakpoint.h @@ -0,0 +1,33 @@ +#pragma once + +#include "kdlib/dbgengine.h" + +#include "boost/shared_ptr.hpp" +#include "boost/noncopyable.hpp" +#include "boost/python/object.hpp" +namespace python = boost::python; + +namespace pykd { + +/////////////////////////////////////////////////////////////////////////////// + +class Breakpoint; +typedef boost::shared_ptr BreakpointPtr; + +class Breakpoint : public boost::noncopyable +{ + +public: + + static + BreakpointPtr setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() ); + +protected: + + virtual ~Breakpoint() {} + +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // end namespace pykd diff --git a/pykd/dbgengine.cpp b/pykd/dbgengine.cpp index e8612cd..bf2bdb5 100644 --- a/pykd/dbgengine.cpp +++ b/pykd/dbgengine.cpp @@ -8,13 +8,17 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////// -void targetGo() +kdlib::ExecutionStatus targetGo() { + kdlib::ExecutionStatus status; + PyThreadState* state = PyEval_SaveThread(); - kdlib::targetGo(); + status = kdlib::targetGo(); PyEval_RestoreThread( state ); + + return status; } /////////////////////////////////////////////////////////////////////////////// @@ -30,24 +34,32 @@ void targetBreak() /////////////////////////////////////////////////////////////////////////////// -void targetStep() +kdlib::ExecutionStatus targetStep() { + kdlib::ExecutionStatus status; + PyThreadState* state = PyEval_SaveThread(); - kdlib::targetStep(); + status = kdlib::targetStep(); PyEval_RestoreThread( state ); + + return status; } /////////////////////////////////////////////////////////////////////////////// -void targetStepIn() +kdlib::ExecutionStatus targetStepIn() { + kdlib::ExecutionStatus status; + PyThreadState* state = PyEval_SaveThread(); - kdlib::targetStepIn(); + status = kdlib::targetStepIn(); PyEval_RestoreThread( state ); + + return status; } /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index 408b32d..3c69355 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -9,10 +9,10 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////// -void targetGo(); +kdlib::ExecutionStatus targetGo(); void targetBreak(); -void targetStep(); -void targetStepIn(); +kdlib::ExecutionStatus targetStep(); +kdlib::ExecutionStatus targetStepIn(); python::tuple getSourceLine( kdlib::MEMOFFSET_64 offset = 0 ); diff --git a/pykd/pykd.vcxproj b/pykd/pykd.vcxproj index a9632d2..2821400 100644 --- a/pykd/pykd.vcxproj +++ b/pykd/pykd.vcxproj @@ -123,6 +123,7 @@ + @@ -136,6 +137,7 @@ + diff --git a/pykd/pykd.vcxproj.filters b/pykd/pykd.vcxproj.filters index 5b7c9f4..dc85d21 100644 --- a/pykd/pykd.vcxproj.filters +++ b/pykd/pykd.vcxproj.filters @@ -48,6 +48,9 @@ Header Files + + Header Files + @@ -68,6 +71,9 @@ Source Files + + Source Files + diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index d9ade43..aaa141c 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -12,6 +12,7 @@ #include "typeinfo.h" #include "typedvar.h" #include "windbgext.h" +#include "breakpoint.h" using namespace pykd; @@ -50,8 +51,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemory_, kdlib::compareMemory, 3, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceLine_, getSourceLine, 0, 1 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceFile_, kdlib::getSourceFile, 0, 1 ); -// -//BOOST_PYTHON_FUNCTION_OVERLOADS( setSoftwareBp_, setSoftwareBp, 1, 2 ); + //BOOST_PYTHON_FUNCTION_OVERLOADS( setHardwareBp_, setHardwareBp, 3, 4 ); // //BOOST_PYTHON_FUNCTION_OVERLOADS( findSymbol_, TypeInfo::findSymbol, 1, 2 ); @@ -272,13 +272,14 @@ BOOST_PYTHON_MODULE( pykd ) // python::def( "getParams", &getParams, // "Get list of function arguments" ); - // // breakpoints - // python::def( "setBp", &setSoftwareBp, setSoftwareBp_( python::args( "offset", "callback" ), - // "Set software breakpoint on executiont" ) ); - // python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) , - // "Set hardware breakpoint" ) ); - // python::def( "removeBp", &removeBp, - // "Remove breapoint by IDs" ); + // breakpoints + python::def( "setBp", &kdlib::softwareBreakPointSet, + "Set software breakpoint on executiont" ); + python::def( "removeBp", &kdlib::breakPointRemove, + "Remove breapoint by IDs" ); + + //python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) , + // "Set hardware breakpoint" ) ); // //python::def( "removeAllBp", &removeAllBp, // // "Remove all breapoints" ); @@ -503,6 +504,13 @@ BOOST_PYTHON_MODULE( pykd ) // .def( "createUnion", &TypeBuilder::createUnion, // "Create custom union" ); + python::class_( "breakpoint", + "class for breakpoint representation", python::no_init ) + .def("__init__", python::make_constructor(Breakpoint::setSoftwareBreakpoint) ) + ; + + + // python::class_ >( // "cpuReg", "CPU regsiter class", boost::python::no_init ) // .def( "name", &CpuReg::name, "The name of the regsiter" ) @@ -613,18 +621,18 @@ BOOST_PYTHON_MODULE( pykd ) // .def( "jumprel", &Disasm::jumprel, "Change the current instruction" ); - // python::enum_("eventResult", "Return value of event handler") - // .value("Proceed", DebugCallbackProceed) - // .value("NoChange", DebugCallbackNoChange) - // .value("Break", DebugCallbackBreak) - // .export_values(); + python::enum_("eventResult", "Return value of event handler") + .value("Proceed", kdlib::DebugCallbackProceed) + .value("NoChange", kdlib::DebugCallbackNoChange) + .value("Break", kdlib::DebugCallbackBreak) + .export_values(); - // python::enum_("executionStatus", "Execution Status") - // .value("NoChange", DebugStatusNoChange ) - // .value("Go", DebugStatusGo ) - // .value("Break", DebugStatusBreak ) - // .value("NoDebuggee", DebugStatusNoDebuggee ) - // .export_values(); + python::enum_("executionStatus", "Execution Status") + .value("NoChange", kdlib::DebugStatusNoChange ) + .value("Go", kdlib::DebugStatusGo ) + .value("Break", kdlib::DebugStatusBreak ) + .value("NoDebuggee", kdlib::DebugStatusNoDebuggee ) + .export_values(); // python::class_( // "eventHandler", "Base class for overriding and handling debug notifications" ) diff --git a/test/scripts/diatest.py b/test/scripts/diatest.py deleted file mode 100644 index 77a3e4d..0000000 --- a/test/scripts/diatest.py +++ /dev/null @@ -1,179 +0,0 @@ -""" -Tests for pyDia -""" - -import unittest -import target -import pykd - -from sets import Set - -class DiaTest( unittest.TestCase ): - - def testCtor(self): - """ DiaSymbol can not be created direct """ - try: pykd.DiaSymbol() - except RuntimeError: pass - - def testFind(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertNotEqual(0, len(gScope)) - symFunction = gScope.find("FuncWithName0") - self.assertTrue(1 == len( symFunction )) - symFunction = gScope.findEx(pykd.SymTagNull, - "FuNc*Name?", - pykd.nsCaseInRegularExpression) - self.assertTrue(len(symFunction) > 1) - - def testSize(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual(1, gScope["g_ucharValue"].type().size()) - self.assertEqual(2, gScope["g_ushortValue"].type().size()) - self.assertEqual(4, gScope["g_ulongValue"].type().size()) - self.assertEqual(8, gScope["g_ulonglongValue"].type().size()) - - def testValue(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual(0x5555, gScope["g_constNumValue"].value()) - self.assertEqual(True, gScope["g_constBoolValue"].value()) - - def testName(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual( "g_constNumValue", - gScope["g_constNumValue"].name() ) - self.assertEqual( "FuncWithName0", - gScope["FuncWithName0"].name() ) - - def testRva(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - _rva = gScope["FuncWithName0"].rva() - self.assertNotEqual(0, _rva) - modLen = target.module.end() - target.module.begin() - self.assertTrue( _rva < modLen ) - _rva = gScope["g_string"].rva() - self.assertNotEqual(0, _rva) - self.assertTrue( _rva < modLen ) - - def testSymTag(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual( pykd.SymTagFunction, - gScope["FuncWithName0"].symTag() ) - self.assertEqual( pykd.SymTagData, - gScope["g_string"].symTag() ) - - def testLocType(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual( pykd.LocIsConstant, - gScope["g_constNumValue"].locType() ) - self.assertEqual( pykd.LocIsStatic, - gScope["FuncWithName1"].locType() ) - - def testBasicType(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertFalse(gScope["g_string"].type().isBasic()) - self.assertEqual( pykd.btBool, - gScope["g_constBoolValue"].type().baseType() ) - self.assertEqual( pykd.btULong, - gScope["g_ulongValue"].type().baseType() ) - - def testBasicName(self): - self.assertEqual( "NoType", pykd.diaBasicType[ pykd.btNoType ] ) - self.assertEqual( "Void", pykd.diaBasicType[ pykd.btVoid ] ) - self.assertEqual( "Char", pykd.diaBasicType[ pykd.btChar ] ) - self.assertEqual( "WChar", pykd.diaBasicType[ pykd.btWChar ] ) - self.assertEqual( "Int", pykd.diaBasicType[ pykd.btInt ] ) - self.assertEqual( "UInt", pykd.diaBasicType[ pykd.btUInt ] ) - self.assertEqual( "Float", pykd.diaBasicType[ pykd.btFloat ] ) - self.assertEqual( "BCD", pykd.diaBasicType[ pykd.btBCD ] ) - self.assertEqual( "Bool", pykd.diaBasicType[ pykd.btBool ] ) - self.assertEqual( "Long", pykd.diaBasicType[ pykd.btLong ] ) - self.assertEqual( "ULong", pykd.diaBasicType[ pykd.btULong ] ) - self.assertEqual( "Currency", pykd.diaBasicType[ pykd.btCurrency ] ) - self.assertEqual( "Date", pykd.diaBasicType[ pykd.btDate ] ) - self.assertEqual( "Variant", pykd.diaBasicType[ pykd.btVariant ] ) - self.assertEqual( "Complex", pykd.diaBasicType[ pykd.btComplex ] ) - self.assertEqual( "Bit", pykd.diaBasicType[ pykd.btBit ] ) - self.assertEqual( "BSTR", pykd.diaBasicType[ pykd.btBSTR ] ) - self.assertEqual( "Hresult", pykd.diaBasicType[ pykd.btHresult ] ) - - def testBits(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - structWithBits = gScope["structWithBits"] - bitField = structWithBits["m_bit0_4"] - self.assertEqual(pykd.LocIsBitField, bitField.locType()) - self.assertEqual(0, bitField.bitPos()) - self.assertEqual(5, bitField.size()) - bitField = structWithBits["m_bit5"] - self.assertEqual(pykd.LocIsBitField, bitField.locType()) - self.assertEqual(5, bitField.bitPos()) - self.assertEqual(1, bitField.size()) - bitField = structWithBits["m_bit6_7"] - self.assertEqual(pykd.LocIsBitField, bitField.locType()) - self.assertEqual(6, bitField.bitPos()) - self.assertEqual(2, bitField.size()) - - def testIndexId(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertNotEqual( gScope["classChild"].indexId(), - gScope["classBase"].indexId() ) - self.assertNotEqual( gScope["FuncWithName0"].indexId(), - gScope["FuncWithName1"].indexId() ) - - def testUdtKind(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual(pykd.UdtStruct, gScope["structTest"].udtKind()) - self.assertEqual(pykd.UdtUnion, gScope["unionTest"].udtKind()) - self.assertEqual(pykd.UdtClass, gScope["classBase"].udtKind()) - - def testOffset(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - structTest = gScope["structTest"] - self.assertEqual( 0, structTest["m_field0"].offset() ) - self.assertTrue( structTest["m_field0"].offset() < - structTest["m_field1"].offset() ) - self.assertTrue( structTest["m_field1"].offset() < - structTest["m_field2"].offset() ) - self.assertTrue( structTest["m_field2"].offset() < - structTest["m_field3"].offset() ) - self.assertTrue( structTest["m_field3"].offset() < - structTest.size() ) - - def testMachine(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - machine = gScope.machineType() - self.assertTrue( (machine == pykd.IMAGE_FILE_MACHINE_I386) or - (machine == pykd.IMAGE_FILE_MACHINE_AMD64) ) - - def testFindByRva(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - func = gScope["FuncWithName0"] - tplSymOffset = gScope.findByRva(func.rva(), pykd.SymTagFunction) - self.assertEqual(tplSymOffset[0].indexId(), func.indexId()) - self.assertEqual(tplSymOffset[1], 0) - tplSymOffset = gScope.findByRva(func.rva()+2, pykd.SymTagFunction) - self.assertEqual(tplSymOffset[0].indexId(), func.indexId()) - self.assertEqual(tplSymOffset[1], 2) - - def testSymbolById(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - func = gScope["FuncWithName0"] - self.assertEqual( gScope.symbolById(func.indexId()).indexId(), - func.indexId()) - - def testCount(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - var = gScope["FuncWithName1"]["_unionTest"] - self.assertEqual( 2, var.type().count() ) - - def testDataKind(self): - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - self.assertEqual( pykd.DataIsGlobal, gScope["g_structTest"].dataKind() ) - self.assertEqual( pykd.DataIsParam, gScope["EnumWindowsProc1"]["hWindow"].dataKind() ) - - def testSymbolHash(self): - """Test set of DIA symbols""" - gScope = pykd.diaLoadPdb( str(target.module.pdb()) ) - symSet = set([ gScope["g_structTest"], gScope["EnumWindowsProc1"], gScope["g_structTest"] ]) - self.assertEqual( 2, len(symSet) ) - self.assertTrue( gScope["g_structTest"] in symSet ) - self.assertFalse( gScope["EnumWindowsProc2"] in symSet ) diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index b307aa8..fc8fdb5 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -18,6 +18,9 @@ import memtest import moduletest import typeinfo import typedvar +import breakpoint + + #import regtest #import mspdbtest #import localstest @@ -56,6 +59,8 @@ def getTestSuite( singleName = "" ): # ^^^ unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ), + unittest.TestLoader().loadTestsFromTestCase( breakpoint.BreakpointTest ), + #unittest.TestLoader().loadTestsFromTestCase( mspdbtest.MsPdbTest ), #unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ), #unittest.TestLoader().loadTestsFromTestCase( ehexcepttest.EhExceptionTest ), @@ -77,4 +82,4 @@ if __name__ == "__main__": target.appPath = sys.argv[1] 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() ) diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py index 4641912..db8704f 100644 --- a/test/scripts/typedvar.py +++ b/test/scripts/typedvar.py @@ -237,7 +237,7 @@ class TypedVarTest( unittest.TestCase ): def testPointerToFunction(self): funcptr = target.module.typedVar( "CdeclFuncPtr" ) - self.assertEqual( funcptr, target.module.CdeclFunc ) + self.assertEqual( funcptr.deref(), target.module.CdeclFunc ) #tv1 = target.module.typedVar( "g_unTypedPtrToFunction" )