mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-22 05:13:22 +08:00
[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:
parent
961932950b
commit
da5633cc12
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
@ -52,3 +52,5 @@ namespace python = boost::python;
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost\thread\win32\recursive_mutex.hpp>
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "dbgexcept.h"
|
||||
#include <DbgEng.h>
|
||||
#include <map>
|
||||
#include <boost\thread\win32\recursive_mutex.hpp>
|
||||
|
||||
namespace pykd {
|
||||
|
||||
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user