📄 kdbreak.c
字号:
ULONG Index;
BOOLEAN Accessible = FALSE;
BOOLEAN Mode16Bit = FALSE; // used for Thumb and MIPS16
BOOLEAN KAccessible = FALSE;
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
ULONG ulBpInstrLen = sizeof (KDP_BREAKPOINT_TYPE);
BOOL fBpSet = FALSE;
BOOL fAddrUnpaged = FALSE;
BOOL fKAddrUnpaged = FALSE;
BOOL fUpdateBPTable = FALSE;
BOOL fAttemptToWrite = FALSE;
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpAddBreakpoint (0x%08X)\r\n", Address));
#if defined(MIPSII) || defined(THUMBSUPPORT)
// update the breakpoint Instruction and ulBpInstrLen if stopped within
// 16-bit code. (16-bit code indicated by LSB of Address)
if (Is16BitSupported && ((ULONG) Address & 1))
{
DEBUGGERMSG (KDZONE_SWBP,(L" KdpAddBreakpoint: 16 Bit breakpoint\r\n"));
ulBpInstrLen = sizeof (KDP_BREAKPOINT_16BIT_TYPE);
KdpBreakpointInstruction = KDP_BREAKPOINT_16BIT_VALUE;
Address = (PVOID) ((ULONG) Address & ~1);
Mode16Bit = TRUE;
}
#endif
// If the specified address is not properly aligned, then return zero.
if ((ULONG) Address & (ulBpInstrLen - 1))
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpAddBreakpoint: Address not aligned\r\n"));
}
else
{
int bphFreeEntry = KD_BPHND_INVALID_GEN_ERR;
// Find an empty spot or identical entry in the table of BP
for (Index = 0; (Index < BREAKPOINT_TABLE_SIZE) && (bphRet == KD_BPHND_INVALID_GEN_ERR); Index++)
{
if ((bphFreeEntry == KD_BPHND_INVALID_GEN_ERR) && !(g_aBreakpointTable [Index].wRefCount))
{
bphFreeEntry = Index + 1; // remember 1st free entry
}
if (g_aBreakpointTable [Index].wRefCount &&
(g_aBreakpointTable [Index].Address == Address))
{
// Then we have a dup entry
DEBUGGERMSG (KDZONE_SWBP | KDZONE_ALERT, (L" KdpAddBreakpoint: Dup - Found existing BP (0x%08X) - should not happening if host-side aliasing / ref count! Risk of improper single steping!!!!\r\n", Address));
bphRet = Index + 1;
++(g_aBreakpointTable [Index].wRefCount);
}
}
if (bphRet == KD_BPHND_INVALID_GEN_ERR)
{ // if no dup, use free entry
bphRet = bphFreeEntry;
if (bphRet != KD_BPHND_INVALID_GEN_ERR)
{ // free entry available
int bphTemp;
// Create table entry
bphRet = bphFreeEntry;
g_aBreakpointTable [bphRet - 1].wRefCount = 1;
g_aBreakpointTable [bphRet - 1].Address = Address;
g_aBreakpointTable [bphRet - 1].Flags = KD_BREAKPOINT_SUSPENDED; // Reserve suspended until actually instantiated
if (Mode16Bit)
{
g_aBreakpointTable [bphRet - 1].Flags |= KD_BREAKPOINT_16BIT;
}
bphTemp = KdpInstantiateSwBreakpoint (bphRet);
if (bphRet != bphTemp)
{ // Instantiation will never be possible for this BP
g_aBreakpointTable [bphRet - 1].Flags = 0; // discard BP entry
g_aBreakpointTable [bphRet - 1].Content = 0;
g_aBreakpointTable [bphRet - 1].Address = NULL;
g_aBreakpointTable [bphRet - 1].wRefCount = 0;
bphRet = bphTemp;
}
else
{
g_nTotalNumDistinctSwCodeBps++;
}
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpAddBreakpoint: Maximum number of Breakpoints reach. Cannot handle this one\r\n"));
}
}
}
DEBUGGERMSG (KDZONE_SWBP, (L"--KdpAddBreakpoint: (handle = %i)\r\n", bphRet));
return bphRet;
}
/*++
Routine Description:
This routine deletes an entry from the breakpoint table.
Arguments:
[in] Handle - Supplies the index plus one of the breakpoint table entry
which is to be deleted.
Return Value:
A value of FALSE is returned if the specified handle is not a valid
value or the breakpoint cannot be deleted because the old instruction
cannot be replaced. Otherwise, a value of TRUE is returned.
--*/
BOOLEAN KdpDeleteBreakpoint (ULONG Handle)
{
BOOLEAN fRet = FALSE;
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
ULONG ulBpInstrLen = sizeof (KDP_BREAKPOINT_TYPE);
ULONG Index = Handle - 1; // Handles are 1-based; 0 is an invalid handle value
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpDeleteBreakpoint Handle=%i\r\n", Handle));
// If the specified handle is not valid, then return FALSE.
if ((Index >= BREAKPOINT_TABLE_SIZE) ||
!(g_aBreakpointTable[Index].wRefCount))
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpDeleteBreakpoint: Invalid handle\r\n"));
}
else
{
--g_aBreakpointTable [Index].wRefCount;
if (!(g_aBreakpointTable [Index].wRefCount))
{ // ref count null: really delete BP
BYTE *pbBpKAddr = MapToDebuggeeCtxKernEquivIfAcc ((BYTE *) (g_aBreakpointTable [Index].Address), TRUE);
#if defined(MIPSII) || defined(THUMBSUPPORT)
// Determine the breakpoint instruction and size
if (Is16BitSupported && (g_aBreakpointTable[Index].Flags & KD_BREAKPOINT_16BIT))
{
ulBpInstrLen = sizeof (KDP_BREAKPOINT_16BIT_TYPE);
KdpBreakpointInstruction = KDP_BREAKPOINT_16BIT_VALUE;
}
#endif
// Kdstub does not know when page is paged out. If we did, we could
// sanitize it to have readonly mem in RAM behave similarily to
// readonly mem in ROM. This block assumes that the kaddr used to
// write the breakpoint is still valid.
if (!pbBpKAddr)
{
if (g_aBreakpointTable[Index].KAddr)
{
KDP_BREAKPOINT_TYPE Instruction = 0;
// Just in case there is an access violation on memmove.
__try
{
if (memmove (&Instruction, g_aBreakpointTable[Index].KAddr, ulBpInstrLen))
{
if (Instruction == KdpBreakpointInstruction) // If Breakpoint Found.
{
DEBUGGERMSG (KDZONE_SWBP,
(L" KdpDeleteBreakpoint: Found BP at kaddr(0x%08X) - Preemptively restoring instruction.\r\n",
g_aBreakpointTable[Index].KAddr));
pbBpKAddr = g_aBreakpointTable[Index].KAddr; // Mark it for cleaning.
}
else
DEBUGGERMSG (KDZONE_SWBP,
(L" KdpDeleteBreakpoint: No BP found at kaddr(0x%08X) - Not restoring instruction.\r\n",
g_aBreakpointTable[Index].KAddr));
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGGERMSG (KDZONE_SWBP,
(L" KdpDeleteBreakpoint: Unable to read kaddr(0x%08X) - Not restoring instruction.\r\n",
g_aBreakpointTable[Index].KAddr));
}
}
}
if (!pbBpKAddr) // Test accessibility (won't page-in)
{ // If the breakpoint is not instatiated, then just nullify the table entry, no need to copy anything
DEBUGGERMSG (KDZONE_SWBP, (L" KdpDeleteBreakpoint: Deleting entry for unpaged address (0x%08X)\r\n", g_aBreakpointTable[Index].Address));
fRet = TRUE;
}
else
{ // Otherwise, if the BP is actually set, then replace the old instruction and nullify the entry
fRet = KdpWriteBpAndVerify (pbBpKAddr, &g_aBreakpointTable [Index].Content, ulBpInstrLen);
if (!fRet)
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpDeleteBreakpoint: Could not write original instruction back for BP (%i) Addr=0x%08X, KAddr=0x%08X\r\n", Index, g_aBreakpointTable[Index].Address, pbBpKAddr));
}
}
if (g_aBreakpointTable [Index].Flags & KD_BREAKPOINT_INROM)
{ // If BP was in ROM, cleanup remapping to RAM
KdpCleanupIfRomSwBp (g_aBreakpointTable[Index].Address);
}
// Delete breakpoint table entry and return TRUE.
g_aBreakpointTable[Index].Flags = 0;
g_aBreakpointTable[Index].Content = 0;
g_aBreakpointTable[Index].Address = NULL;
g_aBreakpointTable[Index].KAddr = NULL;
if (g_nTotalNumDistinctSwCodeBps) g_nTotalNumDistinctSwCodeBps--;
}
else if (!(g_aBreakpointTable[Index].Flags & KD_BREAKPOINT_WRITTEN))
{
// Breakpoint was never written. This should never happen.
DEBUGGERMSG (KDZONE_SWBP | KDZONE_ALERT, (L" KdpDeleteBreakpoint: Deleting entry for unwritten breakpoint @(0x%08X)\r\n", g_aBreakpointTable[Index].Address));
fRet = TRUE;
}
else
{
DEBUGGERMSG (KDZONE_SWBP | KDZONE_ALERT, (L" KdpDeleteBreakpoint: Dup - Removing multi-ref BP @(0x%08X) - should not happening if host-side aliasing / ref count! Risk of improper single steping!!!!\r\n", g_aBreakpointTable[Index].Address));
fRet = TRUE;
}
}
DEBUGGERMSG (KDZONE_SWBP, (L"--KdpDeleteBreakpoint (%d)\r\n", (int) fRet));
return fRet;
}
/*++
Routine Description:
Call KdpDeleteBreakpoint on every breakpoint handle and ignore the result. If all
goes well, this should remove all breakpoints in the system and allow it to
execute normally.
--*/
VOID KdpDeleteAllBreakpoints (VOID)
{
ULONG i;
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpDeleteAllBreakpoints\r\n"));
// handles are 1-based
for (i = 1; g_nTotalNumDistinctSwCodeBps && (i <= BREAKPOINT_TABLE_SIZE); i++)
{
if (g_aBreakpointTable [i - 1].wRefCount) KdpDeleteBreakpoint (i);
}
memset (g_aBreakpointTable, 0, sizeof (g_aBreakpointTable)); // clean up (necessary for 1st time init)
DEBUGGERMSG(KDZONE_SWBP, (L"--KdpDeleteAllBreakpoints\r\n"));
}
/*++
Routine Description:
Suspend the specified breakpoint by restoring its instruction
Arguments:
Index - index of the breakpoint to suspend (NOTE: NOT THE HANDLE)
Return Value:
TRUE - the breakpoint was suspended
FALSE - otherwise
--*/
BOOLEAN KdpSuspendBreakpoint (ULONG Index)
{
BOOLEAN fRet = FALSE;
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
ULONG ulBpInstrLen = sizeof (KDP_BREAKPOINT_TYPE);
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpSuspendBreakpoint (handle=%i)\r\n", Index + 1));
// Determine the breakpoint instruction and size
#if defined(MIPSII) || defined(THUMBSUPPORT)
if (Is16BitSupported && (g_aBreakpointTable[Index].Flags & KD_BREAKPOINT_16BIT))
{
ulBpInstrLen = sizeof(KDP_BREAKPOINT_16BIT_TYPE);
KdpBreakpointInstruction = KDP_BREAKPOINT_16BIT_VALUE;
}
#endif
// Replace the instruction contents.
if (g_aBreakpointTable [Index].wRefCount &&
!(g_aBreakpointTable [Index].Flags & KD_BREAKPOINT_SUSPENDED))
{
BYTE *pbBpKAddr = MapToDebuggeeCtxKernEquivIfAcc ((BYTE *) (g_aBreakpointTable [Index].Address), TRUE);
if (pbBpKAddr)
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpSuspendBreakpoint: Suspending BP 0x%08X\r\n", g_aBreakpointTable[Index].Address));
fRet = KdpWriteBpAndVerify (pbBpKAddr, &g_aBreakpointTable [Index].Content, ulBpInstrLen);
if (!fRet)
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpSuspendBreakpoint: Suspend failed!\r\n"));
}
}
else
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpSuspendBreakpoint: BP at 0x%08X not mapped!\r\n", g_aBreakpointTable[Index].Address));
}
g_aBreakpointTable [Index].Flags |= KD_BREAKPOINT_SUSPENDED; // Tag suspended in all cases (in not writable, the SW trap instr is virtually removed)
}
DEBUGGERMSG(KDZONE_SWBP, (L"--KdpSuspendBreakpoint (%d)\r\n", (int) fRet));
return fRet;
}
/*++
Routine Description:
Suspend all breakpoints that are currently in use and not already suspened.
--*/
VOID KdpSuspendAllBreakpoints (VOID)
{
ULONG Index;
DEBUGGERMSG(KDZONE_SWBP, (L"++KdpSuspendAllBreakpoints\r\n"));
// Examine each entry in the table in turn
for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index++)
{
// Make sure breakpoint is in use and not already suspended
if (g_aBreakpointTable [Index].wRefCount &&
!(g_aBreakpointTable [Index].Flags & KD_BREAKPOINT_SUSPENDED))
{
KdpSuspendBreakpoint (Index);
}
}
DEBUGGERMSG (KDZONE_SWBP, (L"--KdpSuspendAllBreakpoints\r\n"));
}
/*++
Routine Description:
Reinstate any breakpoints that were suspended. This function should be called before exitting KdpTrap.
--*/
VOID KdpReinstateSuspendedBreakpoints (VOID)
{
int Index;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -