- Added basic tracing, breakpoints and disassembly to the kernel debugger.

svn path=/trunk/; revision=8685
This commit is contained in:
David Welch 2004-03-13 18:21:57 +00:00
parent c417fd21b1
commit ff3151887b
6 changed files with 759 additions and 57 deletions

View file

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.117 2004/03/08 08:05:27 navaraf Exp $
# $Id: Makefile,v 1.118 2004/03/13 18:21:56 dwelch Exp $
#
# ReactOS Operating System
#
@ -28,7 +28,7 @@ endif
ifeq ($(KDBG), 1)
OBJECTS_KDBG := dbg/kdb.o dbg/kdb_serial.o dbg/kdb_keyboard.o dbg/rdebug.o \
dbg/i386/kdb_help.o dbg/kdb_stabs.o dbg/profile.o \
../dk/w32/lib/kjs.a
../dk/w32/lib/kjs.a dbg/i386/i386-dis.o
CFLAGS += -I../lib/kjs/include
preall: all

View file

@ -1,35 +1,31 @@
#include <internal/ke.h>
#include <internal/i386/segment.h>
.data
_KdbEipTemp:
.int 0
.text
.globl _KdbEnter
_KdbEnter:
/*
* Set up a stack frame
*/
pushl %ebp
movl %esp, %ebp
* Record when we are inside the debugger.
*/
incl _KdbEntryCount
/*
* Save registers
*/
pushl %edi
pushl %esi
pushl %ebx
* Save the callers eip.
*/
popl _KdbEipTemp
/*
* Set up a trap frame
*/
pushl $0 /* V86_Gs */
pushl $0 /* V86_Fs */
pushl $0 /* V86_Ds */
pushl $0 /* V86_Es */
pushl %ss /* Ss */
pushl %ebp /* Esp */
pushfl /* Eflags */
pushl %cs /* Cs */
pushl 4(%ebp) /* Eip */
pushl _KdbEipTemp /* Eip */
pushl $0 /* ErrorCode */
pushl 0(%ebp) /* Ebp */
pushl %ebp /* Ebp */
pushl %ebx /* Ebx */
pushl %esi /* Esi */
pushl %edi /* Edi */
@ -42,12 +38,21 @@ _KdbEnter:
pushl %ds /* Ds */
pushl %es /* Es */
pushl %gs /* Gs */
pushl $0 /* Dr7 */
pushl $0 /* Dr6 */
pushl $0 /* Dr3 */
pushl $0 /* Dr2 */
pushl $0 /* Dr1 */
pushl $0 /* Dr0 */
movl %dr7, %eax
pushl %eax /* Dr7 */
/* Clear all breakpoint enables in dr7. */
andl $0xFFFF0000, %eax
movl %eax, %dr7
movl %dr6, %eax
pushl %eax /* Dr6 */
movl %dr3, %eax
pushl %eax /* Dr3 */
movl %dr2, %eax
pushl %eax /* Dr2 */
movl %dr1, %eax
pushl %eax /* Dr1 */
movl %dr0, %eax
pushl %eax /* Dr0 */
pushl $0 /* TempEip */
pushl $0 /* TempCs */
pushl $0 /* DebugPointer */
@ -66,23 +71,60 @@ _KdbEnter:
call _KdbInternalEnter
/*
* Pop the argument and destroy the trap frame
* Pop the argument
*/
popl %eax
addl $KTRAP_FRAME_SIZE, %esp
popl %eax
/*
* Restore registers
* Ignore unused portions of the trap frame.
*/
popl %ebx
popl %esi
popl %edi
popl %eax /* DebugEbp */
popl %eax /* DebugEip */
popl %eax /* DebugArgMark */
popl %eax /* DebugPointer */
popl %eax /* TempCs */
popl %eax /* TempEip */
popl %eax /* Dr0 */
movl %eax, %dr0
popl %eax /* Dr1 */
movl %eax, %dr1
popl %eax /* Dr2 */
movl %eax, %dr2
popl %eax /* Dr3 */
movl %eax, %dr3
popl %eax /* Dr6 */
movl %eax, %dr6
popl %eax /* Dr7 */
movl %eax, %dr7
/*
* Return
* Restore registers including any that might have been changed
* inside the debugger.
*/
popl %ebp
ret
popl %gs /* Gs */
popl %es /* Es */
popl %ds /* Ds */
popl %edx /* Edx */
popl %ecx /* Ecx */
popl %eax /* Eax */
addl $4, %esp /* PreviousMode */
addl $4, %esp /* ExceptionList */
popl %fs /* Fs */
popl %edi /* Edi */
popl %esi /* Esi */
popl %ebx /* Ebx */
popl %ebp /* Ebp */
addl $4, %esp /* ErrorCode */
/*
* Record when we are in the debugger.
*/
decl _KdbEntryCount
/*
* Return to the caller.
*/
iret

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: kdb.c,v 1.18 2004/02/24 21:25:40 weiden Exp $
/* $Id: kdb.c,v 1.19 2004/03/13 18:21:56 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/dbg/kdb.c
@ -34,6 +34,8 @@
#include <internal/ps.h>
#include <limits.h>
#include <internal/kd.h>
#include <internal/mm.h>
#include <internal/i386/mm.h>
#include "kdb.h"
#include "kjs.h"
@ -46,9 +48,32 @@
#define BS 8
#define DEL 127
#define UPARROW 56
BOOL KbdEchoOn = TRUE;
typedef struct
{
BOOLEAN Enabled;
BOOLEAN Temporary;
BOOLEAN Assigned;
ULONG Address;
UCHAR SavedInst;
} KDB_ACTIVE_BREAKPOINT;
#define KDB_MAXIMUM_BREAKPOINT_COUNT (255)
static ULONG KdbBreakPointCount = 0;
static KDB_ACTIVE_BREAKPOINT
KdbActiveBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT];
static BOOLEAN KdbIgnoreNextSingleStep = FALSE;
static ULONG KdbLastSingleStepFrom = 0xFFFFFFFF;
static BOOLEAN KdbEnteredOnSingleStep = FALSE;
ULONG KdbEntryCount = 0;
int isalpha( int );
VOID
PsDumpThreads(BOOLEAN System);
@ -84,6 +109,20 @@ ULONG
DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgSetBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgDeleteBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgSetMemoryBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgStep(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgStepOver(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgFinish(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
struct
{
@ -107,12 +146,28 @@ struct
{"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand},
{"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand},
{"js", "js", "Script mode", DbgScriptCommand},
{"disasm", "disasm <address>", "Disables 10 instructions at <address> or "
"eip", DbgDisassemble},
{"bp", "bp <address>", "Sets an int3 breakpoint at a given address",
DbgSetBreakPoint},
{"bc", "bc <breakpoint number>", "Deletes a breakpoint",
DbgDeleteBreakPoint},
{"ba", "ba <debug register> <access type> <length> <address>",
"Sets a breakpoint using a debug register", DbgSetMemoryBreakPoint},
{"t", "t", "Steps forward a single instructions", DbgStep},
{"p", "p", "Steps forward a single instructions skipping calls",
DbgStepOver},
{"finish", "finish", "Runs until the current function exits", DbgFinish},
{"help", "help", "Display help screen", DbgProcessHelpCommand},
{NULL, NULL, NULL}
};
volatile DWORD x_dr0 = 0, x_dr1 = 0, x_dr2 = 0, x_dr3 = 0, x_dr7 = 0;
extern LONG KdbDisassemble(ULONG Address);
extern LONG KdbGetInstLength(ULONG Address);
extern NTSTATUS MmGetPageEntry2(PVOID PAddress, PULONG* Pte, BOOLEAN MayWait);
/* FUNCTIONS *****************************************************************/
/*
@ -206,6 +261,7 @@ KdbGetCommand(PCH Buffer)
{
CHAR Key;
PCH Orig = Buffer;
static UCHAR LastCommand[256] = "";
KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
@ -219,7 +275,19 @@ KdbGetCommand(PCH Buffer)
if (Key == '\r' || Key == '\n')
{
DbgPrint("\n");
*Buffer = 0;
/*
Repeat the last command if the user presses enter. Reduces the
risk of RSI when single-stepping.
*/
if (Buffer == Orig)
{
strcpy(Buffer, LastCommand);
}
else
{
*Buffer = 0;
strcpy(LastCommand, Orig);
}
return;
}
else if (Key == BS || Key == DEL)
@ -234,6 +302,26 @@ KdbGetCommand(PCH Buffer)
DbgPrint(" %c", BS);
}
}
else if (Key == UPARROW)
{
ULONG i;
while (Buffer > Orig)
{
Buffer--;
*Buffer = 0;
if (KbdEchoOn)
DbgPrint("%c %c", BS, BS);
else
DbgPrint(" %c", BS);
}
for (i = 0; LastCommand[i] != 0; i++)
{
if (KbdEchoOn)
DbgPrint("%c", LastCommand[i]);
*Buffer = LastCommand[i];
Buffer++;
}
}
else
{
if (KbdEchoOn)
@ -245,6 +333,444 @@ KdbGetCommand(PCH Buffer)
}
}
BOOLEAN STATIC
KdbDecodeAddress(PUCHAR Buffer, PULONG Address)
{
while (isspace(*Buffer))
{
Buffer++;
}
if (Buffer[0] == '<')
{
PUCHAR ModuleName = Buffer + 1;
PUCHAR AddressString = strpbrk(Buffer, ":");
extern LIST_ENTRY ModuleTextListHead;
PLIST_ENTRY current_entry;
MODULE_TEXT_SECTION* current;
static WCHAR ModuleNameW[256];
ULONG i;
if (AddressString == NULL)
{
DbgPrint("Address %x is malformed.\n", Buffer);
return(FALSE);
}
*AddressString = 0;
AddressString++;
while (isspace(*AddressString))
{
AddressString++;
}
for (i = 0; ModuleName[i] != 0 && !isspace(ModuleName[i]); i++)
{
ModuleNameW[i] = (WCHAR)ModuleName[i];
}
ModuleNameW[i] = 0;
/* Find the module. */
current_entry = ModuleTextListHead.Flink;
while (current_entry != &ModuleTextListHead &&
current_entry != NULL)
{
current =
CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
if (wcscmp(ModuleNameW, current->Name) == 0)
{
break;
}
current_entry = current_entry->Flink;
}
if (current_entry == NULL || current_entry == &ModuleTextListHead)
{
DbgPrint("Couldn't find module %s.\n", ModuleName);
return(FALSE);
}
*Address = current->Base;
*Address += strtoul(AddressString, NULL, 16);
return(TRUE);
}
else
{
*Address = strtoul(Buffer, NULL, 0);
return(TRUE);
}
}
NTSTATUS STATIC
KdbOverwriteInst(ULONG Address, PUCHAR PreviousInst, UCHAR NewInst)
{
PULONG BreakPtePtr;
ULONG SavedPte;
NTSTATUS Status;
/* Get the pte for the page containing the address. */
Status =
MmGetPageEntry2((PVOID)PAGE_ROUND_DOWN(Address), &BreakPtePtr, FALSE);
/* Return if that page isn't present. */
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (!((*BreakPtePtr) & (1 << 0)))
{
return(STATUS_MEMORY_NOT_ALLOCATED);
}
/* Saved the old pte and enable write permissions. */
SavedPte = *BreakPtePtr;
(*BreakPtePtr) |= (1 << 1);
/* Flush the TLB. */
__asm__ __volatile__ ("movl %%cr3, %%eax\n\t"
"movl %%eax, %%cr3\n\t"
: : : "memory", "eax");
/* Copy the old instruction back to the caller. */
if (PreviousInst != NULL)
{
Status = MmSafeCopyFromUser(PreviousInst, (PUCHAR)Address, 1);
if (!NT_SUCCESS(Status))
{
return(Status);
}
}
/* Copy the new instruction in its place. */
Status = MmSafeCopyToUser((PUCHAR)Address, &NewInst, 1);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* Restore the old pte. */
*BreakPtePtr = SavedPte;
/* And flush the tlb again. */
__asm__ __volatile__ ("movl %%cr3, %%eax\n\t"
"movl %%eax, %%cr3\n\t"
: : : "memory", "eax");
return(STATUS_SUCCESS);
}
VOID STATIC
KdbRenableBreakPoints(VOID)
{
ULONG i;
for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
{
if (KdbActiveBreakPoints[i].Assigned &&
!KdbActiveBreakPoints[i].Enabled)
{
KdbActiveBreakPoints[i].Enabled = TRUE;
(VOID)KdbOverwriteInst(KdbActiveBreakPoints[i].Address,
&KdbActiveBreakPoints[i].SavedInst,
0xCC);
}
}
}
LONG STATIC
KdbIsBreakPointOurs(PKTRAP_FRAME Tf)
{
ULONG i;
for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
{
if (KdbActiveBreakPoints[i].Assigned &&
KdbActiveBreakPoints[i].Address == (Tf->Eip - 1))
{
return(i);
}
}
return(-1);
}
VOID STATIC
KdbDeleteBreakPoint(ULONG BreakPointNr)
{
KdbBreakPointCount--;
KdbActiveBreakPoints[BreakPointNr].Assigned = FALSE;
}
NTSTATUS STATIC
KdbInsertBreakPoint(ULONG Address, BOOLEAN Temporary)
{
NTSTATUS Status;
UCHAR SavedInst;
ULONG i;
if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT)
{
return(STATUS_UNSUCCESSFUL);
}
for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
{
if (!KdbActiveBreakPoints[i].Assigned)
{
break;
}
}
Status = KdbOverwriteInst(Address, &SavedInst, 0xCC);
if (!NT_SUCCESS(Status))
{
return(Status);
}
KdbActiveBreakPoints[i].Assigned = TRUE;
KdbActiveBreakPoints[i].Enabled = TRUE;
KdbActiveBreakPoints[i].Address = Address;
KdbActiveBreakPoints[i].Temporary = Temporary;
KdbActiveBreakPoints[i].SavedInst = SavedInst;
return(STATUS_SUCCESS);
}
ULONG
DbgSetBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
ULONG Addr;
NTSTATUS Status;
ULONG i;
if (Argc < 2)
{
DbgPrint("Need an address to set the breakpoint at.\n");
return(1);
}
/* Stitch the remaining arguments back into a single string. */
for (i = 2; i < Argc; i++)
{
Argv[i][-1] = ' ';
}
if (!KdbDecodeAddress(Argv[1], &Addr))
{
return(1);
}
DbgPrint("Setting breakpoint at 0x%X\n", Addr);
if (!NT_SUCCESS(Status = KdbInsertBreakPoint(Addr, FALSE)))
{
DbgPrint("Failed to set breakpoint (Status %X)\n", Status);
}
return(1);
}
ULONG
DbgDeleteBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
ULONG BreakPointNr;
if (Argc != 2)
{
DbgPrint("Need a breakpoint number to delete.\n");
return(1);
}
BreakPointNr = strtoul(Argv[1], NULL, 10);
DbgPrint("Deleting breakpoint %d.\n", BreakPointNr);
KdbDeleteBreakPoint(BreakPointNr);
return(1);
}
ULONG
DbgSetMemoryBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
ULONG DebugRegNr;
UCHAR BreakType;
ULONG Length, Address;
ULONG Rw;
ULONG i;
if (Argc != 2 && Argc < 5)
{
DbgPrint("ba <0-3> <r|w|e> <1|2|4> <address>\n");
return(1);
}
DebugRegNr = strtoul(Argv[1], NULL, 10);
if (DebugRegNr >= 4)
{
DbgPrint("Debug register number should be between 0 and 3.\n");
return(1);
}
if (Argc == 2)
{
/* Clear the breakpoint. */
Tf->Dr7 &= ~(0x3 << (DebugRegNr * 2));
if ((Tf->Dr7 & 0xFF) == 0)
{
/*
If no breakpoints are enabled then
clear the exact match flags.
*/
Tf->Dr7 &= 0xFFFFFCFF;
}
return(1);
}
BreakType = Argv[2][0];
if (BreakType != 'r' && BreakType != 'w' && BreakType != 'e')
{
DbgPrint("Access type to break on should be either 'r', 'w' or 'e'.\n");
return(1);
}
Length = strtoul(Argv[3], NULL, 10);
if (Length != 1 && Length != 2 && Length != 4)
{
DbgPrint("Length of the breakpoint should be one, two or four.\n");
return(1);
}
if (Length != 1 && BreakType == 'e')
{
DbgPrint("The length of an execution breakpoint should be one.\n");
return(1);
}
/* Stitch the remaining arguments back into a single string. */
for (i = 4; i < Argc; i++)
{
Argv[i][-1] = ' ';
}
if (!KdbDecodeAddress(Argv[4], &Address))
{
return(1);
}
if ((Address & (Length - 1)) != 0)
{
DbgPrint("The breakpoint address should be aligned to a multiple of "
"the breakpoint length.\n");
return(1);
}
/* Set the breakpoint address. */
switch (DebugRegNr)
{
case 0: Tf->Dr0 = Address; break;
case 1: Tf->Dr1 = Address; break;
case 2: Tf->Dr2 = Address; break;
case 3: Tf->Dr3 = Address; break;
}
/* Enable the breakpoint. */
Tf->Dr7 |= (0x3 << (DebugRegNr * 2));
/* Enable the exact match bits. */
Tf->Dr7 |= 0x00000300;
/* Clear existing state. */
Tf->Dr7 &= ~(0xF << (16 + (DebugRegNr * 4)));
/* Set the breakpoint type. */
switch (BreakType)
{
case 'r': Rw = 3; break;
case 'w': Rw = 1; break;
case 'e': Rw = 0; break;
}
Tf->Dr7 |= (Rw << (16 + (DebugRegNr * 4)));
/* Set the breakpoint length. */
Tf->Dr7 |= ((Length - 1) << (18 + (DebugRegNr * 4)));
return(1);
}
ULONG
DbgStep(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
/* Set the single step flag and return to the interrupted code. */
Tf->Eflags |= (1 << 8);
KdbIgnoreNextSingleStep = FALSE;
KdbLastSingleStepFrom = Tf->Eip;
return(0);
}
ULONG
DbgStepOver(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
PUCHAR Eip = (PUCHAR)Tf->Eip;
/* Check if the current instruction is a call. */
while (Eip[0] == 0x66 || Eip[0] == 0x67)
{
Eip++;
}
if (Eip[0] == 0xE8 || Eip[0] == 0x9A ||
(Eip[0] == 0xFF && (Eip[0] & 0x3C) == 0x10))
{
ULONG NextInst = Tf->Eip + KdbGetInstLength(Tf->Eip);
KdbLastSingleStepFrom = Tf->Eip;
KdbInsertBreakPoint(NextInst, TRUE);
return(0);
}
else
{
return(DbgStep(Argc, Argv, Tf));
}
}
ULONG
DbgFinish(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
PULONG Ebp = (PULONG)Tf->Ebp;
ULONG ReturnAddress;
NTSTATUS Status;
PKTHREAD CurrentThread;
/* Check that ebp points onto the stack. */
CurrentThread = KeGetCurrentThread();
if (CurrentThread == NULL ||
!(Ebp >= (PULONG)CurrentThread->StackLimit &&
Ebp <= (PULONG)CurrentThread->StackBase))
{
DbgPrint("This function doesn't appear to have a valid stack frame.\n");
return(1);
}
/* Get the address of the caller. */
Status = MmSafeCopyFromUser(&ReturnAddress, Ebp + 1, sizeof(ULONG));
if (!NT_SUCCESS(Status))
{
DbgPrint("Memory access error (%X) while getting return address.\n",
Status);
return(1);
}
/* Set a temporary breakpoint at that location. */
Status = KdbInsertBreakPoint(ReturnAddress, TRUE);
if (!NT_SUCCESS(Status))
{
DbgPrint("Couldn't set a temporary breakpoint at %X (Status %X)\n",
ReturnAddress, Status);
return(1);
}
/*
Otherwise start running again and with any luck we will break back into
the debugger when the current function returns.
*/
return(0);
}
ULONG
DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
ULONG Address, i;
LONG InstLen;
if (Argc >= 2)
{
/* Stitch the remaining arguments back into a single string. */
for (i = 2; i < Argc; i++)
{
Argv[i][-1] = ' ';
}
if (!KdbDecodeAddress(Argv[1], &Address))
{
return(1);
}
}
else
{
Address = Tf->Eip;
}
for (i = 0; i < 10; i++)
{
if (!KdbPrintAddress((PVOID)Address))
{
DbgPrint("<%x>", Address);
}
DbgPrint(": ");
InstLen = KdbDisassemble(Address);
if (InstLen < 0)
{
DbgPrint("<INVALID>\n");
return(1);
}
DbgPrint("\n");
Address += InstLen;
}
return(1);
}
ULONG
DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
@ -979,7 +1505,25 @@ KdbMainLoop(PKTRAP_FRAME Tf)
CHAR Command[256];
ULONG s;
DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
if (!KdbEnteredOnSingleStep)
{
DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
}
else
{
if (!KdbPrintAddress((PVOID)Tf->Eip))
{
DbgPrint("<%x>", Tf->Eip);
}
DbgPrint(": ");
if (KdbDisassemble(Tf->Eip) < 0)
{
DbgPrint("<INVALID>");
}
KdbEnteredOnSingleStep = FALSE;
KdbLastSingleStepFrom = 0xFFFFFFFF;
}
do
{
DbgPrint("\nkdb:> ");
@ -1004,8 +1548,99 @@ KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
PCONTEXT Context,
PKTRAP_FRAME TrapFrame)
{
DbgPrint("Entered debugger on exception number %d.\n",
TrapFrame->DebugArgMark);
LONG BreakPointNr;
ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
/* Exception inside the debugger? Game over. */
if (KdbEntryCount > 0)
{
return(kdHandleException);
}
KdbEntryCount++;
/* Clear the single step flag. */
TrapFrame->Eflags &= ~(1 << 8);
/*
Reenable any breakpoints we disabled so we could execute the breakpointed
instructions.
*/
KdbRenableBreakPoints();
/* Silently ignore a debugger initiated single step. */
if (ExpNr == 1 && KdbIgnoreNextSingleStep)
{
KdbIgnoreNextSingleStep = FALSE;
KdbEntryCount--;
return(kdContinue);
}
/* If we stopped on one of our breakpoints then let the user know. */
if (ExpNr == 3 && (BreakPointNr = KdbIsBreakPointOurs(TrapFrame)) >= 0)
{
DbgPrint("Entered debugger on breakpoint %d.\n", BreakPointNr);
/*
The breakpoint will point to the next instruction by default so
point it back to the start of original instruction.
*/
TrapFrame->Eip--;
/*
..and restore the original instruction.
*/
(VOID)KdbOverwriteInst(TrapFrame->Eip, NULL,
KdbActiveBreakPoints[BreakPointNr].SavedInst);
/*
If this was a breakpoint set by the debugger then delete it otherwise
flag to enable it again after we step over this instruction.
*/
if (KdbActiveBreakPoints[BreakPointNr].Temporary)
{
KdbActiveBreakPoints[BreakPointNr].Assigned = FALSE;
KdbBreakPointCount--;
KdbEnteredOnSingleStep = TRUE;
}
else
{
KdbActiveBreakPoints[BreakPointNr].Enabled = FALSE;
TrapFrame->Eflags |= (1 << 8);
KdbIgnoreNextSingleStep = TRUE;
}
}
else if (ExpNr == 1)
{
if ((TrapFrame->Dr6 & 0xF) != 0)
{
DbgPrint("Entered debugger on memory breakpoint(s) %s%s%s%s.\n",
(TrapFrame->Dr6 & 0x1) ? "1" : "",
(TrapFrame->Dr6 & 0x2) ? "2" : "",
(TrapFrame->Dr6 & 0x4) ? "3" : "",
(TrapFrame->Dr6 & 0x8) ? "4" : "");
}
else if (KdbLastSingleStepFrom != 0xFFFFFFFF)
{
KdbEnteredOnSingleStep = TRUE;
}
else
{
DbgPrint("Entered debugger on unexpected debug trap.\n");
}
}
else
{
DbgPrint("Entered debugger on exception number %d.\n", ExpNr);
}
KdbInternalEnter(TrapFrame);
return(kdHandleException);
KdbEntryCount--;
if (ExpNr != 1 && ExpNr != 3)
{
return(kdHandleException);
}
else
{
/* Clear dr6 status flags. */
TrapFrame->Dr6 &= 0xFFFF1F00;
/* Set the RF flag to we don't trigger the same breakpoint again. */
if (ExpNr == 1)
{
TrapFrame->Eflags |= (1 << 16);
}
return(kdContinue);
}
}

View file

@ -79,12 +79,12 @@ typedef struct _KTRAP_FRAME
PVOID DebugPointer;
PVOID TempCs;
PVOID TempEip;
PVOID Dr0;
PVOID Dr1;
PVOID Dr2;
PVOID Dr3;
PVOID Dr6;
PVOID Dr7;
ULONG Dr0;
ULONG Dr1;
ULONG Dr2;
ULONG Dr3;
ULONG Dr6;
ULONG Dr7;
USHORT Gs;
USHORT Reserved1;
USHORT Es;

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: catch.c,v 1.40 2004/03/06 22:24:13 dwelch Exp $
/* $Id: catch.c,v 1.41 2004/03/13 18:21:57 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/catch.c
@ -88,6 +88,10 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
{
Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
if (Action == kdContinue)
{
return;
}
}
#endif /* KDBG */
if (Action != kdHandleException)

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: trap.s,v 1.18 2003/04/27 16:21:16 hbirr Exp $
/* $Id: trap.s,v 1.19 2004/03/13 18:21:57 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386/trap.s
@ -42,7 +42,19 @@ _KiTrapEpilog:
jmp _KiV86Complete
_KiTrapRet:
/* Skip debug information and unsaved registers */
addl $0x30, %esp
addl $0x18, %esp
popl %eax /* Dr0 */
movl %eax, %dr0
popl %eax /* Dr1 */
movl %eax, %dr1
popl %eax /* Dr2 */
movl %eax, %dr2
popl %eax /* Dr3 */
movl %eax, %dr3
popl %eax /* Dr6 */
movl %eax, %dr6
popl %eax /* Dr7 */
movl %eax, %dr7
popl %gs
popl %es
popl %ds
@ -120,12 +132,21 @@ _KiTrapProlog:
pushl %ds
pushl %es
pushl %gs
pushl $0 /* DR7 */
pushl $0 /* DR6 */
pushl $0 /* DR3 */
pushl $0 /* DR2 */
pushl $0 /* DR1 */
pushl $0 /* DR0 */
movl %dr7, %eax
pushl %eax /* Dr7 */
/* Clear all breakpoint enables in dr7. */
andl $0xFFFF0000, %eax
movl %eax, %dr7
movl %dr6, %eax
pushl %eax /* Dr6 */
movl %dr3, %eax
pushl %eax /* Dr3 */
movl %dr2, %eax
pushl %eax /* Dr2 */
movl %dr1, %eax
pushl %eax /* Dr1 */
movl %dr0, %eax
pushl %eax /* Dr0 */
pushl $0 /* XXX: TempESP */
pushl $0 /* XXX: TempCS */
pushl $0 /* XXX: DebugPointer */