diff --git a/pykd/dllmain.cpp b/pykd/dllmain.cpp index efb52b7..d546fe0 100644 --- a/pykd/dllmain.cpp +++ b/pykd/dllmain.cpp @@ -18,6 +18,8 @@ BOOL APIENTRY DllMain( HMODULE hModule, break; case DLL_PROCESS_DETACH: + int a; + a = 10; break; } return TRUE; diff --git a/pykd/pyeventhandler.cpp b/pykd/pyeventhandler.cpp index cd530d5..d98e6d2 100644 --- a/pykd/pyeventhandler.cpp +++ b/pykd/pyeventhandler.cpp @@ -7,189 +7,6 @@ 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() @@ -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 diff --git a/pykd/pyeventhandler.h b/pykd/pyeventhandler.h index def83aa..2c30fe0 100644 --- a/pykd/pyeventhandler.h +++ b/pykd/pyeventhandler.h @@ -6,6 +6,7 @@ #include "kdlib/dbgengine.h" #include "kdlib/eventhandler.h" +#include "kdlib/breakpoint.h" #include "boost/shared_ptr.hpp" #include "boost/noncopyable.hpp" @@ -40,98 +41,33 @@ private: 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() ) -{ - return globalEventHandler->setSoftwareBreakpoint(offset, callback); -} +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()) ; +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 ) -{ - globalEventHandler->breakPointRemove(id); -} - -inline void breakPointRemoveAll() -{ - globalEventHandler->breakPointRemoveAll(); -} +//class Breakpoint : public kdlib::BaseBreakpoint { +// +//public: +// +// static kdlib::BreakpointPtr setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset ) +// static kdlib::BreakpointPtr setHardwareBreakpoint( kdlib::MEMOFFSET_64 offset, size_t size, kdlib::ACCESS_TYPE accessType ); +// static void breakPointRemove( kdlib::BREAKPOINT_ID id ); +// +// ~Breakpoint(); +// +//protected: +// +// static BreakpointMap m_breakpointMap; +// static boost::recursive_mutex m_breakpointLock; +// +// kdlib::BREAKPOINT_ID m_id; +// +// PyThreadState* m_pystate; +// +//}; /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 577f411..db2ffd5 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -92,14 +92,10 @@ namespace pykd { void initialize() { kdlib::initialize(); - - globalEventHandler = new InternalEventHandler(); } void uninitialize() { - delete globalEventHandler; - kdlib::uninitialize(); } @@ -364,8 +360,6 @@ BOOST_PYTHON_MODULE( pykd ) "Set hardware breakpoint" ) ); python::def( "removeBp", pykd::breakPointRemove, "Remove breapoint by IDs" ); - python::def( "removeAllBp", &breakPointRemoveAll, - "Remove all breapoints" ); // processes and threads python::def ( "getNumberProcesses", pykd::getNumberProcesses, @@ -640,9 +634,10 @@ BOOST_PYTHON_MODULE( pykd ) .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 ) - // .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", diff --git a/test/scripts/breakpoint.py b/test/scripts/breakpoint.py index b28fc3b..3cd2130 100644 --- a/test/scripts/breakpoint.py +++ b/test/scripts/breakpoint.py @@ -9,22 +9,14 @@ class callCounter(object): def __init__(self,func): self.count = 0 self.func = func - def __call__(self,val): + def __call__(self): self.count = self.count+1 - return self.func(val) + return self.func() - -class breakpoint(object): - def __init__(self, offset, callback): - self.id = pykd.setBp(offset,callback) - def __del__(self): - pykd.removeBp(self.id) - - -def stopOnBreak(id): +def stopOnBreak(): return pykd.eventResult.Break -def continueOnBreak(id): +def continueOnBreak(): return pykd.eventResult.Proceed @@ -65,7 +57,7 @@ class BreakpointTest( unittest.TestCase ): breakCount = callCounter(stopOnBreak) - bp = breakpoint( targetModule.CdeclFunc, breakCount ) + bp = pykd.setBp( targetModule.CdeclFunc, breakCount ) self.assertEqual( pykd.Break, pykd.go() ) @@ -80,7 +72,7 @@ class BreakpointTest( unittest.TestCase ): breakCount = callCounter(continueOnBreak) - bp = breakpoint( targetModule.CdeclFunc, breakCount ) + bp = pykd.setBp( targetModule.CdeclFunc, breakCount ) self.assertEqual( pykd.NoDebuggee, pykd.go() )