mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1346 lines
30 KiB
1346 lines
30 KiB
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
SetFile()
|
|
|
|
|
|
BREAKPOINT masterBP = {0L,0L};
|
|
PBREAKPOINT bpList = &masterBP;
|
|
|
|
extern HTHDX thdList;
|
|
extern CRITICAL_SECTION csThreadProcList;
|
|
|
|
|
|
PBREAKPOINT
|
|
GetNewBp(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
BPTP BpType,
|
|
BPNS BpNotify,
|
|
ADDR *AddrBp,
|
|
HPID id,
|
|
PBREAKPOINT BpUse
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a BREAKPOINT structure and initializes it. Note that
|
|
this does NOT add the structure to the breakpoint list (bplist).
|
|
If it is not an address bp (i.e. it is a watchpoint), the hwalk
|
|
field must be initialized later.
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies process to put BP in
|
|
|
|
hthd - Supplies optional thread
|
|
|
|
AddrBp - Supplies address structure for the breakpoint
|
|
|
|
id - Supplies EM id for BP
|
|
|
|
BpUse - Supplies other BP on same address (so we can steal the
|
|
original code from it instead of reading).
|
|
This last one is optional.
|
|
|
|
Return Value:
|
|
|
|
PBREAKPOINT - Pointer to allocated and initialized structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PBREAKPOINT Bp;
|
|
ADDR Addr;
|
|
DWORD i;
|
|
|
|
assert( !BpUse || ( BpUse->hthd != hthd ) );
|
|
|
|
Bp = (PBREAKPOINT)malloc(sizeof(BREAKPOINT));
|
|
assert( Bp );
|
|
|
|
if ( Bp ) {
|
|
|
|
assert( bpList );
|
|
|
|
Bp->next = NULL;
|
|
Bp->hprc = hprc;
|
|
Bp->hthd = hthd;
|
|
Bp->id = id;
|
|
Bp->instances = 1;
|
|
Bp->isStep = FALSE;
|
|
Bp->hBreakPoint = 0;
|
|
Bp->bpType = BpType;
|
|
Bp->bpNotify = BpNotify;
|
|
Bp->hWalk = NULL;
|
|
memset(&Bp->addr, 0, sizeof(Bp->addr));
|
|
|
|
//
|
|
// Get the opcode from the indicated address
|
|
//
|
|
|
|
if ( BpUse ) {
|
|
|
|
Bp->instr1 = BpUse->instr1;
|
|
|
|
} else if (AddrBp) {
|
|
|
|
Bp->instr1 = 0;
|
|
Addr = *AddrBp;
|
|
|
|
Bp->addr = *AddrBp;
|
|
|
|
//
|
|
// Check to make sure that what we have is not a linker index
|
|
// number in the address structure. If it is then we can not
|
|
// currently set this breakpoint due to the fact that we
|
|
// don't have a real address
|
|
//
|
|
|
|
if ( ADDR_IS_LI(Addr) ) {
|
|
|
|
assert(!"Addr is LI");
|
|
free( Bp );
|
|
Bp = NULL;
|
|
|
|
}
|
|
else if (!AddrReadMemory(hprc, hthd, &Addr, &(Bp->instr1), BP_SIZE,
|
|
&i) ||
|
|
(i != BP_SIZE)) {
|
|
|
|
#ifdef KERNEL
|
|
Bp->instr1 = 0;
|
|
#else
|
|
assert(!"AddrReadMemory failed");
|
|
free(Bp);
|
|
Bp = NULL;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
return Bp;
|
|
}
|
|
|
|
|
|
|
|
PBREAKPOINT
|
|
SetBP(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
BPTP bptype,
|
|
BPNS bpnotify,
|
|
LPADDR paddr,
|
|
HPID id
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set a breakpoint, or increment instance count on an existing bp.
|
|
if hthd is non-NULL, BP is only for that thread.
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies process to put BP in
|
|
|
|
hthd - Supplies optional thread
|
|
|
|
bptype - Supplies OSDEBUG BP type
|
|
|
|
paddr - Supplies address structure for the breakpoint
|
|
|
|
id - Supplies EM id for BP
|
|
|
|
Return Value:
|
|
|
|
pointer to bp structure, or NULL for failure
|
|
|
|
--*/
|
|
{
|
|
PBREAKPOINT pbp;
|
|
PBREAKPOINT pbpT;
|
|
ADDR addr;
|
|
ADDR addr2;
|
|
|
|
if (!hprc) {
|
|
return (PBREAKPOINT)NULL;
|
|
}
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
/*
|
|
* First let's try to find a breakpoint that
|
|
* matches this description
|
|
*/
|
|
|
|
pbpT = FindBP(hprc, hthd, bptype, bpnotify, paddr, FALSE);
|
|
|
|
/*
|
|
* If this thread has a breakpoint here,
|
|
* increment reference count.
|
|
*/
|
|
|
|
if (pbpT && pbpT->hthd == hthd) {
|
|
|
|
pbp = pbpT;
|
|
pbp->instances++;
|
|
|
|
} else if ( pbp = GetNewBp( hprc, hthd, bptype, bpnotify, paddr, id, pbpT )) {
|
|
|
|
if ( !pbpT ) {
|
|
|
|
//
|
|
// Now write the cpu-specific breakpoint code.
|
|
//
|
|
|
|
assert(!ADDR_IS_LI(pbp->addr));
|
|
|
|
if ( WriteBreakPoint(pbp) ) {
|
|
AddBpToList(pbp);
|
|
} else {
|
|
free( pbp );
|
|
pbp = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Breakpoint exists, but for wrong thread.
|
|
//
|
|
|
|
*pbp = *pbpT;
|
|
|
|
pbp->hthd = hthd;
|
|
pbp->instances = 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Make it a linear address to start with
|
|
*/
|
|
|
|
addr2 = *paddr;
|
|
TranslateAddress(hprc, hthd, &addr2, TRUE);
|
|
|
|
/*
|
|
* Check with the threads to see if we are at this address. If so then
|
|
* we need to set the BP field so we don't hit the bp imeadiately
|
|
*/
|
|
|
|
if (hthd) {
|
|
AddrFromHthdx(&addr, hthd);
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &addr, &addr2)) {
|
|
SetBPFlag(hthd, pbp);
|
|
}
|
|
} else {
|
|
for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
|
|
AddrFromHthdx(&addr, hthd);
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &addr, &addr2)) {
|
|
SetBPFlag(hthd, pbp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return pbp;
|
|
} /* SetBP() */
|
|
|
|
|
|
#ifdef KERNEL
|
|
|
|
|
|
BOOL
|
|
SetBPEx(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
HPID id,
|
|
DWORD Count,
|
|
ADDR *Addrs,
|
|
PBREAKPOINT *Bps,
|
|
DWORD ContinueStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a bunch of breakpoints from a given list of linear offsets.
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies process to put BP in
|
|
|
|
hthd - Supplies optional thread
|
|
|
|
Count - Supplies count of breakpoints to set
|
|
|
|
Addrs - Supplies list with Count addresses
|
|
|
|
Bps - Supplies buffer to be filled with Count pointers to
|
|
BREAKPOINT structures. Original contents is
|
|
overwritten.
|
|
|
|
ContinueStatus -
|
|
|
|
Return Value:
|
|
|
|
BOOL - If TRUE, then ALL breakpoints were set.
|
|
If FALSE, then NONE of the breakpoints were set.
|
|
|
|
|
|
NOTENOTE - Not sure of what will happen if the list contains duplicated
|
|
addresses!
|
|
|
|
--*/
|
|
|
|
{
|
|
PDBGKD_WRITE_BREAKPOINT DbgKdBp;
|
|
PDBGKD_RESTORE_BREAKPOINT DbgKdBpRes;
|
|
DWORD SetCount = 0;
|
|
DWORD NewCount = 0;
|
|
DWORD i;
|
|
DWORD j;
|
|
PBREAKPOINT BpT;
|
|
BOOL Ok;
|
|
ADDR Addr;
|
|
ADDR Addr2;
|
|
|
|
if (!hprc) {
|
|
assert(!"hprc == NULL is SetBPEx");
|
|
return FALSE;
|
|
}
|
|
|
|
assert( Count > 0 );
|
|
assert( Addrs );
|
|
assert( Bps );
|
|
|
|
if ( Count == 1 ) {
|
|
//
|
|
// Only one breakpoint, faster to simply call SetBP
|
|
//
|
|
Bps[0] = SetBP( hprc, hthd, bptpExec, bpnsStop, &Addrs[0], id );
|
|
return ( Bps[0] != NULL );
|
|
}
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
AddrInit( &Addr, 0, 0, 0, TRUE, TRUE, FALSE, FALSE );
|
|
|
|
//
|
|
// Allocate space for Count breakpoints
|
|
//
|
|
DbgKdBp = (PDBGKD_WRITE_BREAKPOINT)
|
|
malloc( sizeof(DBGKD_WRITE_BREAKPOINT) * Count );
|
|
assert( DbgKdBp );
|
|
|
|
if ( !DbgKdBp ) {
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
return FALSE;
|
|
}
|
|
|
|
for ( i=0; i<Count; i++ ) {
|
|
|
|
//
|
|
// See if we already have a breakpoint at this address.
|
|
//
|
|
Bps[i] = FindBP( hprc, hthd, bptpExec, bpnsStop, &Addrs[i], FALSE );
|
|
|
|
if ( !Bps[i] ) {
|
|
|
|
DbgKdBp[ NewCount ].BreakPointAddress =
|
|
(PVOID)GetAddrOff(Addrs[i]);
|
|
DbgKdBp[ NewCount++ ].BreakPointHandle = (ULONG)NULL;
|
|
Bps[i] = GetNewBp( hprc, hthd, bptpExec, bpnsStop, &Addrs[i], id, NULL );
|
|
assert( Bps[i] );
|
|
|
|
} else if (Bps[i]->hthd != hthd ) {
|
|
|
|
BpT = Bps[i];
|
|
Bps[i] = GetNewBp( hprc, hthd, bptpExec, bpnsStop, &Addrs[i], id, NULL );
|
|
|
|
// BUGBUG kentf should instances be changed?
|
|
|
|
*Bps[i] = *BpT;
|
|
Bps[i]->hthd = hthd;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
Ok = TRUE;
|
|
if ( NewCount > 0 ) {
|
|
|
|
//
|
|
// Set all new breakpoints
|
|
//
|
|
assert( NewCount <= Count );
|
|
Ok = WriteBreakPointEx( hthd, NewCount, DbgKdBp, ContinueStatus );
|
|
}
|
|
|
|
if ( Ok ) {
|
|
//
|
|
// Fill in the breakpoint list
|
|
//
|
|
j = 0;
|
|
for ( i=0; i<Count; i++ ) {
|
|
|
|
if ( Bps[i] && Bps[i]->hBreakPoint && Bps[i]->hthd == hthd ) {
|
|
//
|
|
// Will reuse BP, just increment reference count.
|
|
//
|
|
Bps[i]->instances++;
|
|
|
|
} else {
|
|
|
|
assert( (PVOID)GetAddrOff(Addrs[i]) ==
|
|
DbgKdBp[j].BreakPointAddress );
|
|
//
|
|
// Allocate new BP structure and get handle from
|
|
// the breakpoint packet. Note that we rely on the
|
|
// order of the breakpoints in the breakpoint packet.
|
|
//
|
|
Bps[i]->hBreakPoint = DbgKdBp[j].BreakPointHandle;
|
|
AddBpToList(Bps[i]);
|
|
j++;
|
|
}
|
|
|
|
SetCount++;
|
|
|
|
//
|
|
// Check with the threads to see if we are at this address.
|
|
// If so then we need to set the BP field so we don't hit
|
|
// the bp imeadiately
|
|
//
|
|
|
|
Addr2 = Bps[i]->addr;
|
|
|
|
if ( hthd ) {
|
|
AddrFromHthdx( &Addr, hthd );
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &Addr, &Addr2 )) {
|
|
SetBPFlag(hthd, Bps[i]);
|
|
}
|
|
} else {
|
|
for (hthd=hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
|
|
AddrFromHthdx( &Addr, hthd );
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &Addr, &Addr2)) {
|
|
SetBPFlag(hthd, Bps[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
assert( j == NewCount );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Clean up any breakpoints that were set.
|
|
//
|
|
DbgKdBpRes = (PDBGKD_RESTORE_BREAKPOINT)
|
|
malloc( sizeof(DBGKD_RESTORE_BREAKPOINT) * NewCount );
|
|
assert( DbgKdBpRes );
|
|
|
|
if ( DbgKdBpRes ) {
|
|
|
|
//
|
|
// Put all breakpoints with a valid handle on the list of
|
|
// breakpoints to be removed.
|
|
//
|
|
j = 0;
|
|
for ( i=0; i<NewCount;i++) {
|
|
if ( DbgKdBp[i].BreakPointHandle != (ULONG)NULL ) {
|
|
DbgKdBpRes[j++].BreakPointHandle =
|
|
DbgKdBp[i].BreakPointHandle;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now remove them
|
|
//
|
|
if ( j > 0 ) {
|
|
assert( j <= NewCount );
|
|
RestoreBreakPointEx( j, DbgKdBpRes );
|
|
}
|
|
|
|
free( DbgKdBpRes );
|
|
|
|
//
|
|
// Remove allocated BP structures
|
|
//
|
|
for ( i=0; i<Count; i++ ) {
|
|
if ( Bps[i] && !Bps[i]->hBreakPoint ) {
|
|
assert( !Bps[i]->next );
|
|
free( Bps[i] );
|
|
Bps[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free( DbgKdBp );
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return (SetCount == Count);
|
|
}
|
|
|
|
|
|
#else // KERNEL
|
|
|
|
BOOL
|
|
SetBPEx(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
HPID id,
|
|
DWORD Count,
|
|
ADDR *Addrs,
|
|
PBREAKPOINT *Bps,
|
|
DWORD ContinueStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a bunch of breakpoints from a given list of linear offsets.
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies process to put BP in
|
|
|
|
hthd - Supplies optional thread
|
|
|
|
Count - Supplies count of breakpoints to set
|
|
|
|
Addrs - Supplies list with Count addresses
|
|
|
|
Bps - Supplies buffer to be filled with Count pointers to
|
|
BREAKPOINT structures. Original contents is
|
|
overwritten.
|
|
|
|
ContinueStatus -
|
|
|
|
Return Value:
|
|
|
|
BOOL - If TRUE, then ALL breakpoints were set.
|
|
If FALSE, then NONE of the breakpoints were set.
|
|
|
|
|
|
NOTENOTE - Not sure of what will happen if the list contains duplicated
|
|
addresses!
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD SetCount = 0;
|
|
DWORD NewCount = 0;
|
|
DWORD i;
|
|
DWORD j;
|
|
DWORD k;
|
|
ADDR Addr;
|
|
ADDR Addr2;
|
|
BP_UNIT opcode = BP_OPCODE;
|
|
|
|
if (!hprc) {
|
|
assert(!"hprc == NULL in SetBPEx");
|
|
return FALSE;
|
|
}
|
|
|
|
assert( Count > 0 );
|
|
assert( Addrs );
|
|
assert( Bps );
|
|
|
|
if ( Count == 1 ) {
|
|
//
|
|
// Only one breakpoint, faster to simply call SetBP
|
|
//
|
|
Bps[0] = SetBP( hprc, hthd, bptpExec, bpnsStop, &Addrs[0], id );
|
|
return ( Bps[0] != NULL );
|
|
}
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
for ( i=0; i<Count; i++ ) {
|
|
|
|
//
|
|
// See if we already have a breakpoint at this address.
|
|
//
|
|
Bps[i] = FindBP( hprc, hthd, bptpExec, bpnsStop, &Addrs[i], FALSE );
|
|
|
|
if ( Bps[i] && Bps[i]->hthd == hthd ) {
|
|
|
|
//
|
|
// Reuse this breakpoint
|
|
//
|
|
|
|
Bps[i]->instances++;
|
|
assert( Bps[i]->instances > 1 );
|
|
|
|
} else {
|
|
//
|
|
// Get new breakpoint
|
|
//
|
|
Bps[i] = GetNewBp(hprc, hthd, bptpExec, bpnsStop, &Addrs[i], id, NULL);
|
|
if ( !Bps[i] ) {
|
|
|
|
assert(!"GetNewBp failed in SetBPEx");
|
|
break;
|
|
}
|
|
if ( !ADDR_IS_LI(Bps[i]->addr) ) {
|
|
if ( !AddrWriteMemory(hprc, hthd, &Bps[i]->addr,
|
|
(LPBYTE) &opcode, BP_SIZE, &j) ) {
|
|
|
|
free( Bps[i] );
|
|
Bps[i] = NULL;
|
|
assert(!"DbgWriteMemory failed in SetBPEx");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( i < Count ) {
|
|
//
|
|
// Something went wrong, will backtrack
|
|
//
|
|
|
|
assert(!"i < Count in SetBPEx");
|
|
|
|
for ( j=0; j<i; j++ ) {
|
|
|
|
assert( Bps[j] );
|
|
Bps[j]->instances--;
|
|
if ( Bps[j]->instances == 0 ) {
|
|
|
|
if ( !ADDR_IS_LI(Bps[j]->addr) ) {
|
|
AddrWriteMemory(hprc, hthd, &Bps[j]->addr,
|
|
(LPBYTE) &Bps[j]->instr1, BP_SIZE, &k);
|
|
}
|
|
free( Bps[j] );
|
|
Bps[j] = NULL;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Add all the new breakpoints to the list
|
|
//
|
|
for ( i=0; i<Count; i++ ) {
|
|
|
|
if ( Bps[i]->instances == 1 ) {
|
|
AddBpToList(Bps[i]);
|
|
}
|
|
|
|
//
|
|
// Check with the threads to see if we are at this address. If so then
|
|
// we need to set the BP field so we don't hit the bp imeadiately
|
|
//
|
|
|
|
Addr2 = Bps[i]->addr;
|
|
|
|
if ( hthd ) {
|
|
AddrFromHthdx( &Addr, hthd );
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &Addr, &Addr2 )) {
|
|
SetBPFlag(hthd, Bps[i]);
|
|
}
|
|
} else {
|
|
for (hthd=hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
|
|
AddrFromHthdx( &Addr, hthd );
|
|
if ((hthd->tstate & ts_stopped) &&
|
|
(AtBP(hthd) == NULL) &&
|
|
AreAddrsEqual(hprc, hthd, &Addr, &Addr2)) {
|
|
SetBPFlag(hthd, Bps[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetCount = Count;
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return (SetCount == Count);
|
|
}
|
|
|
|
#endif // KERNEL
|
|
|
|
BOOL
|
|
BPInRange(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
PBREAKPOINT bp,
|
|
LPADDR paddrStart,
|
|
DWORD cb,
|
|
LPDWORD offset,
|
|
BP_UNIT * instr
|
|
)
|
|
{
|
|
ADDR addr1;
|
|
ADDR addr2;
|
|
|
|
/*
|
|
* If the breakpoint has a Loader index address then we can not
|
|
* possibly match it
|
|
*/
|
|
|
|
assert (!ADDR_IS_LI(*paddrStart) );
|
|
if (ADDR_IS_LI(bp->addr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
*offset = 0;
|
|
|
|
/*
|
|
* Now check for "equality" of the addresses.
|
|
*
|
|
* Need to include size of BP in the address range check. Since
|
|
* the address may start half way through a breakpoint.
|
|
*/
|
|
|
|
if ((ADDR_IS_FLAT(*paddrStart) == TRUE) &&
|
|
(ADDR_IS_FLAT(bp->addr) == TRUE)) {
|
|
if ((GetAddrOff(*paddrStart) - sizeof(BP_UNIT) + 1 <=
|
|
GetAddrOff(bp->addr)) &&
|
|
(GetAddrOff(bp->addr) < GetAddrOff(*paddrStart) + cb)) {
|
|
|
|
*offset = (DWORD) GetAddrOff(bp->addr) -
|
|
(DWORD) GetAddrOff(*paddrStart);
|
|
*instr = bp->instr1;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* The two addresses did not start out as flat addresses. So change
|
|
* them to linear addresses so that we can see if the addresses are
|
|
* are really the same
|
|
*/
|
|
|
|
addr1 = *paddrStart;
|
|
if (!TranslateAddress(hprc, hthd, &addr1, TRUE)) {
|
|
return FALSE;
|
|
}
|
|
addr2 = bp->addr;
|
|
if (!TranslateAddress(hprc, hthd, &addr2, TRUE)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((GetAddrOff(addr1) - sizeof(BP_UNIT) + 1 <= GetAddrOff(addr2)) &&
|
|
(GetAddrOff(addr2) < GetAddrOff(addr1) + cb)) {
|
|
*offset = (DWORD) GetAddrOff(addr2) - (DWORD) GetAddrOff(addr1);
|
|
*instr = bp->instr1;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
PBREAKPOINT
|
|
FindBP(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
BPTP bptype,
|
|
BPNS bpnotify,
|
|
LPADDR paddr,
|
|
BOOL fExact
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find and return a pointer to a BP struct. Always returns a BP that
|
|
matches hthd thread if one exists; if fExact is FALSE and there is no
|
|
exact match, a BP matching only hprc and address will succeed.
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies process
|
|
|
|
hthd - Supplies thread
|
|
|
|
bptype - Supplies OSDEBUG BP type
|
|
|
|
paddr - Supplies address
|
|
|
|
fExact - Supplies TRUE if must be for a certain thread
|
|
|
|
Return Value:
|
|
|
|
pointer to BREAKPOINT struct, or NULL if not found.
|
|
|
|
--*/
|
|
{
|
|
PBREAKPOINT pbp;
|
|
PBREAKPOINT pbpFound = NULL;
|
|
ADDR addr;
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
/*
|
|
* Pre-translate the address to a linear address
|
|
*/
|
|
|
|
addr = *paddr;
|
|
TranslateAddress(hprc, hthd, &addr, TRUE);
|
|
|
|
/*
|
|
* Check for an equivalent breakpoint. Breakpoints will be equal if
|
|
*
|
|
* 1. The process is the same
|
|
* 2. The addresses of the breakpoints are the same
|
|
*/
|
|
|
|
for (pbp=bpList->next; pbp; pbp=pbp->next) {
|
|
if ((pbp->hprc == hprc) &&
|
|
AreAddrsEqual(hprc, hthd, &pbp->addr, &addr)) {
|
|
pbpFound = pbp;
|
|
if (pbp->hthd == hthd) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
if (!fExact || (pbpFound && pbpFound->hthd == hthd)) {
|
|
return pbpFound;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
} /* FindBP() */
|
|
|
|
|
|
|
|
|
|
PBREAKPOINT
|
|
BPNextHprcPbp(
|
|
HPRCX hprc,
|
|
PBREAKPOINT pbp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the next breakpoint for the given process after pbp.
|
|
If pbp is NULL start at the front of the list, for a find
|
|
first, find next behaviour.
|
|
|
|
|
|
Arguments:
|
|
|
|
hprc - Supplies the process handle to match breakpoints for
|
|
|
|
pbp - Supplies pointer to breakpoint item to start searching after
|
|
|
|
Return Value:
|
|
|
|
NULL if no matching breakpoint is found else a pointer to the
|
|
matching breakpoint
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&csThreadProcList);
|
|
if (pbp == NULL) {
|
|
pbp = bpList->next;
|
|
} else {
|
|
pbp = pbp->next;
|
|
}
|
|
|
|
for ( ; pbp; pbp = pbp->next ) {
|
|
if (pbp->hprc == hprc) {
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return pbp;
|
|
} /* BPNextHprcPbp() */
|
|
|
|
|
|
PBREAKPOINT
|
|
BPNextHthdPbp(
|
|
HTHDX hthd,
|
|
PBREAKPOINT pbp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the next breakpoint for the given thread after pbp.
|
|
If pbp is NULL start at the front of the list for find
|
|
first, find next behaviour.
|
|
|
|
Arguments:
|
|
|
|
hthd - Supplies the thread handle to match breakpoints for
|
|
pbp - Supplies pointer to breakpoint item to start searching after
|
|
|
|
Return Value:
|
|
|
|
NULL if no matching breakpoint is found else a pointer to the
|
|
matching breakpoint
|
|
|
|
--*/
|
|
|
|
{
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
if (pbp == NULL) {
|
|
pbp = bpList->next;
|
|
} else {
|
|
pbp = pbp->next;
|
|
}
|
|
|
|
for ( ; pbp; pbp = pbp->next ) {
|
|
if (pbp->hthd == hthd) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return pbp;
|
|
} /* BPNextHthdPbp() */
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
RemoveBPHelper(
|
|
PBREAKPOINT pbp,
|
|
BOOL fRestore
|
|
)
|
|
{
|
|
PBREAKPOINT pbpPrev;
|
|
PBREAKPOINT pbpCur;
|
|
PBREAKPOINT pbpT;
|
|
HTHDX hthd;
|
|
BOOL rVal = FALSE;
|
|
|
|
|
|
//
|
|
// first, is it real?
|
|
//
|
|
if (!pbp || pbp == EMBEDDED_BP) {
|
|
return FALSE;
|
|
}
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
/* Decrement the instances counter */
|
|
if (--pbp->instances) {
|
|
|
|
/*
|
|
* BUGBUG: jimsch -- Feb 29 1993
|
|
* This piece of code is most likely incorrect. We need to
|
|
* know if we are the DM freeing a breakpoint or the user
|
|
* freeing a breakpoint before we clear the step bit. Otherwise
|
|
* we may be in the following situation
|
|
*
|
|
* Set a thread specific breakpoint on an address
|
|
* Step the thread so that the address is the destination is
|
|
* where the step ends up (but it takes some time such
|
|
* as over a function call)
|
|
* Clear the thread specific breakpoint
|
|
*
|
|
* This will cause the step breakpoint to be cleared so we will
|
|
* stop at the address instead of just continuing stepping.
|
|
*/
|
|
|
|
pbp->isStep = FALSE;
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Search the list for the specified breakpoint */
|
|
|
|
|
|
for ( pbpPrev = bpList, pbpCur = bpList->next;
|
|
pbpCur;
|
|
pbpPrev = pbpCur, pbpCur = pbpCur->next) {
|
|
|
|
if (pbpCur == pbp) {
|
|
|
|
/*
|
|
* Remove this bp from the list:
|
|
*/
|
|
|
|
pbpPrev->next = pbpCur->next;
|
|
|
|
/*
|
|
* see if there is another bp on the same address:
|
|
*/
|
|
|
|
pbpT = FindBP(pbpCur->hprc,
|
|
pbpCur->hthd,
|
|
pbpCur->bpType,
|
|
pbpCur->bpNotify,
|
|
&pbpCur->addr,
|
|
FALSE);
|
|
|
|
if (!pbpT && pbpCur->bpType == bptpExec) {
|
|
/*
|
|
* if this was the only one, put the
|
|
* opcode back where it belongs.
|
|
*/
|
|
|
|
if ( fRestore ) {
|
|
RestoreBreakPoint( pbpCur );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now we have to go through all the threads to see
|
|
* if any of them are on this breakpoint and clear
|
|
* the breakpoint indicator on these threads
|
|
*/
|
|
|
|
/*
|
|
* Could be on any thread:
|
|
*/
|
|
|
|
/*
|
|
* (We are already in the ThreadProcList critical section)
|
|
*/
|
|
|
|
for (hthd = thdList->next; hthd; hthd = hthd->next) {
|
|
if (hthd->atBP == pbpCur) {
|
|
hthd->atBP = pbpT;
|
|
}
|
|
}
|
|
|
|
free(pbpCur);
|
|
rVal = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return rVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
RemoveBP(
|
|
PBREAKPOINT pbp
|
|
)
|
|
{
|
|
return RemoveBPHelper( pbp, TRUE );
|
|
}
|
|
|
|
#ifdef KERNEL
|
|
|
|
BOOL
|
|
RemoveBPEx(
|
|
DWORD Count,
|
|
PBREAKPOINT *Bps
|
|
)
|
|
{
|
|
|
|
PDBGKD_RESTORE_BREAKPOINT DbgKdBp;
|
|
DWORD RestoreCount = 0;
|
|
DWORD GoneCount = 0;
|
|
DWORD i;
|
|
PBREAKPOINT BpCur;
|
|
PBREAKPOINT BpOther;
|
|
|
|
assert( Count > 0 );
|
|
|
|
if ( Count == 1 ) {
|
|
//
|
|
// Only one breakpoint, its faster to simply call RemoveBP
|
|
//
|
|
return RemoveBP( Bps[0] );
|
|
}
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
DbgKdBp = (PDBGKD_RESTORE_BREAKPOINT)malloc( sizeof(DBGKD_RESTORE_BREAKPOINT) * Count );
|
|
assert( DbgKdBp );
|
|
|
|
if ( DbgKdBp ) {
|
|
|
|
//
|
|
// Find out what breakpoints we have to restore and put them in
|
|
// the list.
|
|
//
|
|
for ( i=0; i<Count;i++ ) {
|
|
|
|
assert( Bps[i] != EMBEDDED_BP );
|
|
|
|
for ( BpCur = bpList->next; BpCur; BpCur = BpCur->next) {
|
|
|
|
if ( BpCur == Bps[i] ) {
|
|
|
|
//
|
|
// See if there is another bp on the same address.
|
|
//
|
|
for ( BpOther = bpList->next; BpOther; BpOther = BpOther->next ) {
|
|
if ( (BpOther != BpCur) &&
|
|
AreAddrsEqual( BpCur->hprc, BpCur->hthd, &BpCur->addr, &BpOther->addr ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !BpOther ) {
|
|
//
|
|
// If this was the only one, put it in the list.
|
|
//
|
|
DbgKdBp[GoneCount++].BreakPointHandle = Bps[i]->hBreakPoint;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore the breakpoints in the list.
|
|
//
|
|
if ( GoneCount > 0 ) {
|
|
assert( GoneCount <= Count );
|
|
RestoreBreakPointEx( GoneCount, DbgKdBp );
|
|
}
|
|
|
|
//
|
|
// All breakpoints that were to be restored have been
|
|
// restored, now go ahead and do the cleaning up stuff.
|
|
//
|
|
for ( i=0; i<Count;i++ ) {
|
|
RemoveBPHelper( Bps[i], FALSE );
|
|
RestoreCount++;
|
|
}
|
|
|
|
free( DbgKdBp );
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return ( RestoreCount == Count );
|
|
}
|
|
|
|
#else // KERNEL
|
|
|
|
BOOL
|
|
RemoveBPEx(
|
|
DWORD Count,
|
|
PBREAKPOINT *Bps
|
|
)
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
assert( Count > 0 );
|
|
|
|
for ( i=0; i<Count;i++ ) {
|
|
RemoveBPHelper( Bps[i], TRUE );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif // KERNEL
|
|
|
|
|
|
void
|
|
SetBPFlag(
|
|
HTHDX hthd,
|
|
PBREAKPOINT bp
|
|
)
|
|
{
|
|
hthd->atBP = bp;
|
|
}
|
|
|
|
|
|
|
|
PBREAKPOINT
|
|
AtBP(
|
|
HTHDX hthd
|
|
)
|
|
{
|
|
return hthd->atBP;
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
ClearBPFlag(
|
|
HTHDX hthd
|
|
)
|
|
{
|
|
hthd->atBP = NULL;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
RestoreInstrBP(
|
|
HTHDX hthd,
|
|
PBREAKPOINT bp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Replace the instruction for a breakpoint. If it was not
|
|
the debugger's BP, skip the IP past it.
|
|
|
|
Arguments:
|
|
|
|
hthd - Thread
|
|
|
|
bp - breakpoint data
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Check if this is an embedded breakpoint
|
|
//
|
|
|
|
if (bp == EMBEDDED_BP) {
|
|
|
|
//
|
|
// It was, so there is no instruction to restore,
|
|
// just increment the EIP
|
|
//
|
|
|
|
IncrementIP(hthd);
|
|
return;
|
|
}
|
|
|
|
if (bp->hWalk) {
|
|
|
|
//
|
|
// This is really a hardware breakpoint. Let the
|
|
// walk manager fix this.
|
|
//
|
|
|
|
ExprBPClearBPForStep(hthd);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Replace the breakpoint current in memory with the correct
|
|
// instruction
|
|
//
|
|
|
|
RestoreBreakPoint( bp );
|
|
bp->hBreakPoint = 0;
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteAllBps(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PBREAKPOINT pbp, bpn;
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
pbp = bpList->next;
|
|
|
|
while (pbp) {
|
|
bpn = pbp->next;
|
|
if (bpn) {
|
|
free( pbp );
|
|
}
|
|
pbp = bpn;
|
|
}
|
|
|
|
bpList->next = NULL;
|
|
bpList->hprc = NULL;
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
}
|
|
|
|
void
|
|
AddBpToList(
|
|
PBREAKPOINT pbp
|
|
)
|
|
{
|
|
assert(bpList);
|
|
EnterCriticalSection(&csThreadProcList);
|
|
pbp->next = bpList->next;
|
|
bpList->next = pbp;
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
}
|
|
|
|
PBREAKPOINT
|
|
FindBpForWalk(
|
|
PVOID pWalk
|
|
)
|
|
{
|
|
PBREAKPOINT pbp;
|
|
|
|
EnterCriticalSection(&csThreadProcList);
|
|
|
|
pbp = bpList;
|
|
while (pbp) {
|
|
if (IsWalkInGroup(pbp->hWalk, pWalk)) {
|
|
break;
|
|
}
|
|
pbp = pbp->next;
|
|
}
|
|
|
|
LeaveCriticalSection(&csThreadProcList);
|
|
|
|
return pbp;
|
|
}
|
|
|
|
PBREAKPOINT
|
|
SetWP(
|
|
HPRCX hprc,
|
|
HTHDX hthd,
|
|
BPTP bptype,
|
|
BPNS bpnotify,
|
|
ADDR addr
|
|
)
|
|
{
|
|
return (PBREAKPOINT)0;
|
|
}
|
|
|