Commit in reactos/ntoskrnl on MAIN
Makefile+2-21.117 -> 1.118
dbg/kdb.c+641-61.18 -> 1.19
dbg/i386/kdb_help.S+76-341.1 -> 1.2
include/internal/i386/ke.h+6-61.5 -> 1.6
ke/i386/trap.s+29-81.18 -> 1.19
ke/catch.c+5-11.40 -> 1.41
+759-57
6 modified files

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

reactos/ntoskrnl
Makefile 1.117 -> 1.118
diff -u -r1.117 -r1.118
--- Makefile	8 Mar 2004 08:05:27 -0000	1.117
+++ Makefile	13 Mar 2004 18:21:56 -0000	1.118
@@ -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 @@
 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
 

reactos/ntoskrnl/dbg
kdb.c 1.18 -> 1.19
diff -u -r1.18 -r1.19
--- kdb.c	24 Feb 2004 21:25:40 -0000	1.18
+++ kdb.c	13 Mar 2004 18:21:56 -0000	1.19
@@ -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 @@
 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 @@
   {"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 @@
 {
   CHAR Key;
   PCH Orig = Buffer;
+  static UCHAR LastCommand[256] = "";
   
   KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
   
@@ -219,7 +275,19 @@
       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 @@
 		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 @@
     }
 }
 
+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 @@
   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 @@
 			  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);
+    }
 }

reactos/ntoskrnl/dbg/i386
kdb_help.S 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- kdb_help.S	10 Apr 2001 17:48:16 -0000	1.1
+++ kdb_help.S	13 Mar 2004 18:21:56 -0000	1.2
@@ -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 @@
 	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 @@
 	call	_KdbInternalEnter
 
 	/*
-	 * Pop the argument and destroy the trap frame
+	 * Pop the argument
+	 */
+	popl	%eax	
+
+	/*
+	 * Ignore unused portions of the trap frame.
 	 */
-	popl	%eax
-	addl	$KTRAP_FRAME_SIZE, %esp
+	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
+
+	/*
+	 * Restore registers including any that might have been changed
+	 * inside the debugger.
+	 */
+	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 */
 
 	/*
-	 * Restore registers
+	 * Record when we are in the debugger.
 	 */
-	popl	%ebx
-	popl	%esi
-	popl	%edi
+	decl	_KdbEntryCount
 
 	/*
-	 * Return
+	 * Return to the caller.
 	 */
-	popl	%ebp
-	ret
+	iret
 
 
 

reactos/ntoskrnl/include/internal/i386
ke.h 1.5 -> 1.6
diff -u -r1.5 -r1.6
--- ke.h	9 Mar 2004 21:49:53 -0000	1.5
+++ ke.h	13 Mar 2004 18:21:56 -0000	1.6
@@ -79,12 +79,12 @@
    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;

reactos/ntoskrnl/ke/i386
trap.s 1.18 -> 1.19
diff -u -r1.18 -r1.19
--- trap.s	27 Apr 2003 16:21:16 -0000	1.18
+++ trap.s	13 Mar 2004 18:21:57 -0000	1.19
@@ -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 @@
 	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 @@
 	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 */

reactos/ntoskrnl/ke
catch.c 1.40 -> 1.41
diff -u -r1.40 -r1.41
--- catch.c	6 Mar 2004 22:24:13 -0000	1.40
+++ catch.c	13 Mar 2004 18:21:57 -0000	1.41
@@ -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 @@
   else if (KdDebuggerEnabled && KdDebugState & KD_DEBUG_KDB)
     {
       Action = KdbEnterDebuggerException (ExceptionRecord, Context, Tf);
+      if (Action == kdContinue)
+	{
+	  return;
+	}
     }
 #endif /* KDBG */
   if (Action != kdHandleException)
CVSspam 0.2.8