diff --git a/pykd-0.3-2010.sln b/pykd-0.3-2010.sln index 2706524..9db6b13 100644 --- a/pykd-0.3-2010.sln +++ b/pykd-0.3-2010.sln @@ -49,6 +49,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "snippets", "snippets", "{AAB21DD2-B0EE-493E-8415-5195F18879EB}" ProjectSection(SolutionItems) = preProject snippets\accessmask.py = snippets\accessmask.py + snippets\avl.py = snippets\avl.py snippets\cr0.py = snippets\cr0.py snippets\cr4.py = snippets\cr4.py snippets\ctlcode.py = snippets\ctlcode.py diff --git a/pykd/pyeventhandler.cpp b/pykd/pyeventhandler.cpp index e4270d1..cd530d5 100644 --- a/pykd/pyeventhandler.cpp +++ b/pykd/pyeventhandler.cpp @@ -7,64 +7,121 @@ namespace pykd { -/////////////////////////////////////////////////////////////////////////////// +pykd::InternalEventHandler *globalEventHandler = NULL; -class SoftwareBreakpoint : public Breakpoint +/////////////////////////////////////////////////////////////////////////////////// + +InternalEventHandler::~InternalEventHandler() { -public: + breakPointRemoveAll(); +} - SoftwareBreakpoint( kdlib::MEMOFFSET_64 offset ) { - m_id = pykd::softwareBreakPointSet( offset ); - } +/////////////////////////////////////////////////////////////////////////////////// - ~SoftwareBreakpoint() { - pykd::breakPointRemove( m_id ); - } - -private: - - kdlib::BREAKPOINT_ID m_id; - -}; - -/////////////////////////////////////////////////////////////////////////////// - -class SoftwareBreakpointWithCallback : public Breakpoint, private kdlib::EventHandler +kdlib::BREAKPOINT_ID InternalEventHandler::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback ) { -public: + kdlib::BREAKPOINT_ID id; + kdlib::PROCESS_DEBUG_ID processId; - SoftwareBreakpointWithCallback( kdlib::MEMOFFSET_64 offset, python::object &callback ) + 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_pystate = PyThreadState_Get(); - m_callback = callback; - m_id = pykd::softwareBreakPointSet( offset ); - } + m_breakPointMap.erase(it); - ~SoftwareBreakpointWithCallback() + 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 { - pykd::breakPointRemove( m_id ); - } catch( kdlib::DbgException& ) - { } + AutoRestorePyState pystate; + kdlib::breakPointRemove(it->first); + } catch(kdlib::DbgException&) + {} } -private: + m_breakPointMap.clear(); +} - virtual kdlib::DebugCallbackResult onBreakpoint( kdlib::BREAKPOINT_ID bpId ) +/////////////////////////////////////////////////////////////////////////////////// + +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() ) { - - kdlib::DebugCallbackResult result; - - if ( bpId != m_id ) - return kdlib::DebugCallbackNoChange; - PyEval_RestoreThread( m_pystate ); - try { + do { - do { + python::object &callback = it->second.getCallback(); - python::object resObj = m_callback( bpId ); + if ( !callback ) + { + result = kdlib::DebugCallbackBreak; + break; + } + + try { + + python::object resObj = callback( bpId ); if ( resObj.is_none() ) { @@ -82,38 +139,55 @@ private: result = kdlib::DebugCallbackResult(retVal); - } while( FALSE ); + } + catch (const python::error_already_set &) + { + printException(); + result = kdlib::DebugCallbackBreak; + } - } - catch (const python::error_already_set &) - { - printException(); - result = kdlib::DebugCallbackBreak; - } + } while( false); m_pystate = PyEval_SaveThread(); - - return result; - } - - kdlib::BREAKPOINT_ID m_id; - python::object m_callback; - PyThreadState* m_pystate; - -}; - -/////////////////////////////////////////////////////////////////////////////// - -BreakpointPtr Breakpoint::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback ) -{ - if ( callback ) - { - return BreakpointPtr( new SoftwareBreakpointWithCallback( offset, callback ) ); } else { - return BreakpointPtr( new SoftwareBreakpoint(offset) ); + 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; } /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/pyeventhandler.h b/pykd/pyeventhandler.h index 310508f..def83aa 100644 --- a/pykd/pyeventhandler.h +++ b/pykd/pyeventhandler.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include + #include "kdlib/dbgengine.h" #include "kdlib/eventhandler.h" @@ -16,53 +20,6 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////// -inline kdlib::BREAKPOINT_ID softwareBreakPointSet( kdlib::MEMOFFSET_64 offset ) -{ - AutoRestorePyState pystate; - return kdlib::softwareBreakPointSet(offset); -} - -inline kdlib::BREAKPOINT_ID hardwareBreakPointSet( kdlib::MEMOFFSET_64 offset, size_t size = 0, kdlib::ACCESS_TYPE accessType = 0 ) -{ - AutoRestorePyState pystate; - return kdlib::hardwareBreakPointSet(offset, size, accessType); -} - - -inline void breakPointRemove( kdlib::BREAKPOINT_ID id ) -{ - AutoRestorePyState pystate; - kdlib::breakPointRemove(id); -} - -inline void breakPointRemoveAll() -{ - AutoRestorePyState pystate; - kdlib::breakPointRemoveAll(); -} - - -/////////////////////////////////////////////////////////////////////////////// - -class Breakpoint; -typedef boost::shared_ptr BreakpointPtr; - -class Breakpoint : public boost::noncopyable -{ - -public: - - static - BreakpointPtr setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() ); - -protected: - - virtual ~Breakpoint() {} - -}; - -/////////////////////////////////////////////////////////////////////////////// - class EventHandler; typedef boost::shared_ptr EventHandlerPtr; @@ -85,4 +42,97 @@ private: /////////////////////////////////////////////////////////////////////////////// +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 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); +} + +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(); +} + +/////////////////////////////////////////////////////////////////////////////// + } // end namespace pykd diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 40163b3..67f8209 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -74,15 +74,37 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( getThreadIdBySystemId_, pykd::getThreadIdBySyst BOOST_PYTHON_FUNCTION_OVERLOADS( createStruct_, pykd::defineStruct, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( createUnion_, pykd::defineUnion, 1, 2 ); +BOOST_PYTHON_FUNCTION_OVERLOADS( setSoftwareBreakpoint_, pykd::setSoftwareBreakpoint, 1, 2 ); +BOOST_PYTHON_FUNCTION_OVERLOADS( setHardwareBreakpoint_, pykd::setHardwareBreakpoint, 3, 4 ); + BOOST_PYTHON_FUNCTION_OVERLOADS( Module_enumSymbols, ModuleAdapter::enumSymbols, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( Module_findSymbol, ModuleAdapter::findSymbol, 2, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( TypeInfo_ptrTo, TypeInfoAdapter::ptrTo, 1, 2 ); + pykd::SysDbgOut sysPykdOut; pykd::SysDbgOut sysPykdErr; pykd::SysDbgIn sysPykdIn; +namespace pykd { + +void initialize() +{ + kdlib::initialize(); + + globalEventHandler = new InternalEventHandler(); +} + +void uninitialize() +{ + delete globalEventHandler; + + kdlib::uninitialize(); +} + +} + BOOST_PYTHON_MODULE( pykd ) { // использовать вместо консоли потоки из sys @@ -93,9 +115,9 @@ BOOST_PYTHON_MODULE( pykd ) python::scope().attr("__version__") = pykdVersion; python::scope().attr("version") = pykdVersion; - python::def( "initialize", &kdlib::initialize, + python::def( "initialize", &pykd::initialize, "Initialize debug engine, only for console mode" ); - python::def( "deinitialize", &kdlib::uninitialize, + python::def( "deinitialize", &pykd::uninitialize, "Deintialize debug engine, only for console mode" ); // DbgEng services @@ -336,15 +358,14 @@ BOOST_PYTHON_MODULE( pykd ) "Get the function argument by name" ); // breakpoints - python::def( "setBp", pykd::softwareBreakPointSet, - "Set software breakpoint on executiont" ); + python::def( "setBp", pykd::setSoftwareBreakpoint, setSoftwareBreakpoint_( python::args( "offset", "callback" ), + "Set software breakpoint on executiont" ) ); + python::def( "setBp", pykd::setHardwareBreakpoint, setHardwareBreakpoint_( python::args( "offset", "size", "accsessType", "callback" ) , + "Set hardware breakpoint" ) ); python::def( "removeBp", pykd::breakPointRemove, "Remove breapoint by IDs" ); - - //python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) , - // "Set hardware breakpoint" ) ); - // //python::def( "removeAllBp", &removeAllBp, - // // "Remove all breapoints" ); + python::def( "removeAllBp", &breakPointRemoveAll, + "Remove all breapoints" ); // processes and threads python::def ( "getNumberProcesses", pykd::getNumberProcesses, @@ -615,10 +636,10 @@ BOOST_PYTHON_MODULE( pykd ) .add_static_property( "VoidPtr", &BaseTypesEnum::getVoidPtr ) ; - python::class_( "breakpoint", - "class for breakpoint representation", python::no_init ) - .def("__init__", python::make_constructor(Breakpoint::setSoftwareBreakpoint) ) - ; + //python::class_( "breakpoint", + // "class for breakpoint representation", python::no_init ) + // .def("__init__", python::make_constructor(Breakpoint::setSoftwareBreakpoint) ) + // ; python::class_( "stackFrame", "class for stack's frame representation", python::no_init ) diff --git a/test/scripts/breakpoint.py b/test/scripts/breakpoint.py index 7944c22..b28fc3b 100644 --- a/test/scripts/breakpoint.py +++ b/test/scripts/breakpoint.py @@ -5,7 +5,7 @@ import pykd import target import testutils -class callCounter: +class callCounter(object): def __init__(self,func): self.count = 0 self.func = func @@ -13,6 +13,14 @@ class callCounter: self.count = self.count+1 return self.func(val) + +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 @@ -57,7 +65,7 @@ class BreakpointTest( unittest.TestCase ): breakCount = callCounter(stopOnBreak) - bp = pykd.breakpoint( targetModule.CdeclFunc, breakCount ) + bp = breakpoint( targetModule.CdeclFunc, breakCount ) self.assertEqual( pykd.Break, pykd.go() ) @@ -72,7 +80,7 @@ class BreakpointTest( unittest.TestCase ): breakCount = callCounter(continueOnBreak) - bp = pykd.breakpoint( targetModule.CdeclFunc, breakCount ) + bp = breakpoint( targetModule.CdeclFunc, breakCount ) self.assertEqual( pykd.NoDebuggee, pykd.go() ) diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index 5d869fc..f309c6b 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -100,7 +100,7 @@ class ModuleTest( unittest.TestCase ): lst = target.module.enumSymbols( "*Const") self.assertEqual( 3, len(lst) ) lst = target.module.enumSymbols( "*cal?Func") - self.assertEqual( 2, len(lst) ) + self.assertEqual( 4, len(lst) ) lst = target.module.enumSymbols( "*virtMethod*") self.assertNotEqual( 0, len(lst) ) lst = target.module.enumSymbols( "classChild" )