[~] python thread state moved from dbgExt to TLS

[+] bp without callback - always break when triggered, goLib - demo for this case
[+]  python thread restore for dbgCommand
[~] remove trailing blanks

git-svn-id: https://pykd.svn.codeplex.com/svn@69510 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2011-09-02 07:48:53 +00:00
parent 105ba17ade
commit 5ac233a473
10 changed files with 205 additions and 173 deletions

View File

@ -14,34 +14,50 @@ dbgBreakpointClass::breakpointMap dbgBreakpointClass::m_breakMap;
HRESULT dbgBreakpointClass::onBreakpointEvnet( IDebugBreakpoint* bp ) HRESULT dbgBreakpointClass::onBreakpointEvnet( IDebugBreakpoint* bp )
{ {
PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); PyThread_StateSave pyThreadSave;
try { try {
breakpointMap::iterator it = m_breakMap.find( bp ); breakpointMap::iterator it = m_breakMap.find( bp );
if ( it != m_breakMap.end() ) if ( it != m_breakMap.end() )
return boost::python::extract<HRESULT>( it->second->m_callback() ); {
boost::python::object &callback = it->second->m_callback;
if (!callback.is_none())
return boost::python::extract<HRESULT>( callback() );
return DEBUG_STATUS_BREAK;
}
} }
catch(...) catch(...)
{} {
}
return DEBUG_STATUS_NO_CHANGE;
return DEBUG_STATUS_NO_CHANGE;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
dbgBreakpointClass::dbgBreakpointClass( ULONG64 offset, boost::python::object &callback ) dbgBreakpointClass::dbgBreakpointClass( ULONG64 offset, boost::python::object &callback )
: m_offset(offset)
, m_callback(callback)
, m_breakpoint(NULL)
{ {
m_offset = offset; set();
m_breakpoint = NULL;
m_callback = callback;
set();
} }
///////////////////////////////////////////////////////////////////////////////
dbgBreakpointClass::dbgBreakpointClass( ULONG64 offset)
: m_offset(offset)
, m_breakpoint(NULL)
{
// m_callback is None, see dbgBreakpointClass::onBreakpointEvnet
set();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
dbgBreakpointClass::~dbgBreakpointClass() dbgBreakpointClass::~dbgBreakpointClass()
{ {
remove(); remove();
@ -53,44 +69,44 @@ bool
dbgBreakpointClass::set() dbgBreakpointClass::set()
{ {
HRESULT hres; HRESULT hres;
try { try {
if ( m_breakpoint ) if ( m_breakpoint )
return true; return true;
hres = dbgExt->control->AddBreakpoint( DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &m_breakpoint ); hres = dbgExt->control->AddBreakpoint( DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &m_breakpoint );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::AddBreakpoint failed" ); throw DbgException( "IDebugControl::AddBreakpoint failed" );
hres = m_breakpoint->SetOffset( m_offset ); hres = m_breakpoint->SetOffset( m_offset );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugBreakpoint::SetOffset failed" ); throw DbgException( "IDebugBreakpoint::SetOffset failed" );
hres = m_breakpoint->SetFlags( DEBUG_BREAKPOINT_ENABLED ); hres = m_breakpoint->SetFlags( DEBUG_BREAKPOINT_ENABLED );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugBreakpoint::SetFlags failed" ); throw DbgException( "IDebugBreakpoint::SetFlags failed" );
m_breakMap.insert( std::make_pair( m_breakpoint, this ) ); m_breakMap.insert( std::make_pair( m_breakpoint, this ) );
return true; return true;
} }
catch( std::exception &e ) catch( std::exception &e )
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() );
} }
catch(...) catch(...)
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" );
} }
remove(); remove();
return false; return false;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void void
dbgBreakpointClass::remove() dbgBreakpointClass::remove()
{ {
@ -111,36 +127,36 @@ dbgBreakpointClass::remove()
std::string std::string
dbgBreakpointClass::print() const dbgBreakpointClass::print() const
{ {
HRESULT status = S_OK; HRESULT status = S_OK;
try try
{ {
if (!m_breakpoint) if (!m_breakpoint)
return "not set"; return "not set";
DEBUG_BREAKPOINT_PARAMETERS params; DEBUG_BREAKPOINT_PARAMETERS params;
status = m_breakpoint->GetParameters(&params); status = m_breakpoint->GetParameters(&params);
if (FAILED(status)) if (FAILED(status))
throw DbgException("IDebugBreakpoint::GetParameters failed"); throw DbgException("IDebugBreakpoint::GetParameters failed");
boost::format fmt("%1$2d %2%%3% %4%:*** "); boost::format fmt("%1$2d %2%%3% %4%:*** ");
fmt % params.Id fmt % params.Id
% (params.Flags & DEBUG_BREAKPOINT_ENABLED ? 'e' : 'd') % (params.Flags & DEBUG_BREAKPOINT_ENABLED ? 'e' : 'd')
% 'u' % 'u'
% params.CurrentPassCount; % params.CurrentPassCount;
return fmt.str(); return fmt.str();
} }
catch (std::exception & e) catch (std::exception & e)
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() );
} }
catch (...) catch (...)
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" );
} }
return ""; return "";
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -10,12 +10,13 @@ class dbgBreakpointClass {
public: public:
dbgBreakpointClass( ULONG64 offset, boost::python::object &callback ); dbgBreakpointClass( ULONG64 offset, boost::python::object &callback );
dbgBreakpointClass( ULONG64 offset );
~dbgBreakpointClass(); ~dbgBreakpointClass();
bool bool
set(); set();
void void
remove(); remove();

View File

@ -16,13 +16,16 @@ dbgCommand( const std::string &command )
HRESULT hres; HRESULT hres;
OutputReader outReader( dbgExt->client ); 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 ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Execute failed" ); throw DbgException( "IDebugControl::Execute failed" );
return std::string( outReader.Line() ); return std::string( outReader.Line() );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -87,7 +90,7 @@ evaluate( const std::string &expression )
&remainderIndex ); &remainderIndex );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Evaluate failed" ); throw DbgException( "IDebugControl::Evaluate failed" );
if ( remainderIndex == expression.length() ) if ( remainderIndex == expression.length() )
value = debugValue.I64; value = debugValue.I64;
@ -101,7 +104,7 @@ evaluate( const std::string &expression )
&remainderIndex ); &remainderIndex );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::Evaluate failed" ); throw DbgException( "IDebugControl::Evaluate failed" );
if ( remainderIndex == expression.length() ) if ( remainderIndex == expression.length() )
value = debugValue.I32; value = debugValue.I32;
@ -118,12 +121,12 @@ breakin()
HRESULT hres; HRESULT hres;
{ {
PyThread_StateRestore state; PyThread_StateRestore pyThreadRestore;
hres = dbgExt->control->SetInterrupt( DEBUG_INTERRUPT_ACTIVE ); hres = dbgExt->control->SetInterrupt( DEBUG_INTERRUPT_ACTIVE );
} }
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetInterrupt" ); throw DbgException( "IDebugControl::SetInterrupt" );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -16,29 +16,27 @@ setExecutionStatus()
HRESULT hres; HRESULT hres;
hres = dbgExt->control->SetExecutionStatus( status ); hres = dbgExt->control->SetExecutionStatus( status );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::SetExecutionStatus failed" ); throw DbgException( "IDebugControl::SetExecutionStatus failed" );
ULONG currentStatus; ULONG currentStatus;
do { do {
{ {
PyThread_StateRestore state(dbgExt->getThreadState()); PyThread_StateRestore pyThreadRestore;
hres = dbgExt->control->WaitForEvent( 0, INFINITE ); hres = dbgExt->control->WaitForEvent( 0, INFINITE );
} }
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" ); throw DbgException( "IDebugControl::WaitForEvent failed" );
hres = dbgExt->control->GetExecutionStatus( &currentStatus ); hres = dbgExt->control->GetExecutionStatus( &currentStatus );
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetExecutionStatus failed" ); throw DbgException( "IDebugControl::GetExecutionStatus failed" );
} while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE ); } while( currentStatus != DEBUG_STATUS_BREAK && currentStatus != DEBUG_STATUS_NO_DEBUGGEE );
} }

