[0.3.x] added : hardware breakpoint with setBp

git-svn-id: https://pykd.svn.codeplex.com/svn@87585 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\kernelnet_cp 2014-03-17 17:10:16 +00:00 committed by Mikhail I. Izmestev
parent c0c47147e2
commit ed35032124
6 changed files with 283 additions and 129 deletions

View File

@ -49,6 +49,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "snippets", "snippets", "{AAB21DD2-B0EE-493E-8415-5195F18879EB}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "snippets", "snippets", "{AAB21DD2-B0EE-493E-8415-5195F18879EB}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
snippets\accessmask.py = snippets\accessmask.py snippets\accessmask.py = snippets\accessmask.py
snippets\avl.py = snippets\avl.py
snippets\cr0.py = snippets\cr0.py snippets\cr0.py = snippets\cr0.py
snippets\cr4.py = snippets\cr4.py snippets\cr4.py = snippets\cr4.py
snippets\ctlcode.py = snippets\ctlcode.py snippets\ctlcode.py = snippets\ctlcode.py

View File

@ -7,64 +7,121 @@
namespace pykd { 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() { kdlib::BREAKPOINT_ID InternalEventHandler::setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback )
pykd::breakPointRemove( m_id );
}
private:
kdlib::BREAKPOINT_ID m_id;
};
///////////////////////////////////////////////////////////////////////////////
class SoftwareBreakpointWithCallback : public Breakpoint, private kdlib::EventHandler
{ {
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_breakPointMap.erase(it);
m_callback = callback;
m_id = pykd::softwareBreakPointSet( offset );
}
~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 { try {
pykd::breakPointRemove( m_id ); AutoRestorePyState pystate;
} catch( kdlib::DbgException& ) 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 ); 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() ) if ( resObj.is_none() )
{ {
@ -82,38 +139,55 @@ private:
result = kdlib::DebugCallbackResult(retVal); result = kdlib::DebugCallbackResult(retVal);
} while( FALSE ); }
catch (const python::error_already_set &)
{
printException();
result = kdlib::DebugCallbackBreak;
}
} } while( false);
catch (const python::error_already_set &)
{
printException();
result = kdlib::DebugCallbackBreak;
}
m_pystate = PyEval_SaveThread(); 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 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;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include <map>
#include <boost/thread/recursive_mutex.hpp>
#include "kdlib/dbgengine.h" #include "kdlib/dbgengine.h"
#include "kdlib/eventhandler.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<Breakpoint> BreakpointPtr;
class Breakpoint : public boost::noncopyable
{
public:
static
BreakpointPtr setSoftwareBreakpoint( kdlib::MEMOFFSET_64 offset, python::object &callback = python::object() );
protected:
virtual ~Breakpoint() {}
};
///////////////////////////////////////////////////////////////////////////////
class EventHandler; class EventHandler;
typedef boost::shared_ptr<EventHandler> EventHandlerPtr; typedef boost::shared_ptr<EventHandler> 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<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);
}
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 } // end namespace pykd

View File

