mirror of
https://github.com/reactos/reactos.git
synced 2024-07-02 18:54:25 +00:00
- Added basic tracing, breakpoints and disassembly to the kernel debugger.
svn path=/trunk/; revision=8685
This commit is contained in:
parent
c417fd21b1
commit
ff3151887b
|
@ -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
|
# ReactOS Operating System
|
||||||
#
|
#
|
||||||
|
@ -28,7 +28,7 @@ endif
|
||||||
ifeq ($(KDBG), 1)
|
ifeq ($(KDBG), 1)
|
||||||
OBJECTS_KDBG := dbg/kdb.o dbg/kdb_serial.o dbg/kdb_keyboard.o dbg/rdebug.o \
|
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 \
|
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
|
CFLAGS += -I../lib/kjs/include
|
||||||
preall: all
|
preall: all
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
#include <internal/ke.h>
|
#include <internal/ke.h>
|
||||||
#include <internal/i386/segment.h>
|
#include <internal/i386/segment.h>
|
||||||
|
|
||||||
|
.data
|
||||||
|
_KdbEipTemp:
|
||||||
|
.int 0
|
||||||
|
|
||||||
|
.text
|
||||||
.globl _KdbEnter
|
.globl _KdbEnter
|
||||||
_KdbEnter:
|
_KdbEnter:
|
||||||
/*
|
/*
|
||||||
* Set up a stack frame
|
* Record when we are inside the debugger.
|
||||||
*/
|
*/
|
||||||
pushl %ebp
|
incl _KdbEntryCount
|
||||||
movl %esp, %ebp
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save registers
|
* Save the callers eip.
|
||||||
*/
|
*/
|
||||||
pushl %edi
|
popl _KdbEipTemp
|
||||||
pushl %esi
|
|
||||||
pushl %ebx
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up a trap frame
|
* 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 */
|
pushfl /* Eflags */
|
||||||
pushl %cs /* Cs */
|
pushl %cs /* Cs */
|
||||||
pushl 4(%ebp) /* Eip */
|
pushl _KdbEipTemp /* Eip */
|
||||||
pushl $0 /* ErrorCode */
|
pushl $0 /* ErrorCode */
|
||||||
pushl 0(%ebp) /* Ebp */
|
pushl %ebp /* Ebp */
|
||||||
pushl %ebx /* Ebx */
|
pushl %ebx /* Ebx */
|
||||||
pushl %esi /* Esi */
|
pushl %esi /* Esi */
|
||||||
pushl %edi /* Edi */
|
pushl %edi /* Edi */
|
||||||
|
@ -42,12 +38,21 @@ _KdbEnter:
|
||||||
pushl %ds /* Ds */
|
pushl %ds /* Ds */
|
||||||
pushl %es /* Es */
|
pushl %es /* Es */
|
||||||
pushl %gs /* Gs */
|
pushl %gs /* Gs */
|
||||||
pushl $0 /* Dr7 */
|
movl %dr7, %eax
|
||||||
pushl $0 /* Dr6 */
|
pushl %eax /* Dr7 */
|
||||||
pushl $0 /* Dr3 */
|
/* Clear all breakpoint enables in dr7. */
|
||||||
pushl $0 /* Dr2 */
|
andl $0xFFFF0000, %eax
|
||||||
pushl $0 /* Dr1 */
|
movl %eax, %dr7
|
||||||
pushl $0 /* Dr0 */
|
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 /* TempEip */
|
||||||
pushl $0 /* TempCs */
|
pushl $0 /* TempCs */
|
||||||
pushl $0 /* DebugPointer */
|
pushl $0 /* DebugPointer */
|
||||||
|
@ -66,23 +71,60 @@ _KdbEnter:
|
||||||
call _KdbInternalEnter
|
call _KdbInternalEnter
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pop the argument and destroy the trap frame
|
* Pop the argument
|
||||||
*/
|
*/
|
||||||
popl %eax
|
popl %eax
|
||||||
addl $KTRAP_FRAME_SIZE, %esp
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore registers
|
* Ignore unused portions of the trap frame.
|
||||||
*/
|
*/
|
||||||
popl %ebx
|
popl %eax /* DebugEbp */
|
||||||
popl %esi
|
popl %eax /* DebugEip */
|
||||||
popl %edi
|
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
|
popl %gs /* Gs */
|
||||||
ret
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: ntoskrnl/dbg/kdb.c
|
* FILE: ntoskrnl/dbg/kdb.c
|
||||||
|
@ -34,6 +34,8 @@
|
||||||
#include <internal/ps.h>
|
#include <internal/ps.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <internal/kd.h>
|
#include <internal/kd.h>
|
||||||
|
#include <internal/mm.h>
|
||||||
|
#include <internal/i386/mm.h>
|
||||||
#include "kdb.h"
|
#include "kdb.h"
|
||||||
#include "kjs.h"
|
#include "kjs.h"
|
||||||
|
|
||||||
|
@ -46,9 +48,32 @@
|
||||||
|
|
||||||
#define BS 8
|
#define BS 8
|
||||||
#define DEL 127
|
#define DEL 127
|
||||||
|
#define UPARROW 56
|
||||||
|
|
||||||
BOOL KbdEchoOn = TRUE;
|
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 );
|
int isalpha( int );
|
||||||
VOID
|
VOID
|
||||||
PsDumpThreads(BOOLEAN System);
|
PsDumpThreads(BOOLEAN System);
|
||||||
|
@ -84,6 +109,20 @@ ULONG
|
||||||
DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
|
DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
|
||||||
ULONG
|
ULONG
|
||||||
DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
|
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
|
struct
|
||||||
{
|
{
|
||||||
|
@ -107,12 +146,28 @@ struct
|
||||||
{"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand},
|
{"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand},
|
||||||
{"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand},
|
{"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand},
|
||||||
{"js", "js", "Script mode", DbgScriptCommand},
|
{"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},
|
{"help", "help", "Display help screen", DbgProcessHelpCommand},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
volatile DWORD x_dr0 = 0, x_dr1 = 0, x_dr2 = 0, x_dr3 = 0, x_dr7 = 0;
|
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 *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -206,6 +261,7 @@ KdbGetCommand(PCH Buffer)
|
||||||
{
|
{
|
||||||
CHAR Key;
|
CHAR Key;
|
||||||
PCH Orig = Buffer;
|
PCH Orig = Buffer;
|
||||||
|
static UCHAR LastCommand[256] = "";
|
||||||
|
|
||||||
KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
|
KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
|
||||||
|
|
||||||
|
@ -219,7 +275,19 @@ KdbGetCommand(PCH Buffer)
|
||||||
if (Key == '\r' || Key == '\n')
|
if (Key == '\r' || Key == '\n')
|
||||||
{
|
{
|
||||||
DbgPrint("\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;
|
return;
|
||||||
}
|
}
|
||||||
else if (Key == BS || Key == DEL)
|
else if (Key == BS || Key == DEL)
|
||||||
|
@ -234,6 +302,26 @@ KdbGetCommand(PCH Buffer)
|
||||||
DbgPrint(" %c", BS);
|
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
|
else
|
||||||
{
|
{
|
||||||
if (KbdEchoOn)
|
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
|
ULONG
|
||||||
DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
|
DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
|
||||||
{
|
{
|
||||||
|
@ -979,7 +1505,25 @@ KdbMainLoop(PKTRAP_FRAME Tf)
|
||||||
CHAR Command[256];
|
CHAR Command[256];
|
||||||
ULONG s;
|
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
|
do
|
||||||
{
|
{
|
||||||
DbgPrint("\nkdb:> ");
|
DbgPrint("\nkdb:> ");
|
||||||
|
@ -1004,8 +1548,99 @@ KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
|
||||||
PCONTEXT Context,
|
PCONTEXT Context,
|
||||||
PKTRAP_FRAME TrapFrame)
|
PKTRAP_FRAME TrapFrame)
|
||||||
{
|
{
|
||||||
DbgPrint("Entered debugger on exception number %d.\n",
|
LONG BreakPointNr;
|
||||||
TrapFrame->DebugArgMark);
|
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);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,12 @@ typedef struct _KTRAP_FRAME
|
||||||
PVOID DebugPointer;
|
PVOID DebugPointer;
|
||||||
PVOID TempCs;
|
PVOID TempCs;
|
||||||
PVOID TempEip;
|
PVOID TempEip;
|
||||||
PVOID Dr0;
|
ULONG Dr0;
|
||||||
PVOID Dr1;
|
ULONG Dr1;
|
||||||
PVOID Dr2;
|
ULONG Dr2;
|
||||||
PVOID Dr3;
|
ULONG Dr3;
|
||||||
PVOID Dr6;
|
ULONG Dr6;
|
||||||
PVOID Dr7;
|
ULONG Dr7;
|
||||||
USHORT Gs;
|
USHORT Gs;
|
||||||
USHORT Reserved1;
|
USHORT Reserved1;
|
||||||
USHORT Es;
|
USHORT Es;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: ntoskrnl/ke/catch.c
|
* FILE: ntoskrnl/ke/catch.c
|
||||||
|
@ -88,6 +88,10 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
|
||||||
else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
|
else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
|
||||||
{
|
{
|
||||||
Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
|
Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
|
||||||
|
if (Action == kdContinue)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* KDBG */
|
#endif /* KDBG */
|
||||||
if (Action != kdHandleException)
|
if (Action != kdHandleException)
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: ntoskrnl/ke/i386/trap.s
|
* FILE: ntoskrnl/ke/i386/trap.s
|
||||||
|
@ -42,7 +42,19 @@ _KiTrapEpilog:
|
||||||
jmp _KiV86Complete
|
jmp _KiV86Complete
|
||||||
_KiTrapRet:
|
_KiTrapRet:
|
||||||
/* Skip debug information and unsaved registers */
|
/* 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 %gs
|
||||||
popl %es
|
popl %es
|
||||||
popl %ds
|
popl %ds
|
||||||
|
@ -120,12 +132,21 @@ _KiTrapProlog:
|
||||||
pushl %ds
|
pushl %ds
|
||||||
pushl %es
|
pushl %es
|
||||||
pushl %gs
|
pushl %gs
|
||||||
pushl $0 /* DR7 */
|
movl %dr7, %eax
|
||||||
pushl $0 /* DR6 */
|
pushl %eax /* Dr7 */
|
||||||
pushl $0 /* DR3 */
|
/* Clear all breakpoint enables in dr7. */
|
||||||
pushl $0 /* DR2 */
|
andl $0xFFFF0000, %eax
|
||||||
pushl $0 /* DR1 */
|
movl %eax, %dr7
|
||||||
pushl $0 /* DR0 */
|
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: TempESP */
|
||||||
pushl $0 /* XXX: TempCS */
|
pushl $0 /* XXX: TempCS */
|
||||||
pushl $0 /* XXX: DebugPointer */
|
pushl $0 /* XXX: DebugPointer */
|
||||||
|
|
Loading…
Reference in a new issue