View File

@ -41,10 +41,10 @@ HRESULT debugEvent::GetInterestMask(
*Mask = 0; *Mask = 0;
*Mask |= DEBUG_EVENT_LOAD_MODULE; *Mask |= DEBUG_EVENT_LOAD_MODULE;
*Mask |= DEBUG_EVENT_UNLOAD_MODULE; *Mask |= DEBUG_EVENT_UNLOAD_MODULE;
*Mask |= DEBUG_EVENT_SESSION_STATUS; *Mask |= DEBUG_EVENT_SESSION_STATUS;
return S_OK; return S_OK;
} }
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
@ -69,8 +69,7 @@ HRESULT debugEvent::LoadModule(
dbgModuleClass module(moduleName, moduleBase, moduleSize); dbgModuleClass module(moduleName, moduleBase, moduleSize);
silentMode.reset(); silentMode.reset();
PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); PyThread_StateSave pyThreadSave;
return onLoadModule( module ); return onLoadModule( module );
} }
@ -91,8 +90,7 @@ HRESULT debugEvent::UnloadModule(
dbgModuleClass module(moduleName, moduleBase, moduleSize); dbgModuleClass module(moduleName, moduleBase, moduleSize);
silentMode.reset(); silentMode.reset();
PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); PyThread_StateSave pyThreadSave;
return onUnloadModule( module ); return onUnloadModule( module );
} }
@ -102,8 +100,7 @@ HRESULT debugEvent::SessionStatus(
__in ULONG Status __in ULONG Status
) )
{ {
PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); PyThread_StateSave pyThreadSave;
return onChangeSessionStatus( Status ); return onChangeSessionStatus( Status );
} }
@ -114,8 +111,7 @@ HRESULT debugEvent::ChangeDebuggeeState(
__in ULONG64 Argument __in ULONG64 Argument
) )
{ {
PyThread_StateSave pyThrdState( dbgExt->getThreadState() ); PyThread_StateSave pyThreadSave;
return onChangeDebugeeState(); return onChangeDebugeeState();
} }

