[0.1.x] + breakpoints, working by ID

git-svn-id: https://pykd.svn.codeplex.com/svn@73565 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-01-24 17:26:08 +00:00 committed by Mikhail I. Izmestev
parent 3902000ae8
commit ebc6910cd6
7 changed files with 303 additions and 4 deletions

157
pykd/bpoint.cpp Normal file
View File

@ -0,0 +1,157 @@
//
// Breakpoints management
//
#include "stdafx.h"
#include "bpoint.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
static IDebugBreakpoint *setBreakPoint(
IDebugControl4 *control,
ULONG bpType,
ULONG64 addr
)
{
IDebugBreakpoint *bp;
HRESULT hres = control->AddBreakpoint(bpType, DEBUG_ANY_ID, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::AddBreakpoint", hres);
hres = bp->SetOffset(addr);
if (S_OK != hres)
{
control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetOffset", hres);
}
ULONG bpFlags;
hres = bp->GetFlags(&bpFlags);
if (S_OK != hres)
{
control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::GetFlags", hres);
}
bpFlags |= DEBUG_BREAKPOINT_ENABLED;
hres = bp->SetFlags(bpFlags);
if (S_OK != hres)
{
control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetFlags", hres);
}
return bp;
}
////////////////////////////////////////////////////////////////////////////////
static ULONG getBpId(IDebugBreakpoint *bp, IDebugControl4 *control = NULL)
{
ULONG Id;
HRESULT hres = bp->GetId(&Id);
if (S_OK != hres)
{
if (control)
control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::GetId", hres);
}
return Id;
}
////////////////////////////////////////////////////////////////////////////////
ULONG DebugClient::setSoftwareBp(ULONG64 addr)
{
addr = addr64(addr);
IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_CODE, addr);
return getBpId(bp, m_control);
}
////////////////////////////////////////////////////////////////////////////////
ULONG DebugClient::setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType)
{
addr = addr64(addr);
IDebugBreakpoint *bp = setBreakPoint(m_control, DEBUG_BREAKPOINT_DATA, addr);
HRESULT hres = bp->SetDataParameters(size, accessType);
if (S_OK != hres)
{
m_control->RemoveBreakpoint(bp);
throw DbgException("IDebugBreakpoint::SetDataParameters", hres);
}
return getBpId(bp, m_control);
}
////////////////////////////////////////////////////////////////////////////////
python::list DebugClient::getAllBp()
{
ULONG numberOfBps;
HRESULT hres = m_control->GetNumberBreakpoints(&numberOfBps);
if (S_OK != hres)
throw DbgException("IDebugControl::GetNumberBreakpoints", hres);
python::list lstIds;
for (ULONG i =0; i < numberOfBps; ++i)
{
IDebugBreakpoint *bp;
hres = m_control->GetBreakpointByIndex(i, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::GetBreakpointByIndex", hres);
lstIds.append( getBpId(bp) );
}
return lstIds;
}
////////////////////////////////////////////////////////////////////////////////
void DebugClient::removeBp(ULONG Id)
{
IDebugBreakpoint *bp;
HRESULT hres = m_control->GetBreakpointById(Id, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::GetBreakpointById", hres);
hres = m_control->RemoveBreakpoint(bp);
if (S_OK != hres)
throw DbgException("IDebugControl::RemoveBreakpoint", hres);
}
////////////////////////////////////////////////////////////////////////////////
void DebugClient::removeAllBp()
{
ULONG numberOfBps;
do {
HRESULT hres = m_control->GetNumberBreakpoints(&numberOfBps);
if (S_OK != hres)
throw DbgException("IDebugControl::GetNumberBreakpoints", hres);
if (!numberOfBps)
break;
IDebugBreakpoint *bp;
hres = m_control->GetBreakpointByIndex(0, &bp);
if (S_OK != hres)
throw DbgException("IDebugControl::GetBreakpointByIndex", hres);
hres = m_control->RemoveBreakpoint(bp);
if (S_OK != hres)
throw DbgException("IDebugControl::RemoveBreakpoint", hres);
} while (numberOfBps);
}
////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
////////////////////////////////////////////////////////////////////////////////

46
pykd/bpoint.h Normal file
View File

@ -0,0 +1,46 @@
//
// Breakpoints management
//
#include "dbgclient.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
inline ULONG setSoftwareBp(ULONG64 addr) {
return g_dbgClient->setSoftwareBp(addr);
}
////////////////////////////////////////////////////////////////////////////////
inline ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType) {
return g_dbgClient->setHardwareBp(addr, size, accessType);
}
////////////////////////////////////////////////////////////////////////////////
inline python::list getAllBp() {
return g_dbgClient->getAllBp();
}
////////////////////////////////////////////////////////////////////////////////
inline void removeBp(ULONG Id) {
return g_dbgClient->removeBp(Id);
}
////////////////////////////////////////////////////////////////////////////////
inline void removeAllBp() {
return g_dbgClient->removeAllBp();
}
////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
////////////////////////////////////////////////////////////////////////////////

View File

@ -297,6 +297,15 @@ public:
return m_symSymbols; return m_symSymbols;
} }
// breakpoints management
ULONG setSoftwareBp(ULONG64 addr);
ULONG setHardwareBp(ULONG64 addr, ULONG size, ULONG accessType);
python::list getAllBp();
void removeBp(ULONG Id);
void removeAllBp();
private: private:
template<typename T> template<typename T>
python::list python::list