@ -74,15 +74,37 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( getThreadIdBySystemId_, pykd::getThreadIdBySyst
BOOST_PYTHON_FUNCTION_OVERLOADS( createStruct_, pykd::defineStruct, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( createStruct_, pykd::defineStruct, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( createUnion_, pykd::defineUnion, 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_enumSymbols, ModuleAdapter::enumSymbols, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( Module_findSymbol, ModuleAdapter::findSymbol, 2, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( Module_findSymbol, ModuleAdapter::findSymbol, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( TypeInfo_ptrTo, TypeInfoAdapter::ptrTo, 1, 2 ); BOOST_PYTHON_FUNCTION_OVERLOADS( TypeInfo_ptrTo, TypeInfoAdapter::ptrTo, 1, 2 );
pykd::SysDbgOut sysPykdOut; pykd::SysDbgOut sysPykdOut;
pykd::SysDbgOut sysPykdErr; pykd::SysDbgOut sysPykdErr;
pykd::SysDbgIn sysPykdIn; pykd::SysDbgIn sysPykdIn;
namespace pykd {
void initialize()
{
kdlib::initialize();
globalEventHandler = new InternalEventHandler();
}
void uninitialize()
{
delete globalEventHandler;
kdlib::uninitialize();
}
}
BOOST_PYTHON_MODULE( pykd ) BOOST_PYTHON_MODULE( pykd )
{ {
// èñïîëüçîâàòü âìåñòî êîíñîëè ïîòîêè èç sys // èñïîëüçîâàòü âìåñòî êîíñîëè ïîòîêè èç sys
@ -93,9 +115,9 @@ BOOST_PYTHON_MODULE( pykd )
python::scope().attr("__version__") = pykdVersion; python::scope().attr("__version__") = pykdVersion;
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" ); "Initialize debug engine, only for console mode" );
python::def( "deinitialize", &kdlib::uninitialize, python::def( "deinitialize", &pykd::uninitialize,
"Deintialize debug engine, only for console mode" ); "Deintialize debug engine, only for console mode" );
// DbgEng services // DbgEng services
@ -336,15 +358,14 @@ BOOST_PYTHON_MODULE( pykd )
"Get the function argument by name" ); "Get the function argument by name" );
// breakpoints // breakpoints
python::def( "setBp", pykd::softwareBreakPointSet, python::def( "setBp", pykd::setSoftwareBreakpoint, setSoftwareBreakpoint_( python::args( "offset", "callback" ),
"Set software breakpoint on executiont" ); "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, python::def( "removeBp", pykd::breakPointRemove,
"Remove breapoint by IDs" ); "Remove breapoint by IDs" );
python::def( "removeAllBp", &breakPointRemoveAll,
//python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) , "Remove all breapoints" );
// "Set hardware breakpoint" ) );
// //python::def( "removeAllBp", &removeAllBp,
// // "Remove all breapoints" );
// processes and threads // processes and threads
python::def ( "getNumberProcesses", pykd::getNumberProcesses, python::def ( "getNumberProcesses", pykd::getNumberProcesses,
@ -615,10 +636,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_<Breakpoint, 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(Breakpoint::setSoftwareBreakpoint) )
; // ;
python::class_<kdlib::StackFrame, kdlib::StackFramePtr, boost::noncopyable>( "stackFrame", python::class_<kdlib::StackFrame, kdlib::StackFramePtr, boost::noncopyable>( "stackFrame",
"class for stack's frame representation", python::no_init ) "class for stack's frame representation", python::no_init )

View File

@ -5,7 +5,7 @@ import pykd
import target import target
import testutils import testutils
class callCounter: class callCounter(object):
def __init__(self,func): def __init__(self,func):
self.count = 0 self.count = 0
self.func = func self.func = func
@ -13,6 +13,14 @@ class callCounter:
self.count = self.count+1 self.count = self.count+1
return self.func(val) 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): def stopOnBreak(id):
return pykd.eventResult.Break return pykd.eventResult.Break
@ -57,7 +65,7 @@ class BreakpointTest( unittest.TestCase ):
breakCount = callCounter(stopOnBreak) breakCount = callCounter(stopOnBreak)
bp = pykd.breakpoint( targetModule.CdeclFunc, breakCount ) bp = breakpoint( targetModule.CdeclFunc, breakCount )
self.assertEqual( pykd.Break, pykd.go() ) self.assertEqual( pykd.Break, pykd.go() )
@ -72,7 +80,7 @@ class BreakpointTest( unittest.TestCase ):
breakCount = callCounter(continueOnBreak) breakCount = callCounter(continueOnBreak)
bp = pykd.breakpoint( targetModule.CdeclFunc, breakCount ) bp = breakpoint( targetModule.CdeclFunc, breakCount )
self.assertEqual( pykd.NoDebuggee, pykd.go() ) self.assertEqual( pykd.NoDebuggee, pykd.go() )

View File

@ -100,7 +100,7 @@ class ModuleTest( unittest.TestCase ):
lst = target.module.enumSymbols( "*Const") lst = target.module.enumSymbols( "*Const")
self.assertEqual( 3, len(lst) ) self.assertEqual( 3, len(lst) )
lst = target.module.enumSymbols( "*cal?Func") lst = target.module.enumSymbols( "*cal?Func")
self.assertEqual( 2, len(lst) ) self.assertEqual( 4, len(lst) )
lst = target.module.enumSymbols( "*virtMethod*") lst = target.module.enumSymbols( "*virtMethod*")
self.assertNotEqual( 0, len(lst) ) self.assertNotEqual( 0, len(lst) )
lst = target.module.enumSymbols( "classChild" ) lst = target.module.enumSymbols( "classChild" )