From df0be475c89d42e8f62fd70422b224b01b029b9d Mon Sep 17 00:00:00 2001 From: "SND\\kernelnet_cp" Date: Tue, 12 Mar 2013 07:08:01 +0000 Subject: [PATCH] [0.2.x] added : getCurrentProcessId routine ( Return PID of the current process ( user mode only ) ) [0.2.x] added : getCurrentThreadId routine ( Return TID of the current thread ( user mode only ) ) [0.2.x] added : eventHandler.onExecutionStatusChange method ( Triggered execution status changed ) git-svn-id: https://pykd.svn.codeplex.com/svn@82898 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/dbgengine.h | 10 +++++ pykd/eventhandler.h | 23 +++++++++- pykd/pykdver.h | 2 +- pykd/python/pymod.cpp | 18 +++++++- pykd/win/dbgeng.cpp | 76 ++++++++++++++++++++++++++++----- pykd/win/dbgeng.h | 5 +++ test/scripts/ehexcepttest.py | 10 +++-- test/scripts/ehstatustest.py | 36 ++++++++++++++++ test/scripts/eventtest.py | 3 ++ test/scripts/moduletest.py | 2 +- test/scripts/pykdtest.py | 4 +- test/targetapp/targetapp.cpp | 13 ++++++ test/targetapp/targetapp.vcproj | 16 ++++--- 13 files changed, 193 insertions(+), 25 deletions(-) create mode 100644 test/scripts/ehstatustest.py diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index f59c0e9..fb0a65d 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -109,6 +109,7 @@ struct DEBUG_EVENT_CALLBACK { virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; + virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; }; enum EVENT_TYPE { @@ -133,6 +134,13 @@ EVENT_TYPE getLastEventType(); ExceptionInfoPtr getLastExceptionInfo(); +enum EXECUTION_STATUS { + DebugStatusNoChange = 0, + DebugStatusGo = 1, + DebugStatusBreak = 6, + DebugStatusNoDebuggee = 7 +}; + struct BUG_CHECK_DATA { ULONG code; @@ -154,7 +162,9 @@ void breakPointRemoveAll(); // processes end threads ULONG64 getCurrentProcess(); +ULONG getCurrentProcessId(); ULONG64 getImplicitThread(); +ULONG getCurrentThreadId(); void setCurrentProcess( ULONG64 processAddr ); void setImplicitThread( ULONG64 threadAddr ); void getAllProcessThreads( std::vector &threadsArray ); diff --git a/pykd/eventhandler.h b/pykd/eventhandler.h index 074732b..b8be6d3 100644 --- a/pykd/eventhandler.h +++ b/pykd/eventhandler.h @@ -26,6 +26,7 @@ private: virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; + virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; }; ////////////////////////////////////////////////////////////////////////////////// @@ -52,15 +53,35 @@ public: return handler("onException", exceptInfo ); } + virtual void onExecutionStatusChange( ULONG executionStatus ) { + void_handler("onExecutionStatusChange", executionStatus ); + } + + private: + template + void void_handler( const char* handlerName, Arg1Type arg1 ) + { + if (python::override pythonHandler = get_override( handlerName )) + { + try { + pythonHandler(arg1); + } + catch (const python::error_already_set &) { + printException(); + } + } + } + + template DEBUG_CALLBACK_RESULT handler( const char* handlerName, Arg1Type arg1 ) { if (python::override pythonHandler = get_override( handlerName )) { try { - return pythonHandler(arg1); + pythonHandler(arg1); } catch (const python::error_already_set &) { printException(); diff --git a/pykd/pykdver.h b/pykd/pykdver.h index 4f62d32..dde416b 100644 --- a/pykd/pykdver.h +++ b/pykd/pykdver.h @@ -2,7 +2,7 @@ #define PYKD_VERSION_MAJOR 0 #define PYKD_VERSION_MINOR 2 #define PYKD_VERSION_SUBVERSION 0 -#define PYKD_VERSION_BUILDNO 17 +#define PYKD_VERSION_BUILDNO 18 #define __VER_STR2__(x) #x diff --git a/pykd/python/pymod.cpp b/pykd/python/pymod.cpp index b296da3..f6cd518 100644 --- a/pykd/python/pymod.cpp +++ b/pykd/python/pymod.cpp @@ -299,6 +299,12 @@ BOOST_PYTHON_MODULE( pykd ) "Set implicit thread for current process" ); python::def( "getProcessThreads", &pysupport::getProcessThreads, "Get all process's threads ( user mode only )" ); + python::def( "getCurrentProcessId", &getCurrentProcessId, + "Return PID of the current process ( user mode only )" ); + python::def( "getCurrentThreadId", &getCurrentThreadId, + "Return TID of the current thread ( user mode only )" ); + + // symbol path python::def( "getSymbolPath", &getSymbolPath, "Returns current symbol path"); @@ -582,6 +588,13 @@ BOOST_PYTHON_MODULE( pykd ) .value("Break", DebugCallbackBreak) .export_values(); + python::enum_("executionStatus", "Execution Status") + .value("NoChange", DebugStatusNoChange ) + .value("Go", DebugStatusGo ) + .value("Break", DebugStatusBreak ) + .value("NoDebuggee", DebugStatusNoDebuggee ) + .export_values(); + python::class_( "eventHandler", "Base class for overriding and handling debug notifications" ) .def( "onBreakpoint", &EventHandlerWrap::OnBreakpoint, @@ -595,7 +608,10 @@ BOOST_PYTHON_MODULE( pykd ) "For ignore event method must return eventResult.noChange" ) .def( "onException", &EventHandlerWrap::OnException, "Triggered exception event. Parameter - exceptionInfo\n" - "For ignore event method must return eventResult.noChange" ); + "For ignore event method must return eventResult.noChange" ) + .def( "onExecutionStatusChange", &EventHandlerWrap::onExecutionStatusChange, + "Triggered execution status changed. Parameter - execution status.\n" + "There is no return value" ); // wrapper for standart python exceptions python::register_exception_translator( &PyException::exceptionTranslate ); diff --git a/pykd/win/dbgeng.cpp b/pykd/win/dbgeng.cpp index ad8e7e3..61b97ff 100644 --- a/pykd/win/dbgeng.cpp +++ b/pykd/win/dbgeng.cpp @@ -1235,14 +1235,6 @@ ULONG breakPointSet( ULONG64 offset, bool hardware, ULONG size, ULONG accessType throw DbgException("IDebugBreakpoint::GetFlags", hres); } - bpFlags |= DEBUG_BREAKPOINT_ENABLED; - hres = bp->SetFlags(bpFlags); - if (S_OK != hres) - { - g_dbgEng->control->RemoveBreakpoint(bp); - throw DbgException("IDebugBreakpoint::SetFlags", hres); - } - if ( hardware ) { HRESULT hres = bp->SetDataParameters(size, accessType); @@ -1253,6 +1245,14 @@ ULONG breakPointSet( ULONG64 offset, bool hardware, ULONG size, ULONG accessType } } + bpFlags |= DEBUG_BREAKPOINT_ENABLED | DEBUG_BREAKPOINT_GO_ONLY; + hres = bp->SetFlags(bpFlags); + if (S_OK != hres) + { + g_dbgEng->control->RemoveBreakpoint(bp); + throw DbgException("IDebugBreakpoint::SetFlags", hres); + } + ULONG breakId; hres = bp->GetId(&breakId); if (S_OK != hres) @@ -1513,6 +1513,30 @@ HRESULT STDMETHODCALLTYPE DebugEngine::Exception( /////////////////////////////////////////////////////////////////////////////// +HRESULT STDMETHODCALLTYPE DebugEngine::ChangeEngineState( + __in ULONG Flags, + __in ULONG64 Argument ) +{ + boost::recursive_mutex::scoped_lock l(m_handlerLock); + + HandlerList::iterator it = m_handlers.begin(); + + for ( ; it != m_handlers.end(); ++it ) + { + if ( ( Flags & DEBUG_CES_EXECUTION_STATUS ) != 0 && + ( Argument & DEBUG_STATUS_INSIDE_WAIT ) == 0 ) + { + PyThread_StateSave pyThreadSave( it->pystate ); + + it->callback->onExecutionStatusChange( (ULONG)Argument ); + } + } + + return S_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + ULONG64 getCurrentProcess() { @@ -1528,6 +1552,24 @@ getCurrentProcess() return processAddr; } + +/////////////////////////////////////////////////////////////////////////////// + +ULONG getCurrentProcessId() +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + ULONG pid; + + hres = g_dbgEng->system->GetCurrentProcessSystemId( &pid ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSystemObjects2::GetCurrentProcessSystemId failed" ); + + return pid; +} + + /////////////////////////////////////////////////////////////////////////////// ULONG64 @@ -1547,6 +1589,22 @@ getImplicitThread() /////////////////////////////////////////////////////////////////////////////// +ULONG getCurrentThreadId() +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + ULONG tid; + + hres = g_dbgEng->system->GetCurrentThreadSystemId( &tid ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSystemObjects2::GetCurrentThreadSystemId failed" ); + + return tid; +} + +/////////////////////////////////////////////////////////////////////////////// + void setCurrentProcess( ULONG64 processAddr ) { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); @@ -1673,8 +1731,6 @@ std::string callExtension( ULONG64 extHandle, const std::wstring command, const /////////////////////////////////////////////////////////////////////////////// - - } // end pykd namespace diff --git a/pykd/win/dbgeng.h b/pykd/win/dbgeng.h index f5e4213..474a65c 100644 --- a/pykd/win/dbgeng.h +++ b/pykd/win/dbgeng.h @@ -55,6 +55,7 @@ public: *Mask |= DEBUG_EVENT_LOAD_MODULE; *Mask |= DEBUG_EVENT_UNLOAD_MODULE; *Mask |= DEBUG_EVENT_EXCEPTION; + *Mask |= DEBUG_EVENT_CHANGE_ENGINE_STATE; return S_OK; } @@ -79,6 +80,10 @@ public: __in PEXCEPTION_RECORD64 Exception, __in ULONG FirstChance ); + STDMETHOD(ChangeEngineState)( + __in ULONG Flags, + __in ULONG64 Argument ); + DbgEngBind* operator->() { diff --git a/test/scripts/ehexcepttest.py b/test/scripts/ehexcepttest.py index cdab7bf..fd03601 100644 --- a/test/scripts/ehexcepttest.py +++ b/test/scripts/ehexcepttest.py @@ -6,15 +6,17 @@ import pykd import testutils class ExceptionHandler(pykd.eventHandler): - """Track load/unload module implementation""" def __init__(self): pykd.eventHandler.__init__(self) self.accessViolationOccured = False def onException(self, exceptInfo): """Exception handler""" - self.accessViolationOccured = exceptInfo.ExceptionCode == 0xC0000005 + self.accessViolationOccured = exceptInfo.ExceptionCode == 0xC0000005 + + print exceptInfo + if self.accessViolationOccured: self.param0 = exceptInfo.Parameters[0] self.param1 = exceptInfo.Parameters[1] @@ -27,7 +29,7 @@ class EhExceptionTest(unittest.TestCase): def testException(self): """Start new process and track exceptions""" - _locProcessId = pykd.startProcess( target.appPath + " -testAccessViolation" ) + _locProcessId = pykd.startProcess( target.appPath + " -testExceptions" ) with testutils.ContextCallIt( testutils.KillProcess(_locProcessId) ) as killStartedProcess : exceptionHandler = ExceptionHandler() @@ -38,7 +40,7 @@ class EhExceptionTest(unittest.TestCase): self.assertTrue( exceptionHandler.accessViolationOccured ) self.assertEqual( exceptionHandler.param0, 1 ) # write - self.assertEqual( exceptionHandler.param1, 6 ) # addr + self.assertEqual( exceptionHandler.param1, 2 ) # addr exceptInfo = pykd.lastException() self.assertEqual( exceptInfo.ExceptionCode, 0xC0000005 ) diff --git a/test/scripts/ehstatustest.py b/test/scripts/ehstatustest.py new file mode 100644 index 0000000..1c0947c --- /dev/null +++ b/test/scripts/ehstatustest.py @@ -0,0 +1,36 @@ +"""Execution status event test""" + +import unittest +import target +import pykd +import testutils + +class StatusChangeHandler(pykd.eventHandler): + + def __init__(self): + pykd.eventHandler.__init__(self) + self.breakCount = 0 + + + def onExecutionStatusChange(self, executionStatus): + if executionStatus == pykd.executionStatus.Break: + self.breakCount = self.breakCount + 1 + + +class EhStatusTest(unittest.TestCase): + """Execution status event test""" + + def testException(self): + """Start new process and track exceptions""" + _locProcessId = pykd.startProcess( target.appPath + " -testChangeStatus" ) + with testutils.ContextCallIt( testutils.KillProcess(_locProcessId) ) as killStartedProcess : + + pykd.go() #skip initial break + + statusChangeHandler = StatusChangeHandler() + + pykd.go() + pykd.go() + + self.assertEqual( 2, statusChangeHandler.breakCount ) + \ No newline at end of file diff --git a/test/scripts/eventtest.py b/test/scripts/eventtest.py index 9f0f47b..5c179dc 100644 --- a/test/scripts/eventtest.py +++ b/test/scripts/eventtest.py @@ -12,6 +12,9 @@ class handler( pykd.eventHandler ): def onException(self, param): self.counter += 1 return pykd.DEBUG_STATUS_NO_CHANGE + + def onExecutionStatusChange(self,status): + print status class EventTest( unittest.TestCase ): diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index c249447..317205f 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -73,7 +73,7 @@ class ModuleTest( unittest.TestCase ): self.assertTrue( re.search('targetapp\\.cpp', fileName ) ) self.assertEqual( 2, displacement ) fileName, lineNo, displacement = pykd.getSourceLine() - self.assertEqual( 663, lineNo ) + self.assertEqual( 673, lineNo ) def testEnumSymbols( self ): lst = target.module.enumSymbols() diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index db9fa98..725fc40 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -22,6 +22,7 @@ import regtest import localstest import customtypestest import ehexcepttest +import ehstatustest class StartProcessWithoutParamsTest(unittest.TestCase): def testStart(self): @@ -53,6 +54,7 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ), unittest.TestLoader().loadTestsFromTestCase( ehexcepttest.EhExceptionTest ), + unittest.TestLoader().loadTestsFromTestCase( ehstatustest.EhStatusTest ), ] ) else: return unittest.TestSuite( @@ -68,5 +70,5 @@ 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() ) diff --git a/test/targetapp/targetapp.cpp b/test/targetapp/targetapp.cpp index 68b6cc3..d8e48bc 100644 --- a/test/targetapp/targetapp.cpp +++ b/test/targetapp/targetapp.cpp @@ -602,6 +602,16 @@ int doExeptions() //////////////////////////////////////////////////////////////////////////////// +int doChangeStatus() +{ + __debugbreak(); + __debugbreak(); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// + #include std::map g_map; @@ -680,6 +690,9 @@ int _tmain(int argc, _TCHAR* argv[]) if ( !_tcsicmp(argv[1], _T("-testExceptions")) ) return doExeptions(); + + if ( !_tcsicmp(argv[1], _T("-testChangeStatus")) ) + return doChangeStatus(); } __debugbreak(); diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj index da0801f..34fd39e 100644 --- a/test/targetapp/targetapp.vcproj +++ b/test/targetapp/targetapp.vcproj @@ -550,12 +550,6 @@ > - - @@ -587,6 +581,10 @@ RelativePath="..\scripts\ehloadtest.py" > + + @@ -640,6 +638,12 @@ > + +