diff --git a/pykd/dbgbreak.cpp b/pykd/dbgbreak.cpp index ac82a93..3f6088e 100644 --- a/pykd/dbgbreak.cpp +++ b/pykd/dbgbreak.cpp @@ -14,34 +14,50 @@ dbgBreakpointClass::breakpointMap dbgBreakpointClass::m_breakMap; HRESULT dbgBreakpointClass::onBreakpointEvnet( IDebugBreakpoint* bp ) { - PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); + PyThread_StateSave pyThreadSave; try { - breakpointMap::iterator it = m_breakMap.find( bp ); - if ( it != m_breakMap.end() ) - return boost::python::extract( it->second->m_callback() ); - + breakpointMap::iterator it = m_breakMap.find( bp ); + if ( it != m_breakMap.end() ) + { + boost::python::object &callback = it->second->m_callback; + if (!callback.is_none()) + return boost::python::extract( callback() ); + + return DEBUG_STATUS_BREAK; + } + } catch(...) - {} - - return DEBUG_STATUS_NO_CHANGE; + { + } + + return DEBUG_STATUS_NO_CHANGE; } /////////////////////////////////////////////////////////////////////////////// dbgBreakpointClass::dbgBreakpointClass( ULONG64 offset, boost::python::object &callback ) + : m_offset(offset) + , m_callback(callback) + , m_breakpoint(NULL) { - m_offset = offset; - m_breakpoint = NULL; - m_callback = callback; - - set(); + set(); } - + +/////////////////////////////////////////////////////////////////////////////// + +dbgBreakpointClass::dbgBreakpointClass( ULONG64 offset) + : m_offset(offset) + , m_breakpoint(NULL) +{ + // m_callback is None, see dbgBreakpointClass::onBreakpointEvnet + set(); +} + /////////////////////////////////////////////////////////////////////////////// - + dbgBreakpointClass::~dbgBreakpointClass() { remove(); @@ -53,44 +69,44 @@ bool dbgBreakpointClass::set() { HRESULT hres; - + try { if ( m_breakpoint ) - return true; - + return true; + hres = dbgExt->control->AddBreakpoint( DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &m_breakpoint ); if ( FAILED( hres ) ) throw DbgException( "IDebugControl::AddBreakpoint failed" ); - + hres = m_breakpoint->SetOffset( m_offset ); if ( FAILED( hres ) ) throw DbgException( "IDebugBreakpoint::SetOffset failed" ); - + hres = m_breakpoint->SetFlags( DEBUG_BREAKPOINT_ENABLED ); if ( FAILED( hres ) ) throw DbgException( "IDebugBreakpoint::SetFlags failed" ); - + m_breakMap.insert( std::make_pair( m_breakpoint, this ) ); - - return true; + + return true; } - catch( std::exception &e ) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); - } - catch(...) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); - } - - remove(); - - return false; + catch( std::exception &e ) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); + } + catch(...) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); + } + + remove(); + + return false; } - + /////////////////////////////////////////////////////////////////////////////// - + void dbgBreakpointClass::remove() { @@ -111,36 +127,36 @@ dbgBreakpointClass::remove() std::string dbgBreakpointClass::print() const { - HRESULT status = S_OK; + HRESULT status = S_OK; - try - { - if (!m_breakpoint) - return "not set"; + try + { + if (!m_breakpoint) + return "not set"; - DEBUG_BREAKPOINT_PARAMETERS params; - status = m_breakpoint->GetParameters(¶ms); - if (FAILED(status)) - throw DbgException("IDebugBreakpoint::GetParameters failed"); + DEBUG_BREAKPOINT_PARAMETERS params; + status = m_breakpoint->GetParameters(¶ms); + if (FAILED(status)) + throw DbgException("IDebugBreakpoint::GetParameters failed"); - boost::format fmt("%1$2d %2%%3% %4%:*** "); - fmt % params.Id - % (params.Flags & DEBUG_BREAKPOINT_ENABLED ? 'e' : 'd') - % 'u' - % params.CurrentPassCount; + boost::format fmt("%1$2d %2%%3% %4%:*** "); + fmt % params.Id + % (params.Flags & DEBUG_BREAKPOINT_ENABLED ? 'e' : 'd') + % 'u' + % params.CurrentPassCount; - return fmt.str(); - } - catch (std::exception & e) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); - } - catch (...) - { - dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); - } + return fmt.str(); + } + catch (std::exception & e) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); + } + catch (...) + { + dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); + } - return ""; + return ""; } /////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgbreak.h b/pykd/dbgbreak.h index e3a2381..a6609e6 100644 --- a/pykd/dbgbreak.h +++ b/pykd/dbgbreak.h @@ -10,12 +10,13 @@ class dbgBreakpointClass { public: dbgBreakpointClass( ULONG64 offset, boost::python::object &callback ); - + dbgBreakpointClass( ULONG64 offset ); + ~dbgBreakpointClass(); - + bool set(); - + void remove(); diff --git a/pykd/dbgcmd.cpp b/pykd/dbgcmd.cpp index cc89d3b..c25cbd6 100644 --- a/pykd/dbgcmd.cpp +++ b/pykd/dbgcmd.cpp @@ -16,13 +16,16 @@ dbgCommand( const std::string &command ) HRESULT hres; OutputReader outReader( dbgExt->client ); - - hres = dbgExt->control->Execute( DEBUG_OUTCTL_THIS_CLIENT, command.c_str(), 0 ); + { + PyThread_StateRestore pyThreadRestore; + + hres = dbgExt->control->Execute( DEBUG_OUTCTL_THIS_CLIENT, command.c_str(), 0 ); + } if ( FAILED( hres ) ) throw DbgException( "IDebugControl::Execute failed" ); - + return std::string( outReader.Line() ); -} +} /////////////////////////////////////////////////////////////////////////////// @@ -87,7 +90,7 @@ evaluate( const std::string &expression ) &remainderIndex ); if ( FAILED( hres ) ) - throw DbgException( "IDebugControl::Evaluate failed" ); + throw DbgException( "IDebugControl::Evaluate failed" ); if ( remainderIndex == expression.length() ) value = debugValue.I64; @@ -101,7 +104,7 @@ evaluate( const std::string &expression ) &remainderIndex ); if ( FAILED( hres ) ) - throw DbgException( "IDebugControl::Evaluate failed" ); + throw DbgException( "IDebugControl::Evaluate failed" ); if ( remainderIndex == expression.length() ) value = debugValue.I32; @@ -118,12 +121,12 @@ breakin() HRESULT hres; { - PyThread_StateRestore state; + PyThread_StateRestore pyThreadRestore; hres = dbgExt->control->SetInterrupt( DEBUG_INTERRUPT_ACTIVE ); } if ( FAILED( hres ) ) - throw DbgException( "IDebugControl::SetInterrupt" ); + throw DbgException( "IDebugControl::SetInterrupt" ); } /////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgcmd.h b/pykd/dbgcmd.h index d6e5bae..5aa8817 100644 --- a/pykd/dbgcmd.h +++ b/pykd/dbgcmd.h @@ -16,29 +16,27 @@ setExecutionStatus() HRESULT hres; hres = dbgExt->control->SetExecutionStatus( status ); - + if ( FAILED( hres ) ) throw DbgException( "IDebugControl::SetExecutionStatus failed" ); - - ULONG currentStatus; - + + ULONG currentStatus; + do { { - PyThread_StateRestore state(dbgExt->getThreadState()); - + PyThread_StateRestore pyThreadRestore; hres = dbgExt->control->WaitForEvent( 0, INFINITE ); - } - + if ( FAILED( hres ) ) throw DbgException( "IDebugControl::WaitForEvent failed" ); hres = dbgExt->control->GetExecutionStatus( ¤tStatus ); - + if ( FAILED( hres ) ) throw DbgException( "IDebugControl::GetExecutionStatus failed" ); - + } while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE ); } diff --git a/pykd/dbgevent.cpp b/pykd/dbgevent.cpp index 2d02b98..4405485 100644 --- a/pykd/dbgevent.cpp +++ b/pykd/dbgevent.cpp @@ -41,10 +41,10 @@ HRESULT debugEvent::GetInterestMask( *Mask = 0; *Mask |= DEBUG_EVENT_LOAD_MODULE; - *Mask |= DEBUG_EVENT_UNLOAD_MODULE; + *Mask |= DEBUG_EVENT_UNLOAD_MODULE; *Mask |= DEBUG_EVENT_SESSION_STATUS; - - return S_OK; + + return S_OK; } /////////////////////////////////////////////////////////////////////////////////// @@ -69,8 +69,7 @@ HRESULT debugEvent::LoadModule( dbgModuleClass module(moduleName, moduleBase, moduleSize); silentMode.reset(); - PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); - + PyThread_StateSave pyThreadSave; return onLoadModule( module ); } @@ -91,8 +90,7 @@ HRESULT debugEvent::UnloadModule( dbgModuleClass module(moduleName, moduleBase, moduleSize); silentMode.reset(); - PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); - + PyThread_StateSave pyThreadSave; return onUnloadModule( module ); } @@ -102,8 +100,7 @@ HRESULT debugEvent::SessionStatus( __in ULONG Status ) { - PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); - + PyThread_StateSave pyThreadSave; return onChangeSessionStatus( Status ); } @@ -114,8 +111,7 @@ HRESULT debugEvent::ChangeDebuggeeState( __in ULONG64 Argument ) { - PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); - + PyThread_StateSave pyThreadSave; return onChangeDebugeeState(); } diff --git a/pykd/dbgevent.h b/pykd/dbgevent.h index 7ca1c09..c8cd9fc 100644 --- a/pykd/dbgevent.h +++ b/pykd/dbgevent.h @@ -4,15 +4,16 @@ #include "dbgeventcb.h" #include "dbgmodule.h" +#include "pyaux.h" ///////////////////////////////////////////////////////////////////////////////// class debugEvent : public DebugBaseEventCallbacks { public: - + debugEvent(); - + virtual ~debugEvent(); virtual ULONG onLoadModule(const dbgModuleClass &/* module */) = 0; @@ -30,8 +31,8 @@ private: STDMETHOD(GetInterestMask)( __out PULONG Mask - ); - + ); + STDMETHOD(LoadModule)( __in ULONG64 ImageFileHandle, __in ULONG64 BaseOffset, @@ -46,18 +47,18 @@ private: __in PCSTR ImageBaseName, __in ULONG64 BaseOffset ); - + STDMETHOD(SessionStatus)( __in ULONG Status ); - + STDMETHOD(ChangeDebuggeeState)( __in ULONG Flags, __in ULONG64 Argument ); - + private: - IDebugClient *m_debugClient; + IDebugClient *m_debugClient; }; ///////////////////////////////////////////////////////////////////////////////// @@ -65,9 +66,9 @@ private: class debugEventWrap : public boost::python::wrapper, public debugEvent { -public: - - +public: + + ULONG onLoadModule(const dbgModuleClass &module) { return handler("onLoadModule", module ); } @@ -75,33 +76,33 @@ public: ULONG onUnloadModule(const dbgModuleClass &module) { return handler("onUnloadModule", module ); } - + ULONG onChangeSessionStatus( ULONG status ) { return handler( "onChangeSessionStatus", status ); - } - + } + ULONG onChangeDebugeeState() { - return handler( "onChangeDebugeeState" ); - } - -private: - + return handler( "onChangeDebugeeState" ); + } + +private: + template ULONG handler( const char* handlerName, Arg1Type arg1 ) { - if (boost::python::override pythonHandler = get_override( handlerName )) + if (boost::python::override pythonHandler = get_override( handlerName )) return pythonHandler(arg1); - + return DEBUG_STATUS_NO_CHANGE; - } + } ULONG handler( const char* handlerName ) { - if (boost::python::override pythonHandler = get_override( handlerName )) + if (boost::python::override pythonHandler = get_override( handlerName )) return pythonHandler(); - + return DEBUG_STATUS_NO_CHANGE; - } + } }; ///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 24ade92..cde7b69 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -38,6 +38,9 @@ DbgExt *dbgExt = NULL; // глобальный клиент dbgClient g_dbgClient; +// контескт исполнения нити питона +__declspec( thread ) PyThreadStatePtr ptrPyThreadState = NULL; + ////////////////////////////////////////////////////////////////////////////// BOOST_PYTHON_FUNCTION_OVERLOADS( dprint, dbgPrint::dprint, 1, 2 ) @@ -340,7 +343,9 @@ BOOST_PYTHON_MODULE( pykd ) boost::python::class_( "bp", "Class representing breakpoint", boost::python::init( boost::python::args("offset", "callback"), - "dbgBreakpointClass constructor" ) ) + "Break point: user callback" ) ) + .def( boost::python::init< ULONG64 >( boost::python::args("offset"), + "Break point constructor: always break" ) ) .def( "set", &dbgBreakpointClass::set, "Set a breakpoint at the specified address" ) .def( "remove", &dbgBreakpointClass::remove, @@ -703,7 +708,6 @@ DebugExtensionUninitialize() } DbgExt::DbgExt( IDebugClient4 *masterClient ) - : m_threadState(NULL) { client = NULL; masterClient->QueryInterface( __uuidof(IDebugClient), (void **)&client ); @@ -753,21 +757,24 @@ DbgExt::DbgExt( IDebugClient4 *masterClient ) DbgExt::~DbgExt() { + BOOST_ASSERT(dbgExt == this); + dbgExt = m_previosExt; + if ( client ) client->Release(); - + if ( client4 ) client4->Release(); - + if ( client5 ) client5->Release(); - + if ( control ) control->Release(); - + if ( control4 ) control4->Release(); - + if ( registers ) registers->Release(); @@ -776,26 +783,24 @@ DbgExt::~DbgExt() if ( symbols2 ) symbols2->Release(); - + if ( symbols3 ) symbols3->Release(); - + if ( dataSpaces ) dataSpaces->Release(); - + if ( dataSpaces4 ) dataSpaces4->Release(); - + if ( advanced2 ) advanced2->Release(); - + if ( system ) system->Release(); - + if ( system2 ) system2->Release(); - - dbgExt = m_previosExt; } ///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgext.h b/pykd/dbgext.h index aa33c2e..39c0f55 100644 --- a/pykd/dbgext.h +++ b/pykd/dbgext.h @@ -32,16 +32,9 @@ public: ~DbgExt(); - PyThreadState** - getThreadState() { - return &m_threadState; - } - -private: +private: DbgExt *m_previosExt; - - PyThreadState *m_threadState; }; extern DbgExt *dbgExt; diff --git a/pykd/pyaux.h b/pykd/pyaux.h index cf83a13..843dc31 100644 --- a/pykd/pyaux.h +++ b/pykd/pyaux.h @@ -2,6 +2,9 @@ /////////////////////////////////////////////////////////////////////////////// +typedef PyThreadState *PyThreadStatePtr; +extern __declspec( thread ) PyThreadStatePtr ptrPyThreadState; + // --> call back // { PyThread_StateSave state( winext->getThreadState() ); // do_callback(); @@ -15,58 +18,40 @@ class PyThread_StateSave { public: - PyThread_StateSave( PyThreadState **state ) - : m_state(NULL) + PyThread_StateSave() + : m_bRestored(false) { - if ( *state ) + if (ptrPyThreadState) { - m_state = state; - PyEval_RestoreThread( *m_state ); + PyEval_RestoreThread( ptrPyThreadState ); + m_bRestored = true; } } ~PyThread_StateSave() { - if ( m_state ) - *m_state =PyEval_SaveThread(); + if ( m_bRestored ) + ptrPyThreadState = PyEval_SaveThread(); } private: - - PyThreadState **m_state; + bool m_bRestored; }; // { PyThread_StateRestore state; // long_or_block_opreration(); // } -class PyThread_StateRestore { - +class PyThread_StateRestore +{ public: - explicit PyThread_StateRestore() { - m_state = &m_ownState; - *m_state =PyEval_SaveThread(); - } - - PyThread_StateRestore( PyThreadState **state ) { - if ( *state ) - { - m_state = state; - *m_state =PyEval_SaveThread(); - } + PyThread_StateRestore() { + ptrPyThreadState = PyEval_SaveThread(); } ~PyThread_StateRestore() { - if (*m_state) - PyEval_RestoreThread( *m_state ); + PyEval_RestoreThread( ptrPyThreadState ); } - -private: - - PyThreadState **m_state; - - PyThreadState *m_ownState; - }; /////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/samples/goLib.py b/samples/goLib.py new file mode 100644 index 0000000..9fa3d69 --- /dev/null +++ b/samples/goLib.py @@ -0,0 +1,34 @@ +""" +Using bp class without callback +""" + +from pykd import * + + +if __name__ == "__main__": + + if not isKernelDebugging(): + + if not isWindbgExt(): + startProcess("calc.exe") + + kernel32 = loadModule("kernel32") + + bpA = bp( kernel32.LoadLibraryA ) + bpW = bp( kernel32.LoadLibraryW ) + + go() + dbgCommand("gu") + + dprintln( dbgCommand("!dlls @$retreg") ) + + else: + + dprintln("Script for user mode only") + + + + + + +