[0.1.x] + breakpoint handler

git-svn-id: https://pykd.svn.codeplex.com/svn@73626 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-01-25 09:13:19 +00:00 committed by Mikhail I. Izmestev
parent 961932950b
commit da5633cc12
10 changed files with 195 additions and 33 deletions

View File

@ -48,9 +48,9 @@ static IDebugBreakpoint *setBreakPoint(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static ULONG getBpId(IDebugBreakpoint *bp, IDebugControl4 *control = NULL) static BPOINT_ID getBpId(IDebugBreakpoint *bp, IDebugControl4 *control = NULL)
{ {
ULONG Id; BPOINT_ID Id;
HRESULT hres = bp->GetId(&Id); HRESULT hres = bp->GetId(&Id);
if (S_OK != hres) if (S_OK != hres)
{ {
@ -63,17 +63,25 @@ static ULONG getBpId(IDebugBreakpoint *bp, IDebugControl4 *control = NULL)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ULONG DebugClient::setSoftwareBp(ULONG64 addr) BPOINT_ID DebugClient::setSoftwareBp(ULONG64 addr, BpCallback &callback /*= BpCallback()*/)
{ {
addr = addr64(addr); addr = addr64(addr);
IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_CODE, addr); IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_CODE, addr);
return getBpId(bp, m_control); const BPOINT_ID Id = getBpId(bp, m_control);
if (!callback.is_none())
{
boost::recursive_mutex::scoped_lock mapBpLock(*m_bpCallbacks.m_lock);
m_bpCallbacks.m_map[Id] = callback;
}
return Id;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ULONG DebugClient::setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType) BPOINT_ID DebugClient::setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType, BpCallback &callback /*= BpCallback()*/)
{ {
addr = addr64(addr); addr = addr64(addr);
IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_DATA, addr); IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_DATA, addr);
@ -85,7 +93,15 @@ ULONG DebugClient::setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType)
throw DbgException("IDebugBreakpoint::SetDataParameters", hres); throw DbgException("IDebugBreakpoint::SetDataParameters", hres);
} }
return getBpId(bp, m_control); const BPOINT_ID Id = getBpId(bp, m_control);
if (!callback.is_none())
{
boost::recursive_mutex::scoped_lock mapBpLock(*m_bpCallbacks.m_lock);
m_bpCallbacks.m_map[Id] = callback;
}
return Id;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -113,7 +129,7 @@ python::list DebugClient::getAllBp()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DebugClient::removeBp(ULONG Id) void DebugClient::removeBp(BPOINT_ID Id)
{ {
IDebugBreakpoint *bp; IDebugBreakpoint *bp;
HRESULT hres = m_control->GetBreakpointById(Id, &bp); HRESULT hres = m_control->GetBreakpointById(Id, &bp);

View File

@ -10,14 +10,14 @@ namespace pykd {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
inline ULONG setSoftwareBp(ULONG64 addr) { inline BPOINT_ID setSoftwareBp(ULONG64 addr, BpCallback &callback = BpCallback()) {
return g_dbgClient->setSoftwareBp(addr); return g_dbgClient->setSoftwareBp(addr, callback);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
inline ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType) { inline BPOINT_ID setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType, BpCallback &callback = BpCallback()) {
return g_dbgClient->setHardwareBp(addr, size, accessType); return g_dbgClient->setHardwareBp(addr, size, accessType, callback);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -28,7 +28,7 @@ inline python::list getAllBp() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
inline void removeBp(ULONG Id) { inline void removeBp(BPOINT_ID Id) {
return g_dbgClient->removeBp(Id); return g_dbgClient->removeBp(Id);
} }

View File

@ -15,7 +15,7 @@ DebugClientPtr g_dbgClient( DebugClient::createDbgClient() );
DebugClient::DebugClient( IDebugClient4 *client ) DebugClient::DebugClient( IDebugClient4 *client )
: DbgObject( client ) : DbgObject( client )
, m_symSymbols( new SyntheticSymbols(*m_symbols, *this) ) , m_symSymbols( new SyntheticSymbols(*m_symbols, *this) )
, m_internalDbgEventHandler(client, m_symSymbols) , m_internalDbgEventHandler(client, this, m_symSymbols, m_bpCallbacks)
{ {
} }

View File

@ -29,6 +29,18 @@ typedef boost::shared_ptr<DebugClient> DebugClientPtr;
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
typedef ULONG BPOINT_ID;
typedef python::object BpCallback;
typedef std::map<BPOINT_ID, BpCallback> BpCallbackMapIml;
struct BpCallbackMap {
boost::shared_ptr<boost::recursive_mutex> m_lock;
BpCallbackMapIml m_map;
BpCallbackMap() : m_lock(new boost::recursive_mutex) {}
};
/////////////////////////////////////////////////////////////////////////////////
class DebugClient : private DbgObject { class DebugClient : private DbgObject {
private: private:
@ -298,12 +310,12 @@ public:
} }
// breakpoints management // breakpoints management
ULONG setSoftwareBp(ULONG64 addr); BPOINT_ID setSoftwareBp(ULONG64 addr, BpCallback &callback = BpCallback());
ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType); BPOINT_ID setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType, BpCallback &callback = BpCallback());
python::list getAllBp(); python::list getAllBp();
void removeBp(ULONG Id); void removeBp(BPOINT_ID Id);
void removeAllBp(); void removeAllBp();
private: private:
@ -314,6 +326,8 @@ private:
//python::list //python::list
//loadArray( ULONG64 offset, ULONG count, bool phyAddr ); //loadArray( ULONG64 offset, ULONG count, bool phyAddr );
BpCallbackMap m_bpCallbacks;
SynSymbolsPtr m_symSymbols; // DebugClient is creator SynSymbolsPtr m_symSymbols; // DebugClient is creator
InternalDbgEventHandler m_internalDbgEventHandler; InternalDbgEventHandler m_internalDbgEventHandler;

View File

@ -85,6 +85,8 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignDWords_, loadSignDWords, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignQWords_, loadSignQWords, 2, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignQWords_, loadSignQWords, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemory_, compareMemory, 3, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemory_, compareMemory, 3, 4 );
BOOST_PYTHON_FUNCTION_OVERLOADS( getLocals_, getLocals, 0, 1 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getLocals_, getLocals, 0, 1 );
BOOST_PYTHON_FUNCTION_OVERLOADS( setSoftwareBp_, setSoftwareBp, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( setHardwareBp_, setHardwareBp, 3, 4 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_loadChars, DebugClient::loadChars, 2, 3 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_loadChars, DebugClient::loadChars, 2, 3 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_loadWChars, DebugClient::loadWChars, 2, 3 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_loadWChars, DebugClient::loadWChars, 2, 3 );
@ -99,6 +101,8 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_loadSignQWords, DebugClient:
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_compareMemory, DebugClient::compareMemory, 3, 4 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_compareMemory, DebugClient::compareMemory, 3, 4 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_getLocals, DebugClient::getLocals, 0, 1 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_getLocals, DebugClient::getLocals, 0, 1 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( pyDia_Symbol_findChildrenEx, pyDia::Symbol::findChildrenEx, 1, 3 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( pyDia_Symbol_findChildrenEx, pyDia::Symbol::findChildrenEx, 1, 3 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setSoftwareBp, DebugClient::setSoftwareBp, 1, 2 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setHardwareBp, DebugClient::setHardwareBp, 3, 4 );
#define DEF_PY_CONST_ULONG(x) \ #define DEF_PY_CONST_ULONG(x) \
python::scope().attr(#x) = ULONG(##x) python::scope().attr(#x) = ULONG(##x)
@ -300,10 +304,10 @@ BOOST_PYTHON_MODULE( pykd )
"Get context of current thread (register values)" ) "Get context of current thread (register values)" )
.def( "getLocals", &DebugClient::getLocals, DebugClient_getLocals( python::args( "ctx" ), .def( "getLocals", &DebugClient::getLocals, DebugClient_getLocals( python::args( "ctx" ),
"Get list of local variables" ) ) "Get list of local variables" ) )
.def( "setBp", &DebugClient::setSoftwareBp, .def( "setBp", &DebugClient::setSoftwareBp, DebugClient_setSoftwareBp( python::args( "offset", "callback" ),
"Set software breakpoint on executiont" ) "Set software breakpoint on executiont" ) )
.def( "setBp", &DebugClient::setHardwareBp, .def( "setBp", &DebugClient::setHardwareBp, DebugClient_setHardwareBp( python::args( "offset", "size", "accsessType", "callback" ),
"Set hardware breakpoint" ) "Set hardware breakpoint" ) )
.def( "getAllBp", &DebugClient::getAllBp, .def( "getAllBp", &DebugClient::getAllBp,
"Get all breapoint IDs" ) "Get all breapoint IDs" )
.def( "removeBp", &DebugClient::removeBp, .def( "removeBp", &DebugClient::removeBp,
@ -485,10 +489,10 @@ BOOST_PYTHON_MODULE( pykd )
"Get context of current thread (register values)" ); "Get context of current thread (register values)" );
python::def( "getLocals", &getLocals, getLocals_( python::args( "ctx" ), python::def( "getLocals", &getLocals, getLocals_( python::args( "ctx" ),
"Get list of local variables" ) ); "Get list of local variables" ) );
python::def( "setBp", &setSoftwareBp, python::def( "setBp", &setSoftwareBp, setSoftwareBp_( python::args( "offset", "callback" ),
"Set software breakpoint on executiont" ); "Set software breakpoint on executiont" ) );
python::def( "setBp", &setHardwareBp, python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) ,
"Set hardware breakpoint" ); "Set hardware breakpoint" ) );
python::def( "getAllBp", &getAllBp, python::def( "getAllBp", &getAllBp,
"Get all breapoint IDs" ); "Get all breapoint IDs" );
python::def( "removeBp", &removeBp, python::def( "removeBp", &removeBp,

View File

@ -1,8 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "inteventhandler.h" #include "dbgclient.h"
#include "dbgexcept.h"
namespace pykd { namespace pykd {
@ -10,13 +9,21 @@ namespace pykd {
InternalDbgEventHandler::InternalDbgEventHandler( InternalDbgEventHandler::InternalDbgEventHandler(
IDebugClient4 *client, IDebugClient4 *client,
SynSymbolsPtr synSymbols DebugClient *parentClient,
) : m_synSymbols(synSymbols) SynSymbolsPtr synSymbols,
BpCallbackMap &bpCallbacks
) : m_parentClient(parentClient)
, m_synSymbols(synSymbols)
, m_bpCallbacks(bpCallbacks)
{ {
HRESULT hres = client->CreateClient(&m_client); HRESULT hres = client->CreateClient(&m_client);
if (FAILED(hres)) if (FAILED(hres))
throw DbgException("Call IDebugClient::CreateClient failed"); throw DbgException("Call IDebugClient::CreateClient failed");
hres = m_client->QueryInterface(__uuidof(IDebugControl), (void**)&m_control);
if ( FAILED( hres ) )
throw DbgException("QueryInterface IDebugControl failed");
m_client->SetEventCallbacks(this); m_client->SetEventCallbacks(this);
} }
@ -34,6 +41,8 @@ HRESULT InternalDbgEventHandler::GetInterestMask(
) )
{ {
*Mask = *Mask =
DEBUG_EVENT_BREAKPOINT |
DEBUG_EVENT_CHANGE_ENGINE_STATE |
DEBUG_EVENT_CHANGE_SYMBOL_STATE; DEBUG_EVENT_CHANGE_SYMBOL_STATE;
return S_OK; return S_OK;
@ -56,6 +65,46 @@ HRESULT InternalDbgEventHandler::ChangeSymbolState(
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
HRESULT InternalDbgEventHandler::ChangeEngineState(
__in ULONG Flags,
__in ULONG64 Argument
)
{
HRESULT hres = S_OK;
if (DEBUG_CES_BREAKPOINTS & Flags)
hres = bpChanged(static_cast<BPOINT_ID>(Argument));
return hres;
}
///////////////////////////////////////////////////////////////////////////////////
HRESULT InternalDbgEventHandler::Breakpoint(IDebugBreakpoint *bp)
{
BPOINT_ID Id;
HRESULT hres = bp->GetId(&Id);
if (S_OK == hres)
{
boost::recursive_mutex::scoped_lock mapBpLock(*m_bpCallbacks.m_lock);
BpCallbackMapIml::iterator it = m_bpCallbacks.m_map.find(Id);
if (it != m_bpCallbacks.m_map.end())
{
try {
PyThread_StateSave pyThreadSave( m_parentClient->getThreadState() );
hres = python::extract<HRESULT>( it->second(Id) );
return hres;
}
catch (const python::error_already_set &) {
// TODO: some logging, alerting...
}
}
}
return DEBUG_STATUS_NO_CHANGE;
}
///////////////////////////////////////////////////////////////////////////////////
HRESULT InternalDbgEventHandler::symLoaded( HRESULT InternalDbgEventHandler::symLoaded(
__in ULONG64 ModuleAddress __in ULONG64 ModuleAddress
) )
@ -73,4 +122,23 @@ HRESULT InternalDbgEventHandler::symLoaded(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
HRESULT InternalDbgEventHandler::bpChanged(BPOINT_ID Id)
{
if (DEBUG_ANY_ID == Id)
return S_OK;
IDebugBreakpoint *bp;
HRESULT hres = m_control->GetBreakpointById(Id, &bp);
if (E_NOINTERFACE == hres)
{
// breakpoint was removed
boost::recursive_mutex::scoped_lock mapBpLock(*m_bpCallbacks.m_lock);
m_bpCallbacks.m_map.erase(Id);
}
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
}; // namespace pykd }; // namespace pykd

View File

@ -7,14 +7,26 @@
#include <DbgEng.h> #include <DbgEng.h>
#include "synsymbol.h" #include "synsymbol.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd { namespace pykd {
////////////////////////////////////////////////////////////////////////////////
struct BpCallbackMap;
class DebugClient;
////////////////////////////////////////////////////////////////////////////////
class InternalDbgEventHandler : public DebugBaseEventCallbacks { class InternalDbgEventHandler : public DebugBaseEventCallbacks {
public: public:
InternalDbgEventHandler( InternalDbgEventHandler(
IDebugClient4 *client, IDebugClient4 *client,
SynSymbolsPtr synSymbols DebugClient *parentClient,
SynSymbolsPtr synSymbols,
BpCallbackMap &bpCallbacks
); );
~InternalDbgEventHandler(); ~InternalDbgEventHandler();
@ -32,14 +44,34 @@ protected:
STDMETHOD(ChangeSymbolState)( STDMETHOD(ChangeSymbolState)(
__in ULONG Flags, __in ULONG Flags,
__in ULONG64 Argument __in ULONG64 Argument
); ) override;
STDMETHOD(ChangeEngineState)(
__in ULONG Flags,
__in ULONG64 Argument
) override;
STDMETHOD(Breakpoint)(
__in IDebugBreakpoint *bp
) override;
private: private:
HRESULT symLoaded(__in ULONG64 ModuleAddress); HRESULT symLoaded(__in ULONG64 ModuleAddress);
HRESULT bpChanged(ULONG Id);
IDebugClient *m_client; IDebugClient *m_client;
IDebugControl *m_control;
DebugClient *m_parentClient;
SynSymbolsPtr m_synSymbols; SynSymbolsPtr m_synSymbols;
BpCallbackMap &m_bpCallbacks;
}; };
////////////////////////////////////////////////////////////////////////////////
}; // namespace pykd }; // namespace pykd
////////////////////////////////////////////////////////////////////////////////

View File

@ -52,3 +52,5 @@ namespace python = boost::python;
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <boost\thread\win32\recursive_mutex.hpp>

View File

@ -7,7 +7,6 @@
#include "dbgexcept.h" #include "dbgexcept.h"
#include <DbgEng.h> #include <DbgEng.h>
#include <map> #include <map>
#include <boost\thread\win32\recursive_mutex.hpp>
namespace pykd { namespace pykd {

View File

@ -43,6 +43,24 @@ class BreakExceptionHandler(pykd.eventHandler):
return pykd.DEBUG_STATUS_BREAK return pykd.DEBUG_STATUS_BREAK
class BpHandlerTestResult:
""" Breakpoint handler test results"""
def __init__(self):
self.wasCodeBp = None
self.wasDataBp = None
bpHandlerTestResult = BpHandlerTestResult()
def codeBpHandler(bpId):
""" Handler of software breakpoint """
bpHandlerTestResult.wasCodeBp = bpId
return pykd.DEBUG_STATUS_NO_CHANGE
def dataBpHandler(bpId):
""" Handler of hardware breakpoint """
bpHandlerTestResult.wasDataBp = bpId
return pykd.DEBUG_STATUS_NO_CHANGE
class EhExceptionBreakpointTest(unittest.TestCase): class EhExceptionBreakpointTest(unittest.TestCase):
"""Unit tests of exceptions end breakpoint handling""" """Unit tests of exceptions end breakpoint handling"""
@ -53,7 +71,8 @@ class EhExceptionBreakpointTest(unittest.TestCase):
targetMod = testClient.loadModule( "targetapp" ) targetMod = testClient.loadModule( "targetapp" )
bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting") ) bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting"),
codeBpHandler )
allBp = testClient.getAllBp() allBp = testClient.getAllBp()
self.assertEqual( 1, len( allBp ) ) self.assertEqual( 1, len( allBp ) )
@ -75,13 +94,18 @@ class EhExceptionBreakpointTest(unittest.TestCase):
1, pykd.DEBUG_BREAK_EXECUTE ) 1, pykd.DEBUG_BREAK_EXECUTE )
bpIdHwWrite = testClient.setBp( targetMod.offset("g_valueForAccessTesting1"), bpIdHwWrite = testClient.setBp( targetMod.offset("g_valueForAccessTesting1"),
1, pykd.DEBUG_BREAK_WRITE ) 1, pykd.DEBUG_BREAK_WRITE, dataBpHandler )
bpIdHwRead = testClient.setBp( targetMod.offset("g_valueForAccessTesting2"), bpIdHwRead = testClient.setBp( targetMod.offset("g_valueForAccessTesting2"),
1, pykd.DEBUG_BREAK_READ ) 1, pykd.DEBUG_BREAK_READ )
self.assertTrue( bpIdSoftware != bpIdHwExecute and
bpIdHwExecute != bpIdHwWrite and
bpIdHwWrite != bpIdHwRead )
allBp = testClient.getAllBp() allBp = testClient.getAllBp()
self.assertEqual( 4, len( allBp ) ) self.assertEqual( 4, len( allBp ) )
self.assertTrue( bpIdSoftware in allBp ) self.assertTrue( bpIdSoftware in allBp )
self.assertTrue( bpIdHwExecute in allBp ) self.assertTrue( bpIdHwExecute in allBp )
self.assertTrue( bpIdHwWrite in allBp ) self.assertTrue( bpIdHwWrite in allBp )
@ -106,3 +130,6 @@ class EhExceptionBreakpointTest(unittest.TestCase):
testClient.removeBp() testClient.removeBp()
self.assertEqual( 0, len( testClient.getAllBp() ) ) self.assertEqual( 0, len( testClient.getAllBp() ) )
self.assertEqual( bpHandlerTestResult.wasCodeBp, bpIdSoftware )
self.assertTrue( bpHandlerTestResult.wasDataBp, bpIdHwWrite )