View File

@ -18,6 +18,7 @@
#include "dbgmem.h" #include "dbgmem.h"
#include "intbase.h" #include "intbase.h"
#include "process.h" #include "process.h"
#include "bpoint.h"
#include "pykdver.h" #include "pykdver.h"
using namespace pykd; using namespace pykd;
@ -284,7 +285,7 @@ BOOST_PYTHON_MODULE( pykd )
.def( "step", &DebugClient::changeDebuggerStatus<DEBUG_STATUS_STEP_OVER>, .def( "step", &DebugClient::changeDebuggerStatus<DEBUG_STATUS_STEP_OVER>,
"Change debugger status to DEBUG_STATUS_STEP_OVER" ) "Change debugger status to DEBUG_STATUS_STEP_OVER" )
.def( "symbolsPath", &DebugClient::dbgSymPath, .def( "symbolsPath", &DebugClient::dbgSymPath,
"Return symbol path" ) "Return symbol path" )
.def( "trace", &DebugClient::changeDebuggerStatus<DEBUG_STATUS_STEP_INTO>, .def( "trace", &DebugClient::changeDebuggerStatus<DEBUG_STATUS_STEP_INTO>,
"Change debugger status to DEBUG_STATUS_STEP_INTO" ) "Change debugger status to DEBUG_STATUS_STEP_INTO" )
.def( "waitForEvent", &DebugClient::waitForEvent, .def( "waitForEvent", &DebugClient::waitForEvent,
@ -299,6 +300,16 @@ 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,
"Set software breakpoint on executiont" )
.def( "setBp", &DebugClient::setHardwareBp,
"Set hardware breakpoint" )
.def( "getAllBp", &DebugClient::getAllBp,
"Get all breapoint IDs" )
.def( "removeBp", &DebugClient::removeBp,
"Remove breapoint by IDs" )
.def( "removeBp", &DebugClient::removeAllBp,
"Remove all breapoints" )
.def( "addSynSymbol", &DebugClient::addSyntheticSymbol, .def( "addSynSymbol", &DebugClient::addSyntheticSymbol,
"Add new synthetic symbol for virtual address" ) "Add new synthetic symbol for virtual address" )
.def( "delAllSynSymbols", &DebugClient::delAllSyntheticSymbols, .def( "delAllSynSymbols", &DebugClient::delAllSyntheticSymbols,
@ -473,7 +484,17 @@ BOOST_PYTHON_MODULE( pykd )
python::def( "getContext", &getThreadContext, python::def( "getContext", &getThreadContext,
"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,
"Set software breakpoint on executiont" );
python::def( "setBp", &setHardwareBp,
"Set hardware breakpoint" );
python::def( "getAllBp", &getAllBp,
"Get all breapoint IDs" );
python::def( "removeBp", &removeBp,
"Remove breapoint by IDs" );
python::def( "removeBp", &removeAllBp,
"Remove all breapoints" );
python::class_<TypeInfo, TypeInfoPtr, python::bases<intBase>, boost::noncopyable >("typeInfo", "Class representing typeInfo", python::no_init ) python::class_<TypeInfo, TypeInfoPtr, python::bases<intBase>, boost::noncopyable >("typeInfo", "Class representing typeInfo", python::no_init )
.def( "name", &TypeInfo::getName ) .def( "name", &TypeInfo::getName )
@ -872,6 +893,15 @@ BOOST_PYTHON_MODULE( pykd )
DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_BRANCH); DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_BRANCH);
DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_OVER); DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_OVER);
DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_INTO); DEF_PY_CONST_ULONG(DEBUG_STATUS_REVERSE_STEP_INTO);
// breakpoints constatns
DEF_PY_CONST_ULONG(DEBUG_BREAKPOINT_CODE);
DEF_PY_CONST_ULONG(DEBUG_BREAKPOINT_DATA);
DEF_PY_CONST_ULONG(DEBUG_BREAK_READ);
DEF_PY_CONST_ULONG(DEBUG_BREAK_WRITE);
DEF_PY_CONST_ULONG(DEBUG_BREAK_EXECUTE);
DEF_PY_CONST_ULONG(DEBUG_BREAK_IO);
} }
#undef DEF_PY_CONST_ULONG #undef DEF_PY_CONST_ULONG

View File