View File

@ -4,15 +4,16 @@
#include "dbgeventcb.h" #include "dbgeventcb.h"
#include "dbgmodule.h" #include "dbgmodule.h"
#include "pyaux.h"
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
class debugEvent : public DebugBaseEventCallbacks class debugEvent : public DebugBaseEventCallbacks
{ {
public: public:
debugEvent(); debugEvent();
virtual ~debugEvent(); virtual ~debugEvent();
virtual ULONG onLoadModule(const dbgModuleClass &/* module */) = 0; virtual ULONG onLoadModule(const dbgModuleClass &/* module */) = 0;
@ -30,8 +31,8 @@ private:
STDMETHOD(GetInterestMask)( STDMETHOD(GetInterestMask)(
__out PULONG Mask __out PULONG Mask
); );
STDMETHOD(LoadModule)( STDMETHOD(LoadModule)(
__in ULONG64 ImageFileHandle, __in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset, __in ULONG64 BaseOffset,
@ -46,18 +47,18 @@ private:
__in PCSTR ImageBaseName, __in PCSTR ImageBaseName,
__in ULONG64 BaseOffset __in ULONG64 BaseOffset
); );
STDMETHOD(SessionStatus)( STDMETHOD(SessionStatus)(
__in ULONG Status __in ULONG Status
); );
STDMETHOD(ChangeDebuggeeState)( STDMETHOD(ChangeDebuggeeState)(
__in ULONG Flags, __in ULONG Flags,
__in ULONG64 Argument ); __in ULONG64 Argument );
private: private:
IDebugClient *m_debugClient; IDebugClient *m_debugClient;
}; };
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
@ -65,9 +66,9 @@ private:
class debugEventWrap : public boost::python::wrapper<debugEvent>, public debugEvent class debugEventWrap : public boost::python::wrapper<debugEvent>, public debugEvent
{ {
public: public:
ULONG onLoadModule(const dbgModuleClass &module) { ULONG onLoadModule(const dbgModuleClass &module) {
return handler<const dbgModuleClass &>("onLoadModule", module ); return handler<const dbgModuleClass &>("onLoadModule", module );
} }
@ -75,33 +76,33 @@ public:
ULONG onUnloadModule(const dbgModuleClass &module) { ULONG onUnloadModule(const dbgModuleClass &module) {
return handler<const dbgModuleClass &>("onUnloadModule", module ); return handler<const dbgModuleClass &>("onUnloadModule", module );
} }
ULONG onChangeSessionStatus( ULONG status ) { ULONG onChangeSessionStatus( ULONG status ) {
return handler( "onChangeSessionStatus", status ); return handler( "onChangeSessionStatus", status );
} }
ULONG onChangeDebugeeState() { ULONG onChangeDebugeeState() {
return handler( "onChangeDebugeeState" ); return handler( "onChangeDebugeeState" );
} }
private: private:
template<typename Arg1Type> template<typename Arg1Type>
ULONG handler( const char* handlerName, Arg1Type arg1 ) 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 pythonHandler(arg1);
return DEBUG_STATUS_NO_CHANGE; return DEBUG_STATUS_NO_CHANGE;
} }
ULONG handler( const char* handlerName ) ULONG handler( const char* handlerName )
{ {
if (boost::python::override pythonHandler = get_override( handlerName )) if (boost::python::override pythonHandler = get_override( handlerName ))
return pythonHandler(); return pythonHandler();
return DEBUG_STATUS_NO_CHANGE; return DEBUG_STATUS_NO_CHANGE;
} }
}; };
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////

