1466 lines
37 KiB
C
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;
|
||
|
}
|