@ -349,6 +349,10 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File
RelativePath=".\bpoint.cpp"
>
</File>
<File <File
RelativePath=".\context.cpp" RelativePath=".\context.cpp"
> >
@ -483,6 +487,10 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath=".\bpoint.h"
>
</File>
<File <File
RelativePath=".\context.h" RelativePath=".\context.h"
> >

View File

@ -14,6 +14,7 @@ class BreakExceptionHandler(pykd.eventHandler):
self.wasSecondChance = False self.wasSecondChance = False
self.wasBreakpoint = False self.wasBreakpoint = False
self.wasBreakpointIds = []
self.bpLastModuleName = "" self.bpLastModuleName = ""
self.bpCount = 0 self.bpCount = 0
@ -24,6 +25,7 @@ class BreakExceptionHandler(pykd.eventHandler):
def onBreakpoint(self, bpId): def onBreakpoint(self, bpId):
"""Breakpoint handler""" """Breakpoint handler"""
self.wasBreakpoint = True self.wasBreakpoint = True
self.wasBreakpointIds.append( bpId )
return pykd.DEBUG_STATUS_NO_CHANGE return pykd.DEBUG_STATUS_NO_CHANGE
def onException(self, exceptParams): def onException(self, exceptParams):
@ -33,7 +35,6 @@ class BreakExceptionHandler(pykd.eventHandler):
if exceptParams["Code"] == pykd.EXCEPTION_ACCESS_VIOLATION: if exceptParams["Code"] == pykd.EXCEPTION_ACCESS_VIOLATION:
if self.wasSecondChance: if self.wasSecondChance:
print exceptParams["Parameters"]
self.secondChanceAccessAddresses.append( exceptParams["Parameters"][1] ) self.secondChanceAccessAddresses.append( exceptParams["Parameters"][1] )
else: else:
self.firstChanceAccessAddresses.append( exceptParams["Parameters"][1] ) self.firstChanceAccessAddresses.append( exceptParams["Parameters"][1] )
@ -50,7 +51,23 @@ class EhExceptionBreakpointTest(unittest.TestCase):
testClient = pykd.createDbgClient() testClient = pykd.createDbgClient()
testClient.startProcess( target.appPath + " -testExceptions" ) testClient.startProcess( target.appPath + " -testExceptions" )
testClient.dbgCommand( ".reload /f; bp targetapp!doExeptions" ) targetMod = testClient.loadModule( "targetapp" )
bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting") )
bpIdHwExecute = testClient.setBp( targetMod.offset("readValueForAccessTesting"),
1,
pykd.DEBUG_BREAK_EXECUTE )
bpIdHwWrite = testClient.setBp( targetMod.offset("g_valueForAccessTesting1"),
1,
pykd.DEBUG_BREAK_WRITE )
bpIdHwRead = testClient.setBp( targetMod.offset("g_valueForAccessTesting2"),
1,
pykd.DEBUG_BREAK_READ )
self.assertEqual( 4, len( testClient.getAllBp() ) )
breakExceptionHandler = BreakExceptionHandler( testClient ) breakExceptionHandler = BreakExceptionHandler( testClient )
while not breakExceptionHandler.wasSecondChance: while not breakExceptionHandler.wasSecondChance:
@ -63,3 +80,11 @@ class EhExceptionBreakpointTest(unittest.TestCase):
self.assertEqual( 2, breakExceptionHandler.bpCount ) # main and doExeptions self.assertEqual( 2, breakExceptionHandler.bpCount ) # main and doExeptions
self.assertEqual( [3, ], breakExceptionHandler.secondChanceAccessAddresses ) self.assertEqual( [3, ], breakExceptionHandler.secondChanceAccessAddresses )
self.assertTrue( bpIdSoftware in breakExceptionHandler.wasBreakpointIds )
testClient.removeBp(bpIdHwRead)
self.assertEqual( 3, len( testClient.getAllBp() ) )
testClient.removeBp()
self.assertEqual( 0, len( testClient.getAllBp() ) )

View File

@ -343,10 +343,34 @@ int doLoadUnload()
return 0; return 0;
} }
////////////////////////////////////////////////////////////////////////////////
int g_valueForAccessTesting1 = 4;
int g_valueForAccessTesting2 = 5;
////////////////////////////////////////////////////////////////////////////////
#pragma optimize("g", off)
void changeValueForAccessTesting()
{
g_valueForAccessTesting1 = 5;
}
////////////////////////////////////////////////////////////////////////////////
void readValueForAccessTesting()
{
std::cout << g_valueForAccessTesting1 << g_valueForAccessTesting2;
}
#pragma optimize("g", on)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int doExeptions() int doExeptions()
{ {
changeValueForAccessTesting();
readValueForAccessTesting();
__debugbreak(); __debugbreak();
PUCHAR _ptr = reinterpret_cast<UCHAR *>(2); PUCHAR _ptr = reinterpret_cast<UCHAR *>(2);