📄 kdbreak.c
字号:
Routine Description:
This routine intanciate (replace original instruction with software trap)
on a given breakpoint table entry.
Arguments:
[in] BpHandle - Supplies the BpHandle to instanciate
Return Value:
Same value as BpHandle if succeeded
0 or negative value if failed
--*/
int KdpInstantiateSwBreakpoint (int BpHandle)
{
int bphRet = BpHandle;
DWORD Index = BpHandle - 1;
BOOL fAccessible = FALSE;
void * Address = NULL;
ULONG ulBpInstrLen = sizeof (KDP_BREAKPOINT_TYPE);
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpInstantiateSwBreakpoint (%d)\r\n", BpHandle));
if ((Index < BREAKPOINT_TABLE_SIZE) &&
g_aBreakpointTable [Index].wRefCount &&
(g_aBreakpointTable [Index].Flags & KD_BREAKPOINT_SUSPENDED))
{ // Check that entry is good
BYTE *pbBpKAddr;
Address = g_aBreakpointTable [Index].Address;
g_aBreakpointTable[Index].KAddr = NULL;
pbBpKAddr = MapToDebuggeeCtxKernEquivIfAcc ((BYTE *) Address, TRUE); // Kernel equivalent if this address is paged-in (do not force page-in)
if (pbBpKAddr)
{ // Memory is paged
#if defined(MIPSII) || defined(THUMBSUPPORT)
if (g_aBreakpointTable [Index].Flags & KD_BREAKPOINT_16BIT)
{
ulBpInstrLen = sizeof (KDP_BREAKPOINT_16BIT_TYPE);
KdpBreakpointInstruction = KDP_BREAKPOINT_16BIT_VALUE;
}
#endif
/* Save the KAddr for the scenario in which the debugger is unable to find the
* KAddr during delete (module pages decommitted/lost before attempt to delete
* breakpoint). */
g_aBreakpointTable[Index].KAddr = pbBpKAddr;
// Get the instruction to be replaced
if (KdpMoveMemory ((char *) &Content, pbBpKAddr, ulBpInstrLen ) != ulBpInstrLen)
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpInstantiateSwBreakpoint: Cannot read access apparently paged KAddress (0x%08X)\r\n", pbBpKAddr));
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Successfully reading BP location\r\n"));
fAccessible = TRUE;
KdpSanitize ((BYTE *) &Content, pbBpKAddr, ulBpInstrLen, FALSE);
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Successfully read 0x%08X at 0x%08X\r\n", (DWORD) Content, pbBpKAddr));
}
if (fAccessible)
{
BOOL fBpSet = FALSE;
BOOL fRomBp = FALSE;
// determine whether the address is in ROM space
if (kdpIsROM (pbBpKAddr, 1))
{
fRomBp = TRUE;
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Breakpoint is reported in ROM\r\n"));
}
else
{
fBpSet = KdpWriteBpAndVerify (pbBpKAddr, &KdpBreakpointInstruction, ulBpInstrLen);
if (!fBpSet)
{ // the write failed
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Breakpoint could not be set - assume it is a ROM BP\r\n"));
fRomBp = TRUE;
}
}
if (fRomBp && *(g_kdKernData.pfForcedPaging))
{ // if BP in ROM and we are in High VM intrusiveness mode
int bphRomRet;
int idxRom2Ram = 0;
void* pvBpRamAddr;
DEBUGGERMSG (KDZONE_SWBP, (TEXT(" KdpInstantiateSwBreakpoint: Address is in ROM space\r\n")));
bphRomRet = KdpRomSwBpAttemptRamPageRemap (Address, pbBpKAddr, &idxRom2Ram, &pvBpRamAddr);
if (bphRomRet != KD_BPHND_ROMBP_SUCCESS)
{
// If we failed, there is no point doing anything else,
// so just leave returning the ROM BP error
bphRet = bphRomRet;
}
else
{ // Try again
fBpSet = KdpWriteBpAndVerify (pvBpRamAddr, &KdpBreakpointInstruction, ulBpInstrLen);
if (!fBpSet)
{ // the write failed again
bphRet = KD_BPHND_INVALID_GEN_ERR;
DEBUGGERMSG (KDZONE_ALERT, (TEXT(" KdpInstantiateSwBreakpoint: Failed to write in remapped ROM!\r\n")));
// fail to instanciate ROM BP, revert mapping
KdpRestoreRomVmPageMapping (idxRom2Ram);
}
}
}
if (fBpSet)
{ // The BP was written
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Updating BP entry\r\n"));
g_aBreakpointTable [Index].Content = Content;
g_aBreakpointTable [Index].Flags &= ~KD_BREAKPOINT_SUSPENDED;
g_aBreakpointTable[Index].Flags |= KD_BREAKPOINT_WRITTEN;
// Check if the address is in ROM and increment the use count.
// We need to do this even if fRomBp == FALSE, since
// a ROM page may already be remapped to RAM.
fRomBp = KdpIncCountIfRomSwBp(Address);
if (fRomBp)
{
g_aBreakpointTable [Index].Flags |= KD_BREAKPOINT_INROM;
}
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: BP cannot set (probably ROM BP in kernel code or ROM BP while in non-intrusive mode)!\r\n"));
if (bphRet > KD_BPHND_INVALID_GEN_ERR) bphRet = KD_BPHND_INVALID_GEN_ERR;
}
}
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpInstantiateSwBreakpoint: Unpaged address\r\n"));
}
}
else
{
DEBUGGERMSG (KDZONE_ALERT, (L" KdpInstantiateSwBreakpoint: invalid BP entry\r\n"));
}
DEBUGGERMSG (KDZONE_SWBP, (L"--KdpInstantiateSwBreakpoint (bph=%i)\r\n", bphRet));
return bphRet;
}
/*++
Routine Name:
KdpHandlePageInBreakpoints
Routine Description:
This routine is called in response to the OS having performed a page in.
The function will determine whether any breakpoints need to be set in the
address range of the recently paged-in page and will attempt to instantiate
those breakpoints by calling into KdpAddBreakpoint.
ASSUMPTIONS:
-XIP ROM code is never paged in or out
-We get multiple notifications in case of multiple VM mappings of the same code.
This is not the case for virtually copied data but we are going to assume that
users will never put code in virtually copied pages themselves. In that unlikely case,
the breakpoints will simply have potential side effects in case of page out / back in.
Arguments:
[in] ulAddress - supplies the starting address of the page just paged in
[in] ulNumPages - The number of pages that were paged in. This is added to make
module load / process load of non-pageable modules / processes faster.
Return Value:
None.
--*/
VOID KdpHandlePageInBreakpoints (ULONG ulAddress, ULONG ulNumPages)
{
int cBp = 0; // Counter of BP tested to speed up iteration
int nIndex;
ULONG ulStartAddress = ulAddress;
ULONG ulEndAddress = ulStartAddress + (ulNumPages * PAGE_SIZE);
DEBUGGERMSG (KDZONE_VIRTMEM && KDZONE_SWBP, (L"++KdpHandlePageInBreakpoints (0x%08X - 0x%08X, %d)\r\n", ulStartAddress, ulEndAddress, ulNumPages));
// Search the global table to see if there are any addresses within
// the page that was just paged in that were supposed
// to have BP's instantiated. This includes addresses that had trap
// instructions in them, but were paged out, and those that were
// not paged in until now and never had a BP written to them. Attempt
// to write BP's to all addresses within the page that fullfil those
// requirements.
// NOTE: Don't try to debug this code using KdStub itself as it will likely modify the BP table
// in order to step
for (nIndex = 0;
(cBp < g_nTotalNumDistinctSwCodeBps) && (nIndex < BREAKPOINT_TABLE_SIZE);
nIndex++)
{
BYTE bFlagsTemp = g_aBreakpointTable [nIndex].Flags;
if (g_aBreakpointTable [nIndex].wRefCount)
{
ULONG ulAddrTemp = (ULONG) g_aBreakpointTable [nIndex].Address;
cBp++; // Note: even suspended BP are counted here as they are part of the g_nTotalNumDistinctSwCodeBps
if (!(kdpKData->dwInDebugger && (bFlagsTemp & KD_BREAKPOINT_SUSPENDED)) &&
(ulAddrTemp >= ulStartAddress) &&
(ulAddrTemp < ulEndAddress))
{ // Any BP in range, except if suspended while in debugger:
ULONG ulBpInstrLen = sizeof (KDP_BREAKPOINT_TYPE);
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
#if defined(MIPSII) || defined(THUMBSUPPORT)
if (bFlagsTemp & KD_BREAKPOINT_16BIT)
{
ulBpInstrLen = sizeof (KDP_BREAKPOINT_16BIT_TYPE);
KdpBreakpointInstruction = KDP_BREAKPOINT_16BIT_VALUE;
}
#endif
ReadBack = 0;
if (ulBpInstrLen != KdpMoveMemory ((char *) &ReadBack, (char *) ulAddrTemp, ulBpInstrLen))
{
DEBUGGERMSG (KDZONE_VIRTMEM && KDZONE_SWBP, (L" KdpHandlePageInBreakpoints: Failed to read instruction of BP\r\n"));
}
else
{
BOOL fIsBpInstr = !memcmp (&ReadBack, &KdpBreakpointInstruction, ulBpInstrLen);
if (fIsBpInstr)
{ // SW Breakpoint instruction already present - Re-instantiation not necessary - Probably new mapping (VirtualCopy) notification only
DEBUGGERMSG (KDZONE_SWBP, (L" KdpHandlePageInBreakpoints: existing instruction already a SW breakpoint - this must be a VirtualCopy PageIn notification - bypassing BP instantiation\r\n"));
}
else
{ // should be reinstantiated
DEBUGGERMSG (KDZONE_VIRTMEM && KDZONE_SWBP, (L" KdpHandlePageInBreakpoints: Found address (0x%08X) within page range(0x%08X - 0x%08X) with flag %02X\r\n", ulAddrTemp, ulStartAddress, ulEndAddress, bFlagsTemp));
g_aBreakpointTable [nIndex].Flags |= KD_BREAKPOINT_SUSPENDED; // tag as suspended until actual instantiation succeeds
KdpInstantiateSwBreakpoint (nIndex + 1); // Attempt instanciations
}
}
}
}
}
// If we are in break state while this notification happens, then tell the host debugger to refresh its memory
if ((kdpKData->dwInDebugger) && !(*(g_kdKernData.pfForcedPaging))) g_fDbgKdStateMemoryChanged = TRUE; // Note: will only be passed on next reply to debugger command
DEBUGGERMSG (KDZONE_VIRTMEM && KDZONE_SWBP, (L"--KdpHandlePageInBreakpoints\r\n"));
}
/*++
Routine Name:
KdpCleanupIfRomSwBp
Routine Description:
This routine is usually called when a breakpoint has sucessfully
been removed from the argument address. It determines whether the
argument address is within the range of any of the used pre-allocated
RAM pages, and if so decrements the breakpoint use count variable
for that page. If the count is zero (since that was the last breakpoint)
then the page is remapped to point to the orginal ROM page address and
the RAM page is marked as free.
Arguments:
[in] pvAddr - supplies the address where a breakpoint was just removed from
Return Value:
TRUE if BP was in ROM.
--*/
BOOL KdpCleanupIfRomSwBp (void * pvAddr)
{
int nIndex = 0;
DWORD dwROMAddrTemp = 0;
DWORD dwAddr = (DWORD) pvAddr;
BOOL fRet = FALSE;
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("++KdpCleanupIfRomSwBp (0x%08X)\r\n"), dwAddr));
for (nIndex = 0; (nIndex < NB_ROM2RAM_PAGES) && !fRet; nIndex++)
{
dwROMAddrTemp = (DWORD) (g_aRom2RamPageTable[nIndex].pvROMAddr);
// Check if the address of the breakpoint just deleted
// falls in any of our preallocated/remapped ROM/RAM pages
if ((dwAddr >= dwROMAddrTemp) && (dwAddr < dwROMAddrTemp + PAGE_SIZE))
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpCleanupIfRomSwBp: Address found in page %d between (0x%08X) and (0x%08X)\r\n"), nIndex, dwROMAddrTemp, dwROMAddrTemp+PAGE_SIZE));
fRet = TRUE;
// Decrement the breakpoint use count for that page
g_aRom2RamPageTable[nIndex].nBPCount--;
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpCleanupIfRomSwBp: Page %d Count decremented to %d\r\n"), nIndex, g_aRom2RamPageTable[nIndex].nBPCount));
// If that pages count variable is zero, we better remap the VA that used
// to point to ROM, back to ROM (since it was changed to point to the RAM
// page until now) - mark the page as free
if (!g_aRom2RamPageTable[nIndex].nBPCount)
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT(" KdpCleanupIfRomSwBp: Count is 0, freeing page\r\n")));
if (!KdpRestoreRomVmPageMapping (nIndex))
{
DEBUGGERMSG (KDZONE_ALERT, (TEXT(" KdpCleanupIfRomSwBp: ROM to RAM unmap failed! System may become unstable\r\n")));
// If remapping failed, there's not much we can do
}
}
}
}
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("--KdpCleanupIfRomSwBp (found=%d)\r\n"),fRet));
return fRet;
}
/*++
Routine Description:
This routine adds an entry to the breakpoint table and returns a handle
to the breakpoint table entry.
Arguments:
[in] Address - Supplies the address where to set the breakpoint.
Return Value:
A value of zero is returned if the specified address is already in the
breakpoint table, there are no free entries in the breakpoint table, the
specified address is not correctly aligned, or the specified address is
not valid. Otherwise, the index of the assigned breakpoint table entry
plus one is returned as the function value.
--*/
ULONG KdpAddBreakpoint (PVOID Address)
{
int bphRet = KD_BPHND_INVALID_GEN_ERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -