Windows2000/private/windbg64/debugger/dm/bp.c
2020-09-30 17:12:32 +02:00

1466 lines
37 KiB
C

#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 - (optional) Supplies other BP on same address (so we can steal the original code from it instead of reading).
Return Value:
PBREAKPOINT - Pointer to allocated and initialized structure.
--*/
{
PBREAKPOINT Bp;
DWORD i;
assert(!BpUse || (BpUse->hthd != hthd) || (BpUse->bpNotify != BpNotify));
Bp = (PBREAKPOINT)MHAlloc(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;
#if defined(TARGET_IA64)
Bp->flags = 1;
#endif
memset(&Bp->addr, 0, sizeof(Bp->addr));
// Get the opcode from the indicated address
if (AddrBp) {
assert(!ADDR_IS_LI(*AddrBp));
if (ADDR_IS_LI(*AddrBp)) {
MHFree(Bp);
Bp = NULL;
} else {
Bp->instr1 = 0;
Bp->addr = *AddrBp;
if (BpUse) {
Bp->instr1 = BpUse->instr1;
} else if (!AddrReadMemory(hprc, hthd, AddrBp, &(Bp->instr1), BP_SIZE, &i) || (i != BP_SIZE)) {
#ifdef KERNEL
Bp->instr1 = 0;
#else
assert(!"AddrReadMemory failed");
MHFree(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
bpnotify - Supplies OSDEBUG notification code
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 && pbpT->bpNotify == bpnotify) {
pbp = pbpT;
pbp->instances++;
} else if (pbp = GetNewBp(hprc, hthd, bptype, bpnotify, paddr, id, pbpT)) {
if (pbpT) {
AddBpToList(pbp); // if already a bp at that addr, just add to list
} else {
// Now write the cpu-specific breakpoint code.
if (WriteBreakPoint(pbp)) {
AddBpToList(pbp);
} else {
MHFree(pbp);
pbp = NULL;
}
}
/*
* 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 are
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_BREAKPOINT64 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_BREAKPOINT64)MHAlloc(sizeof(DBGKD_WRITE_BREAKPOINT64) * 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.
BpT = FindBP(hprc, hthd, bptpExec, bpnsStop, &Addrs[i], FALSE);
if (BpT && BpT->hthd == hthd && BpT->bpNotify == bpnsStop) {
// exact match: just bump the instance count
Bps[i] = BpT;
Bps[i]->instances++;
} else if (BpT) {
// address matched: keep the old BP handle, make a new record
Bps[i] = GetNewBp(hprc, hthd, bptpExec, bpnsStop, &Addrs[i], id, NULL);
Bps[i]->hBreakPoint = BpT->hBreakPoint;
} else {
// no match: need a new BP
Bps[i] = GetNewBp(hprc, hthd, bptpExec, bpnsStop, &Addrs[i], id, NULL);
assert(Bps[i]);
// set instance to 0 to indicate it is unset
Bps[i]->instances = 0;
DbgKdBp[NewCount].BreakPointAddress = GetAddrOff(Addrs[i]);
DbgKdBp[NewCount].BreakPointHandle = 0;
// keep BP packet index in handle field until BP is set
Bps[i]->hBreakPoint = NewCount++;
}
}
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
for (i = 0; i < Count; i++) {
if (Bps[i] && Bps[i]->instances == 0) {
j = Bps[i]->hBreakPoint;
assert(GetAddrOff(Addrs[i]) == DbgKdBp[j].BreakPointAddress);
// Allocate new BP structure and get handle from
// the breakpoint packet.
Bps[i]->hBreakPoint = DbgKdBp[j].BreakPointHandle;
Bps[i]->instances = 1;
AddBpToList(Bps[i]);
}
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)MHAlloc(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 != 0) {
DbgKdBpRes[j++].BreakPointHandle = DbgKdBp[i].BreakPointHandle;
}
}
// Now remove them
if (j > 0) {
assert(j <= NewCount);
RestoreBreakPointEx(j, DbgKdBpRes);
}
MHFree(DbgKdBpRes);
// Remove allocated BP structures
for (i = 0; i < Count; i++) {
if (Bps[i] && Bps[i]->instances == 0) {
assert(!Bps[i]->next);
MHFree(Bps[i]);
Bps[i] = NULL;
}
}
}
}
MHFree(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 cbBytes;
ADDR Addr;
ADDR Addr2;
PBREAKPOINT BpT;
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.
BpT = FindBP(hprc, hthd, bptpExec, bpnsStop, &Addrs[i], FALSE);
if (BpT && BpT->hthd == hthd && BpT->bpNotify == bpnsStop) {
// 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, BpT);
if (!Bps[i]) {
assert(!"GetNewBp failed in SetBPEx");
break;
}
if (!BpT) {
if (!WriteBreakPoint(Bps[i])) {
MHFree(Bps[i]);
Bps[i] = NULL;
assert(!"WriteBreakPoint 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)) {
#if defined(TARGET_IA64)
BP_UNIT Content;
ADDR BundleAddr;
// Read in memory since adjancent instructions in the same bundle may have
// been modified after we save them. Restore only the content of the slot which has
// the break instruction inserted.
AddrReadMemory(hprc, hthd, &Bps[j]->addr, (LPBYTE)&Content, BP_SIZE, &cbBytes);
switch (GetAddrOff(Bps[j]->addr) & 0xf) {
case 0:
Content = (Content & ~(INST_SLOT0_MASK)) | (Bps[j]->instr1 & INST_SLOT0_MASK);
break;
case 4:
Content = (Content & ~(INST_SLOT1_MASK)) | (Bps[j]->instr1 & INST_SLOT1_MASK);
break;
case 8:
Content = (Content & ~(INST_SLOT2_MASK)) | (Bps[j]->instr1 & INST_SLOT2_MASK);
break;
default:
break;
}
AddrWriteMemory(hprc, hthd, &Bps[j]->addr, (LPBYTE)&Content, BP_SIZE, &cbBytes);
// restore template to MLI if displaced instruction was MOVL
if (Bps[j]->flags & BREAKPOINT_IA64_MOVL) {
GetAddrOff(BundleAddr) = GetAddrOff(Bps[j]->addr) & ~0xf;
AddrReadMemory(hprc, hthd, &BundleAddr, (LPBYTE)&Content, BP_SIZE, &cbBytes);
Content &= ~((INST_TEMPL_MASK >> 1) << 1); // set template to MLI
Content |= 0x4;
AddrWriteMemory(hprc, hthd, &BundleAddr, (LPBYTE)&Content, BP_SIZE, &cbBytes);
}
#else
AddrWriteMemory(hprc, hthd, &Bps[j]->addr,
(LPBYTE)&Bps[j]->instr1, BP_SIZE, &cbBytes);
#endif
}
MHFree(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 defined(TARGET_IA64)
// This is a bit different for IA64 because intraslot addresses
// are "quasi" addresses
if (
// we have a match if the BP start within the read memory range
((GetAddrOff(bp->addr) >= GetAddrOff(*paddrStart)) &&
(GetAddrOff(bp->addr) < GetAddrOff(*paddrStart) + cb)) ||
// or we have a match if the range starts within the BP itself -
// notice - the length of BP is 4, not sizeof(BP_UNIT) which is 8
((GetAddrOff(*paddrStart) >= GetAddrOff(bp->addr)) &&
(GetAddrOff(*paddrStart) < GetAddrOff(bp->addr) + 4))
) {
#else
if ((GetAddrOff(*paddrStart) - sizeof(BP_UNIT) + 1 <=
GetAddrOff(bp->addr)) &&
(GetAddrOff(bp->addr) < GetAddrOff(*paddrStart) + cb)) {
#endif
*offset = (DWORD)(GetAddrOff(bp->addr) - 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 defined(TARGET_IA64) //same as above
if (
((GetAddrOff(addr2) >= GetAddrOff(addr1)) &&
(GetAddrOff(addr2) < GetAddrOff(addr1) + cb)) ||
((GetAddrOff(addr1) >= GetAddrOff(addr2)) &&
(GetAddrOff(addr1) < GetAddrOff(addr2) + 4))
) {
#else
if ((GetAddrOff(addr1) - sizeof(BP_UNIT) + 1 <= GetAddrOff(addr2)) &&
(GetAddrOff(addr2) < GetAddrOff(addr1) + cb)) {
#endif
*offset = (DWORD)(GetAddrOff(addr2) - GetAddrOff(addr1));
*instr = bp->instr1;
return TRUE;
}
return FALSE;
}
BOOL
BPPriorityIsGreater(
BPNS n1,
BPNS n2
)
{
if (n1 == bpnsStop) {
return (n2 == bpnsContinue) || (n2 == bpnsCheck);
} else if (n1 == bpnsCheck) {
return (n2 == bpnsContinue);
} else {
return FALSE;
}
}
#if 0
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.
This is called for the following cases:
1) A breakpoint has been hit, and we want to find a BP record for it.
In this case, we want to see the highest priority match, with
preference to the correct thread.
Call with bpnotify == -1, hthd == xxxx, fExact == FALSE
2) We want to step off/through a BP. Any match will do, we just need
the instruction.
Call with bpnotify == -1, hthd == 0, fExact == FALSE
3) We want to delete a BP. Everything must match exactly. (It would
be better to do this directly by the pointer to the BP, but the
shells do not support this properly.)
Call with bpnotify == bpnsXXXX, hthd == xxxx, fExact == TRUE
(N.B. hthd may be NULL, which means "any thread")
Always returns a BP that matches hthd and bpnotify 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
bpnotify -
paddr - Supplies address
fExact - Supplies TRUE if must be for a certain thread
Return Value:
pointer to BREAKPOINT struct, or NULL if none 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 must be the same
// 2. The BP type must be the same
// 3. a) if it is an exec BP the addresses must match
// b) if not, MatchWalk is called
// 4. The thread and notify types must match if fExact is specified
for (pbp = bpList->next; pbp; pbp = pbp->next) {
if ((pbp->hprc == hprc) && (bptype == pbp->bpType)) {
if (bptype == bptpExec && AreAddrsEqual(hprc, hthd, &pbp->addr, &addr)) {
// if it matches exactly, take it now.
// if not, take it if it is better than the
// previous partial match
if (hthd == pbp->hthd && bpnotify == pbp->bpNotify) {
pbpFound = pbp;
break;
}
if (!pbpFound) {
// any match is better than none
pbpFound = pbp;
} else if (pbp->hthd == NULL || pbp->hthd == hthd) {
// this thread matches:
// is it better than the one we had?
if (hthd != pbpFound->hthd) {
pbpFound = pbp;
} else if (bpnotify == pbp->bpNotify && bpnotify != pbpFound->bpNotify) {
pbpFound = pbp;
} else if ((bpnotify == (BPNS)-1) &&
BPPriorityIsGreater(pbp->bpNotify, pbpFound->bpNotify)) {
pbpFound = pbp;
}
}
}
}
}
LeaveCriticalSection(&csThreadProcList);
if (!fExact || (
pbpFound &&
(pbpFound->hthd == hthd) &&
(pbpFound->bpNotify == bpnotify))) {
return pbpFound;
} else {
return NULL;
}
} /* FindBP() */
#endif
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.
This is called for the following cases:
1) A breakpoint has been hit, and we want to find a BP record for it.
In this case, we want to see the highest priority match, with
preference to the correct thread.
Call with bpnotify == -1, hthd == xxxx, fExact == FALSE
2) We want to step off/through a BP. Any match will do, we just need
the instruction.
Call with bpnotify == -1, hthd == 0, fExact == FALSE
3) We want to delete a BP. Everything must match exactly. (It would
be better to do this directly by the pointer to the BP, but the
shells do not support this properly.)
Call with bpnotify == bpnsXXXX, hthd == xxxx, fExact == TRUE
(N.B. hthd may be NULL, which means "any thread")
Always returns a BP that matches hthd and bpnotify 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
bpnotify -
paddr - Supplies address
fExact - Supplies TRUE if must be for a certain thread
Return Value:
pointer to BREAKPOINT struct, or NULL if none 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 must be the same
// 2. The BP type must be the same
// 3. a) if it is an exec BP the addresses must match
// b) if it is a message BP, the addresses must match
// c) other BP types are not supported at this time
// 4. The thread and notify types must match if fExact is specified
for (pbp = bpList->next; pbp; pbp = pbp->next) {
if ((pbp->hprc == hprc) && (bptype == pbp->bpType)) {
switch (bptype) {
case bptpMessage:
case bptpExec:
if (AreAddrsEqual(hprc, hthd, &pbp->addr, &addr)) {
// if it matches exactly, take it now.
// if not, take it if it is better than the
// previous partial match
if (hthd == pbp->hthd && bpnotify == pbp->bpNotify) {
pbpFound = pbp;
goto out_of_loop;
}
if (!pbpFound) {
// any match is better than none
pbpFound = pbp;
} else if (pbp->hthd == NULL || pbp->hthd == hthd) {
// this thread matches:
// is it better than the one we had?
if (hthd != pbpFound->hthd) {
pbpFound = pbp;
} else if (bpnotify == pbp->bpNotify &&
bpnotify != pbpFound->bpNotify) {
pbpFound = pbp;
} else if ((bpnotify == (BPNS)-1) &&
BPPriorityIsGreater(pbp->bpNotify,
pbpFound->bpNotify)
) {
pbpFound = pbp;
}
}
}
break;
default:
// At this time FindBP () only supports types Message and
// exec. Add your matching code this this switch stmt.
assert(FALSE);
}
}
}
out_of_loop:
LeaveCriticalSection(&csThreadProcList);
if (!fExact || (
pbpFound &&
(pbpFound->hthd == hthd) &&
(pbpFound->bpNotify == bpnotify))) {
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;
// pbpT will be used later to replace atBP
// in any thread which happens to be sitting
// on the BP which we are removing.
if (pbpCur->bpType != bptpExec && pbpCur->bpType != bptpMessage) {
pbpT = NULL;
} else {
// see if there is another bp on the same address:
pbpT = FindBP(pbpCur->hprc,
pbpCur->hthd,
pbpCur->bpType,
(BPNS)-1,
&pbpCur->addr,
FALSE);
if (!pbpT && (pbpCur->bpType == bptpExec ||
pbpCur->bpType == bptpMessage)) {
// if this was the only one, put the
// opcode back where it belongs.
if (fRestore) {
RestoreBreakPoint(pbpCur);
}
}
}
if (pbpCur->hWalk) {
RemoveWalk(pbpCur->hWalk, pbpCur->hthd == NULL);
}
// 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->nextGlobalThreadThisProbablyIsntTheOneYouWantedToUse;
hthd;
hthd = hthd->nextGlobalThreadThisProbablyIsntTheOneYouWantedToUse) {
if (hthd->atBP == pbpCur) {
hthd->atBP = pbpT;
}
}
MHFree(pbpCur);
rVal = TRUE;
break;
}
}
LeaveCriticalSection(&csThreadProcList);
return rVal;
}
BOOL
RemoveAllHprcBP(
HPRCX hprc
)
{
PBREAKPOINT pbp, pbpT;
for (pbp = BPNextHprcPbp(hprc, NULL); pbp; pbp = pbpT) {
BYTE count = pbp->instances;
pbpT = BPNextHprcPbp(hprc, pbp);
while (count--) {
RemoveBPHelper(pbp, TRUE);
}
}
// All bps for this process should be cleared.
assert(BPNextHprcPbp(hprc, NULL) == NULL);
return TRUE;
}
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)MHAlloc(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++;
}
MHFree(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)
{
PBREAKPOINT pbp, bpn;
EnterCriticalSection(&csThreadProcList);
pbp = bpList->next;
while (pbp) {
bpn = pbp->next;
if (bpn) {
MHFree(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
SetWP(
HPRCX hprc,
HTHDX hthd,
BPTP bptype,
BPNS bpnotify,
ADDR addr
)
{
return (PBREAKPOINT)0;
}