[0.3.x] refactored : supported new breakpoint model for kdlibcpp

git-svn-id: https://pykd.svn.codeplex.com/svn@87821 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\kernelnet_cp 2014-04-07 16:02:19 +00:00 committed by Mikhail I. Izmestev
parent 782db1ba38
commit 5aa47e8201
5 changed files with 177 additions and 293 deletions

View File

@ -18,6 +18,8 @@ BOOL APIENTRY DllMain( HMODULE hModule,
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
int a;
a = 10;
break; break;
} }
return TRUE; return TRUE;

View File

@ -7,189 +7,6 @@
namespace pykd { namespace pykd {
pykd::InternalEventHandler *globalEventHandler = NULL;
///////////////////////////////////////////////////////////////////////////////////
InternalEventHandler::~InternalEventHandler()
{
breakPointRemoveAll();
}
///////////////////////////////////////////////////////////////////////////////////
kdlib::BREAKPOINT_ID InternalEventHandler::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback )
{
kdlib::BREAKPOINT_ID id;
kdlib::PROCESS_DEBUG_ID processId;
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
do {
AutoRestorePyState pystate;
id = kdlib::softwareBreakPointSet(offset);
processId = kdlib::getCurrentProcessId();
} while(false);
m_breakPointMap[id] = Breakpoint(id, processId, callback);
return id;
}
///////////////////////////////////////////////////////////////////////////////////
kdlib::BREAKPOINT_ID InternalEventHandler::setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType, python::object &callback )
{
kdlib::BREAKPOINT_ID id;
kdlib::PROCESS_DEBUG_ID processId;
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
do {
AutoRestorePyState pystate;
id = kdlib::hardwareBreakPointSet(offset,size,accessType);
processId = kdlib::getCurrentProcessId();
} while(false);
m_breakPointMap[id] = Breakpoint(id, processId, callback);
return id;
}
///////////////////////////////////////////////////////////////////////////////////
void InternalEventHandler::breakPointRemove(kdlib::BREAKPOINT_ID bpId)
{
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
BreakpointMap::iterator it = m_breakPointMap.find(bpId);
if ( it != m_breakPointMap.end() )
{
m_breakPointMap.erase(it);
try {
AutoRestorePyState pystate;
kdlib::breakPointRemove(bpId);
} catch(kdlib::DbgException&)
{}
}
}
///////////////////////////////////////////////////////////////////////////////////
void InternalEventHandler::breakPointRemoveAll()
{
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
BreakpointMap::iterator it;
for ( it = m_breakPointMap.begin(); it != m_breakPointMap.end(); ++it )
{
try {
AutoRestorePyState pystate;
kdlib::breakPointRemove(it->first);
} catch(kdlib::DbgException&)
{}
}
m_breakPointMap.clear();
}
///////////////////////////////////////////////////////////////////////////////////
kdlib::DebugCallbackResult InternalEventHandler::onBreakpoint( kdlib::BREAKPOINT_ID bpId )
{
kdlib::DebugCallbackResult result = kdlib::DebugCallbackNoChange;
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
BreakpointMap::iterator it = m_breakPointMap.find(bpId);
if ( it != m_breakPointMap.end() )
{
PyEval_RestoreThread( m_pystate );
do {
python::object &callback = it->second.getCallback();
if ( !callback )
{
result = kdlib::DebugCallbackBreak;
break;
}
try {
python::object resObj = callback( bpId );
if ( resObj.is_none() )
{
result = kdlib::DebugCallbackNoChange;
break;
}
int retVal = python::extract<int>( resObj );
if ( retVal >= kdlib::DebugCallbackMax )
{
result = kdlib::DebugCallbackBreak;
break;
}
result = kdlib::DebugCallbackResult(retVal);
}
catch (const python::error_already_set &)
{
printException();
result = kdlib::DebugCallbackBreak;
}
} while( false);
m_pystate = PyEval_SaveThread();
}
else
{
result = kdlib::DebugCallbackNoChange;
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////
kdlib::DebugCallbackResult InternalEventHandler::onProcessExit( kdlib::PROCESS_DEBUG_ID processId, kdlib::ProcessExitReason reason, unsigned long exitCode )
{
boost::recursive_mutex::scoped_lock l(m_breakPointLock);
BreakpointMap::iterator it = m_breakPointMap.begin();
while( it != m_breakPointMap.end() )
{
if ( it->second.getProcessId() == processId )
{
kdlib::breakPointRemove(it->first);
PyEval_RestoreThread( m_pystate );
m_breakPointMap.erase(it);
m_pystate = PyEval_SaveThread();
it = m_breakPointMap.begin();
}
else
{
++it;
}
}
return kdlib::DebugCallbackNoChange;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
EventHandler::EventHandler() EventHandler::EventHandler()
@ -425,5 +242,147 @@ kdlib::DebugCallbackResult EventHandler::onModuleUnload( kdlib::MEMOFFSET_64 of
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class CallbackBreakpoint : public kdlib::BaseBreakpoint
{
public:
static kdlib::BREAKPOINT_ID setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback);
static kdlib::BREAKPOINT_ID setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType, python::object &callback );
static void removeBreakpoint( kdlib::BREAKPOINT_ID id );
private:
virtual kdlib::DebugCallbackResult onHit();
python::object m_callback;
PyThreadState* m_pystate;
typedef std::map<kdlib::BREAKPOINT_ID, CallbackBreakpoint*> BreakpointMap;
static boost::recursive_mutex m_breakpointLock;
static BreakpointMap m_breakpointMap;
};
CallbackBreakpoint::BreakpointMap CallbackBreakpoint::m_breakpointMap;
boost::recursive_mutex CallbackBreakpoint::m_breakpointLock;
///////////////////////////////////////////////////////////////////////////////
kdlib::BREAKPOINT_ID CallbackBreakpoint::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback)
{
boost::recursive_mutex::scoped_lock l(m_breakpointLock);
CallbackBreakpoint *bp = new CallbackBreakpoint();
bp->m_pystate = PyThreadState_Get();
bp->m_callback = callback;
bp->set(offset);
m_breakpointMap[bp->m_id] = bp;
return bp->m_id;
}
///////////////////////////////////////////////////////////////////////////////
kdlib::BREAKPOINT_ID CallbackBreakpoint::setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType, python::object &callback )
{
boost::recursive_mutex::scoped_lock l(m_breakpointLock);
CallbackBreakpoint *bp = new CallbackBreakpoint();
bp->m_pystate = PyThreadState_Get();
bp->m_callback = callback;
bp->set(offset,size,accessType);
m_breakpointMap[bp->m_id] = bp;
return bp->m_id;
}
///////////////////////////////////////////////////////////////////////////////
void CallbackBreakpoint::removeBreakpoint( kdlib::BREAKPOINT_ID id )
{
boost::recursive_mutex::scoped_lock l(m_breakpointLock);
BreakpointMap::iterator it = m_breakpointMap.find(id);
if ( it != m_breakpointMap.end() )
m_breakpointMap.erase(it);
kdlib::breakPointRemove(id);
}
///////////////////////////////////////////////////////////////////////////////
kdlib::DebugCallbackResult CallbackBreakpoint::onHit()
{
kdlib::DebugCallbackResult result = kdlib::DebugCallbackNoChange;
PyEval_RestoreThread( m_pystate );
try {
do {
if ( !m_callback )
{
result = kdlib::DebugCallbackBreak;
break;
}
python::object resObj = m_callback();
if ( resObj.is_none() )
{
result = kdlib::DebugCallbackNoChange;
break;
}
int retVal = python::extract<int>( 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 setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback)
{
return CallbackBreakpoint::setSoftwareBreakpoint(offset,callback);
}
///////////////////////////////////////////////////////////////////////////////
kdlib::BREAKPOINT_ID setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType,python::object &callback)
{
return CallbackBreakpoint::setHardwareBreakpoint(offset, size, accessType,callback);
}
///////////////////////////////////////////////////////////////////////////////
void breakPointRemove( kdlib::BREAKPOINT_ID id )
{
CallbackBreakpoint::removeBreakpoint(id);
}
///////////////////////////////////////////////////////////////////////////////
} // end namespace pykd } // end namespace pykd

View File

@ -6,6 +6,7 @@
#include "kdlib/dbgengine.h" #include "kdlib/dbgengine.h"
#include "kdlib/eventhandler.h" #include "kdlib/eventhandler.h"
#include "kdlib/breakpoint.h"
#include "boost/shared_ptr.hpp" #include "boost/shared_ptr.hpp"
#include "boost/noncopyable.hpp" #include "boost/noncopyable.hpp"
@ -40,98 +41,33 @@ private:
PyThreadState* m_pystate; PyThreadState* m_pystate;
}; };
///////////////////////////////////////////////////////////////////////////////
class Breakpoint
{
public:
Breakpoint()
{}
Breakpoint(
kdlib::BREAKPOINT_ID& bpId,
kdlib::PROCESS_DEBUG_ID& targetId,
python::object& callback
) : m_bpId(bpId), m_processId(targetId), m_callback(callback)
{}
kdlib::BREAKPOINT_ID getId() const {
return m_bpId;
}
kdlib::PROCESS_DEBUG_ID getProcessId() const {
return m_processId;
}
python::object& getCallback() {
return m_callback;
}
private:
kdlib::BREAKPOINT_ID m_bpId;
kdlib::PROCESS_DEBUG_ID m_processId;
python::object m_callback;
};
class InternalEventHandler: public kdlib::EventHandler
{
public:
InternalEventHandler() {
m_pystate = PyThreadState_Get();
}
~InternalEventHandler();
kdlib::BREAKPOINT_ID setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() );
kdlib::BREAKPOINT_ID setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size = 0, kdlib::ACCESS_TYPE accessType = 0, python::object &callback = python::object() );
void breakPointRemove(kdlib::BREAKPOINT_ID bpId);
void breakPointRemoveAll();
private:
virtual kdlib::DebugCallbackResult onBreakpoint( kdlib::BREAKPOINT_ID bpId );
virtual kdlib::DebugCallbackResult onProcessExit( kdlib::PROCESS_DEBUG_ID processid, kdlib::ProcessExitReason reason, unsigned long exitCode );
private:
PyThreadState* m_pystate;
typedef std::map<kdlib::BREAKPOINT_ID, Breakpoint> BreakpointMap;
boost::recursive_mutex m_breakPointLock;
BreakpointMap m_breakPointMap;
};
extern pykd::InternalEventHandler *globalEventHandler;
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
inline kdlib::BREAKPOINT_ID setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() ) kdlib::BREAKPOINT_ID setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() );
{ kdlib::BREAKPOINT_ID setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType,python::object &callback = python::object()) ;
return globalEventHandler->setSoftwareBreakpoint(offset, callback); void breakPointRemove( kdlib::BREAKPOINT_ID id );
}
inline kdlib::BREAKPOINT_ID setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size = 0, kdlib::ACCESS_TYPE accessType = 0, python::object &callback = python::object() )
{
return globalEventHandler->setHardwareBreakpoint( offset, size, accessType, callback);
}
inline void breakPointRemove( kdlib::BREAKPOINT_ID id ) //class Breakpoint : public kdlib::BaseBreakpoint {
{ //
globalEventHandler->breakPointRemove(id); //public:
} //
// static kdlib::BreakpointPtr setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset )
inline void breakPointRemoveAll() // static kdlib::BreakpointPtr setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType );
{ // static void breakPointRemove( kdlib::BREAKPOINT_ID id );
globalEventHandler->breakPointRemoveAll(); //
} // ~Breakpoint();
//
//protected:
//
// static BreakpointMap m_breakpointMap;
// static boost::recursive_mutex m_breakpointLock;
//
// kdlib::BREAKPOINT_ID m_id;
//
// PyThreadState* m_pystate;
//
//};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -92,14 +92,10 @@ namespace pykd {
void initialize() void initialize()
{ {
kdlib::initialize(); kdlib::initialize();
globalEventHandler = new InternalEventHandler();
} }
void uninitialize() void uninitialize()
{ {
delete globalEventHandler;
kdlib::uninitialize(); kdlib::uninitialize();
} }
@ -364,8 +360,6 @@ BOOST_PYTHON_MODULE( pykd )
"Set hardware breakpoint" ) ); "Set hardware breakpoint" ) );
python::def( "removeBp", pykd::breakPointRemove, python::def( "removeBp", pykd::breakPointRemove,
"Remove breapoint by IDs" ); "Remove breapoint by IDs" );
python::def( "removeAllBp", &breakPointRemoveAll,
"Remove all breapoints" );
// processes and threads // processes and threads
python::def ( "getNumberProcesses", pykd::getNumberProcesses, python::def ( "getNumberProcesses", pykd::getNumberProcesses,
@ -640,9 +634,10 @@ BOOST_PYTHON_MODULE( pykd )
.add_static_property( "VoidPtr", &BaseTypesEnum::getVoidPtr ) .add_static_property( "VoidPtr", &BaseTypesEnum::getVoidPtr )
; ;
//python::class_<Breakpoint, BreakpointPtr, boost::noncopyable>( "breakpoint", //python::class_<kdlib::Breakpoint, kdlib::BreakpointPtr, boost::noncopyable>( "breakpoint",
// "class for breakpoint representation", python::no_init ) // "class for breakpoint representation", python::no_init )
// .def("__init__", python::make_constructor(Breakpoint::setSoftwareBreakpoint) ) // .def("__init__", python::make_constructor(pykd::Breakpoint::setSoftwareBreakpoint) )
// .def("__init__", python::make_constructor(pykd::Breakpoint::setHardwareBreakpoint) )
// ; // ;
python::class_<kdlib::StackFrame, kdlib::StackFramePtr, boost::noncopyable>( "stackFrame", python::class_<kdlib::StackFrame, kdlib::StackFramePtr, boost::noncopyable>( "stackFrame",

View File

@ -9,22 +9,14 @@ class callCounter(object):
def __init__(self,func): def __init__(self,func):
self.count = 0 self.count = 0
self.func = func self.func = func
def __call__(self,val): def __call__(self):
self.count = self.count+1 self.count = self.count+1
return self.func(val) return self.func()
def stopOnBreak():
class breakpoint(object):
def __init__(self, offset, callback):
self.id = pykd.setBp(offset,callback)
def __del__(self):
pykd.removeBp(self.id)
def stopOnBreak(id):
return pykd.eventResult.Break return pykd.eventResult.Break
def continueOnBreak(id): def continueOnBreak():
return pykd.eventResult.Proceed return pykd.eventResult.Proceed
@ -65,7 +57,7 @@ class BreakpointTest( unittest.TestCase ):
breakCount = callCounter(stopOnBreak) breakCount = callCounter(stopOnBreak)
bp = breakpoint( targetModule.CdeclFunc, breakCount ) bp = pykd.setBp( targetModule.CdeclFunc, breakCount )
self.assertEqual( pykd.Break, pykd.go() ) self.assertEqual( pykd.Break, pykd.go() )
@ -80,7 +72,7 @@ class BreakpointTest( unittest.TestCase ):
breakCount = callCounter(continueOnBreak) breakCount = callCounter(continueOnBreak)
bp = breakpoint( targetModule.CdeclFunc, breakCount ) bp = pykd.setBp( targetModule.CdeclFunc, breakCount )
self.assertEqual( pykd.NoDebuggee, pykd.go() ) self.assertEqual( pykd.NoDebuggee, pykd.go() )