Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

473 lines
11 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
kdbreak.c
Abstract:
This module implements machine dependent functions to add and delete
breakpoints from the kernel debugger breakpoint table.
Author:
David N. Cutler 2-Aug-1990
Revision History:
--*/
#include "kdp.h"
BOOLEAN BreakpointsSuspended = FALSE;
//
// Define external references.
//
VOID
KdSetOwedBreakpoints(
VOID
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEKD, KdpAddBreakpoint)
#pragma alloc_text(PAGEKD, KdpDeleteBreakpoint)
#pragma alloc_text(PAGEKD, KdpDeleteBreakpointRange)
#pragma alloc_text(PAGEKD, KdpSuspendBreakpoint)
#pragma alloc_text(PAGEKD, KdpSuspendAllBreakpoints)
#pragma alloc_text(PAGEKD, KdpRestoreAllBreakpoints)
#endif
ULONG
KdpAddBreakpoint (
IN PVOID Address
)
/*++
Routine Description:
This routine adds an entry to the breakpoint table and returns a handle
to the breakpoint table entry.
Arguments:
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.
--*/
{
KDP_BREAKPOINT_TYPE Content;
ULONG Handle;
ULONG Index;
BOOLEAN Accessible;
//
// If the specified address is not properly aligned, then return zero.
//
if (((ULONG)Address & KDP_BREAKPOINT_ALIGN) != 0) {
return 0;
}
//
// Get the instruction to be replaced. If the instruction cannot be read,
// then mark breakpoint as not accessible.
//
if (KdpMoveMemory(
(PCHAR)&Content,
(PCHAR)Address,
sizeof(KDP_BREAKPOINT_TYPE) ) != sizeof(KDP_BREAKPOINT_TYPE)) {
Accessible = FALSE;
} else {
Accessible = TRUE;
}
//
// If the specified address is not write accessible, then return zero.
//
if (Accessible && MmDbgWriteCheck((PVOID)Address) == NULL) {
return 0;
}
//
// Search the breakpoint table for a free entry and check if the specified
// address is already in the breakpoint table.
//
for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index += 1) {
if (KdpBreakpointTable[Index].Flags == 0) {
Handle = Index + 1;
break;
}
}
//
// If a free entry was found, then write breakpoint and return the handle
// value plus one. Otherwise, return zero.
//
if (Handle != 0) {
if ( Accessible ) {
KdpBreakpointTable[Handle - 1].Address = Address;
KdpBreakpointTable[Handle - 1].Content = Content;
KdpBreakpointTable[Handle - 1].Flags = KD_BREAKPOINT_IN_USE;
if (Address < (PVOID)GLOBAL_BREAKPOINT_LIMIT) {
KdpBreakpointTable[Handle - 1].DirectoryTableBase =
KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
}
KdpMoveMemory(
(PCHAR)Address,
(PCHAR)&KdpBreakpointInstruction,
sizeof(KDP_BREAKPOINT_TYPE)
);
} else {
KdpBreakpointTable[Handle - 1].Address = Address;
KdpBreakpointTable[Handle - 1].Flags = KD_BREAKPOINT_NEEDS_WRITE;
KdpOweBreakpoint = TRUE;
if (Address < (PVOID)GLOBAL_BREAKPOINT_LIMIT) {
KdpBreakpointTable[Handle - 1].DirectoryTableBase =
KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
}
}
}
return Handle;
}
VOID
KdSetOwedBreakpoints(
VOID
)
/*++
Routine Description:
This function is called after returning from memory management calls
that may cause an inpage. Its purpose is to store pending
breakpoints in pages just made valid.
Arguments:
None.
Return Value:
None.
--*/
{
KDP_BREAKPOINT_TYPE Content;
BOOLEAN Enable;
LONG Index;
//
// If we don't owe any breakpoints then return
//
if ( !KdpOweBreakpoint ) {
return;
}
//
// Freeze all other processors, disable interrupts, and save debug
// port state.
//
Enable = KdEnterDebugger(NULL, NULL);
KdpOweBreakpoint = FALSE;
//
// Search the breakpoint table for breakpoints that need to be
// written.
//
for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index += 1) {
if (KdpBreakpointTable[Index].Flags & KD_BREAKPOINT_NEEDS_WRITE) {
//
// Breakpoint needs to be written
//
if ((KdpBreakpointTable[Index].Address >= (PVOID)GLOBAL_BREAKPOINT_LIMIT) ||
(KdpBreakpointTable[Index].DirectoryTableBase ==
KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0])) {
//
// Check to see if we have write access to the memory
//
if (MmDbgWriteCheck((PVOID)KdpBreakpointTable[Index].Address) == NULL) {
KdpOweBreakpoint = TRUE;
break;
}
//
// Breakpoint is global, or it's directory base matches
//
if (KdpMoveMemory(
(PCHAR)&Content,
(PCHAR)KdpBreakpointTable[Index].Address,
sizeof(KDP_BREAKPOINT_TYPE)
) != sizeof(KDP_BREAKPOINT_TYPE)) {
KdpOweBreakpoint = TRUE;
} else {
KdpBreakpointTable[Index].Content = Content;
KdpBreakpointTable[Index].Flags = KD_BREAKPOINT_IN_USE;
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[Index].Address,
(PCHAR)&KdpBreakpointInstruction,
sizeof(KDP_BREAKPOINT_TYPE)
);
}
} else {
//
// Breakpoint is local and it's directory base does not match
//
KdpOweBreakpoint = TRUE;
}
}
}
KdExitDebugger(Enable);
return;
}
BOOLEAN
KdpDeleteBreakpoint (
IN ULONG Handle
)
/*++
Routine Description:
This routine deletes an entry from the breakpoint table.
Arguments:
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.
--*/
{
//
// If the specified handle is not value, then return FALSE.
//
if ((Handle == 0) || (Handle > BREAKPOINT_TABLE_SIZE)) {
return FALSE;
}
Handle -= 1;
//
// If the specified breakpoint table is not valid, the return FALSE.
//
if (KdpBreakpointTable[Handle].Flags == 0) {
return FALSE;
}
//
// If the breakpoint is suspended, just delete from the table
//
if (KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_SUSPENDED) {
KdpBreakpointTable[Handle].Flags = 0;
return TRUE;
}
//
// Replace the instruction contents.
//
if (KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_IN_USE &&
KdpBreakpointTable[Handle].Content != KdpBreakpointInstruction) {
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[Handle].Address,
(PCHAR)&KdpBreakpointTable[Handle].Content,
sizeof(KDP_BREAKPOINT_TYPE)
);
}
//
// Delete breakpoint table entry and return TRUE.
//
KdpBreakpointTable[Handle].Flags = 0;
return TRUE;
}
BOOLEAN
KdpDeleteBreakpointRange (
IN PVOID Lower,
IN PVOID Upper
)
/*++
Routine Description:
This routine deletes all breakpoints falling in a given range
from the breakpoint table.
Arguments:
Lower - inclusive lower address of range from which to remove BPs.
Upper - include upper address of range from which to remove BPs.
Return Value:
TRUE if any breakpoints removed, FALSE otherwise.
--*/
{
ULONG Index;
BOOLEAN ReturnStatus = FALSE;
//
// Examine each entry in the table in turn
//
for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index++) {
if ( (KdpBreakpointTable[Index].Flags & KD_BREAKPOINT_IN_USE) &&
((KdpBreakpointTable[Index].Address >= Lower) &&
(KdpBreakpointTable[Index].Address <= Upper))
) {
//
// Breakpiont is in use and falls in range, clear it.
//
if (KdpBreakpointTable[Index].Content != KdpBreakpointInstruction) {
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[Index].Address,
(PCHAR)&KdpBreakpointTable[Index].Content,
sizeof(KDP_BREAKPOINT_TYPE)
);
}
KdpBreakpointTable[Index].Flags = 0;
ReturnStatus = TRUE;
}
}
return ReturnStatus;
}
VOID
KdpSuspendBreakpoint (
ULONG Handle
)
{
Handle -= 1;
if ( (KdpBreakpointTable[Handle].Flags != 0) &&
!(KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_SUSPENDED) ) {
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[Handle].Address,
(PCHAR)&KdpBreakpointTable[Handle].Content,
sizeof(KDP_BREAKPOINT_TYPE)
);
KdpBreakpointTable[Handle].Flags |= KD_BREAKPOINT_SUSPENDED;
}
return;
} // KdpSuspendBreakpoint
VOID
KdpSuspendAllBreakpoints (
VOID
)
{
ULONG index;
BreakpointsSuspended = TRUE;
for ( index = 0; index < BREAKPOINT_TABLE_SIZE; index++ ) {
if ( (KdpBreakpointTable[index].Flags != 0) &&
!(KdpBreakpointTable[index].Flags & KD_BREAKPOINT_SUSPENDED) ) {
//
// Replace the instruction contents.
//
if ( KdpBreakpointTable[index].Flags & KD_BREAKPOINT_IN_USE &&
KdpBreakpointTable[index].Content != KdpBreakpointInstruction ) {
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[index].Address,
(PCHAR)&KdpBreakpointTable[index].Content,
sizeof(KDP_BREAKPOINT_TYPE)
);
KdpBreakpointTable[index].Flags |= KD_BREAKPOINT_SUSPENDED;
}
}
}
return;
} // KdpSuspendAllBreakpoints
VOID
KdpRestoreAllBreakpoints (
VOID
)
{
ULONG index;
BreakpointsSuspended = FALSE;
for ( index = 0; index < BREAKPOINT_TABLE_SIZE; index++ ) {
if ( KdpBreakpointTable[index].Flags & KD_BREAKPOINT_SUSPENDED ) {
KdpMoveMemory(
(PCHAR)KdpBreakpointTable[index].Address,
(PCHAR)&KdpBreakpointInstruction,
sizeof(KDP_BREAKPOINT_TYPE)
);
KdpBreakpointTable[index].Flags &= ~KD_BREAKPOINT_SUSPENDED;
}
}
return;
} // KdpRestoreAllBreakpoints