[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);
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);
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);
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);
}
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;
HRESULT hres = m_control->GetBreakpointById(Id, &bp);

View File

@ -10,14 +10,14 @@ namespace pykd {
////////////////////////////////////////////////////////////////////////////////
inline ULONG setSoftwareBp(ULONG64 addr) {
return g_dbgClient->setSoftwareBp(addr);
inline BPOINT_ID setSoftwareBp(ULONG64 addr, BpCallback &callback = BpCallback()) {
return g_dbgClient->setSoftwareBp(addr, callback);
}
////////////////////////////////////////////////////////////////////////////////
inline ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType) {
return g_dbgClient->setHardwareBp(addr, size, accessType);
inline BPOINT_ID setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType, BpCallback &callback = BpCallback()) {
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);
}

View File

@ -15,7 +15,7 @@ DebugClientPtr g_dbgClient( DebugClient::createDbgClient() );
DebugClient::DebugClient( IDebugClient4 *client )
: DbgObject( client )
, 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 {
private:
@ -298,12 +310,12 @@ public:
}
// breakpoints management
ULONG setSoftwareBp(ULONG64 addr);
ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType);
BPOINT_ID setSoftwareBp(ULONG64 addr, BpCallback &callback = BpCallback());
BPOINT_ID setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType, BpCallback &callback = BpCallback());
python::list getAllBp();
void removeBp(ULONG Id);
void removeBp(BPOINT_ID Id);
void removeAllBp();
private:
@ -314,6 +326,8 @@ private:
//python::list
//loadArray( ULONG64 offset, ULONG count, bool phyAddr );
BpCallbackMap m_bpCallbacks;
SynSymbolsPtr m_symSymbols; // DebugClient is creator
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( compareMemory_, compareMemory, 3, 4 );
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_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_getLocals, DebugClient::getLocals, 0, 1 );
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) \
python::scope().attr(#x) = ULONG(##x)
@ -300,10 +304,10 @@ BOOST_PYTHON_MODULE( pykd )
"Get context of current thread (register values)" )
.def( "getLocals", &DebugClient::getLocals, DebugClient_getLocals( python::args( "ctx" ),
"Get list of local variables" ) )
.def( "setBp", &DebugClient::setSoftwareBp,
"Set software breakpoint on executiont" )
.def( "setBp", &DebugClient::setHardwareBp,
"Set hardware breakpoint" )
.def( "setBp", &DebugClient::setSoftwareBp, DebugClient_setSoftwareBp( python::args( "offset", "callback" ),
"Set software breakpoint on executiont" ) )
.def( "setBp", &DebugClient::setHardwareBp, DebugClient_setHardwareBp( python::args( "offset", "size", "accsessType", "callback" ),
"Set hardware breakpoint" ) )
.def( "getAllBp", &DebugClient::getAllBp,
"Get all breapoint IDs" )
.def( "removeBp", &DebugClient::removeBp,
@ -485,10 +489,10 @@ BOOST_PYTHON_MODULE( pykd )
"Get context of current thread (register values)" );
python::def( "getLocals", &getLocals, getLocals_( python::args( "ctx" ),
"Get list of local variables" ) );
python::def( "setBp", &setSoftwareBp,
"Set software breakpoint on executiont" );
python::def( "setBp", &setHardwareBp,
"Set hardware breakpoint" );
python::def( "setBp", &setSoftwareBp, setSoftwareBp_( python::args( "offset", "callback" ),
"Set software breakpoint on executiont" ) );
python::def( "setBp", &setHardwareBp, setHardwareBp_( python::args( "offset", "size", "accsessType", "callback" ) ,
"Set hardware breakpoint" ) );
python::def( "getAllBp", &getAllBp,
"Get all breapoint IDs" );
python::def( "removeBp", &removeBp,

View File

@ -1,8 +1,7 @@
#include "stdafx.h"
#include "inteventhandler.h"
#include "dbgexcept.h"
#include "dbgclient.h"
namespace pykd {
@ -10,13 +9,21 @@ namespace pykd {
InternalDbgEventHandler::InternalDbgEventHandler(
IDebugClient4 *client,
SynSymbolsPtr synSymbols
) : m_synSymbols(synSymbols)
DebugClient *parentClient,
SynSymbolsPtr synSymbols,
BpCallbackMap &bpCallbacks
) : m_parentClient(parentClient)
, m_synSymbols(synSymbols)
, m_bpCallbacks(bpCallbacks)
{
HRESULT hres = client->CreateClient(&m_client);
if (FAILED(hres))
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);
}
@ -34,6 +41,8 @@ HRESULT InternalDbgEventHandler::GetInterestMask(
)
{
*Mask =
DEBUG_EVENT_BREAKPOINT |
DEBUG_EVENT_CHANGE_ENGINE_STATE |
DEBUG_EVENT_CHANGE_SYMBOL_STATE;
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(
__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

View File

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

View File

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

View File

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

View File

@ -43,6 +43,24 @@ class BreakExceptionHandler(pykd.eventHandler):
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):
"""Unit tests of exceptions end breakpoint handling"""
@ -53,7 +71,8 @@ class EhExceptionBreakpointTest(unittest.TestCase):
targetMod = testClient.loadModule( "targetapp" )
bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting") )
bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting"),
codeBpHandler )
allBp = testClient.getAllBp()
self.assertEqual( 1, len( allBp ) )
@ -75,13 +94,18 @@ class EhExceptionBreakpointTest(unittest.TestCase):
1, pykd.DEBUG_BREAK_EXECUTE )
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"),
1, pykd.DEBUG_BREAK_READ )
self.assertTrue( bpIdSoftware != bpIdHwExecute and
bpIdHwExecute != bpIdHwWrite and
bpIdHwWrite != bpIdHwRead )
allBp = testClient.getAllBp()
self.assertEqual( 4, len( allBp ) )
self.assertTrue( bpIdSoftware in allBp )
self.assertTrue( bpIdHwExecute in allBp )
self.assertTrue( bpIdHwWrite in allBp )
@ -106,3 +130,6 @@ class EhExceptionBreakpointTest(unittest.TestCase):
testClient.removeBp()
self.assertEqual( 0, len( testClient.getAllBp() ) )
self.assertEqual( bpHandlerTestResult.wasCodeBp, bpIdSoftware )
self.assertTrue( bpHandlerTestResult.wasDataBp, bpIdHwWrite )