View File

@ -38,6 +38,9 @@ DbgExt *dbgExt = NULL;
// ãëîáàëüíûé êëèåíò // ãëîáàëüíûé êëèåíò
dbgClient g_dbgClient; dbgClient g_dbgClient;
// êîíòåñêò èñïîëíåíèÿ íèòè ïèòîíà
__declspec( thread ) PyThreadStatePtr ptrPyThreadState = NULL;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
BOOST_PYTHON_FUNCTION_OVERLOADS( dprint, dbgPrint::dprint, 1, 2 ) BOOST_PYTHON_FUNCTION_OVERLOADS( dprint, dbgPrint::dprint, 1, 2 )
@ -340,7 +343,9 @@ BOOST_PYTHON_MODULE( pykd )
boost::python::class_<dbgBreakpointClass>( "bp", boost::python::class_<dbgBreakpointClass>( "bp",
"Class representing breakpoint", "Class representing breakpoint",
boost::python::init<ULONG64,boost::python::object&>( boost::python::args("offset", "callback"), boost::python::init<ULONG64,boost::python::object&>( 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, .def( "set", &dbgBreakpointClass::set,
"Set a breakpoint at the specified address" ) "Set a breakpoint at the specified address" )
.def( "remove", &dbgBreakpointClass::remove, .def( "remove", &dbgBreakpointClass::remove,
@ -703,7 +708,6 @@ DebugExtensionUninitialize()
} }
DbgExt::DbgExt( IDebugClient4 *masterClient ) DbgExt::DbgExt( IDebugClient4 *masterClient )
: m_threadState(NULL)
{ {
client = NULL; client = NULL;
masterClient->QueryInterface( __uuidof(IDebugClient), (void **)&client ); masterClient->QueryInterface( __uuidof(IDebugClient), (void **)&client );
@ -753,21 +757,24 @@ DbgExt::DbgExt( IDebugClient4 *masterClient )
DbgExt::~DbgExt() DbgExt::~DbgExt()
{ {
BOOST_ASSERT(dbgExt == this);
dbgExt = m_previosExt;
if ( client ) if ( client )
client->Release(); client->Release();
if ( client4 ) if ( client4 )
client4->Release(); client4->Release();
if ( client5 ) if ( client5 )
client5->Release(); client5->Release();
if ( control ) if ( control )
control->Release(); control->Release();
if ( control4 ) if ( control4 )
control4->Release(); control4->Release();
if ( registers ) if ( registers )
registers->Release(); registers->Release();
@ -776,26 +783,24 @@ DbgExt::~DbgExt()
if ( symbols2 ) if ( symbols2 )
symbols2->Release(); symbols2->Release();
if ( symbols3 ) if ( symbols3 )
symbols3->Release(); symbols3->Release();
if ( dataSpaces ) if ( dataSpaces )
dataSpaces->Release(); dataSpaces->Release();
if ( dataSpaces4 ) if ( dataSpaces4 )
dataSpaces4->Release(); dataSpaces4->Release();
if ( advanced2 ) if ( advanced2 )
advanced2->Release(); advanced2->Release();
if ( system ) if ( system )
system->Release(); system->Release();
if ( system2 ) if ( system2 )
system2->Release(); system2->Release();
dbgExt = m_previosExt;
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////

View File

@ -32,16 +32,9 @@ public:
~DbgExt(); ~DbgExt();
PyThreadState** private:
getThreadState() {
return &m_threadState;
}
private:
DbgExt *m_previosExt; DbgExt *m_previosExt;
PyThreadState *m_threadState;
}; };
extern DbgExt *dbgExt; extern DbgExt *dbgExt;

View File

@ -2,6 +2,9 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
typedef PyThreadState *PyThreadStatePtr;
extern __declspec( thread ) PyThreadStatePtr ptrPyThreadState;
// --> call back // --> call back
// { PyThread_StateSave state( winext->getThreadState() ); // { PyThread_StateSave state( winext->getThreadState() );
// do_callback(); // do_callback();
@ -15,58 +18,40 @@ class PyThread_StateSave {
public: public:
PyThread_StateSave( PyThreadState **state ) PyThread_StateSave()
: m_state(NULL) : m_bRestored(false)
{ {
if ( *state ) if (ptrPyThreadState)
{ {
m_state = state; PyEval_RestoreThread( ptrPyThreadState );
PyEval_RestoreThread( *m_state ); m_bRestored = true;
} }
} }
~PyThread_StateSave() { ~PyThread_StateSave() {
if ( m_state ) if ( m_bRestored )
*m_state =PyEval_SaveThread(); ptrPyThreadState = PyEval_SaveThread();
} }
private: private:
bool m_bRestored;
PyThreadState **m_state;
}; };
// { PyThread_StateRestore state; // { PyThread_StateRestore state;
// long_or_block_opreration(); // long_or_block_opreration();
// } // }
class PyThread_StateRestore { class PyThread_StateRestore
{
public: public:
explicit PyThread_StateRestore() { PyThread_StateRestore() {
m_state = &m_ownState; ptrPyThreadState = PyEval_SaveThread();
*m_state =PyEval_SaveThread();
}
PyThread_StateRestore( PyThreadState **state ) {
if ( *state )
{
m_state = state;
*m_state =PyEval_SaveThread();
}
} }
~PyThread_StateRestore() { ~PyThread_StateRestore() {
if (*m_state) PyEval_RestoreThread( ptrPyThreadState );
PyEval_RestoreThread( *m_state );
} }
private:
PyThreadState **m_state;
PyThreadState *m_ownState;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

34
samples/goLib.py Normal file
View File

@ -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")