📄 kdbreak.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
kdbreak.c
Abstract:
This module implements machine dependent functions to add and delete
breakpoints from the kernel debugger breakpoint table.
Revision History:
--*/
#include "kdp.h"
// The following variables are global for a reason. Do not move them to the stack or bad things happen
// when flushing instructions.
KDP_BREAKPOINT_TYPE Content;
KDP_BREAKPOINT_TYPE ReadBack;
static BREAKPOINT_ENTRY g_aBreakpointTable [BREAKPOINT_TABLE_SIZE];
// This int holds the total number of distinct SW Code breakpoints that are set or need to be set
int g_nTotalNumDistinctSwCodeBps;
BOOL KdpWriteBpAndVerify (void * pvAddress, void * pbData, ULONG nSize)
{
BOOL fRet = FALSE;
BOOL fMcRet = FALSE;
ULONG nRbSize;
ULONG nMmSize;
DEBUGGERMSG (KDZONE_SWBP, (L"++KdpWriteBpAndVerify (Addr=0x%08X, size=%d)\r\n", pvAddress, nSize));
ReadBack = 0;
nRbSize = KdpMoveMemory ((char *) &ReadBack, (char *) pvAddress, nSize);
DEBUGGERMSG (KDZONE_SWBP, (L" KdpWriteBpAndVerify: %s %d byte%s at 0x%08X, Data = 0x%0*X \r\n",
(nRbSize == nSize) ? L"Read " : L"Failed to read ", nSize,
(nRbSize == 1) ? L"" : L"s", pvAddress, nSize*2, ReadBack));
nMmSize = KdpMoveMemory ((char *) pvAddress, pbData, nSize);
DEBUGGERMSG (KDZONE_SWBP, (L" KdpWriteBpAndVerify: %s %d byte%s at 0x%08X, Data = 0x%0*X \r\n",
(nMmSize == nSize) ? L"Wrote" : L"Failed to write", nSize,
(nMmSize == 1) ? L"" : L"s", pvAddress, nSize*2 ,*((KDP_BREAKPOINT_TYPE *) pbData)));
ReadBack = 0;
nRbSize = KdpMoveMemory ((char *) &ReadBack, (char *) pvAddress, nSize);
if (nRbSize != nSize)
{
DEBUGGERMSG (KDZONE_SWBP, (L" KdpWriteBpAndVerify: Failed to read back %d byte%s at 0x%08X (read %d)\r\n",
nSize, (nMmSize == 1) ? L"" : L"s", nRbSize));
}
else
{
fMcRet = !memcmp (&ReadBack, pbData, nSize);
DEBUGGERMSG (KDZONE_SWBP, (L" KdpWriteBpAndVerify: Write%s was successful", fMcRet ? L"" : L" NOT"));
if (fMcRet)
{
DEBUGGERMSG (KDZONE_SWBP, (L" (read back OK)\r\n"));
fRet = TRUE;
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (L" (read back 0x%0*X instead of 0x%0*X)\r\n", nSize*2, ReadBack, nSize*2, *((KDP_BREAKPOINT_TYPE *) pbData)));
}
}
DEBUGGERMSG (KDZONE_SWBP, (L"--KdpWriteBpAndVerify (%d)\r\n", (int) fRet));
return fRet;
}
/*++
Routine Name:
KdpRomSwBpAttemptRamPageRemap
Routine Description:
This routine is called by the breakpoint addition routine when a breakpoint
add request is made in ROM address space. When this function exits, if it
has succeeded, the address can be used transparently by other functions -
breakpoints can be successfully added or removed at that address.
Basic algorithm:
This is equivalent to Copy-On-Write.
We have a certain number of pre-allocated RAM pages. The argument ROM virtual address
is within a ROM page. That ROM page will be copied to one of the free, pre-allocated
RAM pages. The section table will be remapped so that the VA that used to point to the
ROM page (that contained the argument address) now points to the RAM page. SW BP
(trap instructions) can then be safely set at that address, and excution of
code can carry on. If a RAM page consists of an address range that the argument
is within, then nothing needs to be done. Various error cases are handled and
returned to the caller, to be returned to PB. If this function fails, other functions
need not worry since no permanent changes would have been made. Also, a count variable
is maintained for each RAM page, and is incremented when a breakpoint is set in it,
and decremented when one is removed from within it. When the count variable is zero,
the ROM virtual address is remapped to its original ROM page address, and
the RAM page is marked as free (done by KdpRestoreRomVmPageMapping).
Arguments:
[in] pvRomAddr - supplies the ROM virtual address where a breakpoint needs to be set
[in] pvRomKAddr - supplies the ROM statically mapped kernel address equivalent where a breakpoint needs to be set
[out] pidxRomRamTbl - return index of Rom2Ram table entry just used for remapping if succeeded
Return Value:
Will return greater than 0 for success, or 0 or negative values for various error conditions
--*/
int KdpRomSwBpAttemptRamPageRemap (void * pvRomAddr, void * pvRomKAddr, int *pidxRomRamTbl, void **ppvRamAddr)
{
int nIndex = 0, nIndToBeUsed = 0, idxRomRamTbl = 0;
DWORD dwTempROMAddr = 0;
DWORD dwTempRAMAddr = 0;
DWORD dwRomAddr = (DWORD) pvRomAddr;
DWORD dwRamAddr = 0;
BOOL fAddrInRange = FALSE, fFreePageFound = FALSE;
int bphRet = KD_BPHND_INVALID_GEN_ERR;
int nBytesCopied = 0;
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("++KdpRomSwBpAttemptRamPageRemap (0x%08X)\r\n"), dwRomAddr));
// Try and find a RAM remap page that contains the range of addresses
// that the given address falls into OR find a free RAM remap page for it
for (nIndex = 0; (nIndex < NB_ROM2RAM_PAGES) && !fAddrInRange; nIndex++)
{
dwTempROMAddr = (DWORD) (g_aRom2RamPageTable[nIndex].pvROMAddr);
if (dwTempROMAddr)
{ // Used entry
if ((dwRomAddr >= dwTempROMAddr) &&
(dwRomAddr < dwTempROMAddr + PAGE_SIZE))
{ // Argument within range of one existing remaped page
fAddrInRange = TRUE;
nIndToBeUsed = nIndex;
}
}
else
{ // A free page available
if (!fFreePageFound)
{
fFreePageFound = TRUE;
nIndToBeUsed = nIndex;
}
}
}
if (fAddrInRange)
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpRomSwBpAttemptRamPageRemap: Address found in existing RAM page (%i)\r\n"), nIndToBeUsed));
idxRomRamTbl = nIndToBeUsed;
dwRamAddr = (DWORD) (g_aRom2RamPageTable[nIndToBeUsed].pbRAMAddr);
dwRamAddr += (dwRomAddr & (PAGE_SIZE - 1));
bphRet = KD_BPHND_ROMBP_SUCCESS;
}
else
{
if (!fFreePageFound)
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpRomSwBpAttemptRamPageRemap: Address not in range and no free pages!\r\n")));
bphRet = KD_BPHND_ROMBP_ERROR_INSUFFICIENT_PAGES;
}
else
{ // found a free page for the ROM address (and one page worth of code)
char* pbROMSource = (char *) (dwRomAddr & ~(PAGE_SIZE - 1)); // Get page start boundary
dwTempRAMAddr = (DWORD) (g_aRom2RamPageTable[nIndToBeUsed].pbRAMAddr);
if (dwTempRAMAddr & (PAGE_SIZE - 1))
{
DEBUGGERMSG (KDZONE_ALERT, (TEXT(" KdpRomSwBpAttemptRamPageRemap: ERROR: RAMPageAddr=0x%08X is not align on a page.\r\n"), dwTempRAMAddr));
}
else
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT(" KdpRomSwBpAttemptRamPageRemap: Use new page (%i), RAMPageAddr=0x%08X, ROMPageAddr=0x%08X\r\n"), nIndToBeUsed, dwTempRAMAddr, (DWORD) pbROMSource));
// Attempt the copy of the ROM page containing the argument to the free RAM page found
nBytesCopied = KdpMoveMemory ((char *) dwTempRAMAddr, (char *) pbROMSource, PAGE_SIZE);
if (nBytesCopied != PAGE_SIZE)
{
DEBUGGERMSG (KDZONE_ALERT, (TEXT(" KdpRomSwBpAttemptRamPageRemap: KdpMoveMemory failed, copied %d bytes\r\n"), nBytesCopied));
bphRet = KD_BPHND_ERROR_COPY_FAILED;
}
else
{
// Remap the addresses so that the ROM page boundary virtual address will now point to
// the RAM address (also the start of a page boundary)
if (!KdpRemapVirtualMemory ((void *) pbROMSource, (void *) dwTempRAMAddr, NULL))
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpRomSwBpAttemptRamPageRemap: KdpRemapVirtualMemory failed\r\n")));
bphRet = KD_BPHND_ROMBP_ERROR_REMAP_FAILED;
}
else
{
idxRomRamTbl = nIndToBeUsed;
// Save all pertinent info and return success, if we got to this point
g_aRom2RamPageTable[nIndToBeUsed].pvROMAddr = (void *) pbROMSource;
g_aRom2RamPageTable[nIndToBeUsed].pvROMAddrKern = (void *)(((DWORD)pvRomKAddr) & ~(PAGE_SIZE - 1)); // Save page start boundary
dwRamAddr = (DWORD) (g_aRom2RamPageTable[nIndToBeUsed].pbRAMAddr);
dwRamAddr += (dwRomAddr & (PAGE_SIZE - 1));
bphRet = KD_BPHND_ROMBP_SUCCESS;
DEBUGGERMSG(KDZONE_SWBP, (TEXT(" KdpRomSwBpAttemptRamPageRemap: ROM to RAM mapping Table updated\r\n")));
}
}
}
}
}
if (pidxRomRamTbl) *pidxRomRamTbl = idxRomRamTbl;
if (ppvRamAddr) *ppvRamAddr = (void *)dwRamAddr;
DEBUGGERMSG (KDZONE_SWBP, (TEXT("--KdpRomSwBpAttemptRamPageRemap bphRet=%i, idxRomRamTbl=%i, dwRamAddr=0x%08X\r\n"), bphRet, idxRomRamTbl, dwRamAddr));
return bphRet;
}
/*++
Routine Name:
KdpRestoreRomVmPageMapping
Routine Description:
This routine will attempt to restore the old page mapping that
existed between a copied ROM/RAM page and the original ROM
page, before it was remapped by KdpRomSwBpAttemptRamPageRemap.
Arguments:
[in] ulROMTbaleIndex - supplies the index into the ROMRAM page table
Return Value:
--*/
BOOL KdpRestoreRomVmPageMapping (ULONG ulROMBPTableIndex)
{
int nIndex = ulROMBPTableIndex;
BOOL fRet = FALSE;
DWORD dwFlags = 0;
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("++KdpRestoreRomVmPageMapping %d\r\n"), ulROMBPTableIndex));
// Bounds check
if (nIndex < NB_ROM2RAM_PAGES)
{
// Is the RAM page still in use?
if (g_aRom2RamPageTable[nIndex].nBPCount > 0)
{
DEBUGGERMSG(KDZONE_SWBP, (TEXT(" KdpRestoreRomVmPageMapping: Cannot free page %d, still in use\r\n"), nIndex));
fRet = TRUE;
}
else
{ // Page unused now, attempt the unmap
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpRestoreRomVmPageMapping: Remapping page %d from (0x%08X) back to (0x%8.8x)\r\n"), nIndex, (DWORD) (g_aRom2RamPageTable[nIndex].pbRAMAddr), (DWORD) (g_aRom2RamPageTable[nIndex].pvROMAddr)));
// Perform the remapping
dwFlags = PAGE_EXECUTE_READ;
if (!KdpRemapVirtualMemory (g_aRom2RamPageTable[nIndex].pvROMAddr, g_aRom2RamPageTable[nIndex].pvROMAddrKern, &dwFlags))
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT(" KdpRestoreRomVmPageMapping: Remap failed!\r\n")));
fRet = FALSE;
}
else
{
g_aRom2RamPageTable[nIndex].pvROMAddr = 0; // Mark the page as free
fRet = TRUE;
DEBUGGERMSG (KDZONE_SWBP, (TEXT(" KdpRestoreRomVmPageMapping: Page remapped and freed\r\n")));
}
}
}
else
{
DEBUGGERMSG(KDZONE_SWBP, (TEXT(" KdpRestoreRomVmPageMapping: Error, bad index (%d)\r\n"), nIndex));
}
DEBUGGERMSG (KDZONE_SWBP, (TEXT("--KdpRestoreRomVmPageMapping\r\n")));
return fRet;
}
/*++
Routine Name:
KdpIncCountIfRomSwBp
Routine Description:
This routine is usually called when a breakpoint has sucessfully
been written to 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 increment the breakpoint use count variable
for that page.
Arguments:
[in] pvAddr - supplies the address where a breakpoint was just written
Return Value:
TRUE if BP was in ROM.
--*/
BOOL KdpIncCountIfRomSwBp (void * pvAddr)
{
int nIndex = 0;
DWORD dwROMAddrTemp = 0;
DWORD dwAddr = (DWORD) pvAddr;
BOOL fRet = FALSE;
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("++KdpIncCountIfRomSwBp (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 added
// falls in any of our preallocated/remapped ROM/RAM pages
if ((dwAddr >= dwROMAddrTemp) && (dwAddr < dwROMAddrTemp + PAGE_SIZE))
{
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpIncCountIfRomSwBp: Address found in page %d between (0x%08X) and (0x%08X)\r\n"), nIndex, dwROMAddrTemp, dwROMAddrTemp+PAGE_SIZE));
fRet = TRUE;
// Increment the breakpoint use count for that page
g_aRom2RamPageTable[nIndex].nBPCount++;
DEBUGGERMSG (KDZONE_SWBP, (TEXT (" KdpIncCountIfRomSwBp: Page %d Count incremented to %d\r\n"), nIndex, g_aRom2RamPageTable[nIndex].nBPCount));
}
}
DEBUGGERMSG (KDZONE_SWBP, (TEXT ("--KdpIncCountIfRomSwBp (found=%d)\r\n"),fRet));
return fRet;
}
/*++
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -