Little KDB update ;-) If you have any problems and/or questions let me know. I hope...
authorGregor Anich <blight@blight.eu.org>
Sat, 5 Mar 2005 23:35:08 +0000 (23:35 +0000)
committerGregor Anich <blight@blight.eu.org>
Sat, 5 Mar 2005 23:35:08 +0000 (23:35 +0000)
svn path=/trunk/; revision=13841

24 files changed:
reactos/Makefile
reactos/drivers/input/keyboard/keyboard.c
reactos/media/drivers/etc/KDB.init [new file with mode: 0644]
reactos/ntoskrnl/Makefile
reactos/ntoskrnl/dbg/i386/i386-dis.c
reactos/ntoskrnl/dbg/i386/kdb_help.S
reactos/ntoskrnl/dbg/i386/longjmp.S [new file with mode: 0644]
reactos/ntoskrnl/dbg/i386/setjmp.S [new file with mode: 0644]
reactos/ntoskrnl/dbg/kdb.c
reactos/ntoskrnl/dbg/kdb.h
reactos/ntoskrnl/dbg/kdb_cli.c [new file with mode: 0644]
reactos/ntoskrnl/dbg/kdb_expr.c [new file with mode: 0644]
reactos/ntoskrnl/dbg/kdb_keyboard.c
reactos/ntoskrnl/dbg/kdb_serial.c
reactos/ntoskrnl/dbg/kdb_string.c [new file with mode: 0644]
reactos/ntoskrnl/dbg/kdb_symbols.c
reactos/ntoskrnl/include/internal/i386/ke.h
reactos/ntoskrnl/include/internal/kd.h
reactos/ntoskrnl/ke/catch.c
reactos/ntoskrnl/ke/i386/trap.s
reactos/ntoskrnl/ke/i386/tskswitch.S
reactos/ntoskrnl/ke/kthread.c
reactos/ntoskrnl/ke/main.c
reactos/ntoskrnl/ps/w32call.c

index a349d64..cb49026 100644 (file)
@@ -216,6 +216,8 @@ bootcd_install_before:
        $(CP) media/nls/l_intl.nls $(BOOTCD_DIR)/reactos/l_intl.nls
        $(HALFVERBOSEECHO) [COPY]    media/drivers/etc/services to $(BOOTCD_DIR)/reactos/services
        $(CP) media/drivers/etc/services $(BOOTCD_DIR)/reactos/services
+       $(HALFVERBOSEECHO) [COPY]    media/drivers/etc/KDB.init to $(BOOTCD_DIR)/reactos/KDB.init
+       $(CP) media/drivers/etc/KDB.init $(BOOTCD_DIR)/reactos/KDB.init
 
 bootcd_basic: bootcd_directory_layout bootcd_bootstrap_files bootcd_install_before
 
@@ -1043,6 +1045,8 @@ install_before:
        $(CP) media/nls/l_intl.nls $(INSTALL_DIR)/system32/casemap.nls
        $(HALFVERBOSEECHO) [INSTALL] media/drivers/etc/services to $(INSTALL_DIR)/system32/drivers/etc/services
        $(CP) media/drivers/etc/services $(INSTALL_DIR)/system32/drivers/etc/services
+       $(HALFVERBOSEECHO) [INSTALL] media/drivers/etc/KDB.init to $(INSTALL_DIR)/system32/drivers/etc/KDB.init
+       $(CP) media/drivers/etc/KDB.init $(INSTALL_DIR)/system32/drivers/etc/KDB.init
 
 .PHONY: install_clean install_dirs install_before
 
index d87d142..e30c58b 100644 (file)
@@ -38,6 +38,7 @@ static BYTE capsDown,numDown,scrollDown;
 static DWORD ctrlKeyState;
 static PKINTERRUPT KbdInterrupt;
 static KDPC KbdDpc;
+static PIO_WORKITEM KbdWorkItem = NULL;
 static BOOLEAN AlreadyOpened = FALSE;
 
 /*
@@ -407,6 +408,24 @@ static WORD ScanToVirtual(BYTE scanCode)
 }
 
 
+/*
+ * Debug request handler
+ */
+
+static VOID STDCALL
+KbdWorkItemRoutine(IN PDEVICE_OBJECT DeviceObject,
+                   IN PVOID Context)
+{
+   LONG Debug;
+
+   Debug = InterlockedExchange(&DoSystemDebug, -1);
+   if (Debug != -1)
+     {
+       KdSystemDebugControl(Debug);
+     }
+}
+
+
 /*
  * Keyboard IRQ handler
  */
@@ -419,14 +438,21 @@ KbdDpcRoutine(PKDPC Dpc,
 {
    PIRP Irp = (PIRP)SystemArgument2;
    PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)SystemArgument1;
-   
+
    if (SystemArgument1 == NULL && DoSystemDebug != -1)
      {
-       KdSystemDebugControl(DoSystemDebug);
-       DoSystemDebug = -1;
+       if (KbdWorkItem != NULL)
+         {
+           IoQueueWorkItem(KbdWorkItem, (PIO_WORKITEM_ROUTINE)KbdWorkItemRoutine, DelayedWorkQueue, NULL);
+         }
+       else
+         {
+           KdSystemDebugControl(DoSystemDebug);
+           DoSystemDebug = -1;
+         }
        return;
      }
-
+     
    CHECKPOINT;
    DPRINT("KbdDpcRoutine(DeviceObject %x, Irp %x)\n",
            DeviceObject,Irp);
@@ -436,6 +462,7 @@ KbdDpcRoutine(PKDPC Dpc,
    IoStartNextPacket(DeviceObject,FALSE);
 }
 
+
 static BOOLEAN STDCALL
 KeyboardHandler(PKINTERRUPT Interrupt,
                PVOID Context)
@@ -538,7 +565,7 @@ KeyboardHandler(PKINTERRUPT Interrupt,
    else if (InSysRq == TRUE && ScanToVirtual(thisKey) >= VK_A &&
            ScanToVirtual(thisKey) <= VK_Z && isDown)
      {
-       DoSystemDebug = ScanToVirtual(thisKey) - VK_A;
+       InterlockedExchange(&DoSystemDebug, ScanToVirtual(thisKey) - VK_A);
        KeInsertQueueDpc(&KbdDpc, NULL, NULL);
        return(TRUE);
      }
@@ -659,6 +686,11 @@ static int InitializeKeyboard(PDEVICE_OBJECT DeviceObject)
    KbdClearInput();
    KeyboardConnectInterrupt(DeviceObject);
    KeInitializeDpc(&KbdDpc,KbdDpcRoutine,NULL);
+   KbdWorkItem = IoAllocateWorkItem(DeviceObject);
+   if (KbdWorkItem == NULL)
+     {
+        DPRINT("Warning: Couldn't allocate work item!\n");
+     }
    return 0;
 }
 
diff --git a/reactos/media/drivers/etc/KDB.init b/reactos/media/drivers/etc/KDB.init
new file mode 100644 (file)
index 0000000..53a68e1
--- /dev/null
@@ -0,0 +1,15 @@
+# Example KDB.init file\r
+#\r
+# The disassembly flavor is set to "intel" (default is "at&t") and the\r
+#\r
+\r
+# Set the disassembly flavor to "intel" (default is "at&t")\r
+set syntax intel\r
+\r
+# Change the condition to enter KDB on INT3 to "always" (default is "kmode")\r
+set condition INT3 first always\r
+\r
+# This is a special command available only in the KDB.init file - it breaks into\r
+# KDB when it is interpreting the init file at startup.\r
+#break\r
+\r
index 9dc41bf..f9987f3 100644 (file)
@@ -25,14 +25,10 @@ LINKER_SCRIPT := ntoskrnl.lnk
 STRIP_FLAGS := -Wl,-s
 
 ifeq ($(KDBG), 1)
-OBJECTS_KDBG := dbg/kdb.o dbg/kdb_serial.o dbg/kdb_keyboard.o dbg/rdebug.o \
-                dbg/i386/kdb_help.o \
-               ../dk/w32/lib/libkjs.a dbg/i386/i386-dis.o
-CFLAGS_KDBG := -I../lib/kjs/include
+OBJECTS_KDBG := dbg/kdb.o dbg/kdb_cli.o dbg/kdb_expr.o dbg/kdb_keyboard.o \
+                dbg/kdb_serial.o dbg/kdb_string.o dbg/rdebug.o dbg/i386/kdb_help.o \
+                dbg/i386/i386-dis.o dbg/i386/longjmp.o dbg/i386/setjmp.o
 preall: all
-
-../dk/w32/lib/libkjs.a:
-       $(MAKE) -C ../lib/kjs
 else
 OBJECTS_KDBG :=
 endif
index 66bb380..95c5f4c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id:$
+/* $Id$
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -52,10 +52,10 @@ extern long MmSafeCopyFromUser(void *Dest, void *Src, unsigned long NumberOfByte
 
 
 int
-print_insn_i386_att (bfd_vma pc, struct disassemble_info *info);
+print_insn_i386 (bfd_vma pc, struct disassemble_info *info);
 
 int
-KdbPrintDisasm(void* Ignored, const char* fmt, ...)
+KdbpPrintDisasm(void* Ignored, const char* fmt, ...)
 {
   va_list ap;
   static char buffer[256];
@@ -69,46 +69,46 @@ KdbPrintDisasm(void* Ignored, const char* fmt, ...)
 }
 
 int
-KdbNopPrintDisasm(void* Ignored, const char* fmt, ...)
+KdbpNopPrintDisasm(void* Ignored, const char* fmt, ...)
 {
   return(0);
 }
 
 int static
-KdbReadMemory(unsigned int Addr, unsigned char* Data, unsigned int Length, 
-             struct disassemble_info * Ignored)
+KdbpReadMemory(unsigned int Addr, unsigned char* Data, unsigned int Length,
+              struct disassemble_info * Ignored)
 {
   return KdbpSafeReadMemory(Data, (void *)Addr, Length); /* 0 means no error */
 }
 
 void static
-KdbMemoryError(int Status, unsigned int Addr, 
-              struct disassemble_info * Ignored)
+KdbpMemoryError(int Status, unsigned int Addr,
+               struct disassemble_info * Ignored)
 {
 }
 
 void static
-KdbPrintAddressInCode(unsigned int Addr, struct disassemble_info * Ignored)
+KdbpPrintAddressInCode(unsigned int Addr, struct disassemble_info * Ignored)
 {
   if (!KdbSymPrintAddress((void*)Addr))
     {
-      DbgPrint("<0x%X>", Addr);
+      DbgPrint("<%08x>", Addr);
     }
 }
 
 void static
-KdbNopPrintAddress(unsigned int Addr, struct disassemble_info * Ignored)
+KdbpNopPrintAddress(unsigned int Addr, struct disassemble_info * Ignored)
 {
 }
 
 #include "dis-asm.h"
 
 long
-KdbGetInstLength(unsigned int Address)
+KdbpGetInstLength(unsigned int Address)
 {
   disassemble_info info;
 
-  info.fprintf_func = KdbNopPrintDisasm;
+  info.fprintf_func = KdbpNopPrintDisasm;
   info.stream = NULL;
   info.application_data = NULL;
   info.flavour = bfd_target_unknown_flavour;
@@ -116,9 +116,9 @@ KdbGetInstLength(unsigned int Address)
   info.mach = bfd_mach_i386_i386;
   info.insn_sets = 0;
   info.flags = 0;
-  info.read_memory_func = KdbReadMemory;
-  info.memory_error_func = KdbMemoryError;
-  info.print_address_func = KdbNopPrintAddress;
+  info.read_memory_func = KdbpReadMemory;
+  info.memory_error_func = KdbpMemoryError;
+  info.print_address_func = KdbpNopPrintAddress;
   info.symbol_at_address_func = NULL;
   info.buffer = NULL;
   info.buffer_vma = info.buffer_length = 0;
@@ -126,25 +126,25 @@ KdbGetInstLength(unsigned int Address)
   info.display_endian = BIG_ENDIAN_LITTLE;
   info.disassembler_options = NULL;
 
-  return(print_insn_i386_att(Address, &info));
+  return(print_insn_i386(Address, &info));
 }
 
 long
-KdbDisassemble(unsigned int Address)
+KdbpDisassemble(unsigned int Address, unsigned long IntelSyntax)
 {
   disassemble_info info;
 
-  info.fprintf_func = KdbPrintDisasm;
+  info.fprintf_func = KdbpPrintDisasm;
   info.stream = NULL;
   info.application_data = NULL;
   info.flavour = bfd_target_unknown_flavour;
   info.arch = bfd_arch_i386;
-  info.mach = bfd_mach_i386_i386;
+  info.mach = IntelSyntax ? bfd_mach_i386_i386_intel_syntax : bfd_mach_i386_i386;
   info.insn_sets = 0;
   info.flags = 0;
-  info.read_memory_func = KdbReadMemory;
-  info.memory_error_func = KdbMemoryError;
-  info.print_address_func = KdbPrintAddressInCode;
+  info.read_memory_func = KdbpReadMemory;
+  info.memory_error_func = KdbpMemoryError;
+  info.print_address_func = KdbpPrintAddressInCode;
   info.symbol_at_address_func = NULL;
   info.buffer = NULL;
   info.buffer_vma = info.buffer_length = 0;
@@ -152,7 +152,7 @@ KdbDisassemble(unsigned int Address)
   info.display_endian = BIG_ENDIAN_LITTLE;
   info.disassembler_options = NULL;
 
-  return(print_insn_i386_att(Address, &info));
+  return(print_insn_i386(Address, &info));
 }
 
 /* Print i386 instructions for GDB, the GNU debugger.
@@ -2113,7 +2113,7 @@ print_insn (pc, info)
 #else
   mode_64bit = 0;
   priv.orig_sizeflag = AFLAG | DFLAG;
-  intel_syntax = 0;
+  /*intel_syntax = 0;*/
 #endif
 
   if (intel_syntax)
index 2da6570..cda895a 100644 (file)
@@ -1,29 +1,19 @@
 #include <internal/ke.h>
 #include <internal/i386/segment.h>
 
-       .data
-_KdbEipTemp:
-       .int    0
+.text
 
-       .text
-.globl _KdbEnter       
+.globl _KdbEnter
 _KdbEnter:
-       /*
-        * Record when we are inside the debugger.
-        */
-       incl    _KdbEntryCount
-
-       /*
-        * Save the callers eip.
-        */
-       popl    _KdbEipTemp
-               
        /*
         * Set up a trap frame
         */
+                                /* Ss - space already reserved by return EIP */
+        pushl   %esp            /* Esp */
        pushfl                  /* Eflags */
        pushl   %cs             /* Cs */
-       pushl   _KdbEipTemp     /* Eip */
+       pushl   12(%esp)        /* Eip */
+       movl    %ss, 16(%esp)   /* Save Ss */
        pushl   $0              /* ErrorCode */
        pushl   %ebp            /* Ebp */
        pushl   %ebx            /* Ebx */
@@ -56,34 +46,35 @@ _KdbEnter:
        pushl   $0              /* TempEip */
        pushl   $0              /* TempCs */
        pushl   $0              /* DebugPointer */
-       pushl   $0              /* DebugArgMark */
-       pushl   _KdbEipTemp     /* DebugEip */
+       pushl   $3              /* DebugArgMark (Exception number) */
+       pushl   0x60(%esp)      /* DebugEip */
        pushl   %ebp            /* DebugEbp */
 
-       /*
-        * Push a pointer to the trap frame
-        */
-       pushl   %esp
-
        /*
         * Call KDB
         */
-       call    _KdbInternalEnter
+       movl    %esp, %eax
+       pushl   $1              /* FirstChance */
+       pushl   %eax            /* Push a pointer to the trap frame */
+       pushl   $0              /* Context */
+       pushl   $0              /* PreviousMode (KernelMode) */
+       pushl   $0              /* ExceptionRecord */
+       call    _KdbEnterDebuggerException
 
        /*
-        * Pop the argument
+        * Pop the arguments and unused portions of the trap frame:
+        *   DebugEbp
+        *   DebugEip
+        *   DebugArgMark
+        *   DebugPointer
+        *   TempCs
+        *   TempEip
         */
-       popl    %eax    
+       addl    $(11*4), %esp
 
        /*
-        * Ignore unused portions of the trap frame.
+        * Restore/update debugging registers.
         */
-       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 */
@@ -113,13 +104,17 @@ _KdbEnter:
        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
+        /* Remove SS:ESP from the stack */
+        movl    16(%esp), %ebp
+        movl    %ebp, 24(%esp)
+        movl    12(%esp), %ebp
+        movl    %ebp, 20(%esp)
+        movl    8(%esp), %ebp
+        movl    %ebp, 16(%esp)
+        
+       popl    %ebp            /* Ebp */
+       addl    $12, %esp       /* ErrorCode and SS:ESP */
 
        /*
         * Return to the caller.
@@ -127,5 +122,26 @@ _KdbEnter:
        iret
 
 
+.globl _KdbpStackSwitchAndCall@8
+_KdbpStackSwitchAndCall@8:
+        pushl   %ebp
+        movl    %esp, %ebp
+        
+        movl    0x8(%esp), %eax         /* New stack */
+        movl    0xC(%esp), %ecx         /* Function to call */
+        movl    %esp, %edx              /* Old stack */
+
+        /* Switch stack */
+        movl    %eax, %esp
+        pushl   %edx
+
+        /* Call function */
+        call    *%ecx
+
+        /* Switch back to old stack */
+        popl    %esp
+
+        /* Return */
+        popl    %ebp
+        ret     $8
 
-       
diff --git a/reactos/ntoskrnl/dbg/i386/longjmp.S b/reactos/ntoskrnl/dbg/i386/longjmp.S
new file mode 100644 (file)
index 0000000..1edbaaf
--- /dev/null
@@ -0,0 +1,70 @@
+        .file   "longjmp.S"\r
+/*\r
+ * Copyright (C) 1998, 1999, Jonathan S. Shapiro.\r
+ *\r
+ * This file is part of the EROS Operating System.\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2,\r
+ * or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+        /*\r
+         * typedef struct {\r
+         *  unsigned long ebx, esi, edi;\r
+         *  unsigned long ebp;\r
+         *  unsigned long sp;\r
+         *  unsigned long pc;\r
+         * } jmp_buf[1];\r
+         */\r
+        \r
+        /*\r
+         * On entry, the stack to longjmp looks like:\r
+         *\r
+         *     value\r
+         *     ptr to jmp_buf\r
+         *     return PC\r
+         */\r
+\r
+.globl _longjmp\r
+_longjmp:\r
+        pushl   %ebp\r
+        movl    %esp,%ebp\r
+\r
+        movl    8(%ebp),%ecx            /* address of jmp_buf to ecx */\r
+        movl    12(%ebp),%eax           /* return value to %eax */\r
+        testl   %eax,%eax\r
+        jne     1f\r
+        incl    %eax                    /* return 1 if handed 0 */\r
+\r
+1:      \r
+        movl    (%ecx),%ebx             /* restore %ebx */\r
+        movl    4(%ecx),%esi            /* restore %esi */\r
+        movl    8(%ecx),%edi            /* restore %edi */\r
+        \r
+        /*\r
+         * From this instant on we are not running in a valid frame\r
+         */\r
+        \r
+        movl    12(%ecx),%ebp           /* restore %ebp */\r
+        movl    16(%ecx),%esp           /* restore %esp */\r
+        /* movl 20(%ecx),%eax           return PC */\r
+\r
+        /*\r
+         * Since we are abandoning the stack in any case, \r
+         * there isn't much point in doing the usual return \r
+         * discipline.\r
+         */\r
+        \r
+        jmpl    *20(%ecx)\r
+       \r
diff --git a/reactos/ntoskrnl/dbg/i386/setjmp.S b/reactos/ntoskrnl/dbg/i386/setjmp.S
new file mode 100644 (file)
index 0000000..d53e059
--- /dev/null
@@ -0,0 +1,59 @@
+        .file   "setjmp.S"\r
+/*\r
+ * Copyright (C) 1998, 1999, Jonathan S. Shapiro.\r
+ *\r
+ * This file is part of the EROS Operating System.\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2,\r
+ * or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+/* #include <eros/i486/asm.h> */\r
+        \r
+        \r
+        /*\r
+         * typedef struct {\r
+         *  unsigned long ebx, esi, edi;\r
+         *  unsigned long ebp;\r
+         *  unsigned long sp;\r
+         *  unsigned long pc;\r
+         * } jmp_buf[1];\r
+         */\r
+        \r
+        /*\r
+         * On entry, the stack to setjmp looks like:\r
+         *\r
+         *     ptr to jmp_buf\r
+         *     return PC\r
+         */\r
+.globl _setjmp\r
+_setjmp:       \r
+        pushl   %ebp\r
+        movl    %esp,%ebp\r
+        \r
+        movl    0x8(%ebp),%eax          /* address of jmp_buf to eax */\r
+        movl    %ebx,(%eax)             /* save %ebx */\r
+        movl    %esi,4(%eax)            /* save %esi */\r
+        movl    %edi,8(%eax)            /* save %edi */\r
+        leal    8(%ebp),%edx            /* calling proc's esp, not ours! */\r
+        movl    %edx,16(%eax)\r
+        movl    4(%ebp), %edx           /* save return PC */\r
+        movl    %edx,20(%eax)\r
+        movl    0(%ebp),%edx            /* calling proc's ebp, not ours! */\r
+        movl    %edx,12(%eax)\r
+\r
+        xorl    %eax,%eax               /* return 0 the first time */\r
+        leave\r
+        ret    $4\r
+\r
index fa97e88..910905c 100644 (file)
 
 #include <ntoskrnl.h>
 #include "kdb.h"
-#include "kjs.h"
 #define NDEBUG
 #include <internal/debug.h>
 
 /* TYPES *********************************************************************/
 
-/* GLOBALS *******************************************************************/
-
-#define BS 8
-#define DEL 127
-
-BOOL KbdEchoOn = TRUE;
-
-typedef struct
-{
-  BOOLEAN Enabled;
-  BOOLEAN Temporary;
-  BOOLEAN Assigned;
-  ULONG Address;
-  UCHAR SavedInst;
-} KDB_ACTIVE_BREAKPOINT;
+/* DEFINES *******************************************************************/
 
-#define KDB_MAXIMUM_BREAKPOINT_COUNT (255)
+#define KDB_STACK_SIZE                   (4096*3)
+#define KDB_MAXIMUM_BREAKPOINT_COUNT     256
+#define KDB_MAXIMUM_HW_BREAKPOINT_COUNT  4
+#define KDB_MAXIMUM_SW_BREAKPOINT_COUNT  256
 
-static ULONG KdbBreakPointCount = 0;
-static KDB_ACTIVE_BREAKPOINT 
- KdbActiveBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT];
+#define __STRING(x) #x
+#define _STRING(x) __STRING(x)
 
-static BOOLEAN KdbHandleUmode = FALSE;
-static BOOLEAN KdbHandleHandled = FALSE;
-static BOOLEAN KdbBreakOnModuleLoad = FALSE;
-
-static BOOLEAN KdbIgnoreNextSingleStep = FALSE;
-static ULONG KdbLastSingleStepFrom = 0xFFFFFFFF;
-static BOOLEAN KdbEnteredOnSingleStep = FALSE;
-
-ULONG KdbEntryCount = 0;
+/* GLOBALS *******************************************************************/
 
-int isalpha( int );
-VOID
-PsDumpThreads(BOOLEAN System);
-ULONG 
-DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG 
-DbgStopCondition(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgModuleLoadedAction(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG 
-DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG 
-DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG 
-DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG 
-DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgAddrCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgXCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgScriptCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgThreadListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-ULONG
-DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-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
+STATIC LONG KdbEntryCount = 0;
+STATIC CHAR KdbStack[KDB_STACK_SIZE];
+
+STATIC ULONG KdbBreakPointCount = 0;  /* Number of used breakpoints in the array */
+STATIC KDB_BREAKPOINT KdbBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT] = {{0}};  /* Breakpoint array */
+STATIC ULONG KdbSwBreakPointCount = 0;  /* Number of enabled software breakpoints */
+STATIC ULONG KdbHwBreakPointCount = 0;  /* Number of enabled hardware breakpoints */
+STATIC PKDB_BREAKPOINT KdbSwBreakPoints[KDB_MAXIMUM_SW_BREAKPOINT_COUNT]; /* Enabled software breakpoints, orderless */
+STATIC PKDB_BREAKPOINT KdbHwBreakPoints[KDB_MAXIMUM_HW_BREAKPOINT_COUNT]; /* Enabled hardware breakpoints, orderless */
+STATIC PKDB_BREAKPOINT KdbBreakPointToReenable = NULL; /* Set to a breakpoint struct when single stepping after
+                                                          a software breakpoint was hit, to reenable it */
+LONG KdbLastBreakPointNr = -1;  /* Index of the breakpoint which cause KDB to be entered */
+ULONG KdbNumSingleSteps = 0; /* How many single steps to do */
+BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */
+
+STATIC BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered because of single step */
+PEPROCESS KdbCurrentProcess = NULL;  /* The current process context in which KDB runs */
+PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered */
+PETHREAD KdbCurrentThread = NULL;  /* The current thread context in which KDB runs */
+PETHREAD KdbOriginalThread = NULL; /* The thread in whichs context KDB was entered */
+PKDB_KTRAP_FRAME KdbCurrentTrapFrame = NULL; /* Pointer to the current trapframe */
+STATIC KDB_KTRAP_FRAME KdbTrapFrame = { { 0 } };  /* The trapframe which was passed to KdbEnterDebuggerException */
+STATIC KDB_KTRAP_FRAME KdbThreadTrapFrame = { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */
+STATIC KAPC_STATE KdbApcState;
+
+/* Array of conditions when to enter KDB */
+STATIC KDB_ENTER_CONDITION KdbEnterConditions[][2] =
 {
-  PCH Name;
-  PCH Syntax;
-  PCH Help;
-  ULONG (*Fn)(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
-} DebuggerCommands[] = {
-  {"cont", "cont", "Exit the debugger", DbgContCommand},
-  {"echo", "echo", "Toggle serial echo", DbgEchoToggle},
-  {"condition", "condition [all|umode|kmode]", "Kdbg enter condition", DbgStopCondition},
-  {"module-loaded", "module-loaded [break|continue]", "Module-loaded action", DbgModuleLoadedAction},
-
-  {"regs", "regs", "Display general purpose registers", DbgRegsCommand},
-  {"dregs", "dregs", "Display debug registers", DbgDRegsCommand},
-  {"cregs", "cregs", "Display control registers", DbgCRegsCommand},
-  {"bugcheck", "bugcheck", "Bugcheck the system", DbgBugCheckCommand},
-  {"bt", "bt [*frame-address]|[thread-id]","Do a backtrace", DbgBackTraceCommand},
-  {"addr", "addr <address>", "Displays symbol info", DbgAddrCommand},
-  {"x", "x <addr> <words>", "Displays <addr> for <words>", DbgXCommand},
-  {"plist", "plist", "Display processes in the system", DbgProcessListCommand},
-  {"tlist", "tlist [sys]", "Display threads in the system", DbgThreadListCommand},
-  {"sfiles", "sfiles", "Show files that print debug prints", DbgShowFilesCommand},
-  {"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}
+   /* First chance       Last chance */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* Zero devide */
+   { KdbEnterAlways,     KdbDoNotEnter },       /* Debug trap */
+   { KdbDoNotEnter,      KdbEnterAlways },      /* NMI */
+   { KdbEnterFromKmode,  KdbDoNotEnter },       /* INT3 */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* Overflow */
+   { KdbDoNotEnter,      KdbEnterFromKmode },
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* Invalid opcode */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* No math coprocessor fault */
+   { KdbEnterAlways,     KdbEnterAlways },
+   { KdbEnterAlways,     KdbEnterAlways },
+   { KdbDoNotEnter,      KdbEnterFromKmode },
+   { KdbDoNotEnter,      KdbEnterFromKmode },
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* Stack fault */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* General protection fault */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* Page fault */
+   { KdbEnterAlways,     KdbEnterAlways },      /* Reserved (15) */
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* FPU fault */
+   { KdbDoNotEnter,      KdbEnterFromKmode },
+   { KdbDoNotEnter,      KdbEnterFromKmode },
+   { KdbDoNotEnter,      KdbEnterFromKmode },   /* SIMD fault */
+   { KdbDoNotEnter,      KdbEnterFromKmode }    /* Last entry: used for unknown exceptions */
 };
 
-static const char *ExceptionTypeStrings[] =
-  {
-    "Divide Error",
-    "Debug Trap",
-    "NMI",
-    "Breakpoint",
-    "Overflow",
-    "BOUND range exceeded",
-    "Invalid Opcode",
-    "No Math Coprocessor",
-    "Double Fault",
-    "Unknown(9)",
-    "Invalid TSS",
-    "Segment Not Present",
-    "Stack Segment Fault",
-    "General Protection",
-    "Page Fault",
-    "Reserved(15)",
-    "Math Fault",
-    "Alignment Check",
-    "Machine Check",
-    "SIMD Fault"
-  };
-
-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);
+/* Exception descriptions */
+STATIC CONST PCHAR ExceptionNrToString[] =
+{
+   "Divide Error",
+   "Debug Trap",
+   "NMI",
+   "Breakpoint",
+   "Overflow",
+   "BOUND range exceeded",
+   "Invalid Opcode",
+   "No Math Coprocessor",
+   "Double Fault",
+   "Unknown(9)",
+   "Invalid TSS",
+   "Segment Not Present",
+   "Stack Segment Fault",
+   "General Protection",
+   "Page Fault",
+   "Reserved(15)",
+   "Math Fault",
+   "Alignment Check",
+   "Machine Check",
+   "SIMD Fault"
+};
 
 /* FUNCTIONS *****************************************************************/
 
-/*
- * Convert a string to an unsigned long integer.
+/*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
+ *        the old instruction in *OldInst.
+ *
+ * \param Process  Process in which's context to overwrite the instruction.
+ * \param Address  Address at which to overwrite the instruction.
+ * \param NewInst  New instruction (written to \a Address)
+ * \param OldInst  Old instruction (read from \a Address)
  *
- * Ignores `locale' stuff.  Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
+ * \returns NTSTATUS
  */
-unsigned long
-strtoul(const char *nptr, char **endptr, int base)
+STATIC NTSTATUS
+KdbpOverwriteInstruction(
+   IN  PEPROCESS Process,
+   IN  ULONG_PTR Address,
+   IN  UCHAR NewInst,
+   OUT PUCHAR OldInst  OPTIONAL)
 {
-  const char *s = nptr;
-  unsigned long acc;
-  int c;
-  unsigned long cutoff;
-  int neg = 0, any, cutlim;
-
-  /*
-   * See strtol for comments as to the logic used.
-   */
-  do {
-    c = *s++;
-  } while (isspace(c));
-  if (c == '-')
-  {
-    neg = 1;
-    c = *s++;
-  }
-  else if (c == '+')
-    c = *s++;
-  if ((base == 0 || base == 16) &&
-      c == '0' && (*s == 'x' || *s == 'X'))
-  {
-    c = s[1];
-    s += 2;
-    base = 16;
-  }
-  if (base == 0)
-    base = c == '0' ? 8 : 10;
-  cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
-  cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
-  for (acc = 0, any = 0;; c = *s++)
-  {
-    if (isdigit(c))
-      c -= '0';
-    else if (isalpha(c))
-      c -= isupper(c) ? 'A' - 10 : 'a' - 10;
-    else
-      break;
-    if (c >= base)
-      break;
-    if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
-      any = -1;
-    else {
-      any = 1;
-      acc *= base;
-      acc += c;
-    }
-  }
-  if (any < 0)
-  {
-    acc = ULONG_MAX;
-  }
-  else if (neg)
-    acc = -acc;
-  if (endptr != 0)
-    *endptr = any ? (char *)s - 1 : (char *)nptr;
-  return acc;
-}
+   NTSTATUS Status;
+   ULONG Protect;
+   PEPROCESS CurrentProcess = PsGetCurrentProcess();
+   KAPC_STATE ApcState;
 
+   /* Get the protection for the address. */
+   Protect = MmGetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address));
+   
+   /* Return if that page isn't present. */
+   if (Protect & PAGE_NOACCESS)
+   {
+      return STATUS_MEMORY_NOT_ALLOCATED;
+   }
+   
+   /* Attach to the process */
+   if (CurrentProcess != Process)
+   {
+      KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process), &ApcState);
+   }
+
+   /* Make the page writeable if it is read only. */
+   if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
+   {
+      MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address),
+                      (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE);
+   }
+   
+   /* Copy the old instruction back to the caller. */
+   if (OldInst != NULL)
+   {
+      Status = KdbpSafeReadMemory(OldInst, (PUCHAR)Address, 1);
+      if (!NT_SUCCESS(Status))
+      {
+         if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
+         {
+            MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect);
+         }
+         /* Detach from process */
+         if (CurrentProcess != Process)
+         {
+            KeDetachProcess();
+         }
+        return Status;
+      }
+   }
+   
+   /* Copy the new instruction in its place. */
+   Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1);
+   
+   /* Restore the page protection. */
+   if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
+   {
+      MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect);
+   }
+   
+   /* Detach from process */
+   if (CurrentProcess != Process)
+   {
+      KeUnstackDetachProcess(&ApcState);
+   }
 
-char*
-strpbrk(const char* s, const char* accept)
-{
-  int i;
-  for (; (*s) != 0; s++)
-    {
-      for (i = 0; accept[i] != 0; i++)
-       {
-         if (accept[i] == (*s))
-           {
-             return((char *)s);
-           }
-       }
-    }
-  return(NULL);
+   return Status;
 }
 
-
-#if 0
-NTSTATUS
-KdbpSafeReadMemory(PVOID dst, PVOID src, INT size)
+/*!\brief Checks whether the given instruction can be single stepped or has to be
+ *        stepped over using a temporary breakpoint.
+ *
+ * \retval TRUE   Instruction is a call.
+ * \retval FALSE  Instruction is not a call.
+ */
+BOOLEAN
+KdbpShouldStepOverInstruction(ULONG_PTR Eip)
 {
-  INT page, page_end;
-  
-  /* check source */
-  page_end = (((ULONG_PTR)src + size) / PAGE_SIZE);
-  for (page = ((ULONG_PTR)src / PAGE_SIZE); page <= page_end; page++)
-  {
-    if (!MmIsPagePresent(NULL, (PVOID)(page * PAGE_SIZE)))
-      return STATUS_UNSUCCESSFUL;
-  }
+   UCHAR Mem[3];
+   INT i = 0;
 
-  /* copy memory */
-  RtlCopyMemory(dst, src, size);
-  return STATUS_SUCCESS;
-}
+   if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
+   {
+      KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Eip);
+      return FALSE;
+   }
 
+   /* Check if the current instruction is a call. */
+   while ((i < sizeof (Mem)) && (Mem[i] == 0x66 || Mem[i] == 0x67))
+      i++;
+   if (i == sizeof (Mem))
+      return FALSE;
+   if (Mem[i] == 0xE8 || Mem[i] == 0x9A || Mem[i] == 0xF2 || Mem[i] == 0xF3 ||
+       (((i + 1) < sizeof (Mem)) && Mem[i] == 0xFF && (Mem[i+1] & 0x38) == 0x10))
+   {
+      return TRUE;
+   }
+   return FALSE;
+}
 
-NTSTATUS
-KdbpSafeWriteMemory(PVOID dst, PVOID src, INT size)
+/*!\brief Steps over an instruction
+ *
+ * If the given instruction should be stepped over, this function inserts a
+ * temporary breakpoint after the instruction and returns TRUE, otherwise it
+ * returns FALSE.
+ *
+ * \retval TRUE   Temporary breakpoint set after instruction.
+ * \retval FALSE  No breakpoint was set.
+ */
+BOOLEAN
+KdbpStepOverInstruction(ULONG_PTR Eip)
 {
-  return KdbpSafeWriteMemory(dst, src, size);
-  INT page, page_end;
-
-  /* check destination */
-  page_end = (((ULONG_PTR)dst + size) / PAGE_SIZE);
-  for (page = ((ULONG_PTR)dst / PAGE_SIZE); page <= page_end; page++)
-  {
-    if (!MmIsPagePresent(NULL, (PVOID)(page * PAGE_SIZE)))
-      return STATUS_UNSUCCESSFUL;
-  }
+   LONG InstLen;
 
-  /* copy memory */
-  RtlCopyMemory(dst, src, size);
-  return STATUS_SUCCESS;
-}
-#endif /* unused */
+   if (!KdbpShouldStepOverInstruction(Eip))
+      return FALSE;
 
+   InstLen = KdbpGetInstLength(Eip);
+   if (InstLen < 1)
+      return FALSE;
 
-VOID
-KdbGetCommand(PCH Buffer)
-{
-  CHAR Key;
-  PCH Orig = Buffer;
-  static CHAR LastCommand[256] = "";
-  ULONG ScanCode = 0;
-  static CHAR LastKey = '\0';
-  
-  KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
-  
-  for (;;)
-    {
-      if (KdDebugState & KD_DEBUG_KDSERIAL)
-       while ((Key = KdbTryGetCharSerial()) == -1);
-      else
-       while ((Key = KdbTryGetCharKeyboard(&ScanCode)) == -1);
-
-      if (Key == '\n' && LastKey == '\r')
-        {
-          /* Ignore this key... */
-        }
-      else if (Key == '\r' || Key == '\n')
-       {
-         DbgPrint("\n");
-         /*
-           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);
-           }
-         LastKey = Key;
-         return;
-       }
-      else if (Key == BS || Key == DEL)
-        {
-          if (Buffer > Orig)
-            {
-              Buffer--;
-              *Buffer = 0;
-             if (KbdEchoOn)
-               DbgPrint("%c %c", BS, BS);
-             else
-               DbgPrint(" %c", BS);
-           }
-        }
-      else if (ScanCode == 72)
-       {
-         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)
-           DbgPrint("%c", Key);
-
-          *Buffer = Key;
-          Buffer++;
-        }
-      LastKey = Key;
-    }
+   if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip + InstLen, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL)))
+      return FALSE;
+
+   return TRUE;
 }
 
-BOOLEAN STATIC
-KdbDecodeAddress(PCHAR Buffer, PULONG Address)
+/*!\brief Steps into an instruction (interrupts)
+ *
+ * If the given instruction should be stepped into, this function inserts a
+ * temporary breakpoint at the target instruction and returns TRUE, otherwise it
+ * returns FALSE.
+ *
+ * \retval TRUE   Temporary breakpoint set at target instruction.
+ * \retval FALSE  No breakpoint was set.
+ */
+BOOLEAN
+KdbpStepIntoInstruction(ULONG_PTR Eip)
 {
-  while (isspace(*Buffer))
-    {
-      Buffer++;
-    }
-  if (Buffer[0] == '<')
-    {
-      PCHAR ModuleName = Buffer + 1;
-      PCHAR AddressString = strpbrk(Buffer, ":");
-      extern LIST_ENTRY ModuleTextListHead;
-      PLIST_ENTRY current_entry;
-      MODULE_TEXT_SECTION* current = NULL;
-      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;
+   struct __attribute__((packed)) {
+      USHORT Limit;
+      ULONG Base;
+   } Idtr;
+   UCHAR Mem[2];
+   INT IntVect;
+   ULONG IntDesc[2];
+   ULONG_PTR TargetEip;
+
+   /* Read memory */
+   if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
+   {
+      /*KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Eip);*/
+      return FALSE;
+   }
+
+   /* Check for INT instruction */
+   /* FIXME: Check for iret */
+   if (Mem[0] == 0xcc)
+      IntVect = 3;
+   else if (Mem[0] == 0xcd)
+      IntVect = Mem[1];
+   else if (Mem[0] == 0xce && KdbCurrentTrapFrame->Tf.Eflags & (1<<11)) /* 1 << 11 is the overflow flag */
+      IntVect = 4;
+   else
+      return FALSE;
+
+   if (IntVect < 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
+   {
+      return FALSE;
+   }
+
+   /* Read the interrupt descriptor table register  */
+   asm volatile("sidt %0" : : "m"(Idtr));
+   if (IntVect >= (Idtr.Limit + 1) / 8)
+   {
+      /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
+      return TRUE;
+   }
+
+   /* Get the interrupt descriptor */
+   if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc, (PVOID)(Idtr.Base + (IntVect * 8)), sizeof (IntDesc))))
+   {
+      /*KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Idtr.Base + (IntVect * 8));*/
+      return FALSE;
+   }
    
-      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);
-    }
+   /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
+   if ((IntDesc[1] & (1 << 15)) == 0) /* not present */
+   {
+      return FALSE;
+   }
+   if ((IntDesc[1] & 0x1f00) == 0x0500) /* Task gate */
+   {
+      /* FIXME: Task gates not supported */
+      return FALSE;
+   }
+   else if (((IntDesc[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
+            ((IntDesc[1] & 0x1fe0) == 0x0f00))   /* 32 bit Trap gate */
+   {
+      /* FIXME: Should the segment selector of the interrupt gate be checked? */
+      TargetEip = (IntDesc[1] & 0xffff0000) | (IntDesc[0] & 0x0000ffff);
+   }
+   else
+   {
+      return FALSE;
+   }
+
+   /* Insert breakpoint */
+   if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL)))
+      return FALSE;
+
+   return TRUE;
 }
 
-NTSTATUS STATIC
-KdbOverwriteInst(ULONG Address, PUCHAR PreviousInst, UCHAR NewInst)
+/*!\brief Gets the number of the next breakpoint >= Start.
+ *
+ * \param Start   Breakpoint number to start searching at. -1 if no more breakpoints are found.
+ *
+ * \returns Breakpoint number (-1 if no more breakpoints are found)
+ */
+LONG
+KdbpGetNextBreakPointNr(
+   IN ULONG Start  OPTIONAL)
 {
-  NTSTATUS Status;
-  ULONG Protect;
-  /* Get the protection for the address. */
-  Protect = MmGetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
-  /* Return if that page isn't present. */
-  if (Protect & PAGE_NOACCESS)
-    {
-      return(STATUS_MEMORY_NOT_ALLOCATED);
-    }
-  if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
-    {
-      MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address), 
-                      (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE);
-    }
-  /* Copy the old instruction back to the caller. */
-  if (PreviousInst != NULL)
-    {
-      Status = KdbpSafeReadMemory(PreviousInst, (PUCHAR)Address, 1);
-      if (!NT_SUCCESS(Status))
-           {
-          if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
-            {
-              MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address), Protect);
-            }
-             return(Status);
-           }
-    }
-  /* Copy the new instruction in its place. */
-  Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1);
-  if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
-    {
-      MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address), Protect);
-    }
-  return Status;
+   for (; Start < RTL_NUMBER_OF(KdbBreakPoints); Start++)
+   {
+      if (KdbBreakPoints[Start].Type != KdbBreakPointNone)
+         return Start;
+   }
+   return -1;
 }
 
-
-VOID STATIC
-KdbRenableBreakPoints(VOID)
+/*!\brief Returns information of the specified breakpoint.
+ *
+ * \param BreakPointNr         Number of the breakpoint to return information of.
+ * \param Address              Receives the address of the breakpoint.
+ * \param Type                 Receives the type of the breakpoint (hardware or software)
+ * \param Size                 Size - for memory breakpoints.
+ * \param AccessType           Access type - for hardware breakpoints.
+ * \param DebugReg             Debug register - for enabled hardware breakpoints.
+ * \param Enabled              Whether the breakpoint is enabled or not.
+ * \param Process              The owning process of the breakpoint.
+ * \param ConditionExpression  The expression which was given as condition for the bp.
+ *
+ * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
+ */
+BOOLEAN
+KdbpGetBreakPointInfo(
+   IN  ULONG BreakPointNr,
+   OUT ULONG_PTR *Address  OPTIONAL,
+   OUT KDB_BREAKPOINT_TYPE *Type  OPTIONAL,
+   OUT UCHAR *Size  OPTIONAL,
+   OUT KDB_ACCESS_TYPE *AccessType  OPTIONAL,
+   OUT UCHAR *DebugReg  OPTIONAL,
+   OUT BOOLEAN *Enabled  OPTIONAL,
+   OUT BOOLEAN *Global  OPTIONAL,
+   OUT PEPROCESS *Process  OPTIONAL,
+   OUT PCHAR *ConditionExpression  OPTIONAL)
 {
-  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);
-       }
-    }
-}
+   PKDB_BREAKPOINT bp;
 
-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);
+   if (BreakPointNr >= RTL_NUMBER_OF(KdbBreakPoints) ||
+       KdbBreakPoints[BreakPointNr].Type == KdbBreakPointNone)
+   {
+      return FALSE;
+   }
+   
+   bp = KdbBreakPoints + BreakPointNr;
+   if (Address != NULL)
+      *Address = bp->Address;
+   if (Type != NULL)
+      *Type = bp->Type;
+   if (bp->Type == KdbBreakPointHardware)
+   {
+      if (Size != NULL)
+         *Size = bp->Data.Hw.Size;
+      if (AccessType != NULL)
+         *AccessType = bp->Data.Hw.AccessType;
+      if (DebugReg != NULL && bp->Enabled)
+         *DebugReg = bp->Data.Hw.DebugReg;
+   }
+   if (Enabled != NULL)
+      *Enabled = bp->Enabled;
+   if (Global != NULL)
+      *Global = bp->Global;
+   if (Process != NULL)
+      *Process = bp->Process;
+   if (ConditionExpression != NULL)
+      *ConditionExpression = bp->ConditionExpression;
+
+   return TRUE;
 }
 
-VOID STATIC
-KdbDeleteBreakPoint(ULONG BreakPointNr)
+/*!\brief Inserts a breakpoint into the breakpoint array.
+ *
+ * The \a Process of the breakpoint is set to \a KdbCurrentProcess
+ *
+ * \param Address              Address at which to set the breakpoint.
+ * \param Type                 Type of breakpoint (hardware or software)
+ * \param Size                 Size of breakpoint (for hardware/memory breakpoints)
+ * \param AccessType           Access type (for hardware breakpoins)
+ * \param ConditionExpression  Expression which must evaluate to true for conditional breakpoints.
+ * \param Global               Wether the breakpoint is global or local to a process.
+ * \param BreakPointNumber     Receives the breakpoint number on success
+ *
+ * \returns NTSTATUS
+ */
+NTSTATUS
+KdbpInsertBreakPoint(
+   IN  ULONG_PTR Address,
+   IN  KDB_BREAKPOINT_TYPE Type,
+   IN  UCHAR Size  OPTIONAL,
+   IN  KDB_ACCESS_TYPE AccessType  OPTIONAL,
+   IN  PCHAR ConditionExpression  OPTIONAL,
+   IN  BOOLEAN Global,
+   OUT PULONG BreakPointNumber  OPTIONAL)
 {
-  KdbBreakPointCount--;
-  KdbActiveBreakPoints[BreakPointNr].Assigned = FALSE;
-}
+   LONG i;
+   PVOID Condition;
+   PCHAR ConditionExpressionDup;
+   LONG ErrOffset;
+   CHAR ErrMsg[128];
 
-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);
-}
+   ASSERT(Type != KdbBreakPointNone);
 
-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);
-}
+   if (Type == KdbBreakPointHardware)
+   {
+      if ((Address % Size) != 0)
+      {
+         KdbpPrint("Address (0x%x) must be aligned to a multiple of the size (%d)\n", Address, Size);
+         return STATUS_UNSUCCESSFUL;
+      }
+      if (AccessType == KdbAccessExec && Size != 1)
+      {
+         KdbpPrint("Size must be 1 for execution breakpoints.\n");
+         return STATUS_UNSUCCESSFUL;
+      }
+   }
 
-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);
-}
+   if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT)
+   {
+      return STATUS_UNSUCCESSFUL;
+   }
+   
+   /* Parse conditon expression string and duplicate it */
+   if (ConditionExpression != NULL)
+   {
+      Condition = KdbpRpnParseExpression(ConditionExpression, &ErrOffset, ErrMsg);
+      if (Condition == NULL)
+      {
+         if (ErrOffset >= 0)
+            KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg, ErrOffset);
+         else
+            KdbpPrint("Couldn't parse expression: %s", ErrMsg);
+         return STATUS_UNSUCCESSFUL;
+      }
 
-ULONG
-DbgSetMemoryBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  ULONG DebugRegNr;
-  UCHAR BreakType;
-  ULONG Length, Address;
-  ULONG Rw = 0;
-  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);
-}
+      i = strlen(ConditionExpression) + 1;
+      ConditionExpressionDup = ExAllocatePoolWithTag(NonPagedPool, i, TAG_KDBG);
+      RtlCopyMemory(ConditionExpressionDup, ConditionExpression, i);
+
+   }
+   else
+   {
+      Condition = NULL;
+      ConditionExpressionDup = NULL;
+   }
+
+   /* Find unused breakpoint */
+   if (Type == KdbBreakPointTemporary)
+   {
+      for (i = RTL_NUMBER_OF(KdbBreakPoints) - 1; i >= 0; i--)
+      {
+         if (KdbBreakPoints[i].Type == KdbBreakPointNone)
+            break;
+      }
+   }
+   else
+   {
+      for (i = 0; i < RTL_NUMBER_OF(KdbBreakPoints); i++)
+      {
+         if (KdbBreakPoints[i].Type == KdbBreakPointNone)
+            break;
+      }
+   }
+   ASSERT(i < RTL_NUMBER_OF(KdbBreakPoints));
+   
+   /* Set the breakpoint */
+   ASSERT(KdbCurrentProcess != NULL);
+   KdbBreakPoints[i].Type = Type;
+   KdbBreakPoints[i].Address = Address;
+   KdbBreakPoints[i].Enabled = FALSE;
+   KdbBreakPoints[i].Global = Global;
+   KdbBreakPoints[i].Process = KdbCurrentProcess;
+   KdbBreakPoints[i].ConditionExpression = ConditionExpressionDup;
+   KdbBreakPoints[i].Condition = Condition;
+   if (Type == KdbBreakPointHardware)
+   {
+
+      KdbBreakPoints[i].Data.Hw.Size = Size;
+      KdbBreakPoints[i].Data.Hw.AccessType = AccessType;
+   }
+   KdbBreakPointCount++;
+   
+   if (Type != KdbBreakPointTemporary)
+      KdbpPrint("Breakpoint %d inserted.\n", i);
 
-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);
-}
+   /* Try to enable the breakpoint */
+   KdbpEnableBreakPoint(i, NULL);
 
-ULONG
-DbgStepOver(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  PUCHAR Eip;
-  UCHAR Mem[3];
-
-  if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Tf->Eip, sizeof (Mem))))
-    {
-      DbgPrint("Couldn't access memory at 0x%x\n", (UINT)Tf->Eip);
-      return(1);
-    }
-  Eip = Mem;
-
-  /* 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] == 0xF2 || Eip[0] == 0xF3 ||
-      (Eip[0] == 0xFF && (Eip[1] & 0x38) == 0x10))
-    {
-      ULONG NextInst = Tf->Eip + KdbGetInstLength(Tf->Eip);
-      KdbLastSingleStepFrom = Tf->Eip;
-      KdbInsertBreakPoint(NextInst, TRUE);
-      return(0);
-    }
-  else
-    {
-      return(DbgStep(Argc, Argv, Tf));
-    }
-}
+   /* Return the breakpoint number */
+   if (BreakPointNumber != NULL)
+      *BreakPointNumber = i;
 
-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 = KdbpSafeReadMemory(&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);
+   return STATUS_SUCCESS;
 }
 
-ULONG
-DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Deletes a breakpoint
+ *
+ * \param BreakPointNr  Number of the breakpoint to delete. Can be -1
+ * \param BreakPoint    Breakpoint to delete. Can be NULL.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure (invalid breakpoint number)
+ */
+BOOLEAN
+KdbpDeleteBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
 {
-  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 (!KdbSymPrintAddress((PVOID)Address))
-       {
-         DbgPrint("<%x>", Address);
-       }
-      DbgPrint(": ");
-      InstLen = KdbDisassemble(Address);      
-      if (InstLen < 0)
-       {
-         DbgPrint("<INVALID>\n");
-         return(1);
-       }
-      DbgPrint("\n");
-      Address += InstLen;
-    }
-  
-  return(1);
+   if (BreakPointNr < 0)
+   {
+      ASSERT(BreakPoint != NULL);
+      BreakPointNr = BreakPoint - KdbBreakPoints;
+   }
+   if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+   if (BreakPoint == NULL)
+   {
+      BreakPoint = KdbBreakPoints + BreakPointNr;
+   }
+   if (BreakPoint->Type == KdbBreakPointNone)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+
+   if (BreakPoint->Enabled &&
+       !KdbpDisableBreakPoint(-1, BreakPoint))
+      return FALSE;
+
+   if (BreakPoint->Type != KdbBreakPointTemporary)
+      KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr);
+   BreakPoint->Type = KdbBreakPointNone;
+   KdbBreakPointCount--;
+   
+   return TRUE;
 }
 
-ULONG
-DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Checks if the breakpoint was set by the debugger
+ *
+ * Tries to find a breakpoint in the breakpoint array which caused
+ * the debug exception to happen.
+ *
+ * \param ExpNr      Exception Number (1 or 3)
+ * \param TrapFrame  Exception trapframe
+ *
+ * \returns Breakpoint number, -1 on error.
+ */
+STATIC LONG
+KdbpIsBreakPointOurs(
+   IN ULONG ExpNr,
+   IN PKTRAP_FRAME TrapFrame)
 {
-  ULONG i, j, len;
-
-  DbgPrint("Kernel debugger commands:\n");
-  for (i = 0; DebuggerCommands[i].Name != NULL; i++)
-    {
-      DbgPrint("  %s", DebuggerCommands[i].Syntax);
-      len = strlen(DebuggerCommands[i].Syntax);
-      if (len < 35)
-        {
-          for (j = 0; j < 35 - len; j++)
-          {
-            DbgPrint(" ");
-          }
-        }
-      DbgPrint(" - %s\n", DebuggerCommands[i].Help);
-    }
-  return(1);
-}
+   INT i;
+   ASSERT(ExpNr == 1 || ExpNr == 3);
 
-ULONG
-DbgThreadListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  BOOL System = FALSE;
-  if (Argc == 2 && (!strcmp(Argv[1], "sys") || !strcmp(Argv[1], "SYS")))
-    System = TRUE;
-    
-  PsDumpThreads(System);
-  return(1);
+   if (ExpNr == 3) /* Software interrupt */
+   {
+      ULONG_PTR BpEip = (ULONG_PTR)TrapFrame->Eip - 1; /* Get EIP of INT3 instruction */
+      for (i = 0; i < KdbSwBreakPointCount; i++)
+      {
+         ASSERT((KdbSwBreakPoints[i]->Type == KdbBreakPointSoftware ||
+                 KdbSwBreakPoints[i]->Type == KdbBreakPointTemporary));
+         ASSERT(KdbSwBreakPoints[i]->Enabled);
+         if (KdbSwBreakPoints[i]->Address == BpEip)
+         {
+            return KdbSwBreakPoints[i] - KdbBreakPoints;
+         }
+      }
+   }
+   else if (ExpNr == 1) /* Hardware interrupt */
+   {
+      UCHAR DebugReg;
+      for (i = 0; i < KdbHwBreakPointCount; i++)
+      {
+         ASSERT(KdbHwBreakPoints[i]->Type == KdbBreakPointHardware &&
+                KdbHwBreakPoints[i]->Enabled);
+         DebugReg = KdbHwBreakPoints[i]->Data.Hw.DebugReg;
+         if ((TrapFrame->Dr6 & (1 << DebugReg)) != 0)
+         {
+            return KdbHwBreakPoints[i] - KdbBreakPoints;
+         }
+      }
+   }
+   
+   return -1;
 }
 
-ULONG
-DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Enables a breakpoint.
+ *
+ * \param BreakPointNr  Number of the breakpoint to enable Can be -1.
+ * \param BreakPoint    Breakpoint to enable. Can be NULL.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure.
+ *
+ * \sa KdbpDisableBreakPoint
+ */
+BOOLEAN
+KdbpEnableBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
 {
-  extern LIST_ENTRY PsActiveProcessHead;
-  PLIST_ENTRY current_entry;
-  PEPROCESS current;
-  ULONG i = 1;
-
-  if (PsActiveProcessHead.Flink == NULL)
-    {
-      DbgPrint("No processes.\n");
-      return(1);
-    }
-
-  DbgPrint("Process list: ");
-  current_entry = PsActiveProcessHead.Flink;
-  while (current_entry != &PsActiveProcessHead)
-    {
-      current = CONTAINING_RECORD(current_entry, EPROCESS, ProcessListEntry);
-      DbgPrint("%d %.8s", current->UniqueProcessId, 
-              current->ImageFileName);
-      i++;
-      if ((i % 4) == 0)
-       {
-         DbgPrint("\n");
-       }
-      current_entry = current_entry->Flink;
-    }
-  return(1);
-}
+   NTSTATUS Status;
+   INT i;
+   ULONG ul;
+
+   if (BreakPointNr < 0)
+   {
+      ASSERT(BreakPoint != NULL);
+      BreakPointNr = BreakPoint - KdbBreakPoints;
+   }
+   if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+   if (BreakPoint == NULL)
+   {
+      BreakPoint = KdbBreakPoints + BreakPointNr;
+   }
+   if (BreakPoint->Type == KdbBreakPointNone)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+   
+   if (BreakPoint->Enabled == TRUE)
+   {
+      KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr);
+      return TRUE;
+   }
+
+   if (BreakPoint->Type == KdbBreakPointSoftware ||
+       BreakPoint->Type == KdbBreakPointTemporary)
+   {
+      if (KdbSwBreakPointCount >= KDB_MAXIMUM_SW_BREAKPOINT_COUNT)
+      {
+         KdbpPrint("Maximum number of SW breakpoints (%d) used. "
+                   "Disable another breakpoint in order to enable this one.\n",
+                   KDB_MAXIMUM_SW_BREAKPOINT_COUNT);
+         return FALSE;
+      }
+      Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
+                                        0xCC, &BreakPoint->Data.SavedInstruction);
+      if (!NT_SUCCESS(Status))
+      {
+         KdbpPrint("Couldn't access memory at 0x%x\n", BreakPoint->Address);
+         return FALSE;
+      }
+      KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint;
+   }
+   else
+   {
+      if (BreakPoint->Data.Hw.AccessType == KdbAccessExec)
+         ASSERT(BreakPoint->Data.Hw.Size == 1);
+      ASSERT((BreakPoint->Address % BreakPoint->Data.Hw.Size) == 0);
+      if (KdbHwBreakPointCount >= KDB_MAXIMUM_HW_BREAKPOINT_COUNT)
+      {
+         KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
+                   "Disable another breakpoint in order to enable this one.\n",
+                   KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
+         return FALSE;
+      }
 
-VOID
-DbgPrintBackTrace(PULONG Frame, ULONG_PTR StackBase, ULONG_PTR StackLimit)
-{
-  PVOID Address;
-
-  DbgPrint("Frames:\n");
-  while (Frame != NULL)
-    {
-      if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, Frame + 1, sizeof (Address))))
-        {
-          DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)(Frame + 1));
-          break;
-        }
-      KdbSymPrintAddress(Address);
-      DbgPrint("\n");
-      if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame, Frame, sizeof (Frame))))
-        {
-          DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)Frame);
-          break;
-        }
-    }
-}
+      /* Find unused hw breakpoint */
+      ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT == 4);
+      for (i = 0; i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT; i++)
+      {
+         if ((KdbTrapFrame.Tf.Dr7 & (0x3 << (i * 2))) == 0)
+            break;
+      }
+      ASSERT(i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
 
-ULONG
-DbgAddrCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
-{
-  PVOID Addr;
+      /* Set the breakpoint address. */
+      switch (i)
+      {
+      case 0:
+         KdbTrapFrame.Tf.Dr0 = BreakPoint->Address;
+         break;
+      case 1:
+         KdbTrapFrame.Tf.Dr1 = BreakPoint->Address;
+         break;
+      case 2:
+         KdbTrapFrame.Tf.Dr2 = BreakPoint->Address;
+         break;
+      case 3:
+         KdbTrapFrame.Tf.Dr3 = BreakPoint->Address;
+         break;
+      }
 
-  if (Argc == 2)
-    {
-      Addr = (PVOID)strtoul(Argv[1], NULL, 0);
-      KdbSymPrintAddress(Addr);
-    }
+      /* Enable the global breakpoint */
+      KdbTrapFrame.Tf.Dr7 |= (0x2 << (i * 2));
 
-  return(1);
-}
+      /* Enable the exact match bits. */
+      KdbTrapFrame.Tf.Dr7 |= 0x00000300;
 
-ULONG
-DbgXCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
-{
-  PDWORD Addr = NULL;
-  DWORD Items = 1;
-  DWORD i = 0;
-  DWORD Item;
-
-  if (Argc >= 2)
-    Addr = (PDWORD)strtoul(Argv[1], NULL, 0);
-  if (Argc >= 3)
-    Items = (DWORD)strtoul(Argv[2], NULL, 0);
-
-  if (Addr == NULL)
-    return(1);
-
-  for (i = 0; i < Items; i++)
-    {
-      if( (i % 4) == 0 )
-        {
-         if (i != 0)
-            DbgPrint("\n");
-         DbgPrint("%08x:", (int)(&Addr[i]));
-        }
-      if (!NT_SUCCESS(KdbpSafeReadMemory(&Item, Addr + i, sizeof (Item))))
-        {
-          DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)(Addr + i));
-          break;
-        }
-      DbgPrint("%08x ", Item);
-    }
-
-  return(1);
-}
+      /* Clear existing state. */
+      KdbTrapFrame.Tf.Dr7 &= ~(0xF << (16 + (i * 4)));
 
-static int KjsReadRegValue( void *context,
-                           JSNode *result,
-                           JSNode *args ) {
-  PCHAR cp;
-  PVOID *context_list = context;
-  PKJS kjs = (PKJS)context_list[0];
-  JSVirtualMachine *vm = kjs->vm;
-  NTSTATUS Status;
-  RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { 0 } };
-  UNICODE_STRING NameString;
-  UNICODE_STRING PathString;
-  UNICODE_STRING DefaultString;
-  UNICODE_STRING ValueResult;
-  ANSI_STRING AnsiResult;
-  
-  if (args->u.vinteger != 2 ||
-      args[1].type != JS_STRING || args[2].type != JS_STRING) {
-    return JS_PROPERTY_FOUND;
-  }
-
-  RtlInitUnicodeString(&PathString,NULL);
-  RtlInitUnicodeString(&NameString,NULL);
-  
-  cp = js_string_to_c_string (vm, &args[1]);
-  RtlCreateUnicodeStringFromAsciiz(&PathString,cp);
-  js_free(cp);
-  cp = js_string_to_c_string (vm, &args[2]);
-  RtlCreateUnicodeStringFromAsciiz(&NameString,cp);
-  js_free(cp);
-  
-  RtlInitUnicodeString(&ValueResult,NULL);
-  RtlInitUnicodeString(&DefaultString,L"");
-  RtlInitAnsiString(&AnsiResult,NULL);
-
-  QueryTable->EntryContext = 0;
-  QueryTable->Flags =
-    RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
-  QueryTable->Name = NameString.Buffer;
-  QueryTable->DefaultType = REG_SZ;
-  QueryTable->DefaultData = &DefaultString;
-  QueryTable->EntryContext = &ValueResult;
-  Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, 
-                                  PathString.Buffer, 
-                                  QueryTable, 
-                                  NULL, 
-                                  NULL );
-  
-  RtlFreeUnicodeString(&NameString);
-  RtlFreeUnicodeString(&PathString);
-  
-  if (NT_SUCCESS(Status)) {
-    RtlInitAnsiString(&AnsiResult,NULL);
-    RtlUnicodeStringToAnsiString(&AnsiResult,
-                                &ValueResult,
-                                TRUE);
-    js_vm_make_string (vm, result, AnsiResult.Buffer, 
-                      strlen(AnsiResult.Buffer));
-    RtlFreeAnsiString(&AnsiResult);
-  } else {
-    result->type = JS_INTEGER;
-    result->u.vinteger = Status;
-  }
-
-  return JS_PROPERTY_FOUND;
-}
+      /* Set the breakpoint type. */
+      switch (BreakPoint->Data.Hw.AccessType)
+      {
+      case KdbAccessExec:
+         ul = 0;
+         break;
+      case KdbAccessWrite:
+         ul = 1;
+         break;
+      case KdbAccessRead:
+      case KdbAccessReadWrite:
+         ul = 3;
+         break;
+      default:
+         ASSERT(0);
+         return TRUE;
+         break;
+      }
+      KdbTrapFrame.Tf.Dr7 |= (ul << (16 + (i * 4)));
 
-static int KjsGetRegister( void *context, 
-                          JSNode *result, 
-                          JSNode *args ) {
-  PVOID *context_list = context;
-  if( args->u.vinteger == 1 && args->type == JS_INTEGER ) {
-    DWORD Result = ((DWORD *)context_list[1])[args[1].u.vinteger];
-    result->type = JS_INTEGER;
-    result->u.vinteger = Result;
-  }
-
-  return JS_PROPERTY_FOUND;
-}
+      /* Set the breakpoint length. */
+      KdbTrapFrame.Tf.Dr7 |= ((BreakPoint->Data.Hw.Size - 1) << (18 + (i * 4)));
 
-static int KjsGetNthModule( void *context,
-                           JSNode *result,
-                           JSNode *args ) {
-  PVOID *context_list = context;
-  PKJS kjs = (PKJS)context_list[0];
-  JSVirtualMachine *vm = kjs->vm;
-  PLIST_ENTRY current_entry;
-  MODULE_TEXT_SECTION *current = NULL;
-  extern LIST_ENTRY ModuleTextListHead;
-  int n = 0;
-  
-  if (args->u.vinteger != 1 || args[1].type != JS_INTEGER) {
-    return JS_PROPERTY_FOUND;
-  }
-
-  current_entry = ModuleTextListHead.Flink;
-
-  while (current_entry != &ModuleTextListHead &&
-        current_entry != NULL &&
-        n <= args[1].u.vinteger) {
-    current = CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION,
-                               ListEntry);    
-    current_entry = current_entry->Flink;
-    n++;
-  }
-
-  if (current_entry && current) {
-    ANSI_STRING NameStringNarrow;
-    UNICODE_STRING NameUnicodeString;
-
-    RtlInitUnicodeString( &NameUnicodeString, current->Name );
-    RtlUnicodeStringToAnsiString( &NameStringNarrow,
-                                 &NameUnicodeString,
-                                 TRUE );
-
-    js_vm_make_array (vm, result, 2);
-  
-    js_vm_make_string (vm, 
-                      &result->u.varray->data[0], 
-                      NameStringNarrow.Buffer,
-                      NameStringNarrow.Length);
-
-    RtlFreeAnsiString(&NameStringNarrow);
-
-    result->u.varray->data[1].type = JS_INTEGER;
-    result->u.varray->data[1].u.vinteger = (DWORD)current->Base;
-    result->type = JS_ARRAY;
-    return JS_PROPERTY_FOUND;
-  }
-  result->type = JS_UNDEFINED;
-  return JS_PROPERTY_FOUND;
-}
+      /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
+      if (&KdbTrapFrame != KdbCurrentTrapFrame)
+      {
+         KdbCurrentTrapFrame->Tf.Dr0 = KdbTrapFrame.Tf.Dr0;
+         KdbCurrentTrapFrame->Tf.Dr1 = KdbTrapFrame.Tf.Dr1;
+         KdbCurrentTrapFrame->Tf.Dr2 = KdbTrapFrame.Tf.Dr2;
+         KdbCurrentTrapFrame->Tf.Dr3 = KdbTrapFrame.Tf.Dr3;
+         KdbCurrentTrapFrame->Tf.Dr6 = KdbTrapFrame.Tf.Dr6;
+         KdbCurrentTrapFrame->Tf.Dr7 = KdbTrapFrame.Tf.Dr7;
+      }
 
-static BOOL FindJSEndMark( PCHAR Buffer ) {
-  int i;
+      BreakPoint->Data.Hw.DebugReg = i;
+      KdbHwBreakPoints[KdbHwBreakPointCount++] = BreakPoint;
+   }
 
-  for( i = 0; Buffer[i] && Buffer[i+1]; i++ ) {
-    if( Buffer[i] == ';' && Buffer[i+1] == ';' ) return TRUE;
-  }
-  return FALSE;
+   BreakPoint->Enabled = TRUE;
+   if (BreakPoint->Type != KdbBreakPointTemporary)
+      KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr);
+   return TRUE;
 }
 
-ULONG
-DbgScriptCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
+/*!\brief Disables a breakpoint.
+ *
+ * \param BreakPointNr  Number of the breakpoint to disable. Can be -1
+ * \param BreakPoint    Breakpoint to disable. Can be NULL.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure.
+ *
+ * \sa KdbpEnableBreakPoint
+ */
+BOOLEAN
+KdbpDisableBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL)
 {
-  PCHAR Buffer;
-  PCHAR BufferStart;
-  static void *interp = 0;
-  void *script_cmd_context[2];
-
-  if( !interp ) interp = kjs_create_interp(NULL);
-  if( !interp ) return 1;
-
-  BufferStart = Buffer = ExAllocatePool( NonPagedPool, 4096 );
-  if( !Buffer ) return 1;
-
-  script_cmd_context[0] = interp;
-  script_cmd_context[1] = &tf;
-  
-  kjs_system_register( interp, "regs", script_cmd_context,
-                      KjsGetRegister );
-  kjs_system_register( interp, "regread", script_cmd_context,
-                      KjsReadRegValue );
-  kjs_system_register( interp, "getmodule", script_cmd_context,
-                      KjsGetNthModule );
-
-  kjs_eval( interp,
-           "eval("
-           "System.regread("
-           "'\\\\Registry\\\\Machine\\\\System\\\\"
-           "CurrentControlSet\\\\Control\\\\Kdb',"
-           "'kjsinit'));" );
-
-  DbgPrint("\nKernel Debugger Script Interface (JavaScript :-)\n");
-  DbgPrint("Terminate input with ;; and end scripting with .\n");
-  do
-    {
-      if( Buffer != BufferStart )
-       DbgPrint("..... ");
-      else
-       DbgPrint("kjs:> ");
-      KdbGetCommand( BufferStart );
-      if( BufferStart[0] == '.' ) {
-       if( BufferStart != Buffer ) {
-         DbgPrint("Input Aborted.\n");
-         BufferStart = Buffer;
-       } else {
-         /* Single dot input -> exit */
-         break;
-       }
-      } else {
-       if( FindJSEndMark( Buffer ) ) {
-         kjs_eval( interp, Buffer );
-         BufferStart = Buffer;
-         DbgPrint("\n");
-       } else {
-         BufferStart = BufferStart + strlen(BufferStart);
-       }
+   INT i;
+   NTSTATUS Status;
+   
+   if (BreakPointNr < 0)
+   {
+      ASSERT(BreakPoint != NULL);
+      BreakPointNr = BreakPoint - KdbBreakPoints;
+   }
+   if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+   if (BreakPoint == NULL)
+   {
+      BreakPoint = KdbBreakPoints + BreakPointNr;
+   }
+   if (BreakPoint->Type == KdbBreakPointNone)
+   {
+      KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
+      return FALSE;
+   }
+
+   if (BreakPoint->Enabled == FALSE)
+   {
+      KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr);
+      return TRUE;
+   }
+
+   if (BreakPoint->Type == KdbBreakPointSoftware ||
+       BreakPoint->Type == KdbBreakPointTemporary)
+   {
+      ASSERT(KdbSwBreakPointCount > 0);
+      Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
+                                        BreakPoint->Data.SavedInstruction, NULL);
+      if (!NT_SUCCESS(Status))
+      {
+         KdbpPrint("Couldn't restore original instruction.\n");
+         return FALSE;
+      }
+         
+      for (i = 0; i < KdbSwBreakPointCount; i++)
+      {
+         if (KdbSwBreakPoints[i] == BreakPoint)
+         {
+            KdbSwBreakPoints[i] = KdbSwBreakPoints[--KdbSwBreakPointCount];
+            i = -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
+            break;
+         }
+      }
+      if (i != -1) /* not found */
+         ASSERT(0);
+   }
+   else
+   {
+      ASSERT(BreakPoint->Type == KdbBreakPointHardware);
+      
+      /* Clear the breakpoint. */
+      KdbTrapFrame.Tf.Dr7 &= ~(0x3 << (BreakPoint->Data.Hw.DebugReg * 2));
+      if ((KdbTrapFrame.Tf.Dr7 & 0xFF) == 0)
+      {
+         /*
+          * If no breakpoints are enabled then clear the exact match flags.
+          */
+         KdbTrapFrame.Tf.Dr7 &= 0xFFFFFCFF;
       }
-    } while (TRUE);
-
-  ExFreePool( Buffer );
-
-  kjs_system_unregister( interp, script_cmd_context, KjsGetRegister );
-  kjs_system_unregister( interp, script_cmd_context, KjsReadRegValue );
-  kjs_system_unregister( interp, script_cmd_context, KjsGetNthModule );
 
-  return(1);
+      for (i = 0; i < KdbHwBreakPointCount; i++)
+      {
+         if (KdbHwBreakPoints[i] == BreakPoint)
+         {
+            KdbHwBreakPoints[i] = KdbHwBreakPoints[--KdbHwBreakPointCount];
+            i = -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
+            break;
+         }
+      }
+      if (i != -1) /* not found */
+         ASSERT(0);
+   }
+
+   BreakPoint->Enabled = FALSE;
+   if (BreakPoint->Type != KdbBreakPointTemporary)
+      KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr);
+   return TRUE;
 }
 
-ULONG
-DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
+ *
+ * \param ExceptionNr  Number of the exception to get condition of.
+ * \param FirstChance  Whether to get first or last chance condition.
+ * \param Condition    Receives the condition setting.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure (invalid exception nr)
+ */
+BOOLEAN
+KdbpGetEnterCondition(
+   IN LONG ExceptionNr,
+   IN BOOLEAN FirstChance,
+   OUT KDB_ENTER_CONDITION *Condition)
 {
-  ULONG_PTR StackBase, StackLimit;
-  extern unsigned int init_stack, init_stack_top;
-
-  /* Without an argument we print the current stack. */
-  if (Argc == 1)
-    {
-      if (PsGetCurrentThread() != NULL)
-       {
-         StackBase = (ULONG_PTR)PsGetCurrentThread()->Tcb.StackBase;
-         StackLimit = PsGetCurrentThread()->Tcb.StackLimit;
-       }
-      else
-       {
-         StackBase = (ULONG_PTR)init_stack_top;
-         StackLimit = (ULONG_PTR)init_stack;
-       }
-      DbgPrintBackTrace((PULONG)&Tf->DebugEbp, StackBase, StackLimit);
-    }
-  /* 
-   * If there are two arguments and the second begins with a asterik treat it
-   * as the address of a frame to start printing the back trace from.
-   */
-  else if (Argc == 2 && Argv[1][0] == '*')
-    {
-      PULONG Frame;
-      Frame = (PULONG)strtoul(&Argv[1][1], NULL, 0);
-      DbgPrintBackTrace(Frame, ULONG_MAX, 0);
-    }
-  /*
-   * Otherwise treat the argument as the id of a thread whose back trace is to
-   * be printed.
-   */
-  else
-    {
-    }
-  return(1);
+   if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions))
+      return FALSE;
+
+   *Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1];
+   return TRUE;
 }
 
-VOID
-DbgPrintCr0(ULONG Cr0)
+/*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
+ *
+ * \param ExceptionNr  Number of the exception to set condition of (-1 for all)
+ * \param FirstChance  Whether to set first or last chance condition.
+ * \param Condition    The new condition setting.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure (invalid exception nr)
+ */
+BOOLEAN
+KdbpSetEnterCondition(
+   IN LONG ExceptionNr,
+   IN BOOLEAN FirstChance,
+   IN KDB_ENTER_CONDITION Condition)
 {
-  ULONG i;
-
-  DbgPrint("CR0:");
-  if (Cr0 & (1 << 0))
-    {
-      DbgPrint(" PE");
-    }
-  if (Cr0 & (1 << 1))
-    {
-      DbgPrint(" MP");
-    }
-  if (Cr0 & (1 << 2))
-    {
-      DbgPrint(" EM");
-    }
-  if (Cr0 & (1 << 3))
-    {
-      DbgPrint(" TS");
-    }
-  if (!(Cr0 & (1 << 4)))
-    {
-      DbgPrint(" !BIT5");
-    }
-  if (Cr0 & (1 << 5))
-    {
-      DbgPrint(" NE");
-    }
-  for (i = 6; i < 16; i++)
-    {
-      if (Cr0 & (1 << i))
-       {
-         DbgPrint(" BIT%d", i);
-       }
-    }
-  if (Cr0 & (1 << 16))
-    {
-      DbgPrint(" WP");
-    }
-  if (Cr0 & (1 << 17))
-    {
-      DbgPrint(" BIT17");
-    }
-  if (Cr0 & (1 << 18))
-    {
-      DbgPrint(" AM");
-    }
-  for (i = 19; i < 29; i++)
-    {
-      if (Cr0 & (1 << i))
-       {
-         DbgPrint(" BIT%d", i);
-       }
-    }
-  if (Cr0 & (1 << 29))
-    {
-      DbgPrint(" NW");
-    }
-  if (Cr0 & (1 << 30))
-    {
-      DbgPrint(" CD");
-    }
-  if (Cr0 & (1 << 31))
-    {
-      DbgPrint(" PG");
-    }
-  DbgPrint("\n");
+   if (ExceptionNr < 0)
+   {
+      for (ExceptionNr = 0; ExceptionNr < RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++)
+      {
+         if (ExceptionNr == 1 || ExceptionNr == 8 ||
+             ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */
+         {
+            continue;
+         }
+         KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
+      }
+   }
+   else
+   {
+      if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions) ||
+          ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */
+          ExceptionNr == 9 || ExceptionNr == 15)  /* trap or reserved exceptions */
+      {
+         return FALSE;
+      }
+      KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
+   }
+   return TRUE;
 }
 
-ULONG 
-DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Switches to another thread context
+ *
+ * \param ThreadId  Id of the thread to switch to.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure (i.e. invalid thread id)
+ */
+BOOLEAN
+KdbpAttachToThread(
+   PVOID ThreadId)
 {
-  ULONG Cr0, Cr1, Cr2, Cr3, Cr4;
-  ULONG Ldtr;
-  USHORT Tr;
-  
-  __asm__ __volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0));
-  /*  __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
-  Cr1 = 0;
-  __asm__ __volatile__ ("movl %%cr2, %0\n\t" : "=d" (Cr2));
-  __asm__ __volatile__ ("movl %%cr3, %0\n\t" : "=d" (Cr3));
-  __asm__ __volatile__ ("movl %%cr4, %0\n\t" : "=d" (Cr4));
-  __asm__ __volatile__ ("str %0\n\t" : "=d" (Tr));
-  __asm__ __volatile__ ("sldt %0\n\t" : "=d" (Ldtr));
-  DbgPrintCr0(Cr0);
-  DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
-          Cr1, Cr2, Cr3, Cr4, (ULONG)Tf, Ldtr);
-  return(1);
+   PETHREAD Thread = NULL;
+   PEPROCESS Process;
+
+   /* Get a pointer to the thread */
+   if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread)))
+   {
+      KdbpPrint("Invalid thread id: 0x%08x\n", (UINT)ThreadId);
+      return FALSE;
+   }
+   Process = Thread->ThreadsProcess;
+
+   if (KeIsExecutingDpc() && Process != KdbCurrentProcess)
+   {
+      KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
+      return FALSE;
+   }
+   
+   /* Save the current thread's context (if we previously attached to a thread) */
+   if (KdbCurrentThread != KdbOriginalThread)
+   {
+      ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame);
+      RtlCopyMemory(KdbCurrentThread->Tcb.TrapFrame, &KdbCurrentTrapFrame->Tf, sizeof (KTRAP_FRAME));
+   }
+   else
+   {
+      ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame);
+   }
+
+   /* Switch to the thread's context */
+   if (Thread != KdbOriginalThread)
+   {
+      ASSERT(Thread->Tcb.TrapFrame != NULL);
+      RtlCopyMemory(&KdbThreadTrapFrame.Tf, Thread->Tcb.TrapFrame, sizeof (KTRAP_FRAME));
+      asm volatile(
+         "movl %%cr0, %0"    "\n\t"
+         "movl %%cr2, %1"    "\n\t"
+         "movl %%cr3, %2"    "\n\t"
+         "movl %%cr4, %3"    "\n\t"
+         : "=r"(KdbTrapFrame.Cr0), "=r"(KdbTrapFrame.Cr2),
+           "=r"(KdbTrapFrame.Cr3), "=r"(KdbTrapFrame.Cr4));
+      KdbCurrentTrapFrame = &KdbThreadTrapFrame;
+   }
+   else /* Switching back to original thread */
+   {
+      KdbCurrentTrapFrame = &KdbTrapFrame;
+   }
+   KdbCurrentThread = Thread;
+
+   /* Attach to the thread's process */
+   ASSERT(KdbCurrentProcess == PsGetCurrentProcess());
+   if (KdbCurrentProcess != Process)
+   {
+      if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */
+      {
+         KeUnstackDetachProcess(&KdbApcState);
+      }
+      if (KdbOriginalProcess != Process)
+      {
+         KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process), &KdbApcState);
+      }
+      KdbCurrentProcess = Process;
+   }
+
+   return TRUE;
 }
 
-ULONG 
-DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Switches to another process/thread context
+ *
+ * This function switches to the first thread in the specified process.
+ *
+ * \param ProcessId  Id of the process to switch to.
+ *
+ * \retval TRUE   Success.
+ * \retval FALSE  Failure (i.e. invalid process id)
+ */
+BOOLEAN
+KdbpAttachToProcess(
+   PVOID ProcessId)
 {
-  DbgPrint("Trap   : DR0 %.8x DR1 %.8x DR2 %.8x DR3 %.8x DR6 %.8x DR7 %.8x\n",
-          Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, Tf->Dr6, Tf->Dr7);
-  return(1);
+   PEPROCESS Process = NULL;
+   PETHREAD Thread;
+   PLIST_ENTRY Entry;
+
+   /* Get a pointer to the process */
+   if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
+   {
+      KdbpPrint("Invalid process id: 0x%08x\n", (UINT)ProcessId);
+      return FALSE;
+   }
+
+   Entry = Process->ThreadListHead.Flink;
+   if (Entry == &KdbCurrentProcess->ThreadListHead)
+   {
+      KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (UINT)ProcessId);
+      return FALSE;
+   }
+
+   Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
+
+   return KdbpAttachToThread(Thread->Cid.UniqueThread);
 }
 
-ULONG
-DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief Calls the main loop ...
+ */
+STATIC VOID
+KdbpCallMainLoop()
 {
-  /* Not too difficult. */
-  return(0);
+   KdbpCliMainLoop(KdbEnteredOnSingleStep);
 }
 
-ULONG
-DbgStopCondition(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-    if( Argc == 1 ) {
-       if( KdbHandleHandled ) DbgPrint("all\n");
-       else if( KdbHandleUmode ) DbgPrint("umode\n");
-       else DbgPrint("kmode\n");
-    } 
-    else if( !strcmp(Argv[1],"all") ) 
-    { KdbHandleHandled = TRUE; KdbHandleUmode = TRUE; }
-    else if( !strcmp(Argv[1],"umode") )
-    { KdbHandleHandled = FALSE; KdbHandleUmode = TRUE; }
-    else if( !strcmp(Argv[1],"kmode") )
-    { KdbHandleHandled = FALSE; KdbHandleUmode = FALSE; }
-
-    return(TRUE);
+/*!\brief Internal function to enter KDB.
+ *
+ * Disables interrupts, releases display ownership, ...
+ */
+STATIC VOID
+KdbpInternalEnter()
+{  
+   PETHREAD Thread;
+   PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
+   ULONG SavedStackLimit;
+   
+   KbdDisableMouse();
+   if (KdDebugState & KD_DEBUG_SCREEN)
+   {
+      HalReleaseDisplayOwnership();
+   }
+
+   /* Call the interface's main loop on a different stack */
+   Thread = PsGetCurrentThread();
+   SavedInitialStack = Thread->Tcb.InitialStack;
+   SavedStackBase = Thread->Tcb.StackBase;
+   SavedStackLimit = Thread->Tcb.StackLimit;
+   SavedKernelStack = Thread->Tcb.KernelStack;
+   Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE;
+   Thread->Tcb.StackLimit = (ULONG)KdbStack;
+   Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE;
+
+   /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase);*/
+
+   KdbpStackSwitchAndCall(Thread->Tcb.KernelStack, KdbpCallMainLoop);
+
+   Thread->Tcb.InitialStack = SavedInitialStack;
+   Thread->Tcb.StackBase = SavedStackBase;
+   Thread->Tcb.StackLimit = SavedStackLimit;
+   Thread->Tcb.KernelStack = SavedKernelStack;
+   KbdEnableMouse();
 }
 
-ULONG
-DbgModuleLoadedAction(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
+/*!\brief KDB Exception filter
+ *
+ * Called by the exception dispatcher.
+ *
+ * \param ExceptionRecord  Unused.
+ * \param PreviousMode     UserMode if the exception was raised from umode, otherwise KernelMode.
+ * \param Context          Unused.
+ * \param TrapFrame        Exception TrapFrame.
+ * \param FirstChance      TRUE when called before exception frames were serached,
+ *                         FALSE for the second call.
+ *
+ * \returns KD_CONTINUE_TYPE
+ */
+KD_CONTINUE_TYPE
+KdbEnterDebuggerException(
+   IN PEXCEPTION_RECORD ExceptionRecord  OPTIONAL,
+   IN KPROCESSOR_MODE PreviousMode,
+   IN PCONTEXT Context  OPTIONAL,
+   IN OUT PKTRAP_FRAME TrapFrame,
+   IN BOOLEAN FirstChance)
 {
-    if (Argc == 1)
+   ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
+   KDB_ENTER_CONDITION EnterCondition;
+   KD_CONTINUE_TYPE ContinueType = kdHandleException;
+   PKDB_BREAKPOINT BreakPoint;
+   ULONG ul;
+   ULONGLONG ull;
+   BOOLEAN Resume = FALSE;
+   BOOLEAN EnterConditionMet = TRUE;
+   ULONG OldEflags;
+
+   /* Exception inside the debugger? Game over. */
+   if (InterlockedIncrement(&KdbEntryCount) > 1)
+   {
+      return kdHandleException;
+   }
+
+   KdbCurrentProcess = PsGetCurrentProcess();
+
+   /* Set continue type to kdContinue for single steps and breakpoints */
+   if (ExpNr == 1 || ExpNr == 3)
+      ContinueType = kdContinue;
+
+   /* Check if we should handle the exception. */
+   ul = min(ExpNr, RTL_NUMBER_OF(KdbEnterConditions) - 1);
+   EnterCondition = KdbEnterConditions[ul][FirstChance ? 0 : 1];
+   if (EnterCondition == KdbDoNotEnter ||
+       (EnterCondition == KdbEnterFromUmode && PreviousMode != UserMode) ||
+       (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
+   {
+      EnterConditionMet = FALSE;
+   }
+
+   /* If we stopped on one of our breakpoints then let the user know. */
+   KdbLastBreakPointNr = -1;
+   KdbEnteredOnSingleStep = FALSE;
+
+   if (FirstChance && (ExpNr == 1 || ExpNr == 3) &&
+       (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExpNr, TrapFrame)) >= 0)
+   {
+      BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
+
+      if (ExpNr == 3)
       {
-       if (KdbBreakOnModuleLoad)
-          DbgPrint("Current setting: break\n");
-       else
-          DbgPrint("Current setting: continue\n");
+         /*
+          * 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.
+          */
+         if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address,
+                                                  BreakPoint->Data.SavedInstruction, NULL)))
+         {
+            DbgPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
+            KEBUGCHECK(0);
+         }
       }
-    else if (!strcmp(Argv[1], "break"))
+
+      if ((BreakPoint->Type == KdbBreakPointHardware) &&
+          (BreakPoint->Data.Hw.AccessType == KdbAccessExec))
       {
-        KdbBreakOnModuleLoad = TRUE;
+         Resume = TRUE; /* Set the resume flag when continuing execution */
       }
-    else if (!strcmp(Argv[1], "continue"))
+      
+      /*
+       * When a temporary breakpoint is hit we have to make sure that we are
+       * in the same context in which it was set, otherwise it could happen
+       * that another process/thread hits it before and it gets deleted.
+       */
+      else if (BreakPoint->Type == KdbBreakPointTemporary &&
+               BreakPoint->Process == KdbCurrentProcess)
       {
-        KdbBreakOnModuleLoad = FALSE;
+         ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) == 0);
+         
+         /*
+          * Delete the temporary breakpoint which was used to step over or into the instruction.
+          */
+         KdbpDeleteBreakPoint(-1, BreakPoint);
+
+         if (--KdbNumSingleSteps > 0)
+         {
+            if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
+                (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
+            {
+               TrapFrame->Eflags |= X86_EFLAGS_TF;
+            }
+            goto continue_execution; /* return */
+         }
+
+         KdbEnteredOnSingleStep = TRUE;
       }
-    else
+
+      /*
+       * If we hit a breakpoint set by the debugger we set the single step flag,
+       * ignore the next single step and reenable the breakpoint.
+       */
+      else if (BreakPoint->Type == KdbBreakPointSoftware ||
+               BreakPoint->Type == KdbBreakPointTemporary)
       {
-        DbgPrint("Unknown setting: %s\n", Argv[1]);
+         ASSERT(ExpNr == 3);
+         TrapFrame->Eflags |= X86_EFLAGS_TF;
+         KdbBreakPointToReenable = BreakPoint;
+      }
+      
+      /*
+       * Make sure that the breakpoint should be triggered in this context
+       */
+      if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
+      {
+            goto continue_execution; /* return */
+      }
+      
+      /*
+       * Check if the condition for the breakpoint is met.
+       */
+      if (BreakPoint->Condition != NULL)
+      {
+         /* Setup the KDB trap frame */
+         RtlCopyMemory(&KdbTrapFrame.Tf, TrapFrame, sizeof (KTRAP_FRAME));
+         asm volatile(
+            "movl %%cr0, %0"    "\n\t"
+            "movl %%cr2, %1"    "\n\t"
+            "movl %%cr3, %2"    "\n\t"
+            "movl %%cr4, %3"    "\n\t"
+            : "=r"(KdbTrapFrame.Cr0), "=r"(KdbTrapFrame.Cr2),
+              "=r"(KdbTrapFrame.Cr3), "=r"(KdbTrapFrame.Cr4));
+
+         ull = 0;
+         if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
+         {
+            /* FIXME: Print warning? */
+         }
+         else if (ull == 0) /* condition is not met */
+         {
+            goto continue_execution; /* return */
+         }
       }
 
-    return(TRUE);
-}
-
-ULONG
-DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  KbdEchoOn = !KbdEchoOn;
-  return(TRUE);
-}
+      if (BreakPoint->Type == KdbBreakPointSoftware)
+      {
+         DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
+                  KdbLastBreakPointNr, TrapFrame->Cs & 0xffff, TrapFrame->Eip);
+      }
+      else if (BreakPoint->Type == KdbBreakPointHardware)
+      {
+         DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
+                  KdbLastBreakPointNr,
+                  (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
+                  ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
+                   ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")
+                  ),
+                  BreakPoint->Address
+                 );
 
-VOID
-DbgPrintEflags(ULONG Eflags)
-{
-  DbgPrint("EFLAGS:");
-  if (Eflags & (1 << 0))
-    {
-      DbgPrint(" CF");
-    }
-  if (!(Eflags & (1 << 1)))
-    {
-      DbgPrint(" !BIT1");
-    }
-  if (Eflags & (1 << 2))
-    {
-      DbgPrint(" PF");
-    }
-  if (Eflags & (1 << 3))
-    {
-      DbgPrint(" BIT3");
-    }
-  if (Eflags & (1 << 4))
-    {
-      DbgPrint(" AF");
-    }
-  if (Eflags & (1 << 5))
-    {
-      DbgPrint(" BIT5");
-    }
-  if (Eflags & (1 << 6))
-    {
-      DbgPrint(" ZF");
-    }
-  if (Eflags & (1 << 7))
-    {
-      DbgPrint(" SF");
-    }
-  if (Eflags & (1 << 8))
-    {
-      DbgPrint(" TF");
-    }
-  if (Eflags & (1 << 9))
-    {
-      DbgPrint(" IF");
-    }
-  if (Eflags & (1 << 10))
-    {
-      DbgPrint(" DF");
-    }
-  if (Eflags & (1 << 11))
-    {
-      DbgPrint(" OF");
-    }
-  if ((Eflags & ((1 << 12) | (1 << 13))) == 0)
-    {
-      DbgPrint(" IOPL0");
-    }
-  else if ((Eflags & ((1 << 12) | (1 << 13))) == 1)
-    {
-      DbgPrint(" IOPL1");
-    }
-  else if ((Eflags & ((1 << 12) | (1 << 13))) == 2)
-    {
-      DbgPrint(" IOPL2");
-    }
-  else if ((Eflags & ((1 << 12) | (1 << 13))) == 3)
-    {
-      DbgPrint(" IOPL3");
-    }
-  if (Eflags & (1 << 14))
-    {
-      DbgPrint(" NT");
-    }
-  if (Eflags & (1 << 15))
-    {
-      DbgPrint(" BIT15");
-    }
-  if (Eflags & (1 << 16))
-    {
-      DbgPrint(" RF");
-    }
-  if (Eflags & (1 << 17))
-    {
-      DbgPrint(" VF");
-    }
-  if (Eflags & (1 << 18))
-    {
-      DbgPrint(" AC");
-    }
-  if (Eflags & (1 << 19))
-    {
-      DbgPrint(" VIF");
-    }
-  if (Eflags & (1 << 20))
-    {
-      DbgPrint(" VIP");
-    }
-  if (Eflags & (1 << 21))
-    {
-      DbgPrint(" ID");
-    }
-  if (Eflags & (1 << 22))
-    {
-      DbgPrint(" BIT22");
-    }
-  if (Eflags & (1 << 23))
-    {
-      DbgPrint(" BIT23");
-    }
-  if (Eflags & (1 << 24))
-    {
-      DbgPrint(" BIT24");
-    }
-  if (Eflags & (1 << 25))
-    {
-      DbgPrint(" BIT25");
-    }
-  if (Eflags & (1 << 26))
-    {
-      DbgPrint(" BIT26");
-    }
-  if (Eflags & (1 << 27))
-    {
-      DbgPrint(" BIT27");
-    }
-  if (Eflags & (1 << 28))
-    {
-      DbgPrint(" BIT28");
-    }
-  if (Eflags & (1 << 29))
-    {
-      DbgPrint(" BIT29");
-    }
-  if (Eflags & (1 << 30))
-    {
-      DbgPrint(" BIT30");
-    }
-  if (Eflags & (1 << 31))
-    {
-      DbgPrint(" BIT31");
-    }
-  DbgPrint("\n");
-}
+      }
+   }
+   else if (ExpNr == 1)
+   {
+      /* Silently ignore a debugger initiated single step. */
+      if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable != NULL)
+      {
+         /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
+         BreakPoint = KdbBreakPointToReenable;
+         KdbBreakPointToReenable = NULL;
+         ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
+                BreakPoint->Type == KdbBreakPointTemporary);
+
+         /*
+          * Reenable the breakpoint we disabled to execute the breakpointed
+          * instruction.
+          */
+         if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
+                                                  &BreakPoint->Data.SavedInstruction)))
+         {
+            DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
+                     BreakPoint - KdbBreakPoints);
+         }
+
+         /* Unset TF if we are no longer single stepping. */
+         if (KdbNumSingleSteps == 0)
+            TrapFrame->Eflags &= ~X86_EFLAGS_TF;
+         goto continue_execution; /* return */
+      }
 
-ULONG
-DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  DbgPrint("CS:EIP %.4x:%.8x, EAX %.8x EBX %.8x ECX %.8x EDX %.8x\n",
-          Tf->Cs & 0xFFFF, Tf->Eip, Tf->Eax, Tf->Ebx, Tf->Ecx, Tf->Edx);
-  DbgPrint("ESI %.8x EDI %.8x EBP %.8x SS:ESP %.4x:%.8x\n",
-          Tf->Esi, Tf->Edi, Tf->Ebp, Tf->Ss & 0xFFFF, Tf->Esp);
-  DbgPrintEflags(Tf->Eflags);
-  return(1);
-}
+      /* Check if we expect a single step */
+      if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
+      {
+         /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
+         if (--KdbNumSingleSteps > 0)
+         {
+            if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
+                (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
+            {
+               TrapFrame->Eflags &= ~X86_EFLAGS_TF;
+            }
+            else
+            {
+               TrapFrame->Eflags |= X86_EFLAGS_TF;
+            }
+            goto continue_execution; /* return */
+         }
 
-ULONG
-DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  KEBUGCHECK(0xDEADDEAD);
-  return(1);
-}
+         TrapFrame->Eflags &= ~X86_EFLAGS_TF;
+         KdbEnteredOnSingleStep = TRUE;
+      }
+      else
+      {
+         if (!EnterConditionMet)
+         {
+            InterlockedDecrement(&KdbEntryCount);
+            return ContinueType;
+         }
+         DbgPrint("Entered debugger on unexpected debug trap!\n");
+      }
+   }
+   else if (ExpNr == 3)
+   {
+      if (KdbInitFileBuffer != NULL)
+      {
+         KdbpCliInterpretInitFile();
+         EnterConditionMet = FALSE;
+      }
+      if (!EnterConditionMet)
+      {
+         InterlockedDecrement(&KdbEntryCount);
+         return ContinueType;
+      }
 
-ULONG
-DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  DbgShowFiles();
-  return(1);
-}
+      DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
+               TrapFrame->Cs & 0xffff, TrapFrame->Eip - 1);
+   }
+   else
+   {
+      CONST PCHAR ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
+                                    (ExceptionNrToString[ExpNr]) :
+                                    ("Unknown/User defined exception");
 
-ULONG
-DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  if (Argc == 2)
-    {
-      if (strlen(Argv[1]) > 0)
-        {
-          DbgEnableFile(Argv[1]);
-        }
-    }
-  return(1);
-}
+      if (!EnterConditionMet)
+      {
+         InterlockedDecrement(&KdbEntryCount);
+         return ContinueType;
+      }
 
-ULONG
-DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
-{
-  if (Argc == 2)
-    {
-      if (strlen(Argv[1]) > 0)
-        {
-          DbgDisableFile(Argv[1]);
-        }
-    }
-  return(1);
-}
+      DbgPrint("Entered debugger on %s-chance exception number %d (%s)\n",
+               FirstChance ? "first" : "last", ExpNr, ExceptionString);
+      if (ExpNr == 14)
+      {
+         /* FIXME: Add noexec memory stuff */
+         ULONG Cr2, Err;
+         asm volatile("movl %%cr2, %0" : "=r"(Cr2));
+         Err = TrapFrame->ErrorCode;
+         DbgPrint("Memory at 0x%x could not be %s: ", Cr2, (Err & (1 << 1)) ? "written" : "read");
+         if ((Err & (1 << 0)) == 0)
+            DbgPrint("Page not present.\n");
+         else
+         {
+            if ((Err & (1 << 3)) != 0)
+               DbgPrint("Reserved bits in page directory set.\n");
+            else
+               DbgPrint("Page protection violation.\n");
+         }
+      }
+   }
+   
+   /* Once we enter the debugger we do not expect any more single steps to happen */
+   KdbNumSingleSteps = 0;
+   
+   /* Update the current process pointer */
+   KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
+   KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
+   KdbCurrentTrapFrame = &KdbTrapFrame;
+
+   /* Setup the KDB trap frame */
+   RtlCopyMemory(&KdbTrapFrame.Tf, TrapFrame, sizeof(KTRAP_FRAME));
+   asm volatile(
+      "movl %%cr0, %0"    "\n\t"
+      "movl %%cr2, %1"    "\n\t"
+      "movl %%cr3, %2"    "\n\t"
+      "movl %%cr4, %3"    "\n\t"
+      : "=r"(KdbTrapFrame.Cr0), "=r"(KdbTrapFrame.Cr2),
+        "=r"(KdbTrapFrame.Cr3), "=r"(KdbTrapFrame.Cr4));
+
+   /* Enter critical section */
+   Ke386SaveFlags(OldEflags);
+   Ke386DisableInterrupts();
+
+   /* Call the main loop. */
+   KdbpInternalEnter();
+
+   /* Check if we should single step */
+   if (KdbNumSingleSteps > 0)
+   {
+      if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) ||
+          (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip)))
+      {
+         ASSERT((KdbCurrentTrapFrame->Tf.Eflags & X86_EFLAGS_TF) == 0);
+         /*KdbCurrentTrapFrame->Tf.Eflags &= ~X86_EFLAGS_TF;*/
+      }
+      else
+      {
+         KdbCurrentTrapFrame->Tf.Eflags |= X86_EFLAGS_TF;
+      }
+   }
+
+   /* Save the current thread's trapframe */
+   if (KdbCurrentTrapFrame == &KdbThreadTrapFrame)
+   {
+      RtlCopyMemory(KdbCurrentThread->Tcb.TrapFrame, KdbCurrentTrapFrame, sizeof (KTRAP_FRAME));
+   }
+
+   /* Detach from attached process */
+   if (KdbCurrentProcess != KdbOriginalProcess)
+   {
+      KeUnstackDetachProcess(&KdbApcState);
+   }
+
+   /* Update the exception TrapFrame */
+   RtlCopyMemory(TrapFrame, &KdbTrapFrame.Tf, sizeof(KTRAP_FRAME));
+#if 0
+   asm volatile(
+      "movl %0, %%cr0"    "\n\t"
+      "movl %1, %%cr2"    "\n\t"
+      "movl %2, %%cr3"    "\n\t"
+      "movl %3, %%cr4"    "\n\t"
+      : : "r"(KdbTrapFrame.Cr0), "r"(KdbTrapFrame.Cr2),
+          "r"(KdbTrapFrame.Cr3), "r"(KdbTrapFrame.Cr4));
+#endif
+
+   /* Leave critical section */
+   Ke386RestoreFlags(OldEflags);
+
+continue_execution:
+   /* Clear debug status */
+   if (ExpNr == 1 || ExpNr == 3) /* FIXME: Why clear DR6 on INT3? */
+   {
+      /* Set the RF flag so we don't trigger the same breakpoint again. */
+      if (Resume)
+      {
+         TrapFrame->Eflags |= X86_EFLAGS_RF;
+      }
+         
+      /* Clear dr6 status flags. */
+      TrapFrame->Dr6 &= ~0x0000e00f;
 
-VOID
-KdbCreateThreadHook(PCONTEXT Context)
-{
-  Context->Dr0 = x_dr0;
-  Context->Dr1 = x_dr1;
-  Context->Dr2 = x_dr2;
-  Context->Dr3 = x_dr3;
-  Context->Dr7 = x_dr7;
-}
+   }
 
-ULONG
-KdbDoCommand(PCH CommandLine, PKTRAP_FRAME Tf)
-{
-  ULONG i;
-  PCH s1;
-  PCH s;
-  static PCH Argv[256];
-  ULONG Argc;
-  static CHAR OrigCommand[256];
-
-  strcpy(OrigCommand, CommandLine);
-
-  Argc = 0;
-  s = CommandLine;
-  while ((s1 = strpbrk(s, "\t ")) != NULL)
-    {
-      Argv[Argc] = s;
-      *s1 = 0;
-      s = s1 + 1;
-      Argc++;
-    }
-  Argv[Argc] = s;
-  Argc++;
-
-  for (i = 0; DebuggerCommands[i].Name != NULL; i++)
-    {
-      if (strcmp(DebuggerCommands[i].Name, Argv[0]) == 0)
-       {
-         return(DebuggerCommands[i].Fn(Argc, Argv, Tf));
-       }
-    }
-  DbgPrint("Command '%s' is unknown.", OrigCommand);
-  return(1);
+   InterlockedDecrement(&KdbEntryCount);
+   return ContinueType;
 }
 
 VOID
-KdbMainLoop(PKTRAP_FRAME Tf)
+KdbInit()
 {
-  CHAR Command[256];
-  ULONG s;
-
-  if (!KdbEnteredOnSingleStep)
-    {
-      DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
-    }
-  else
-    {
-      if (!KdbSymPrintAddress((PVOID)Tf->Eip))
-       {
-         DbgPrint("<%x>", Tf->Eip);
-       }
-      DbgPrint(": ");
-      if (KdbDisassemble(Tf->Eip) < 0)
-       {
-         DbgPrint("<INVALID>");
-       }
-      KdbEnteredOnSingleStep = FALSE;
-      KdbLastSingleStepFrom = 0xFFFFFFFF;
-    }
-
-  do
-    {
-      DbgPrint("\nkdb:> ");
-
-      KdbGetCommand(Command);
-      s = KdbDoCommand(Command, Tf);    
-    } while (s != 0);
+   KdbpCliInit();
 }
 
 VOID
-KdbInternalEnter(PKTRAP_FRAME Tf)
-{  
-  __asm__ __volatile__ ("cli\n\t");
-  KbdDisableMouse();
-  if (KdDebugState & KD_DEBUG_SCREEN)
-    {
-      HalReleaseDisplayOwnership();
-    }
-  (VOID)KdbMainLoop(Tf);
-  KbdEnableMouse();
-  __asm__ __volatile__("sti\n\t");
-}
-
-KD_CONTINUE_TYPE
-KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
-                         KPROCESSOR_MODE PreviousMode,
-                         PCONTEXT Context,
-                         PKTRAP_FRAME TrapFrame,
-                         BOOLEAN AlwaysHandle)
+KdbDeleteProcessHook(IN PEPROCESS Process)
 {
-  LONG BreakPointNr;
-  ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
-
-  /* Always handle beakpoints */
-  if (ExpNr != 1 && ExpNr != 3)
-    {
-      DbgPrint(":KDBG:Entered:%s:%s\n",
-               PreviousMode==KernelMode ? "kmode" : "umode",
-               AlwaysHandle ? "always" : "if-unhandled");
-
-      /* If we aren't handling umode exceptions then return */
-      if (PreviousMode == UserMode && !KdbHandleUmode && !AlwaysHandle)
-        {
-          return kdHandleException;
-        }
-
-      /* If the exception would be unhandled (and we care) then handle it */
-      if (PreviousMode == KernelMode && !KdbHandleHandled && !AlwaysHandle)
-        {
-          return kdHandleException;
-        }
-    }
-
-  /* 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
-    {
-      const char *ExceptionString =
-         (ExpNr < (sizeof (ExceptionTypeStrings) / sizeof (ExceptionTypeStrings[0]))) ?
-         (ExceptionTypeStrings[ExpNr]) :
-         ("Unknown/User defined exception");
-      DbgPrint("Entered debugger on exception number %d (%s)\n", ExpNr, ExceptionString);
-    }
-  KdbInternalEnter(TrapFrame);
-  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);
-    }
+   KdbSymFreeProcessSymbols(Process);
+   
+   /* FIXME: Delete breakpoints for process */
 }
 
 VOID
 KdbModuleLoaded(IN PUNICODE_STRING Name)
 {
-  if (!KdbBreakOnModuleLoad)
-    return;
-    
-  DbgPrint("Module %wZ loaded.\n", Name);
-  DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
+   KdbpCliModuleLoaded(Name);
 }
 
+
index 46c0876..8f08613 100644 (file)
@@ -1,6 +1,82 @@
+#ifndef NTOSKRNL_KDB_H
+#define NTOSKRNL_KDB_H
+
+/* INCLUDES ******************************************************************/
+
 #define NTOS_MODE_KERNEL
 #include <ntos.h>
 
+#include <internal/ke.h>
+
+/* DEFINES *******************************************************************/
+
+#define TAG_KDBG        (('K' << 24) | ('D' << 16) | ('B' << 8) | 'G')
+
+#ifndef RTL_NUMBER_OF
+# define RTL_NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+
+/* TYPES *********************************************************************/
+
+/* from kdb.c */
+typedef struct _KDB_KTRAP_FRAME
+{
+   KTRAP_FRAME  Tf;
+   ULONG        Cr0;
+   ULONG        Cr1; /* reserved/unused */
+   ULONG        Cr2;
+   ULONG        Cr3;
+   ULONG        Cr4;
+} KDB_KTRAP_FRAME, *PKDB_KTRAP_FRAME;
+
+typedef enum _KDB_BREAKPOINT_TYPE
+{
+   KdbBreakPointNone = 0,
+   KdbBreakPointSoftware,
+   KdbBreakPointHardware,
+   KdbBreakPointTemporary
+} KDB_BREAKPOINT_TYPE;
+
+typedef enum _KDB_ACCESS_TYPE
+{
+   KdbAccessRead,
+   KdbAccessWrite,
+   KdbAccessReadWrite,
+   KdbAccessExec
+} KDB_ACCESS_TYPE;
+
+typedef struct _KDB_BREAKPOINT
+{
+   KDB_BREAKPOINT_TYPE    Type;         /* Type of breakpoint */
+   BOOLEAN                Enabled;      /* Whether the bp is enabled */
+   ULONG_PTR              Address;      /* Address of the breakpoint */
+   BOOLEAN                Global;       /* Whether the breakpoint is global or local to a process */
+   PEPROCESS              Process;      /* Owning process */
+   PCHAR                  ConditionExpression;
+   PVOID                  Condition;
+   union {
+      /* KdbBreakPointSoftware */
+      UCHAR               SavedInstruction;
+      /* KdbBreakPointHardware */
+      struct {
+         UCHAR            DebugReg : 2;
+         UCHAR            Size : 3;
+         KDB_ACCESS_TYPE  AccessType;
+      } Hw;
+   } Data;
+} KDB_BREAKPOINT, *PKDB_BREAKPOINT;
+
+typedef enum _KDB_ENTER_CONDITION
+{
+   KdbDoNotEnter,
+   KdbEnterAlways,
+   KdbEnterFromKmode,
+   KdbEnterFromUmode
+} KDB_ENTER_CONDITION;
+
+
+/* from kdb_symbols.c */
 typedef struct _KDB_MODULE_INFO
 {
     WCHAR        Name[256];
@@ -9,6 +85,74 @@ typedef struct _KDB_MODULE_INFO
     PROSSYM_INFO RosSymInfo;
 } KDB_MODULE_INFO, *PKDB_MODULE_INFO;
 
+
+/* FUNCTIONS *****************************************************************/
+
+/* from i386/i386-dis.c */
+
+LONG
+KdbpDisassemble(
+   IN ULONG Address,
+   IN ULONG IntelSyntax);
+   
+LONG
+KdbpGetInstLength(
+   IN ULONG Address);
+
+/* from i386/kdb_help.S */
+
+STDCALL VOID
+KdbpStackSwitchAndCall(
+   IN PVOID NewStack,
+   IN VOID (*Function)(VOID));
+
+/* from kdb_cli.c */
+
+extern PCHAR KdbInitFileBuffer;
+
+VOID
+KdbpCliInit();
+
+VOID
+KdbpCliMainLoop(
+   IN BOOLEAN EnteredOnSingleStep);
+
+VOID
+KdbpCliModuleLoaded(
+   IN PUNICODE_STRING Name);
+
+VOID
+KdbpCliInterpretInitFile();
+
+VOID
+KdbpPrint(
+   IN PCHAR Format,
+   IN ...  OPTIONAL);
+
+/* from kdb_expr.c */
+
+BOOLEAN
+KdbpRpnEvaluateExpression(
+   IN  PCHAR Expression,
+   IN  PKDB_KTRAP_FRAME TrapFrame,
+   OUT PULONGLONG Result,
+   OUT PLONG ErrOffset  OPTIONAL,
+   OUT PCHAR ErrMsg  OPTIONAL);
+
+PVOID
+KdbpRpnParseExpression(
+   IN  PCHAR Expression,
+   OUT PLONG ErrOffset  OPTIONAL,
+   OUT PCHAR ErrMsg  OPTIONAL);
+
+BOOLEAN
+KdbpRpnEvaluateParsedExpression(
+   IN  PVOID Expression,
+   IN  PKDB_KTRAP_FRAME TrapFrame,
+   OUT PULONGLONG Result,
+   OUT PLONG ErrOffset  OPTIONAL,
+   OUT PCHAR ErrMsg  OPTIONAL);
+
 /* from kdb_symbols.c */
 
 BOOLEAN
@@ -33,23 +177,86 @@ KdbSymGetAddressInformation(IN PROSSYM_INFO  RosSymInfo,
                             OUT PCH FileName  OPTIONAL,
                             OUT PCH FunctionName  OPTIONAL);
 
-/* other functions */
-#define KdbpSafeReadMemory(dst, src, size) MmSafeCopyFromUser(dst, src, size)
-#define KdbpSafeWriteMemory(dst, src, size) MmSafeCopyToUser(dst, src, size)
-CHAR
-KdbTryGetCharKeyboard(PULONG ScanCode);
-ULONG
-KdbTryGetCharSerial(VOID);
-VOID
-KdbEnter(VOID);
-VOID
-DbgRDebugInit(VOID);
-VOID
-DbgShowFiles(VOID);
+/* from kdb.c */
+
+extern PEPROCESS KdbCurrentProcess;
+extern PETHREAD KdbCurrentThread;
+extern LONG KdbLastBreakPointNr;
+extern ULONG KdbNumSingleSteps;
+extern BOOLEAN KdbSingleStepOver;
+extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
+
 VOID
-DbgEnableFile(PCH Filename);
+KdbInit();
+
 VOID
-DbgDisableFile(PCH Filename);
+KdbModuleLoaded(
+   IN PUNICODE_STRING Name);
+
+LONG
+KdbpGetNextBreakPointNr(
+   IN ULONG Start  OPTIONAL);
+
+BOOLEAN
+KdbpGetBreakPointInfo(
+   IN  ULONG BreakPointNr,
+   OUT ULONG_PTR *Address  OPTIONAL,
+   OUT KDB_BREAKPOINT_TYPE *Type  OPTIONAL,
+   OUT UCHAR *Size  OPTIONAL,
+   OUT KDB_ACCESS_TYPE *AccessType  OPTIONAL,
+   OUT UCHAR *DebugReg  OPTIONAL,
+   OUT BOOLEAN *Enabled  OPTIONAL,
+   OUT BOOLEAN *Global  OPTIONAL,
+   OUT PEPROCESS *Process  OPTIONAL,
+   OUT PCHAR *ConditionExpression  OPTIONAL);
+
+NTSTATUS
+KdbpInsertBreakPoint(
+   IN  ULONG_PTR Address,
+   IN  KDB_BREAKPOINT_TYPE Type,
+   IN  UCHAR Size  OPTIONAL,
+   IN  KDB_ACCESS_TYPE AccessType  OPTIONAL,
+   IN  PCHAR ConditionExpression  OPTIONAL,
+   IN  BOOLEAN Global,
+   OUT PULONG BreakPointNumber  OPTIONAL);
+   
+BOOLEAN
+KdbpDeleteBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL);
+
+BOOLEAN
+KdbpEnableBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL);
+
+BOOLEAN
+KdbpDisableBreakPoint(
+   IN LONG BreakPointNr  OPTIONAL,
+   IN OUT PKDB_BREAKPOINT BreakPoint  OPTIONAL);
+
+BOOLEAN
+KdbpGetEnterCondition(
+   IN LONG ExceptionNr,
+   IN BOOLEAN FirstChance,
+   OUT KDB_ENTER_CONDITION *Condition);
+
+BOOLEAN
+KdbpSetEnterCondition(
+   IN LONG ExceptionNr,
+   IN BOOLEAN FirstChance,
+   IN KDB_ENTER_CONDITION Condition);
+
+BOOLEAN
+KdbpAttachToThread(
+   PVOID ThreadId);
+
+BOOLEAN
+KdbpAttachToProcess(
+   PVOID ProcessId);
+
+/* from profile.c */
+
 VOID
 KdbInitProfiling();
 VOID
@@ -61,13 +268,25 @@ KdbEnableProfiling();
 VOID
 KdbProfileInterrupt(ULONG_PTR Eip);
 
+/* other functions */
+
+#define KdbpSafeReadMemory(dst, src, size)   MmSafeCopyFromUser(dst, src, size)
+#define KdbpSafeWriteMemory(dst, src, size)  MmSafeCopyToUser(dst, src, size)
+CHAR
+KdbpTryGetCharKeyboard(PULONG ScanCode);
+ULONG
+KdbpTryGetCharSerial(VOID);
+VOID
+KdbEnter(VOID);
 VOID
-KdbModuleLoaded(IN PUNICODE_STRING Name);
+DbgRDebugInit(VOID);
+VOID
+DbgShowFiles(VOID);
+VOID
+DbgEnableFile(PCH Filename);
+VOID
+DbgDisableFile(PCH Filename);
+
 
+#endif /* NTOSKRNL_KDB_H */
 
-struct KDB_BPINFO {
-    DWORD Addr;
-    DWORD Type;
-    DWORD Size;
-    DWORD Enabled;
-};
diff --git a/reactos/ntoskrnl/dbg/kdb_cli.c b/reactos/ntoskrnl/dbg/kdb_cli.c
new file mode 100644 (file)
index 0000000..318a4a3
--- /dev/null
@@ -0,0 +1,2307 @@
+/*\r
+ *  ReactOS kernel\r
+ *  Copyright (C) 2005 ReactOS Team\r
+ *\r
+ *  This program is free software; you can redistribute it and/or modify\r
+ *  it under the terms of the GNU General Public License as published by\r
+ *  the Free Software Foundation; either version 2 of the License, or\r
+ *  (at your option) any later version.\r
+ *\r
+ *  This program is distributed in the hope that it will be useful,\r
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *  GNU General Public License for more details.\r
+ *\r
+ *  You should have received a copy of the GNU General Public License\r
+ *  along with this program; if not, write to the Free Software\r
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+/* $Id$\r
+ *\r
+ * PROJECT:         ReactOS kernel\r
+ * FILE:            ntoskrnl/dbg/kdb_cli.c\r
+ * PURPOSE:         Kernel debugger command line interface\r
+ * PROGRAMMER:      Gregor Anich (blight@blight.eu.org)\r
+ * UPDATE HISTORY:\r
+ *                  Created 16/01/2005\r
+ */\r
\r
+/* INCLUDES ******************************************************************/\r
+\r
+#include <ntoskrnl.h>\r
+#include "kdb.h"\r
+#define NDEBUG\r
+#include <internal/debug.h>\r
+\r
+/* DEFINES *******************************************************************/\r
+\r
+#define KEY_BS          8\r
+#define KEY_ESC         27\r
+#define KEY_DEL         127\r
+\r
+#define KEY_SCAN_UP     72\r
+#define KEY_SCAN_DOWN   80\r
+\r
+#define KDB_ENTER_CONDITION_TO_STRING(cond)                               \\r
+                   ((cond) == KdbDoNotEnter ? "never" :                   \\r
+                   ((cond) == KdbEnterAlways ? "always" :                 \\r
+                   ((cond) == KdbEnterFromKmode ? "kmode" : "umode")))\r
+\r
+#define KDB_ACCESS_TYPE_TO_STRING(type)                                   \\r
+                   ((type) == KdbAccessRead ? "read" :                    \\r
+                   ((type) == KdbAccessWrite ? "write" :                  \\r
+                   ((type) == KdbAccessReadWrite ? "rdwr" : "exec")))\r
+\r
+#define NPX_STATE_TO_STRING(state)                                        \\r
+                   ((state) == NPX_STATE_INVALID ? "Invalid" :            \\r
+                   ((state) == NPX_STATE_VALID ? "Valid" :                \\r
+                   ((state) == NPX_STATE_DIRTY ? "Dirty" : "Unknown")))\r
+\r
+/* PROTOTYPES ****************************************************************/\r
+\r
+STATIC BOOLEAN KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdRegs(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]);\r
+\r
+STATIC BOOLEAN KdbpCmdContinue(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdStep(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]);\r
+\r
+STATIC BOOLEAN KdbpCmdThread(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdProc(ULONG Argc, PCHAR Argv[]);\r
+\r
+STATIC BOOLEAN KdbpCmdMod(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdPcr(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]);\r
+\r
+STATIC BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]);\r
+STATIC BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);\r
+\r
+/* GLOBALS *******************************************************************/\r
+\r
+STATIC BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */\r
+\r
+STATIC CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */\r
+STATIC PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */\r
+STATIC LONG KdbCommandHistoryBufferIndex = 0;\r
+STATIC LONG KdbCommandHistoryIndex = 0;\r
+\r
+STATIC ULONG KdbNumberOfRowsPrinted = 0;\r
+STATIC ULONG KdbNumberOfColsPrinted = 0;\r
+STATIC BOOLEAN KdbOutputAborted = FALSE;\r
+STATIC LONG KdbNumberOfRowsTerminal = -1;\r
+STATIC LONG KdbNumberOfColsTerminal = -1;\r
+\r
+PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDB.init file is loaded into during initialization */\r
+\r
+STATIC CONST struct\r
+{\r
+   PCHAR Name;\r
+   PCHAR Syntax;\r
+   PCHAR Help;\r
+   BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]);\r
+} KdbDebuggerCommands[] = {\r
+   /* Data */\r
+   { NULL, NULL, "Data", NULL },\r
+   { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression },\r
+   { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX },\r
+   { "x", "x [address] [L count]", "Display count dwords, starting at addr.", KdbpCmdDisassembleX },\r
+   { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs },\r
+   { "cregs", "cregs", "Display control registers.", KdbpCmdRegs },\r
+   { "sregs", "sregs", "Display status registers.", KdbpCmdRegs },\r
+   { "dregs", "dregs", "Display debug registers.", KdbpCmdRegs },\r
+   { "bt", "bt [*frameaddr|thread id]", "Prints current backtrace or from given frame addr", KdbpCmdBackTrace },\r
+\r
+   /* Flow control */\r
+   { NULL, NULL, "Flow control", NULL },\r
+   { "cont", "cont", "Continue execution (leave debugger)", KdbpCmdContinue },\r
+   { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep },\r
+   { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep },\r
+   { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList },\r
+   { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint },\r
+   { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint },\r
+   { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint },\r
+   { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint },\r
+   { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint },\r
+\r
+   /* Process/Thread */\r
+   { NULL, NULL, "Process/Thread", NULL },\r
+   { "thread", "thread [list[ pid]|[attach ]tid]", "List threads in current or specified process, display thread with given id or attach to thread.", KdbpCmdThread },\r
+   { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc },\r
+\r
+   /* System information */\r
+   { NULL, NULL, "System info", NULL },\r
+   { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod },\r
+   { "gdt", "gdt", "Display global descriptor table.", KdbpCmdGdtLdtIdt },\r
+   { "ldt", "ldt", "Display local descriptor table.", KdbpCmdGdtLdtIdt },\r
+   { "idt", "idt", "Display interrupt descriptor table.", KdbpCmdGdtLdtIdt },\r
+   { "pcr", "pcr", "Display processor control region.", KdbpCmdPcr },\r
+   { "tss", "tss", "Display task state segment.", KdbpCmdTss },\r
+\r
+   /* Others */\r
+   { NULL, NULL, "Others", NULL },\r
+   { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck },\r
+   { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet },\r
+   { "help", "help", "Display help screen.", KdbpCmdHelp }\r
+};\r
+\r
+/* FUNCTIONS *****************************************************************/\r
+\r
+/*!\brief Evaluates an expression...\r
+ *\r
+ * Much like KdbpRpnEvaluateExpression, but prints the error message (if any)\r
+ * at the given offset.\r
+ *\r
+ * \param Expression  Expression to evaluate.\r
+ * \param ErrOffset   Offset (in characters) to print the error message at.\r
+ * \param Result      Receives the result on success.\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpEvaluateExpression(\r
+   IN  PCHAR Expression,\r
+   IN  LONG ErrOffset,\r
+   OUT PULONGLONG Result)\r
+{\r
+   STATIC CHAR ErrMsgBuffer[130] = "^ ";\r
+   LONG ExpressionErrOffset = -1;\r
+   PCHAR ErrMsg = ErrMsgBuffer;\r
+   BOOLEAN Ok;\r
+\r
+   Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result,\r
+                                  &ExpressionErrOffset, ErrMsgBuffer + 2);\r
+   if (!Ok)\r
+   {\r
+      if (ExpressionErrOffset >= 0)\r
+         ExpressionErrOffset += ErrOffset;\r
+      else\r
+         ErrMsg += 2;\r
+      KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg);\r
+   }\r
+   \r
+   return Ok;\r
+}\r
+\r
+/*!\brief Evaluates an expression and displays the result.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[])\r
+{\r
+   INT i, len;\r
+   ULONGLONG Result = 0;\r
+   ULONG ul;\r
+   LONG l = 0;\r
+   BOOLEAN Ok;\r
+\r
+   if (Argc < 2)\r
+   {\r
+      KdbpPrint("?: Argument required\n");\r
+      return TRUE;\r
+   }\r
+   \r
+   /* Put the arguments back together */\r
+   Argc--;\r
+   for (i = 1; i < Argc; i++)\r
+   {\r
+      len = strlen(Argv[i]);\r
+      Argv[i][len] = ' ';\r
+   }\r
+   \r
+   /* Evaluate the expression */\r
+   Ok = KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result);\r
+   if (Ok)\r
+   {\r
+      if (Result > 0x00000000ffffffffLL)\r
+      {\r
+         if (Result & 0x8000000000000000LL)\r
+            KdbpPrint("0x%016I64x  %20I64u  %20I64d\n", Result, Result, Result);\r
+         else\r
+            KdbpPrint("0x%016I64x  %20I64u\n", Result, Result);\r
+      }\r
+      else\r
+      {\r
+         ul = (ULONG)Result;\r
+         if (ul <= 0xff && ul >= 0x80)\r
+            l = (LONG)((CHAR)ul);\r
+         else if (ul <= 0xffff && ul >= 0x8000)\r
+            l = (LONG)((SHORT)ul);\r
+         else\r
+            l = (LONG)ul;\r
+         if (l < 0)\r
+            KdbpPrint("0x%08lx  %10lu  %10ld\n", ul, ul, l);\r
+         else\r
+            KdbpPrint("0x%08lx  %10lu\n", ul, ul);\r
+      }\r
+   }\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Disassembles 10 instructions at eip or given address or\r
+ *        displays 16 dwords from memory at given address.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONG Count;\r
+   ULONG ul;\r
+   INT i;\r
+   ULONGLONG Result = 0;\r
+   ULONG_PTR Address = KdbCurrentTrapFrame->Tf.Eip;\r
+   LONG InstLen;\r
+\r
+   if (Argv[0][0] == 'x') /* display memory */\r
+      Count = 16;\r
+   else /* disassemble */\r
+      Count = 10;\r
+\r
+   if (Argc >= 2)\r
+   {\r
+      /* Check for [L count] part */\r
+      ul = 0;\r
+      if (strcmp(Argv[Argc-2], "L") == 0)\r
+      {\r
+         ul = strtoul(Argv[Argc-1], NULL, 0);\r
+         if (ul > 0)\r
+         {\r
+            Count = ul;\r
+            Argc -= 2;\r
+         }\r
+      }\r
+      else if (Argv[Argc-1][0] == 'L')\r
+      {\r
+         ul = strtoul(Argv[Argc-1] + 1, NULL, 0);\r
+         if (ul > 0)\r
+         {\r
+            Count = ul;\r
+            Argc--;\r
+         }\r
+      }\r
+\r
+      /* Put the remaining arguments back together */\r
+      Argc--;\r
+      for (ul = 1; ul < Argc; ul++)\r
+      {\r
+         Argv[ul][strlen(Argv[ul])] = ' ';\r
+      }\r
+      Argc++;\r
+   }\r
+\r
+   /* Evaluate the expression */\r
+   if (Argc > 1)\r
+   {\r
+      if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result))\r
+         return TRUE;\r
+      if (Result > (ULONGLONG)(~((ULONG_PTR)0)))\r
+         KdbpPrint("Warning: Address %I64x is beeing truncated\n");\r
+      Address = (ULONG_PTR)Result;\r
+   }\r
+   else if (Argv[0][0] == 'x')\r
+   {\r
+      KdbpPrint("x: Address argument required.\n");\r
+      return TRUE;\r
+   }\r
+\r
+   if (Argv[0][0] == 'x')\r
+   {\r
+      /* Display dwords */\r
+      ul = 0;\r
+      while (Count > 0)\r
+      {\r
+         if (!KdbSymPrintAddress((PVOID)Address))\r
+            KdbpPrint("<%x>:", Address);\r
+         else\r
+            KdbpPrint(":");\r
+         i = min(4, Count);\r
+         Count -= i;\r
+         while (--i >= 0)\r
+         {\r
+            if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul))))\r
+               KdbpPrint(" ????????");\r
+            else\r
+               KdbpPrint(" %08x", ul);\r
+            Address += sizeof(ul);\r
+         }\r
+         KdbpPrint("\n");\r
+      }\r
+   }\r
+   else\r
+   {\r
+      /* Disassemble */\r
+      while (Count-- > 0)\r
+      {\r
+         if (!KdbSymPrintAddress((PVOID)Address))\r
+            KdbpPrint("<%08x>: ", Address);\r
+         else\r
+            KdbpPrint(": ");\r
+         InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax);\r
+         if (InstLen < 0)\r
+         {\r
+            KdbpPrint("<INVALID>\n");\r
+            return TRUE;\r
+         }\r
+         KdbpPrint("\n");\r
+         Address += InstLen;\r
+      }\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays CPU registers.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdRegs(ULONG Argc, PCHAR Argv[])\r
+{\r
+   PKTRAP_FRAME Tf = &KdbCurrentTrapFrame->Tf;\r
+   INT i;\r
+   STATIC CONST PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5",\r
+                                         " ZF", " SF", " TF", " IF", " DF", " OF",\r
+                                         NULL, NULL, " NT", " BIT15", " RF", " VF",\r
+                                         " AC", " VIF", " VIP", " ID", " BIT22",\r
+                                         " BIT23", " BIT24", " BIT25", " BIT26",\r
+                                         " BIT27", " BIT28", " BIT29", " BIT30",\r
+                                         " BIT31" };\r
+\r
+   if (Argv[0][0] == 'r') /* regs */\r
+   {\r
+      KdbpPrint("CS:EIP  0x%04x:0x%08x\n"\r
+                "SS:ESP  0x%04x:0x%08x\n"\r
+                "   EAX  0x%08x   EBX  0x%08x\n"\r
+                "   ECX  0x%08x   EDX  0x%08x\n"\r
+                "   ESI  0x%08x   EDI  0x%08x\n"\r
+                "   EBP  0x%08x\n",\r
+                Tf->Cs & 0xFFFF, Tf->Eip,\r
+                Tf->Ss, Tf->Esp,\r
+                Tf->Eax, Tf->Ebx,\r
+                Tf->Ecx, Tf->Edx,\r
+                Tf->Esi, Tf->Edi,\r
+                Tf->Ebp);\r
+      KdbpPrint("EFLAGS  0x%08x ", Tf->Eflags);\r
+      for (i = 0; i < 32; i++)\r
+      {\r
+         if (i == 1)\r
+         {\r
+            if ((Tf->Eflags & (1 << 1)) == 0)\r
+               KdbpPrint(" !BIT1");\r
+         }\r
+         else if (i == 12)\r
+         {\r
+            KdbpPrint(" IOPL%d", (Tf->Eflags >> 12) & 3);\r
+         }\r
+         else if (i == 13)\r
+         {\r
+         }\r
+         else if ((Tf->Eflags & (1 << i)) != 0)\r
+            KdbpPrint(EflagsBits[i]);\r
+      }\r
+      KdbpPrint("\n");\r
+   }\r
+   else if (Argv[0][0] == 'c') /* cregs */\r
+   {\r
+      ULONG Cr0, Cr2, Cr3, Cr4;\r
+      struct __attribute__((packed)) {\r
+         USHORT Limit;\r
+         ULONG Base;\r
+      } Gdtr, Ldtr, Idtr;\r
+      ULONG Tr;\r
+      STATIC CONST PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL,\r
+                                         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
+                                         " WP", NULL, " AM", NULL, NULL, NULL, NULL, NULL,\r
+                                         NULL, NULL, NULL, NULL, NULL, " NW", " CD", " PG" };\r
+      STATIC CONST PCHAR Cr4Bits[32] = { " VME", " PVI", " TSD", " DE", " PSE", " PAE", " MCE", " PGE",\r
+                                         " PCE", " OSFXSR", " OSXMMEXCPT", NULL, NULL, NULL, NULL, NULL,\r
+                                         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\r
+                                         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };\r
+                                         \r
+      Cr0 = KdbCurrentTrapFrame->Cr0;\r
+      Cr2 = KdbCurrentTrapFrame->Cr2;\r
+      Cr3 = KdbCurrentTrapFrame->Cr3;\r
+      Cr4 = KdbCurrentTrapFrame->Cr4;\r
+\r
+      /* Get descriptor table regs */\r
+      asm volatile("sgdt %0" : : "m"(Gdtr));\r
+      asm volatile("sldt %0" : : "m"(Ldtr));\r
+      asm volatile("sidt %0" : : "m"(Idtr));\r
+\r
+      /* Get the task register */\r
+      asm volatile("str %0" : "=g"(Tr));\r
+      \r
+      /* Display the control registers */\r
+      KdbpPrint("CR0  0x%08x ", Cr0);\r
+      for (i = 0; i < 32; i++)\r
+      {\r
+         if (Cr0Bits[i] == NULL)\r
+            continue;\r
+         if ((Cr0 & (1 << i)) != 0)\r
+            KdbpPrint(Cr0Bits[i]);\r
+      }\r
+      KdbpPrint("\nCR2  0x%08x\n", Cr2);\r
+      KdbpPrint("CR3  0x%08x  Pagedir-Base 0x%08x %s%s\n", Cr3, (Cr3 & 0xfffff000),\r
+                (Cr3 & (1 << 3)) ? " PWT" : "", (Cr3 & (1 << 4)) ? " PCD" : "" );\r
+      KdbpPrint("CR4  0x%08x ", Cr4);\r
+      for (i = 0; i < 32; i++)\r
+      {\r
+         if (Cr4Bits[i] == NULL)\r
+            continue;\r
+         if ((Cr4 & (1 << i)) != 0)\r
+            KdbpPrint(Cr4Bits[i]);\r
+      }\r
+      \r
+      /* Display the descriptor table regs */\r
+      KdbpPrint("\nGDTR  Base 0x%08x  Size 0x%04x\n", Gdtr.Base, Gdtr.Limit);\r
+      KdbpPrint("LDTR  Base 0x%08x  Size 0x%04x\n", Ldtr.Base, Ldtr.Limit);\r
+      KdbpPrint("IDTR  Base 0x%08x  Size 0x%04x\n", Idtr.Base, Idtr.Limit);\r
+   }\r
+   else if (Argv[0][0] == 's') /* sregs */\r
+   {\r
+      KdbpPrint("CS  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Cs & 0xffff, (Tf->Cs & 0xffff) >> 3,\r
+                (Tf->Cs & (1 << 2)) ? 'L' : 'G', Tf->Cs & 3);\r
+      KdbpPrint("DS  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Ds, Tf->Ds >> 3, (Tf->Ds & (1 << 2)) ? 'L' : 'G', Tf->Ds & 3);\r
+      KdbpPrint("ES  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Es, Tf->Es >> 3, (Tf->Es & (1 << 2)) ? 'L' : 'G', Tf->Es & 3);\r
+      KdbpPrint("FS  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Fs, Tf->Fs >> 3, (Tf->Fs & (1 << 2)) ? 'L' : 'G', Tf->Fs & 3);\r
+      KdbpPrint("GS  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Gs, Tf->Gs >> 3, (Tf->Gs & (1 << 2)) ? 'L' : 'G', Tf->Gs & 3);\r
+      KdbpPrint("SS  0x%04x  Index 0x%04x  %cDT RPL%d\n",\r
+                Tf->Ss, Tf->Ss >> 3, (Tf->Ss & (1 << 2)) ? 'L' : 'G', Tf->Ss & 3);\r
+   }\r
+   else /* dregs */\r
+   {\r
+      ASSERT(Argv[0][0] == 'd');\r
+      KdbpPrint("DR0  0x%08x\n"\r
+                "DR1  0x%08x\n"\r
+                "DR2  0x%08x\n"\r
+                "DR3  0x%08x\n"\r
+                "DR6  0x%08x\n"\r
+                "DR7  0x%08x\n",\r
+                Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3,\r
+                Tf->Dr6, Tf->Dr7);\r
+   }\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays a backtrace.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONG Count;\r
+   ULONG ul;\r
+   ULONGLONG Result = 0;\r
+   ULONG_PTR Frame = KdbCurrentTrapFrame->Tf.Ebp;\r
+   ULONG_PTR Address;\r
+\r
+   if (Argc >= 2)\r
+   {\r
+      /* Check for [L count] part */\r
+      ul = 0;\r
+      if (strcmp(Argv[Argc-2], "L") == 0)\r
+      {\r
+         ul = strtoul(Argv[Argc-1], NULL, 0);\r
+         if (ul > 0)\r
+         {\r
+            Count = ul;\r
+            Argc -= 2;\r
+         }\r
+      }\r
+      else if (Argv[Argc-1][0] == 'L')\r
+      {\r
+         ul = strtoul(Argv[Argc-1] + 1, NULL, 0);\r
+         if (ul > 0)\r
+         {\r
+            Count = ul;\r
+            Argc--;\r
+         }\r
+      }\r
+\r
+      /* Put the remaining arguments back together */\r
+      Argc--;\r
+      for (ul = 1; ul < Argc; ul++)\r
+      {\r
+         Argv[ul][strlen(Argv[ul])] = ' ';\r
+      }\r
+      Argc++;\r
+   }\r
+\r
+   /* Check if frame addr or thread id is given. */\r
+   if (Argc > 1)\r
+   {\r
+      if (Argv[1][0] == '*')\r
+      {\r
+         Argv[1]++;\r
+         /* Evaluate the expression */\r
+         if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result))\r
+            return TRUE;\r
+         if (Result > (ULONGLONG)(~((ULONG_PTR)0)))\r
+            KdbpPrint("Warning: Address %I64x is beeing truncated\n");\r
+         Frame = (ULONG_PTR)Result;\r
+      }\r
+      else\r
+      {\r
+\r
+         KdbpPrint("Thread backtrace not supported yet!\n");\r
+         return TRUE;\r
+      }\r
+   }\r
+\r
+   KdbpPrint("Frames:\n");\r
+   while (Frame != 0)\r
+   {\r
+      if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof (ULONG_PTR))))\r
+      {\r
+         KdbpPrint("Couldn't access memory at 0x%x!\n", Frame + sizeof(ULONG_PTR));\r
+         break;\r
+      }\r
+      if (!KdbSymPrintAddress((PVOID)Address))\r
+         KdbpPrint("<%08x>\n", Address);\r
+      else\r
+         KdbpPrint("\n");\r
+      if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof (ULONG_PTR))))\r
+      {\r
+         KdbpPrint("Couldn't access memory at 0x%x!\n", Frame);\r
+         break;\r
+      }\r
+   }\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Continues execution of the system/leaves KDB.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdContinue(ULONG Argc, PCHAR Argv[])\r
+{\r
+   /* Exit the main loop */\r
+   return FALSE;\r
+}\r
+\r
+/*!\brief Continues execution of the system/leaves KDB.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdStep(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONG Count = 1;\r
+   \r
+   if (Argc > 1)\r
+   {\r
+      Count = strtoul(Argv[1], NULL, 0);\r
+      if (Count == 0)\r
+      {\r
+         KdbpPrint("%s: Integer argument required\n", Argv[0]);\r
+         return TRUE;\r
+      }\r
+   }\r
+   \r
+   if (Argv[0][0] == 'n')\r
+      KdbSingleStepOver = TRUE;\r
+   else\r
+      KdbSingleStepOver = FALSE;\r
+\r
+   /* Set the number of single steps and return to the interrupted code. */\r
+   KdbNumSingleSteps = Count;\r
+\r
+   return FALSE;\r
+}\r
+\r
+/*!\brief Lists breakpoints.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[])\r
+{\r
+   LONG l;\r
+   ULONG_PTR Address = 0;\r
+   KDB_BREAKPOINT_TYPE Type = 0;\r
+   KDB_ACCESS_TYPE AccessType = 0;\r
+   UCHAR Size = 0;\r
+   UCHAR DebugReg = 0;\r
+   BOOLEAN Enabled = FALSE;\r
+   BOOLEAN Global = FALSE;\r
+   PEPROCESS Process = NULL;\r
+   PCHAR str1, str2, ConditionExpr, GlobalOrLocal;\r
+   CHAR Buffer[20];\r
+\r
+   l = KdbpGetNextBreakPointNr(0);\r
+   if (l < 0)\r
+   {\r
+      KdbpPrint("No breakpoints.\n");\r
+      return TRUE;\r
+   }\r
+   \r
+   KdbpPrint("Breakpoints:\n");\r
+   do\r
+   {\r
+      if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg,\r
+                                 &Enabled, &Global, &Process, &ConditionExpr))\r
+      {\r
+         continue;\r
+      }\r
+\r
+      if (l == KdbLastBreakPointNr)\r
+      {\r
+         str1 = "\x1b[1m*";\r
+         str2 = "\x1b[0m";\r
+      }\r
+      else\r
+      {\r
+         str1 = " ";\r
+         str2 = "";\r
+      }\r
+\r
+      if (Global)\r
+         GlobalOrLocal = "  global";\r
+      else\r
+      {\r
+         GlobalOrLocal = Buffer;\r
+         sprintf(Buffer, "  PID 0x%08lx",\r
+                 (ULONG)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE));\r
+      }\r
+\r
+      if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary)\r
+      {\r
+         KdbpPrint(" %s%03d  BPX  0x%08x%s%s%s%s%s\n",\r
+                   str1, l, Address,\r
+                   Enabled ? "" : "  disabled",\r
+                   GlobalOrLocal,\r
+                   ConditionExpr ? "  IF " : "",\r
+                   ConditionExpr ? ConditionExpr : "",\r
+                   str2);\r
+      }\r
+      else if (Type == KdbBreakPointHardware)\r
+      {\r
+         if (!Enabled)\r
+         {\r
+            KdbpPrint(" %s%03d  BPM  0x%08x  %-5s %-5s  disabled%s%s%s%s\n", str1, l, Address,\r
+                      KDB_ACCESS_TYPE_TO_STRING(AccessType),\r
+                      Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"),\r
+                      GlobalOrLocal,\r
+                      ConditionExpr ? "  IF " : "",\r
+                      ConditionExpr ? ConditionExpr : "",\r
+                      str2);\r
+         }\r
+         else\r
+         {\r
+            KdbpPrint(" %s%03d  BPM  0x%08x  %-5s %-5s  DR%d%s%s%s%s\n", str1, l, Address,\r
+                      KDB_ACCESS_TYPE_TO_STRING(AccessType),\r
+                      Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"),\r
+                      DebugReg,\r
+                      GlobalOrLocal,\r
+                      ConditionExpr ? "  IF " : "",\r
+                      ConditionExpr ? ConditionExpr : "",\r
+                      str2);\r
+         }\r
+      }\r
+   }\r
+   while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0);\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Enables, disables or clears a breakpoint.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[])\r
+{\r
+   PCHAR pend;\r
+   ULONG BreakPointNr;\r
+\r
+   if (Argc < 2)\r
+   {\r
+      KdbpPrint("%s: argument required\n", Argv[0]);\r
+      return TRUE;\r
+   }\r
+\r
+   pend = Argv[1];\r
+   BreakPointNr = strtoul(Argv[1], &pend, 0);\r
+   if (pend == Argv[1] || *pend != '\0')\r
+   {\r
+      KdbpPrint("%s: integer argument required\n", Argv[0]);\r
+      return TRUE;\r
+   }\r
+\r
+   if (Argv[0][1] == 'e') /* enable */\r
+   {\r
+      KdbpEnableBreakPoint(BreakPointNr, NULL);\r
+   }\r
+   else if (Argv [0][1] == 'd') /* disable */\r
+   {\r
+      KdbpDisableBreakPoint(BreakPointNr, NULL);\r
+   }\r
+   else /* clear */\r
+   {\r
+      ASSERT(Argv[0][1] == 'c');\r
+      KdbpDeleteBreakPoint(BreakPointNr, NULL);\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Sets a software or hardware (memory) breakpoint at the given address.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONGLONG Result = 0;\r
+   ULONG_PTR Address;\r
+   KDB_BREAKPOINT_TYPE Type;\r
+   UCHAR Size = 0;\r
+   KDB_ACCESS_TYPE AccessType = 0;\r
+   INT AddressArgIndex, ConditionArgIndex, i;\r
+   BOOLEAN Global = TRUE;\r
+   \r
+   if (Argv[0][2] == 'x') /* software breakpoint */\r
+   {\r
+      if (Argc < 2)\r
+      {\r
+         KdbpPrint("bpx: Address argument required.\n");\r
+         return TRUE;\r
+      }\r
+\r
+      AddressArgIndex = 1;\r
+      Type = KdbBreakPointSoftware;\r
+   }\r
+   else /* memory breakpoint */\r
+   {\r
+      ASSERT(Argv[0][2] == 'm');\r
+      \r
+      if (Argc < 2)\r
+      {\r
+         KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n");\r
+         return TRUE;\r
+      }\r
+\r
+      if (_stricmp(Argv[1], "x") == 0)\r
+         AccessType = KdbAccessExec;\r
+      else if (_stricmp(Argv[1], "r") == 0)\r
+         AccessType = KdbAccessRead;\r
+      else if (_stricmp(Argv[1], "w") == 0)\r
+         AccessType = KdbAccessWrite;\r
+      else if (_stricmp(Argv[1], "rw") == 0)\r
+         AccessType = KdbAccessReadWrite;\r
+      else\r
+      {\r
+         KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]);\r
+         return TRUE;\r
+      }\r
+      \r
+      if (Argc < 3)\r
+      {\r
+         KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size");\r
+         return TRUE;\r
+      }\r
+      AddressArgIndex = 3;\r
+      if (_stricmp(Argv[2], "byte") == 0)\r
+         Size = 1;\r
+      else if (_stricmp(Argv[2], "word") == 0)\r
+         Size = 2;\r
+      else if (_stricmp(Argv[2], "dword") == 0)\r
+         Size = 4;\r
+      else if (AccessType == KdbAccessExec)\r
+      {\r
+         Size = 1;\r
+         AddressArgIndex--;\r
+      }\r
+      else\r
+      {\r
+         KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]);\r
+         return TRUE;\r
+      }\r
+      \r
+      if (Argc <= AddressArgIndex)\r
+      {\r
+         KdbpPrint("bpm: Address argument required.\n");\r
+         return TRUE;\r
+      }\r
+\r
+      Type = KdbBreakPointHardware;\r
+   }\r
+   \r
+   /* Put the arguments back together */\r
+   ConditionArgIndex = -1;\r
+   for (i = AddressArgIndex; i < (Argc-1); i++)\r
+   {\r
+      if (strcmp(Argv[i+1], "IF") == 0) /* IF found */\r
+      {\r
+         ConditionArgIndex = i + 2;\r
+         if (ConditionArgIndex >= Argc)\r
+         {\r
+            KdbpPrint("%s: IF requires condition expression.\n", Argv[0]);\r
+            return TRUE;\r
+         }\r
+         for (i = ConditionArgIndex; i < (Argc-1); i++)\r
+            Argv[i][strlen(Argv[i])] = ' ';\r
+         break;\r
+      }\r
+      Argv[i][strlen(Argv[i])] = ' ';\r
+   }\r
+\r
+   /* Evaluate the address expression */\r
+   if (!KdbpEvaluateExpression(Argv[AddressArgIndex],\r
+                               sizeof("kdb:> ")-1 + (Argv[AddressArgIndex]-Argv[0]),\r
+                               &Result))\r
+   {\r
+      return TRUE;\r
+   }\r
+   if (Result > (ULONGLONG)(~((ULONG_PTR)0)))\r
+      KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]);\r
+   Address = (ULONG_PTR)Result;\r
+\r
+   KdbpInsertBreakPoint(Address, Type, Size, AccessType,\r
+                        (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex],\r
+                        Global, NULL);\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Lists threads or switches to another thread context.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdThread(ULONG Argc, PCHAR Argv[])\r
+{\r
+   PLIST_ENTRY Entry;\r
+   PETHREAD Thread = NULL;\r
+   PEPROCESS Process = NULL;\r
+   PULONG Esp;\r
+   PULONG Ebp;\r
+   ULONG Eip, ul;\r
+   PCHAR State, pend, str1, str2;\r
+   STATIC CONST PCHAR ThreadStateToString[THREAD_STATE_MAX] =\r
+                                          { "Initialized", "Ready", "Running",\r
+                                            "Suspended", "Frozen", "Terminated1",\r
+                                            "Terminated2", "Blocked" };\r
+   ASSERT(KdbCurrentProcess != NULL);\r
+\r
+   if (Argc >= 2 && _stricmp(Argv[1], "list") == 0)\r
+   {\r
+      Process = KdbCurrentProcess;\r
+      \r
+      if (Argc >= 3)\r
+      {\r
+         ul = strtoul(Argv[2], &pend, 0);\r
+         if (Argv[2] == pend)\r
+         {\r
+            KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]);\r
+            return TRUE;\r
+         }\r
+         if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process)))\r
+         {\r
+            KdbpPrint("thread: Invalid process id!\n");\r
+            return TRUE;\r
+         }\r
+      }\r
+      \r
+      Entry = Process->ThreadListHead.Flink;\r
+      if (Entry == &Process->ThreadListHead)\r
+      {\r
+         if (Argc >= 3)\r
+            KdbpPrint("No threads in process 0x%08x!\n", ul);\r
+         else\r
+            KdbpPrint("No threads in current process!\n");\r
+         return TRUE;\r
+      }\r
+\r
+      KdbpPrint("  TID         State        Prior.  Affinity    EBP         EIP\n");\r
+      do\r
+      {\r
+         Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);\r
+\r
+         if (Thread == KdbCurrentThread)\r
+         {\r
+            str1 = "\x1b[1m*";\r
+            str2 = "\x1b[0m";\r
+         }\r
+         else\r
+         {\r
+            str1 = " ";\r
+            str2 = "";\r
+         }\r
+\r
+         if (Thread->Tcb.TrapFrame != NULL)\r
+         {\r
+            Esp = (PULONG)Thread->Tcb.TrapFrame->Esp;\r
+            Ebp = (PULONG)Thread->Tcb.TrapFrame->Ebp;\r
+            Eip = Thread->Tcb.TrapFrame->Eip;\r
+         }\r
+         else\r
+         {\r
+            Esp = (PULONG)Thread->Tcb.KernelStack;\r
+            Ebp = (PULONG)Esp[4];\r
+            Eip = 0;\r
+            if (Ebp != NULL) /* FIXME: Should we attach to the process to read Ebp[1]? */\r
+               KdbpSafeReadMemory(&Eip, Ebp + 1, sizeof (Eip));;\r
+         }\r
+         if (Thread->Tcb.State < THREAD_STATE_MAX)\r
+            State = ThreadStateToString[Thread->Tcb.State];\r
+         else\r
+            State = "Unknown";\r
+      \r
+         KdbpPrint(" %s0x%08x  %-11s  %3d     0x%08x  0x%08x  0x%08x%s\n",\r
+                   str1,\r
+                   Thread->Cid.UniqueThread,\r
+                   State,\r
+                   Thread->Tcb.Priority,\r
+                   Thread->Tcb.Affinity,\r
+                   Ebp,\r
+                   Eip,\r
+                   str2);\r
+      \r
+         Entry = Entry->Flink;\r
+      }\r
+      while (Entry != &Process->ThreadListHead);\r
+   }\r
+   else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0)\r
+   {\r
+      if (Argc < 3)\r
+      {\r
+         KdbpPrint("thread attach: thread id argument required!\n");\r
+         return TRUE;\r
+      }\r
+\r
+      ul = strtoul(Argv[2], &pend, 0);\r
+      if (Argv[2] == pend)\r
+      {\r
+         KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]);\r
+         return TRUE;\r
+      }\r
+      if (!KdbpAttachToThread((PVOID)ul))\r
+      {\r
+         return TRUE;\r
+      }\r
+      KdbpPrint("Attached to thread 0x%08x.\n", ul);\r
+   }\r
+   else\r
+   {\r
+      Thread = KdbCurrentThread;\r
+\r
+      if (Argc >= 2)\r
+      {\r
+         ul = strtoul(Argv[1], &pend, 0);\r
+         if (Argv[1] == pend)\r
+         {\r
+            KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]);\r
+            return TRUE;\r
+         }\r
+         if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread)))\r
+         {\r
+            KdbpPrint("thread: Invalid thread id!\n");\r
+            return TRUE;\r
+         }\r
+      }\r
+      \r
+      if (Thread->Tcb.State < THREAD_STATE_MAX)\r
+         State = ThreadStateToString[Thread->Tcb.State];\r
+      else\r
+         State = "Unknown";\r
+      KdbpPrint("%s"\r
+                "  TID:            0x%08x\n"\r
+                "  State:          %s (0x%x)\n"\r
+                "  Priority:       %d\n"\r
+                "  Affinity:       0x%08x\n"\r
+                "  Initial Stack:  0x%08x\n"\r
+                "  Stack Limit:    0x%08x\n"\r
+                "  Stack Base:     0x%08x\n"\r
+                "  Kernel Stack:   0x%08x\n"\r
+                "  Trap Frame:     0x%08x\n"\r
+                "  NPX State:      %s (0x%x)\n",\r
+                (Argc < 2) ? "Current Thread:\n" : "",\r
+                Thread->Cid.UniqueThread,\r
+                State, Thread->Tcb.State,\r
+                Thread->Tcb.Priority,\r
+                Thread->Tcb.Affinity,\r
+                Thread->Tcb.InitialStack,\r
+                Thread->Tcb.StackLimit,\r
+                Thread->Tcb.StackBase,\r
+                Thread->Tcb.KernelStack,\r
+                Thread->Tcb.TrapFrame,\r
+                NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState);\r
+\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Lists processes or switches to another process context.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdProc(ULONG Argc, PCHAR Argv[])\r
+{\r
+   PLIST_ENTRY Entry;\r
+   PEPROCESS Process;\r
+   PCHAR State, pend, str1, str2;\r
+   ULONG ul;\r
+   extern LIST_ENTRY PsActiveProcessHead;\r
+\r
+   if (Argc >= 2 && _stricmp(Argv[1], "list") == 0)\r
+   {\r
+      Entry = PsActiveProcessHead.Flink;\r
+      if (Entry == &PsActiveProcessHead)\r
+      {\r
+         KdbpPrint("No processes in the system!\n");\r
+         return TRUE;\r
+      }\r
+   \r
+      KdbpPrint("  PID         State       Filename\n");\r
+      do\r
+      {\r
+         Process = CONTAINING_RECORD(Entry, EPROCESS, ProcessListEntry);\r
+\r
+         if (Process == KdbCurrentProcess)\r
+         {\r
+            str1 = "\x1b[1m*";\r
+            str2 = "\x1b[0m";\r
+         }\r
+         else\r
+         {\r
+            str1 = " ";\r
+            str2 = "";\r
+         }\r
+\r
+         State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" :\r
+                 ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown"));\r
+      \r
+         KdbpPrint(" %s0x%08x  %-10s  %s%s\n",\r
+                   str1,\r
+                   Process->UniqueProcessId,\r
+                   State,\r
+                   Process->ImageFileName,\r
+                   str2);\r
+      \r
+         Entry = Entry->Flink;\r
+      }\r
+      while(Entry != &PsActiveProcessHead);\r
+   }\r
+   else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0)\r
+   {\r
+      if (Argc < 3)\r
+      {\r
+         KdbpPrint("process attach: process id argument required!\n");\r
+         return TRUE;\r
+      }\r
+\r
+      ul = strtoul(Argv[2], &pend, 0);\r
+      if (Argv[2] == pend)\r
+      {\r
+         KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]);\r
+         return TRUE;\r
+      }\r
+      if (!KdbpAttachToProcess((PVOID)ul))\r
+      {\r
+         return TRUE;\r
+      }\r
+      KdbpPrint("Attached to process 0x%08x, thread 0x%08x.\n", (UINT)ul,\r
+                (UINT)KdbCurrentThread->Cid.UniqueThread);\r
+   }\r
+   else\r
+   {\r
+      Process = KdbCurrentProcess;\r
+\r
+      if (Argc >= 2)\r
+      {\r
+         ul = strtoul(Argv[1], &pend, 0);\r
+         if (Argv[1] == pend)\r
+         {\r
+            KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]);\r
+            return TRUE;\r
+         }\r
+         if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process)))\r
+         {\r
+            KdbpPrint("proc: Invalid process id!\n");\r
+            return TRUE;\r
+         }\r
+      }\r
+\r
+      State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" :\r
+              ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown"));\r
+      KdbpPrint("%s"\r
+                "  PID:             0x%08x\n"\r
+                "  State:           %s (0x%x)\n"\r
+                "  Image Filename:  %s\n",\r
+                (Argc < 2) ? "Current process:\n" : "",\r
+                Process->UniqueProcessId,\r
+                State, Process->Pcb.State,\r
+                Process->ImageFileName);\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Lists loaded modules or the one containing the specified address.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdMod(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONGLONG Result = 0;\r
+   ULONG_PTR Address;\r
+   KDB_MODULE_INFO Info;\r
+   BOOLEAN DisplayOnlyOneModule = FALSE;\r
+   INT i = 0;\r
+\r
+   if (Argc >= 2)\r
+   {\r
+      /* Put the arguments back together */\r
+      Argc--;\r
+      while (--Argc >= 1)\r
+         Argv[Argc][strlen(Argv[Argc])] = ' ';\r
+\r
+      /* Evaluate the expression */\r
+      if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result))\r
+      {\r
+         return TRUE;\r
+      }\r
+      if (Result > (ULONGLONG)(~((ULONG_PTR)0)))\r
+         KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]);\r
+      Address = (ULONG_PTR)Result;\r
+      \r
+      if (!KdbpSymFindModuleByAddress((PVOID)Address, &Info))\r
+      {\r
+         KdbpPrint("No module containing address 0x%x found!\n", Address);\r
+         return TRUE;\r
+      }\r
+      DisplayOnlyOneModule = TRUE;\r
+   }\r
+   else\r
+   {\r
+      if (!KdbpSymFindModuleByIndex(0, &Info))\r
+      {\r
+         KdbpPrint("No modules.\n");\r
+         return TRUE;\r
+      }\r
+      i = 1;\r
+   }\r
+\r
+   KdbpPrint("  Base      Size      Name\n");\r
+   for (;;)\r
+   {\r
+      KdbpPrint("  %08x  %08x  %ws\n", Info.Base, Info.Size, Info.Name);\r
+\r
+      if ((!DisplayOnlyOneModule && !KdbpSymFindModuleByIndex(i++, &Info)) ||\r
+          DisplayOnlyOneModule)\r
+      {\r
+         break;\r
+      }\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays GDT, LDT or IDTd.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[])\r
+{\r
+   struct __attribute__((packed)) {\r
+      USHORT Limit;\r
+      ULONG Base;\r
+   } Reg;\r
+   ULONG SegDesc[2];\r
+   ULONG SegBase;\r
+   ULONG SegLimit;\r
+   PCHAR SegType;\r
+   USHORT SegSel;\r
+   UCHAR Type, Dpl;\r
+   INT i;\r
+   ULONG ul;\r
+\r
+   if (Argv[0][0] == 'i')\r
+   {\r
+      /* Read IDTR */\r
+      asm volatile("sidt %0" : : "m"(Reg));\r
+\r
+      if (Reg.Limit < 7)\r
+      {\r
+         KdbpPrint("Interrupt descriptor table is empty.\n");\r
+         return TRUE;\r
+      }\r
+      KdbpPrint("IDT Base: 0x%08x  Limit: 0x%04x\n", Reg.Base, Reg.Limit);\r
+      KdbpPrint("  Idx  Type        Seg. Sel.  Offset      DPL\n");\r
+      for ( ; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8)\r
+      {\r
+         if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc))))\r
+         {\r
+            KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i);\r
+            return TRUE;\r
+         }\r
+         \r
+         if ((SegDesc[1] & 0x1f00) == 0x0500)        /* Task gate */\r
+            SegType = "TASKGATE";\r
+         else if ((SegDesc[1] & 0x1fe0) == 0x0e00)   /* 32 bit Interrupt gate */\r
+            SegType = "INTGATE32";\r
+         else if ((SegDesc[1] & 0x1fe0) == 0x0600)   /* 16 bit Interrupt gate */\r
+            SegType = "INTGATE16";\r
+         else if ((SegDesc[1] & 0x1fe0) == 0x0f00)   /* 32 bit Trap gate */\r
+            SegType = "TRAPGATE32";\r
+         else if ((SegDesc[1] & 0x1fe0) == 0x0700)   /* 16 bit Trap gate */\r
+            SegType = "TRAPGATE16";\r
+\r
+         if ((SegDesc[1] & (1 << 15)) == 0) /* not present */\r
+         {\r
+            KdbpPrint("  %03d  %-10s  [NP]       [NP]        %02d\n",\r
+                      i / 8, SegType, Dpl);\r
+         }\r
+         else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */\r
+         {\r
+            SegSel = SegDesc[0] >> 16;\r
+            KdbpPrint("  %03d  %-10s  0x%04x                 %02d\n",\r
+                      i / 8, SegType, SegSel, Dpl);\r
+         }\r
+         else\r
+         {\r
+            SegSel = SegDesc[0] >> 16;\r
+            SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff);\r
+            KdbpPrint("  %03d  %-10s  0x%04x     0x%08x  %02d\n",\r
+                      i / 8, SegType, SegSel, SegBase, Dpl);\r
+         }\r
+      }\r
+   }\r
+   else\r
+   {\r
+      ul = 0;\r
+      if (Argv[0][0] == 'g')\r
+      {\r
+         /* Read GDTR */\r
+         asm volatile("sgdt %0" : : "m"(Reg));\r
+         i = 8;\r
+      }\r
+      else\r
+      {\r
+         ASSERT(Argv[0][0] == 'l');\r
+         /* Read LDTR */\r
+         asm volatile("sldt %0" : : "m"(Reg));\r
+         i = 0;\r
+         ul = 1 << 2;\r
+      }\r
+      \r
+      if (Reg.Limit < 7)\r
+      {\r
+         KdbpPrint("%s descriptor table is empty.\n",\r
+                   Argv[0][0] == 'g' ? "Global" : "Local");\r
+         return TRUE;\r
+      }\r
+      KdbpPrint("%cDT Base: 0x%08x  Limit: 0x%04x\n",\r
+                Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit);\r
+      KdbpPrint("  Idx  Sel.    Type         Base        Limit       DPL  Attribs\n");\r
+      for ( ; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8)\r
+      {\r
+         if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc))))\r
+         {\r
+            KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i);\r
+            return TRUE;\r
+         }\r
+         Dpl = ((SegDesc[1] >> 13) & 3);\r
+         Type = ((SegDesc[1] >> 8) & 0xf);\r
+\r
+         SegBase = SegDesc[0] >> 16;\r
+         SegBase |= (SegDesc[1] & 0xff) << 16;\r
+         SegBase |= SegDesc[1] & 0xff000000;\r
+         SegLimit = SegDesc[0] & 0x0000ffff;\r
+         SegLimit |= (SegDesc[1] >> 16) & 0xf;\r
+         if ((SegDesc[1] & (1 << 23)) != 0)\r
+         {\r
+            SegLimit *= 4096;\r
+            SegLimit += 4095;\r
+         }\r
+         else\r
+         {\r
+            SegLimit++;\r
+         }\r
+\r
+         if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */\r
+         {\r
+            switch (Type)\r
+            {\r
+            case 1: SegType = "TSS16(Avl)"; break;\r
+            case 2: SegType = "LDT"; break;\r
+            case 3: SegType = "TSS16(Busy)"; break;\r
+            case 4: SegType = "CALLGATE16"; break;\r
+            case 5: SegType = "TASKGATE"; break;\r
+            case 6: SegType = "INTGATE16"; break;\r
+            case 7: SegType = "TRAPGATE16"; break;\r
+            case 9: SegType = "TSS32(Avl)"; break;\r
+            case 11: SegType = "TSS32(Busy)"; break;\r
+            case 12: SegType = "CALLGATE32"; break;\r
+            case 14: SegType = "INTGATE32"; break;\r
+            case 15: SegType = "INTGATE32"; break;\r
+            default: SegType = "UNKNOWN"; break;\r
+            }\r
+            if (!(Type >= 1 && Type <= 3) &&\r
+                Type != 9 && Type != 11)\r
+            {\r
+               SegBase = 0;\r
+               SegLimit = 0;\r
+            }\r
+         }\r
+         else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */\r
+         {\r
+            if ((SegDesc[1] & (1 << 22)) != 0)\r
+               SegType = "DATA32";\r
+            else\r
+               SegType = "DATA16";\r
+\r
+         }\r
+         else /* Code segment */\r
+         {\r
+            if ((SegDesc[1] & (1 << 22)) != 0)\r
+               SegType = "CODE32";\r
+            else\r
+               SegType = "CODE16";\r
+         }\r
+\r
+         if ((SegDesc[1] & (1 << 15)) == 0) /* not present */\r
+         {\r
+            KdbpPrint("  %03d  0x%04x  %-11s  [NP]        [NP]        %02d   NP\n",\r
+                      i / 8, i | Dpl | ul, SegType, Dpl);\r
+         }\r
+         else\r
+         {\r
+            KdbpPrint("  %03d  0x%04x  %-11s  0x%08x  0x%08x  %02d  ",\r
+                      i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl);\r
+            if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */\r
+            {\r
+               /* FIXME: Display system segment */\r
+            }\r
+            else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */\r
+            {\r
+               if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */\r
+                  KdbpPrint(" E");\r
+               KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R");\r
+               if ((SegDesc[1] & (1 << 8)) != 0)\r
+                  KdbpPrint(" A");\r
+            }\r
+            else /* Code segment */\r
+            {\r
+               if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */\r
+                  KdbpPrint(" C");\r
+               KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X");\r
+               if ((SegDesc[1] & (1 << 8)) != 0)\r
+                  KdbpPrint(" A");\r
+            }\r
+            if ((SegDesc[1] & (1 << 20)) != 0)\r
+               KdbpPrint(" AVL");\r
+            KdbpPrint("\n");\r
+         }\r
+      }\r
+   }\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays the KPCR\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdPcr(ULONG Argc, PCHAR Argv[])\r
+{\r
+   PKPCR Pcr = KeGetCurrentKPCR();\r
+\r
+   KdbpPrint("Current PCR is at 0x%08x.\n", (INT)Pcr);\r
+   KdbpPrint("  Tib.ExceptionList:         0x%08x\n"\r
+             "  Tib.StackBase:             0x%08x\n"\r
+             "  Tib.StackLimit:            0x%08x\n"\r
+             "  Tib.SubSystemTib:          0x%08x\n"\r
+             "  Tib.FiberData/Version:     0x%08x\n"\r
+             "  Tib.ArbitraryUserPointer:  0x%08x\n"\r
+             "  Tib.Self:                  0x%08x\n"\r
+             "  Self:                      0x%08x\n"\r
+             "  PCRCB:                     0x%08x\n"\r
+             "  Irql:                      0x%02x\n"\r
+             "  IRR:                       0x%08x\n"\r
+             "  IrrActive:                 0x%08x\n"\r
+             "  IDR:                       0x%08x\n"\r
+             "  KdVersionBlock:            0x%08x\n"\r
+             "  IDT:                       0x%08x\n"\r
+             "  GDT:                       0x%08x\n"\r
+             "  TSS:                       0x%08x\n"\r
+             "  MajorVersion:              0x%04x\n"\r
+             "  MinorVersion:              0x%04x\n"\r
+             "  SetMember:                 0x%08x\n"\r
+             "  StallScaleFactor:          0x%08x\n"\r
+             "  DebugActive:               0x%02x\n"\r
+             "  ProcessorNumber:           0x%02x\n"\r
+             "  L2CacheAssociativity:      0x%02x\n"\r
+             "  VdmAlert:                  0x%08x\n"\r
+             "  L2CacheSize:               0x%08x\n"\r
+             "  InterruptMode:             0x%08x\n",\r
+             Pcr->Tib.ExceptionList, Pcr->Tib.StackBase, Pcr->Tib.StackLimit,\r
+             Pcr->Tib.SubSystemTib, Pcr->Tib.FiberData, Pcr->Tib.ArbitraryUserPointer,\r
+             Pcr->Tib.Self, Pcr->Self, Pcr->PCRCB, Pcr->Irql, Pcr->IRR, Pcr->IrrActive,\r
+             Pcr->IDR, Pcr->KdVersionBlock, Pcr->IDT, Pcr->GDT, Pcr->TSS,\r
+             Pcr->MajorVersion, Pcr->MinorVersion, Pcr->SetMember, Pcr->StallScaleFactor,\r
+             Pcr->DebugActive, Pcr->ProcessorNumber, Pcr->L2CacheAssociativity,\r
+             Pcr->VdmAlert, Pcr->L2CacheSize, Pcr->InterruptMode);\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays the TSS\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdTss(ULONG Argc, PCHAR Argv[])\r
+{\r
+   KTSS *Tss = KeGetCurrentKPCR()->TSS;\r
+\r
+   KdbpPrint("Current TSS is at 0x%08x.\n", (INT)Tss);\r
+   KdbpPrint("  PreviousTask:  0x%08x\n"\r
+             "  Ss0:Esp0:      0x%04x:0x%08x\n"\r
+             "  Ss1:Esp1:      0x%04x:0x%08x\n"\r
+             "  Ss2:Esp2:      0x%04x:0x%08x\n"\r
+             "  Cr3:           0x%08x\n"\r
+             "  Eip:           0x%08x\n"\r
+             "  Eflags:        0x%08x\n"\r
+             "  Eax:           0x%08x\n"\r
+             "  Ecx:           0x%08x\n"\r
+             "  Edx:           0x%08x\n"\r
+             "  Ebx:           0x%08x\n"\r
+             "  Esp:           0x%08x\n"\r
+             "  Ebp:           0x%08x\n"\r
+             "  Esi:           0x%08x\n"\r
+             "  Edi:           0x%08x\n"\r
+             "  Es:            0x%04x\n"\r
+             "  Cs:            0x%04x\n"\r
+             "  Ss:            0x%04x\n"\r
+             "  Ds:            0x%04x\n"\r
+             "  Fs:            0x%04x\n"\r
+             "  Gs:            0x%04x\n"\r
+             "  Ldt:           0x%04x\n"\r
+             "  Trap:          0x%04x\n"\r
+             "  IoMapBase:     0x%04x\n",\r
+             Tss->PreviousTask, Tss->Ss0, Tss->Esp0, Tss->Ss1, Tss->Esp1,\r
+             Tss->Ss2, Tss->Esp2, Tss->Cr3, Tss->Eip, Tss->Eflags, Tss->Eax,\r
+             Tss->Ecx, Tss->Edx, Tss->Ebx, Tss->Esp, Tss->Ebp, Tss->Esi,\r
+             Tss->Edi, Tss->Es, Tss->Cs, Tss->Ss, Tss->Ds, Tss->Fs, Tss->Gs,\r
+             Tss->Ldt, Tss->Trap, Tss->IoMapBase);\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Bugchecks the system.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[])\r
+{\r
+   KEBUGCHECK(0xDEADDEAD);\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Sets or displays a config variables value.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdSet(ULONG Argc, PCHAR Argv[])\r
+{\r
+   LONG l;\r
+   BOOLEAN First;\r
+   PCHAR pend = 0;\r
+   KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter;\r
+   KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter;\r
+   STATIC CONST PCHAR ExceptionNames[21] =\r
+      { "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP",\r
+        "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT",\r
+        "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK",\r
+        "MACHINECHECK", "SIMDFAULT", "OTHERS" };\r
+\r
+   if (Argc == 1)\r
+   {\r
+      KdbpPrint("Available settings:\n");\r
+      KdbpPrint("  syntax [intel|at&t]\n");\r
+      KdbpPrint("  condition [exception|*] [first|last] [never|always|kmode|umode]\n");\r
+   }\r
+   else if (strcmp(Argv[1], "syntax") == 0)\r
+   {\r
+      if (Argc == 2)\r
+         KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t");\r
+      else if (Argc >= 3)\r
+      {\r
+         if (_stricmp(Argv[2], "intel") == 0)\r
+            KdbUseIntelSyntax = TRUE;\r
+         else if (_stricmp(Argv[2], "at&t") == 0)\r
+            KdbUseIntelSyntax = FALSE;\r
+         else\r
+            KdbpPrint("Unknown syntax '%s'.\n", Argv[2]);\r
+      }\r
+   }\r
+   else if (strcmp(Argv[1], "condition") == 0)\r
+   {\r
+      if (Argc == 2)\r
+      {\r
+         KdbpPrint("Conditions:                 (First)  (Last)\n");\r
+         for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++)\r
+         {\r
+            if (ExceptionNames[l] == NULL)\r
+               continue;\r
+            if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst))\r
+               ASSERT(0);\r
+            if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast))\r
+               ASSERT(0);\r
+            KdbpPrint("  #%02d  %-20s %-8s %-8s\n", l, ExceptionNames[l],\r
+                      KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),\r
+                      KDB_ENTER_CONDITION_TO_STRING(ConditionLast));\r
+         }\r
+         ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1));\r
+         KdbpPrint("       %-20s %-8s %-8s\n", ExceptionNames[l],\r
+                   KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),\r
+                   KDB_ENTER_CONDITION_TO_STRING(ConditionLast));\r
+      }\r
+      else\r
+      {\r
+         if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */\r
+            l = -1;\r
+         else\r
+         {\r
+            l = (LONG)strtoul(Argv[2], &pend, 0);\r
+            if (Argv[2] == pend)\r
+            {\r
+               for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++)\r
+               {\r
+                  if (ExceptionNames[l] == NULL)\r
+                     continue;\r
+                  if (_stricmp(ExceptionNames[l], Argv[2]) == 0)\r
+                     break;\r
+               }\r
+            }\r
+            if (l >= RTL_NUMBER_OF(ExceptionNames))\r
+            {\r
+               KdbpPrint("Unknown exception '%s'.\n", Argv[2]);\r
+               return TRUE;\r
+            }\r
+         }\r
+         if (Argc > 4)\r
+         {\r
+            if (_stricmp(Argv[3], "first") == 0)\r
+               First = TRUE;\r
+            else if (_stricmp(Argv[3], "last") == 0)\r
+               First = FALSE;\r
+            else\r
+            {\r
+               KdbpPrint("set condition: second argument must be 'first' or 'last'\n");\r
+               return TRUE;\r
+            }\r
+            if (_stricmp(Argv[4], "never") == 0)\r
+               ConditionFirst = KdbDoNotEnter;\r
+            else if (_stricmp(Argv[4], "always") == 0)\r
+               ConditionFirst = KdbEnterAlways;\r
+            else if (_stricmp(Argv[4], "umode") == 0)\r
+               ConditionFirst = KdbEnterFromUmode;\r
+            else if (_stricmp(Argv[4], "kmode") == 0)\r
+               ConditionFirst = KdbEnterFromKmode;\r
+            else\r
+            {\r
+               KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n");\r
+               return TRUE;\r
+            }\r
+            if (!KdbpSetEnterCondition(l, First, ConditionFirst))\r
+            {\r
+               if (l >= 0)\r
+                  KdbpPrint("Couldn't change condition for exception #%02d\n", l);\r
+               else\r
+                  KdbpPrint("Couldn't change condition for all exceptions\n", l);\r
+            }\r
+         }\r
+         else /* Argc >= 3 */\r
+         {\r
+            if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst))\r
+               ASSERT(0);\r
+            if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast))\r
+               ASSERT(0);\r
+            if (l < (RTL_NUMBER_OF(ExceptionNames) - 1))\r
+            {\r
+               KdbpPrint("Condition for exception #%02d (%s): FirstChance %s  LastChance %s\n",\r
+                         l, ExceptionNames[l],\r
+                         KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),\r
+                         KDB_ENTER_CONDITION_TO_STRING(ConditionLast));\r
+            }\r
+            else\r
+            {\r
+               KdbpPrint("Condition for all other exceptions: FirstChance %s  LastChance %s\n",\r
+                         KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),\r
+                         KDB_ENTER_CONDITION_TO_STRING(ConditionLast));\r
+            }\r
+         }\r
+      }\r
+   }\r
+   else\r
+      KdbpPrint("Unknown setting '%s'.\n", Argv[1]);\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Displays help screen.\r
+ */\r
+STATIC BOOLEAN\r
+KdbpCmdHelp(ULONG Argc, PCHAR Argv[])\r
+{\r
+   ULONG i;\r
+\r
+   KdbpPrint("Kernel debugger commands:\n");\r
+   for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++)\r
+   {\r
+      if (KdbDebuggerCommands[i].Syntax == NULL) /* Command group */\r
+      {\r
+         if (i > 0)\r
+            KdbpPrint("\n");\r
+         KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help);\r
+         continue;\r
+      }\r
+\r
+      KdbpPrint("  %-20s - %s\n",\r
+                KdbDebuggerCommands[i].Syntax,\r
+                KdbDebuggerCommands[i].Help);\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Prints the given string with printf-like formatting.\r
+ *\r
+ * \param Format  Format of the string/arguments.\r
+ * \param ...     Variable number of arguments matching the format specified in \a Format.\r
+ *\r
+ * \note Doesn't correctly handle \\t and terminal escape sequences when calculating the\r
+ *       number of lines required to print a single line from the Buffer in the terminal.\r
+ */\r
+VOID\r
+KdbpPrint(\r
+   IN PCHAR Format,\r
+   IN ...  OPTIONAL)\r
+{\r
+   STATIC CHAR Buffer[4096];\r
+   STATIC BOOLEAN TerminalInitialized = FALSE;\r
+   STATIC BOOLEAN TerminalReportsSize = TRUE;\r
+   CHAR c;\r
+   PCHAR p;\r
+   INT Length;\r
+   INT i;\r
+   INT RowsPrintedByTerminal;\r
+   va_list ap;\r
+\r
+   /* Check if the user has aborted output of the current command */\r
+   if (KdbOutputAborted)\r
+      return;\r
+\r
+   /* Initialize the terminal */\r
+   if (!TerminalInitialized)\r
+   {\r
+      DbgPrint("\x1b[7h");      /* Enable linewrap */\r
+      TerminalInitialized = TRUE;\r
+   }\r
+\r
+   /* Get number of rows and columns in terminal */\r
+   if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||\r
+       (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */\r
+   {\r
+      if ((KdDebugState & KD_DEBUG_KDSERIAL) && TerminalReportsSize)\r
+      {\r
+         /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */\r
+         TerminalReportsSize = FALSE;\r
+         DbgPrint("\x1b[18t");\r
+         i = 10;\r
+         while ((i-- > 0) && ((c = KdbpTryGetCharSerial()) == -1));\r
+         if (c == KEY_ESC)\r
+         {\r
+            i = 5;\r
+            while ((i-- > 0) && ((c = KdbpTryGetCharSerial()) == -1));\r
+            if (c == '[')\r
+            {\r
+               Length = 0;\r
+               for (;;)\r
+               {\r
+                  i = 5;\r
+                  while ((i-- > 0) && ((c = KdbpTryGetCharSerial()) == -1));\r
+                  if (c == -1)\r
+                     break;\r
+                  Buffer[Length++] = c;\r
+                  if (isalpha(c) || Length >= (sizeof (Buffer) - 1))\r
+                     break;\r
+               }\r
+               Buffer[Length] = '\0';\r
+               if (Buffer[0] == '8' && Buffer[1] == ';')\r
+               {\r
+                  for (i = 2; (i < Length) && (Buffer[i] != ';'); i++);\r
+                  if (Buffer[i] == ';')\r
+                  {\r
+                     Buffer[i++] = '\0';\r
+                     /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */\r
+                     KdbNumberOfRowsTerminal = strtoul(Buffer + 2, NULL, 0);\r
+                     KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0);\r
+                     TerminalReportsSize = TRUE;\r
+                  }\r
+               }\r
+            }\r
+         }\r
+      }\r
+\r
+      if (KdbNumberOfRowsTerminal <= 0)\r
+      {\r
+         /* Set number of rows to the default. */\r
+         KdbNumberOfRowsTerminal = 24;\r
+      }\r
+      else if (KdbNumberOfColsTerminal <= 0)\r
+      {\r
+         /* Set number of cols to the default. */\r
+         KdbNumberOfColsTerminal = 80;\r
+      }\r
+   }\r
+\r
+   /* Get the string */\r
+   va_start(ap, Format);\r
+   Length = _vsnprintf(Buffer, sizeof (Buffer) - 1, Format, ap);\r
+   Buffer[Length] = '\0';\r
+   va_end(ap);\r
+\r
+   p = Buffer;\r
+   while (p[0] != '\0')\r
+   {\r
+      i = strcspn(p, "\n");\r
+      \r
+      /* Calculate the number of lines which will be printed in the terminal\r
+       * when outputting the current line\r
+       */\r
+      if (i > 0)\r
+         RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal;\r
+      else\r
+         RowsPrintedByTerminal = 0;\r
+      if (p[i] == '\n')\r
+         RowsPrintedByTerminal++;\r
+         \r
+      /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/\r
+\r
+      /* Display a prompt if we printed one screen full of text */\r
+      if ((KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)\r
+      {\r
+         if (KdbNumberOfColsPrinted > 0)\r
+            DbgPrint("\n");\r
+         DbgPrint("--- Press q to abort, any other key to continue ---");\r
+         while ((c = KdbpTryGetCharSerial()) == -1);\r
+         if (c == '\r')\r
+         {\r
+            /* Ignore \r and wait for \n or another \r - if \n is not received here\r
+             * it will be interpreted as "return" when the next command should be read.\r
+             */\r
+            while ((c = KdbpTryGetCharSerial()) == -1);\r
+         }\r
+         DbgPrint("\n");\r
+         if (c == 'q')\r
+         {\r
+            KdbOutputAborted = TRUE;\r
+            return;\r
+         }\r
+         KdbNumberOfRowsPrinted = 0;\r
+         KdbNumberOfColsPrinted = 0;\r
+      }\r
+\r
+      /* Insert a NUL after the line and print only the current line. */\r
+      if (p[i] == '\n' && p[i + 1] != '\0')\r
+      {\r
+         c = p[i + 1];\r
+         p[i + 1] = '\0';\r
+      }\r
+      else\r
+      {\r
+         c = '\0';\r
+      }\r
+\r
+      DbgPrint("%s", p);\r
+\r
+      if (c != '\0')\r
+         p[i + 1] = c;\r
+\r
+      /* Set p to the start of the next line and\r
+       * remember the number of rows/cols printed\r
+       */\r
+      p += i;\r
+      if (p[0] == '\n')\r
+      {\r
+         p++;\r
+         KdbNumberOfColsPrinted = 0;\r
+      }\r
+      else\r
+      {\r
+         ASSERT(p[0] == '\0');\r
+         KdbNumberOfColsPrinted += i;\r
+      }\r
+      KdbNumberOfRowsPrinted += RowsPrintedByTerminal;\r
+   }\r
+}\r
+\r
+/*!\brief Appends a command to the command history\r
+ *\r
+ * \param Command  Pointer to the command to append to the history.\r
+ */\r
+STATIC VOID\r
+KdbpCommandHistoryAppend(\r
+   IN PCHAR Command)\r
+{\r
+   LONG Length1 = strlen(Command) + 1;\r
+   LONG Length2 = 0;\r
+   INT i;\r
+   PCHAR Buffer;\r
+   \r
+   ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer));\r
+\r
+   if (Length1 <= 1 ||\r
+       (KdbCommandHistory[KdbCommandHistoryIndex] != NULL &&\r
+        strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0))\r
+   {\r
+      return;\r
+   }\r
+\r
+   /* Calculate Length1 and Length2 */\r
+   Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex;\r
+   KdbCommandHistoryBufferIndex += Length1;\r
+   if (KdbCommandHistoryBufferIndex >= RTL_NUMBER_OF(KdbCommandHistoryBuffer))\r
+   {\r
+      KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer);\r
+      Length2 = KdbCommandHistoryBufferIndex;\r
+      Length1 -= Length2;\r
+   }\r
+\r
+   /* Remove previous commands until there is enough space to append the new command */\r
+   for (i = KdbCommandHistoryIndex; KdbCommandHistory[i] != NULL;)\r
+   {\r
+      if ((Length2 > 0 &&\r
+           (KdbCommandHistory[i] >= Buffer ||\r
+            KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) ||\r
+          (Length2 <= 0 &&\r
+           (KdbCommandHistory[i] >= Buffer &&\r
+            KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))))\r
+      {\r
+         KdbCommandHistory[i] = NULL;\r
+      }\r
+      i--;\r
+      if (i < 0)\r
+         i = RTL_NUMBER_OF(KdbCommandHistory) - 1;\r
+      if (i == KdbCommandHistoryIndex)\r
+         break;\r
+   }\r
+\r
+   /* Make sure the new command history entry is free */\r
+   KdbCommandHistoryIndex++;\r
+   KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory);\r
+   if (KdbCommandHistory[KdbCommandHistoryIndex] != NULL)\r
+   {\r
+      KdbCommandHistory[KdbCommandHistoryIndex] = NULL;\r
+   }\r
+\r
+   /* Append command */\r
+   KdbCommandHistory[KdbCommandHistoryIndex] = Buffer;\r
+   ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer));\r
+   memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1);\r
+   if (Length2 > 0)\r
+   {\r
+      memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2);\r
+   }\r
+}\r
+\r
+/*!\brief Reads a line of user-input.\r
+ *\r
+ * \param Buffer  Buffer to store the input into. Trailing newlines are removed.\r
+ * \param Size    Size of \a Buffer.\r
+ *\r
+ * \note Accepts only \n newlines, \r is ignored.\r
+ */\r
+STATIC VOID\r
+KdbpReadCommand(\r
+   OUT PCHAR Buffer,\r
+   IN  ULONG Size)\r
+{\r
+   CHAR Key;\r
+   PCHAR Orig = Buffer;\r
+   ULONG ScanCode = 0;\r
+   BOOLEAN EchoOn;\r
+   STATIC CHAR LastCommand[1024] = "";\r
+   STATIC CHAR LastKey = '\0';\r
+   INT CmdHistIndex = -1;\r
+   INT i;\r
+\r
+   EchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);\r
+\r
+   for (;;)\r
+   {\r
+      if (KdDebugState & KD_DEBUG_KDSERIAL)\r
+      {\r
+         while ((Key = KdbpTryGetCharSerial()) == -1);\r
+         ScanCode = 0;\r
+         if (Key == KEY_ESC) /* ESC */\r
+         {\r
+            while ((Key = KdbpTryGetCharSerial()) == -1);\r
+            if (Key == '[')\r
+            {\r
+               while ((Key = KdbpTryGetCharSerial()) == -1);\r
+               switch (Key)\r
+               {\r
+               case 'A':\r
+                  ScanCode = KEY_SCAN_UP;\r
+                  break;\r
+               case 'B':\r
+                  ScanCode = KEY_SCAN_DOWN;\r
+                  break;\r
+               case 'C':\r
+                  break;\r
+               case 'D':\r
+                  break;\r
+               }\r
+            }\r
+         }\r
+      }\r
+      else\r
+         while ((Key = KdbpTryGetCharKeyboard(&ScanCode)) == -1);\r
+\r
+      if ((Buffer - Orig) >= (Size - 1))\r
+      {\r
+         /* Buffer is full, accept only newlines */\r
+         if (Key != '\n')\r
+            continue;\r
+      }\r
+\r
+      if (Key == '\r')\r
+      {\r
+         /* Ignore this key... */\r
+      }\r
+      else if (Key == '\n')\r
+      {\r
+         DbgPrint("\n");\r
+        /*\r
+         * Repeat the last command if the user presses enter. Reduces the\r
+         * risk of RSI when single-stepping.\r
+         */\r
+        if (Buffer == Orig)\r
+        {\r
+            strncpy(Buffer, LastCommand, Size);\r
+            Buffer[Size - 1] = '\0';\r
+        }\r
+        else\r
+        {\r
+            *Buffer = '\0';\r
+            strncpy(LastCommand, Orig, sizeof (LastCommand));\r
+            LastCommand[sizeof (LastCommand) - 1] = '\0';\r
+         }\r
+         LastKey = Key;\r
+         return;\r
+      }\r
+      else if (Key == KEY_BS || Key == KEY_DEL)\r
+      {\r
+         if (Buffer > Orig)\r
+         {\r
+            Buffer--;\r
+            *Buffer = 0;\r
+            if (EchoOn)\r
+               DbgPrint("%c %c", KEY_BS, KEY_BS);\r
+           else\r
+               DbgPrint(" %c", KEY_BS);\r
+         }\r
+      }\r
+      else if (ScanCode == KEY_SCAN_UP)\r
+      {\r
+         BOOLEAN Print = TRUE;\r
+         if (CmdHistIndex < 0)\r
+            CmdHistIndex = KdbCommandHistoryIndex;\r
+         else\r
+         {\r
+            i = CmdHistIndex - 1;\r
+            if (i < 0)\r
+               CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1;\r
+            if (KdbCommandHistory[i] != NULL && i != KdbCommandHistoryIndex)\r
+               CmdHistIndex = i;\r
+            else\r
+               Print = FALSE;\r
+         }\r
+         if (Print && KdbCommandHistory[CmdHistIndex] != NULL)\r
+         {\r
+            while (Buffer > Orig)\r
+            {\r
+               Buffer--;\r
+               *Buffer = 0;\r
+               if (EchoOn)\r
+                  DbgPrint("%c %c", KEY_BS, KEY_BS);\r
+               else\r
+                  DbgPrint(" %c", KEY_BS);\r
+            }\r
+            i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);\r
+            memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);\r
+            Orig[i] = '\0';\r
+            Buffer = Orig + i;\r
+            DbgPrint("%s", Orig);\r
+         }\r
+      }\r
+      else if (ScanCode == KEY_SCAN_DOWN)\r
+      {\r
+         if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex)\r
+         {\r
+            i = CmdHistIndex + 1;\r
+            if (i >= RTL_NUMBER_OF(KdbCommandHistory))\r
+               i = 0;\r
+            if (KdbCommandHistory[i] != NULL)\r
+            {\r
+               CmdHistIndex = i;\r
+               while (Buffer > Orig)\r
+               {\r
+                  Buffer--;\r
+                  *Buffer = 0;\r
+                  if (EchoOn)\r
+                     DbgPrint("%c %c", KEY_BS, KEY_BS);\r
+                  else\r
+                     DbgPrint(" %c", KEY_BS);\r
+               }\r
+               i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);\r
+               memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);\r
+               Orig[i] = '\0';\r
+               Buffer = Orig + i;\r
+               DbgPrint("%s", Orig);\r
+            }\r
+         }\r
+      }\r
+      else\r
+      {\r
+         if (EchoOn)\r
+            DbgPrint("%c", Key);\r
+\r
+         *Buffer = Key;\r
+         Buffer++;\r
+      }\r
+      LastKey = Key;\r
+   }\r
+}\r
+\r
+/*!\brief Parses command line and executes command if found\r
+ *\r
+ * \param Command    Command line to parse and execute if possible.\r
+ *\r
+ * \retval TRUE   Don't continue execution.\r
+ * \retval FALSE  Continue execution (leave KDB)\r
+ */\r
+STATIC BOOL\r
+KdbpDoCommand(\r
+   IN PCHAR Command)\r
+{\r
+   ULONG i;\r
+   PCHAR p;\r
+   ULONG Argc;\r
+   STATIC PCH Argv[256];\r
+   STATIC CHAR OrigCommand[1024];\r
+\r
+   strncpy(OrigCommand, Command, sizeof(OrigCommand) - 1);\r
+   OrigCommand[sizeof(OrigCommand) - 1] = '\0';\r
+\r
+   Argc = 0;\r
+   p = Command;\r
+   for (;;)\r
+   {\r
+      while (*p == '\t' || *p == ' ')\r
+         p++;\r
+      if (*p == '\0')\r
+         break;\r
+         \r
+      i = strcspn(p, "\t ");\r
+      Argv[Argc++] = p;\r
+      p += i;\r
+      if (*p == '\0')\r
+         break;\r
+      *p = '\0';\r
+      p++;\r
+   }\r
+   if (Argc < 1)\r
+      return TRUE;\r
+\r
+   for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++)\r
+   {\r
+      if (KdbDebuggerCommands[i].Name == NULL)\r
+         continue;\r
+\r
+      if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0)\r
+      {\r
+         return KdbDebuggerCommands[i].Fn(Argc, Argv);\r
+      }\r
+   }\r
+\r
+   KdbpPrint("Command '%s' is unknown.\n", OrigCommand);\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief KDB Main Loop.\r
+ *\r
+ * \param EnteredOnSingleStep  TRUE if KDB was entered on single step.\r
+ */\r
+VOID\r
+KdbpCliMainLoop(\r
+   IN BOOLEAN EnteredOnSingleStep)\r
+{\r
+   STATIC CHAR Command[1024];\r
+   BOOLEAN Continue;\r
+\r
+   if (EnteredOnSingleStep)\r
+   {\r
+      if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip))\r
+      {\r
+         DbgPrint("<%x>", KdbCurrentTrapFrame->Tf.Eip);\r
+      }\r
+      DbgPrint(": ");\r
+      if (KdbpDisassemble(KdbCurrentTrapFrame->Tf.Eip, KdbUseIntelSyntax) < 0)\r
+      {\r
+         DbgPrint("<INVALID>");\r
+      }\r
+      DbgPrint("\n");\r
+   }\r
+\r
+   do\r
+   {\r
+      /* Print the prompt */\r
+      DbgPrint("kdb:> ");\r
+\r
+      /* Read a command and remember it */\r
+      KdbpReadCommand(Command, sizeof (Command));\r
+      KdbpCommandHistoryAppend(Command);\r
+      \r
+      /* Reset the number of rows/cols printed and output aborted state */\r
+      KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;\r
+      KdbOutputAborted = FALSE;\r
+      \r
+      /* Call the command */\r
+      Continue = KdbpDoCommand(Command);\r
+   } while (Continue);\r
+}\r
+\r
+/*!\brief Called when a module is loaded.\r
+ *\r
+ * \param Name  Filename of the module which was loaded.\r
+ */\r
+VOID\r
+KdbpCliModuleLoaded(IN PUNICODE_STRING Name)\r
+{\r
+   return;\r
+\r
+   DbgPrint("Module %wZ loaded.\n", Name);\r
+   DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);\r
+}\r
+\r
+/*!\brief This function is called by KdbEnterDebuggerException...\r
+ *\r
+ * Used to interpret the init file in a context with a trapframe setup\r
+ * (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will\r
+ * call this function if KdbInitFileBuffer is not NULL.\r
+ */\r
+VOID\r
+KdbpCliInterpretInitFile()\r
+{\r
+   PCHAR p1, p2;\r
+   INT i;\r
+   CHAR c;\r
+\r
+   /* Execute the commands in the init file */\r
+   DbgPrint("KDB: Executing KDB.init file...\n");\r
+   p1 = KdbInitFileBuffer;\r
+   while (p1[0] != '\0')\r
+   {\r
+      i = strcspn(p1, "\r\n");\r
+      if (i > 0)\r
+      {\r
+         c = p1[i];\r
+         p1[i] = '\0';\r
+\r
+         /* Look for "break" command and comments */\r
+         p2 = p1;\r
+         while (isspace(p2[0]))\r
+            p2++;\r
+         if (strncmp(p2, "break", sizeof("break")-1) == 0 &&\r
+             (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1])))\r
+         {\r
+            /* break into the debugger */\r
+            KdbpCliMainLoop(FALSE);\r
+         }\r
+         else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */\r
+         {\r
+            KdbpDoCommand(p1);\r
+         }\r
+         \r
+         p1[i] = c;\r
+      }\r
+      p1 += i;\r
+      while (p1[0] == '\r' || p1[0] == '\n')\r
+         p1++;\r
+   }\r
+   DbgPrint("KDB: KDB.init executed\n");\r
+}\r
+\r
+/*!\brief Called when KDB is initialized\r
+ *\r
+ * Reads the KDB.init file from the SystemRoot\system32\drivers\etc directory and executes it.\r
+ */\r
+VOID\r
+KdbpCliInit()\r
+{\r
+   NTSTATUS Status;\r
+   OBJECT_ATTRIBUTES ObjectAttributes;\r
+   UNICODE_STRING FileName;\r
+   IO_STATUS_BLOCK Iosb;\r
+   FILE_STANDARD_INFORMATION FileStdInfo;\r
+   HANDLE hFile = NULL;\r
+   INT FileSize;\r
+   PCHAR FileBuffer;\r
+   ULONG OldEflags;\r
+\r
+   /* Initialize the object attributes */\r
+   RtlInitUnicodeString(&FileName, L"\\SystemRoot\\system32\\drivers\\etc\\KDB.init");\r
+   InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL);\r
+   \r
+   /* Open the file */\r
+   Status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0,\r
+                       FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |\r
+                       FILE_NO_INTERMEDIATE_BUFFERING);\r
+   if (!NT_SUCCESS(Status))\r
+   {\r
+      DPRINT("Could not open \\SystemRoot\\system32\\drivers\\etc\\KDB.init (Status 0x%x)", Status);\r
+      return;\r
+   }\r
+\r
+   /* Get the size of the file */\r
+   Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof (FileStdInfo),\r
+                                   FileStandardInformation);\r
+   if (!NT_SUCCESS(Status))\r
+   {\r
+      ZwClose(hFile);\r
+      DPRINT("Could not query size of \\SystemRoot\\system32\\drivers\\etc\\KDB.init (Status 0x%x)", Status);\r
+      return;\r
+   }\r
+   FileSize = FileStdInfo.EndOfFile.u.LowPart;\r
+\r
+   /* Allocate memory for the file */\r
+   FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */\r
+   if (FileBuffer == NULL)\r
+   {\r
+      ZwClose(hFile);\r
+      DPRINT("Could not allocate %d bytes for KDB.init file\n", FileSize);\r
+      return;\r
+   }\r
+\r
+   /* Load file into memory */\r
+   Status = ZwReadFile(hFile, 0, 0, 0, &Iosb, FileBuffer, FileSize, 0, 0);\r
+   ZwClose(hFile);\r
+   if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)\r
+   {\r
+      ExFreePool(FileBuffer);\r
+      DPRINT("Could not read KDB.init file into memory (Status 0x%lx)\n", Status);\r
+      return;\r
+   }\r
+   FileSize = min(FileSize, Iosb.Information);\r
+   FileBuffer[FileSize] = '\0';\r
+\r
+   /* Enter critical section */\r
+   Ke386SaveFlags(OldEflags);\r
+   Ke386DisableInterrupts();\r
+\r
+   /* Interpret the init file... */\r
+   KdbInitFileBuffer = FileBuffer;\r
+   KdbEnter();\r
+   KdbInitFileBuffer = NULL;\r
+\r
+   /* Leave critical section */\r
+   Ke386RestoreFlags(OldEflags);\r
+\r
+   ExFreePool(FileBuffer);\r
+}\r
+\r
diff --git a/reactos/ntoskrnl/dbg/kdb_expr.c b/reactos/ntoskrnl/dbg/kdb_expr.c
new file mode 100644 (file)
index 0000000..fb36fed
--- /dev/null
@@ -0,0 +1,1081 @@
+/*\r
+ *  ReactOS kernel\r
+ *  Copyright (C) 2005 ReactOS Team\r
+ *\r
+ *  This program is free software; you can redistribute it and/or modify\r
+ *  it under the terms of the GNU General Public License as published by\r
+ *  the Free Software Foundation; either version 2 of the License, or\r
+ *  (at your option) any later version.\r
+ *\r
+ *  This program is distributed in the hope that it will be useful,\r
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *  GNU General Public License for more details.\r
+ *\r
+ *  You should have received a copy of the GNU General Public License\r
+ *  along with this program; if not, write to the Free Software\r
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+/* $Id$\r
+ *\r
+ * PROJECT:         ReactOS kernel\r
+ * FILE:            ntoskrnl/dbg/kdb_expr.c\r
+ * PURPOSE:         Kernel debugger expression evaluation\r
+ * PROGRAMMER:      Gregor Anich (blight@blight.eu.org)\r
+ * UPDATE HISTORY:\r
+ *                  Created 15/01/2005\r
+ */\r
+\r
+/* Note:\r
+ *\r
+ * The given expression is parsed and stored in reverse polish notation,\r
+ * then it is evaluated and the result is returned.\r
+ */\r
+\r
+/* INCLUDES ******************************************************************/\r
+\r
+#include <ntoskrnl.h>\r
+#include "kdb.h"\r
+#define NDEBUG\r
+#include <internal/debug.h>\r
+\r
+/* TYPES *********************************************************************/\r
+typedef enum _RPN_OP_TYPE\r
+{\r
+   RpnOpNop,\r
+   RpnOpBinaryOperator,\r
+   RpnOpUnaryOperator,\r
+   RpnOpImmediate,\r
+   RpnOpRegister,\r
+   RpnOpDereference\r
+} RPN_OP_TYPE;\r
+\r
+typedef ULONGLONG (*RPN_BINARY_OPERATOR)(ULONGLONG a, ULONGLONG b);\r
+\r
+typedef struct _RPN_OP\r
+{\r
+   RPN_OP_TYPE  Type;\r
+   ULONG        CharacterOffset;\r
+   union {\r
+      /* RpnOpBinaryOperator */\r
+      RPN_BINARY_OPERATOR  BinaryOperator;\r
+      /* RpnOpImmediate */\r
+      ULONGLONG            Immediate;\r
+      /* RpnOpRegister */\r
+      UCHAR                Register;\r
+      /* RpnOpDereference */\r
+      UCHAR                DerefMemorySize;\r
+   } Data;\r
+} RPN_OP, *PRPN_OP;\r
+\r
+typedef struct _RPN_STACK\r
+{\r
+   ULONG   Size;     /* Number of RPN_OPs on Ops */\r
+   ULONG   Sp;       /* Stack pointer */\r
+   RPN_OP  Ops[1];   /* Array of RPN_OPs */\r
+} RPN_STACK, *PRPN_STACK;\r
+\r
+/* DEFINES *******************************************************************/\r
+#define stricmp _stricmp\r
+\r
+#ifndef RTL_FIELD_SIZE\r
+# define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))\r
+#endif\r
+\r
+#define CONST_STRCPY(dst, src) \\r
+        do { if ((dst) != NULL) { memcpy(dst, src, sizeof(src)); } } while (0);\r
+\r
+#define RPN_OP_STACK_SIZE     256\r
+#define RPN_VALUE_STACK_SIZE  256\r
+\r
+/* GLOBALS *******************************************************************/\r
+STATIC struct { ULONG Size; ULONG Sp; RPN_OP Ops[RPN_OP_STACK_SIZE]; } RpnStack = { RPN_OP_STACK_SIZE, 0 };\r
+\r
+STATIC CONST struct { PCHAR Name; UCHAR Offset; UCHAR Size; } RegisterToTrapFrame[] =\r
+{\r
+   {"eip",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eip),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eip)},\r
+   {"eflags",  FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eflags),  RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eflags)},\r
+   {"eax",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eax),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eax)},\r
+   {"ebx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebx)},\r
+   {"ecx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ecx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ecx)},\r
+   {"edx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edx)},\r
+   {"esi",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Esi),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Esi)},\r
+   {"edi",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edi),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edi)},\r
+   {"esp",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Esp),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Esp)},\r
+   {"ebp",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebp),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebp)},\r
+   {"cs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Cs),      2 }, /* Use only the lower 2 bytes */\r
+   {"ds",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ds),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ds)},\r
+   {"es",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Es),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Es)},\r
+   {"fs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Fs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Fs)},\r
+   {"gs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Gs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Gs)},\r
+   {"ss",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ss),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ss)},\r
+   {"dr0",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr0),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr0)},\r
+   {"dr1",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr1),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr1)},\r
+   {"dr2",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr2),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr2)},\r
+   {"dr3",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr3),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr3)},\r
+   {"dr6",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr6),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr6)},\r
+   {"dr7",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr7),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr7)},\r
+   {"cr0",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr0),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr0)},\r
+   {"cr2",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr2),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr2)},\r
+   {"cr3",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr3),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr3)},\r
+   {"cr4",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr4),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr4)}\r
+};\r
+STATIC CONST INT RegisterToTrapFrameCount =\r
+                     sizeof (RegisterToTrapFrame) / sizeof (RegisterToTrapFrame[0]);\r
+\r
+/* FUNCTIONS *****************************************************************/\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorAdd(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return a + b;\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorSub(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return a - b;\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorMul(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return a * b;\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorDiv(ULONGLONG a, ULONGLONG b)\r
+{\r
+\r
+   return a / b;\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorMod(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return a % b;\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorEquals(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a == b);\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorNotEquals(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a != b);\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorLessThan(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a < b);\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorLessThanOrEquals(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a <= b);\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorGreaterThan(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a > b);\r
+}\r
+\r
+ULONGLONG\r
+RpnBinaryOperatorGreaterThanOrEquals(ULONGLONG a, ULONGLONG b)\r
+{\r
+   return (a >= b);\r
+}\r
+\r
+/*!\brief Dumps the given RPN stack content\r
+ *\r
+ * \param Stack  Pointer to a RPN_STACK structure.\r
+ */\r
+VOID\r
+RpnpDumpStack(\r
+   IN PRPN_STACK Stack)\r
+{\r
+   ULONG ul;\r
+\r
+   ASSERT(Stack != NULL);\r
+   DbgPrint("\nStack size: %ld\n", Stack->Sp);\r
+   for (ul = 0; ul < Stack->Sp; ul++)\r
+   {\r
+      PRPN_OP Op = Stack->Ops + ul;\r
+      switch (Op->Type)\r
+      {\r
+      case RpnOpNop:\r
+         DbgPrint("NOP,");\r
+         break;\r
+         \r
+      case RpnOpImmediate:\r
+         DbgPrint("0x%I64x,", Op->Data.Immediate);\r
+         break;\r
+         \r
+      case RpnOpBinaryOperator:\r
+         if (Op->Data.BinaryOperator == RpnBinaryOperatorAdd)\r
+            DbgPrint("+,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorSub)\r
+            DbgPrint("-,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorMul)\r
+            DbgPrint("*,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorDiv)\r
+            DbgPrint("/,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorMod)\r
+            DbgPrint("%%,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorEquals)\r
+            DbgPrint("==,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorNotEquals)\r
+            DbgPrint("!=,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThan)\r
+            DbgPrint("<,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThanOrEquals)\r
+            DbgPrint("<=,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThan)\r
+            DbgPrint(">,");\r
+         else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThanOrEquals)\r
+            DbgPrint(">=,");\r
+         else\r
+            DbgPrint("UNKNOWN OP,");\r
+         break;\r
+         \r
+      case RpnOpRegister:\r
+         DbgPrint("%s,", RegisterToTrapFrame[Op->Data.Register].Name);\r
+         break;\r
+         \r
+      case RpnOpDereference:\r
+         DbgPrint("[%s],",\r
+                (Op->Data.DerefMemorySize == 1) ? ("byte") :\r
+                ((Op->Data.DerefMemorySize == 2) ? ("word") :\r
+                 ((Op->Data.DerefMemorySize == 4) ? ("dword") : ("qword"))\r
+                )\r
+               );\r
+         break;\r
+         \r
+      default:\r
+         DbgPrint("\nUnsupported Type: %d\n", Op->Type);\r
+         ul = Stack->Sp;\r
+         break;\r
+      }\r
+   }\r
+   DbgPrint("\n");\r
+}\r
+\r
+/*!\brief Clears the given RPN stack.\r
+ *\r
+ * \param Stack  Pointer to a RPN_STACK structure.\r
+ */\r
+STATIC VOID\r
+RpnpClearStack(\r
+   OUT PRPN_STACK Stack)\r
+{\r
+   ASSERT(Stack != NULL);\r
+   Stack->Sp = 0;\r
+}\r
+\r
+/*!\brief Pushes an RPN_OP onto the stack.\r
+ *\r
+ * \param Stack  Pointer to a RPN_STACK structure.\r
+ * \param Op     RPN_OP to be copied onto the stack.\r
+ */\r
+STATIC BOOLEAN\r
+RpnpPushStack(\r
+   IN OUT PRPN_STACK Stack,\r
+   IN     PRPN_OP Op)\r
+{\r
+   ASSERT(Stack != NULL);\r
+   ASSERT(Op != NULL);\r
+\r
+   if (Stack->Sp >= Stack->Size)\r
+      return FALSE;\r
+\r
+   memcpy(Stack->Ops + Stack->Sp, Op, sizeof (RPN_OP));\r
+   Stack->Sp++;\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Pops the top op from the stack.\r
+ *\r
+ * \param Stack  Pointer to a RPN_STACK structure.\r
+ * \param Op     Pointer to an RPN_OP to store the popped op into (can be NULL).\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure (stack empty)\r
+ */\r
+STATIC BOOLEAN\r
+RpnpPopStack(\r
+   IN OUT PRPN_STACK Stack,\r
+   OUT    PRPN_OP Op  OPTIONAL)\r
+{\r
+   ASSERT(Stack != NULL);\r
+\r
+   if (Stack->Sp == 0)\r
+      return FALSE;\r
+\r
+   Stack->Sp--;\r
+   if (Op != NULL)\r
+      memcpy(Op, Stack->Ops + Stack->Sp, sizeof (RPN_OP));\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Gets the top op from the stack (not popping it)\r
+ *\r
+ * \param Stack  Pointer to a RPN_STACK structure.\r
+ * \param Op     Pointer to an RPN_OP to copy the top op into.\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure (stack empty)\r
+ */\r
+STATIC BOOLEAN\r
+RpnpTopStack(\r
+   IN  PRPN_STACK Stack,\r
+   OUT PRPN_OP Op)\r
+{\r
+   ASSERT(Stack != NULL);\r
+   ASSERT(Op != NULL);\r
+\r
+   if (Stack->Sp == 0)\r
+      return FALSE;\r
+\r
+   memcpy(Op, Stack->Ops + Stack->Sp - 1, sizeof (RPN_OP));\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Parses an expression.\r
+ *\r
+ * This functions parses the given expression until the end of string or a closing\r
+ * brace is found. As the function parses the string it pushes RPN_OPs onto the\r
+ * stack.\r
+ *\r
+ * Examples: 1+2*3 ; eax+10 ; (eax+16) * (ebx+4) ; dword[eax]\r
+ *\r
+ * \param Stack            Pointer to a RPN_STACK structure.\r
+ * \param Expression       String to parse.\r
+ * \param CharacterOffset  Character offset of the subexpression from the beginning of the expression.\r
+ * \param End              On success End is set to the character at which parsing stopped.\r
+ * \param ErrOffset        On failure this is set to the character offset at which the error occoured.\r
+ * \param ErrMsg           On failure a message describing the problem is copied into this buffer (128 bytes)\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure.\r
+ */\r
+STATIC BOOLEAN\r
+RpnpParseExpression(\r
+   IN  PRPN_STACK Stack,\r
+   IN  PCHAR Expression,\r
+   OUT PCHAR *End  OPTIONAL,\r
+   IN  ULONG CharacterOffset,\r
+   OUT PLONG ErrOffset  OPTIONAL,\r
+   OUT PCHAR ErrMsg  OPTIONAL)\r
+{\r
+   PCHAR p = Expression;\r
+   PCHAR pend;\r
+   PCHAR Operator = NULL;\r
+   LONG OperatorOffset = -1;\r
+   RPN_OP RpnOp;\r
+   RPN_OP PoppedOperator;\r
+   BOOLEAN HavePoppedOperator = FALSE;\r
+   RPN_OP ComparativeOp;\r
+   BOOLEAN ComparativeOpFilled = FALSE;\r
+   BOOLEAN IsComparativeOp;\r
+   INT i, i2;\r
+   ULONG ul;\r
+   UCHAR MemorySize;\r
+   CHAR Buffer[16];\r
+   BOOLEAN First;\r
+\r
+   ASSERT(Stack != NULL);\r
+   ASSERT(Expression != NULL);\r
+\r
+   First = TRUE;\r
+   for (;;)\r
+   {\r
+      /* Skip whitespace */\r
+      while (isspace(*p))\r
+      {\r
+         p++;\r
+         CharacterOffset++;\r
+      }\r
+      \r
+      /* Check for end of expression */\r
+      if (p[0] == '\0' || p[0] == ')' || p[0] == ']')\r
+         break;\r
+\r
+      if (!First)\r
+      {\r
+         /* Remember operator */\r
+         Operator = p++;\r
+         OperatorOffset = CharacterOffset++;;\r
+      \r
+         /* Pop operator (to get the right operator precedence) */\r
+         HavePoppedOperator = FALSE;\r
+         if (*Operator == '*' || *Operator == '/' || *Operator == '%')\r
+         {\r
+            if (RpnpTopStack(Stack, &PoppedOperator) &&\r
+                PoppedOperator.Type == RpnOpBinaryOperator &&\r
+                (PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorAdd ||\r
+                PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorSub))\r
+            {\r
+               RpnpPopStack(Stack, NULL);\r
+               HavePoppedOperator = TRUE;\r
+            }\r
+            else if (PoppedOperator.Type == RpnOpNop)\r
+            {\r
+               RpnpPopStack(Stack, NULL);\r
+               /* Discard the NOP - it was only pushed to indicate there was a\r
+                * closing brace, so the previous operator shouldn't be popped.\r
+                */\r
+            }\r
+         }\r
+         else if ((Operator[0] == '=' && Operator[1] == '=') ||\r
+                  (Operator[0] == '!' && Operator[1] == '=') ||\r
+                  Operator[0] == '<' || Operator[0] == '>')\r
+         {\r
+            if (Operator[0] == '=' || Operator[0] == '!' ||\r
+                (Operator[0] == '<' && Operator[1] == '=') ||\r
+                (Operator[0] == '>' && Operator[1] == '='))\r
+            {\r
+               p++;\r
+               CharacterOffset++;\r
+            }\r
+#if 0\r
+            /* Parse rest of expression */\r
+            if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,\r
+                                     ErrOffset, ErrMsg))\r
+            {\r
+               return FALSE;\r
+            }\r
+            else if (pend == p + 1)\r
+            {\r
+               CONST_STRCPY(ErrMsg, "Expression expected");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = CharacterOffset + 1;\r
+               return FALSE;\r
+            }\r
+            goto end_of_expression; /* return */\r
+#endif\r
+         }\r
+         else if (Operator[0] != '+' && Operator[0] != '-')\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Operator expected");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = OperatorOffset;\r
+            return FALSE;\r
+         }\r
+\r
+         /* Skip whitespace */\r
+         while (isspace(*p))\r
+         {\r
+            p++;\r
+            CharacterOffset++;\r
+         }\r
+      }\r
+\r
+      /* Get operand */\r
+      MemorySize = sizeof(ULONG_PTR); /* default to pointer size */\r
+get_operand:\r
+      i = strcspn(p, "+-*/%()[]<>!=");\r
+      if (i > 0)\r
+      {\r
+         i2 = i;\r
+\r
+         /* Copy register name/memory size */\r
+         while (isspace(p[--i2]));\r
+         i2 = min(i2 + 1, sizeof (Buffer) - 1);\r
+         strncpy(Buffer, p, i2);\r
+         Buffer[i2] = '\0';\r
+\r
+         /* Memory size prefix */\r
+         if (p[i] == '[')\r
+         {\r
+            if (stricmp(Buffer, "byte") == 0)\r
+               MemorySize = 1;\r
+            else if (stricmp(Buffer, "word") == 0)\r
+               MemorySize = 2;\r
+            else if (stricmp(Buffer, "dword") == 0)\r
+               MemorySize = 4;\r
+            else if (stricmp(Buffer, "qword") == 0)\r
+               MemorySize = 8;\r
+            else\r
+            {\r
+               CONST_STRCPY(ErrMsg, "Invalid memory size prefix");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = CharacterOffset;\r
+               return FALSE;\r
+            }\r
+            \r
+            p += i;\r
+            CharacterOffset += i;\r
+            goto get_operand;\r
+         }\r
+\r
+         /* Try to find register */\r
+         for (i = 0; i < RegisterToTrapFrameCount; i++)\r
+         {\r
+            if (stricmp(RegisterToTrapFrame[i].Name, Buffer) == 0)\r
+               break;\r
+         }\r
+         if (i < RegisterToTrapFrameCount)\r
+         {\r
+            RpnOp.Type = RpnOpRegister;\r
+            RpnOp.CharacterOffset = CharacterOffset;\r
+            RpnOp.Data.Register = i;\r
+            i = strlen(RegisterToTrapFrame[i].Name);\r
+            CharacterOffset += i;\r
+            p += i;\r
+         }\r
+         else\r
+         {\r
+            /* Immediate value */\r
+            /* FIXME: Need string to ULONGLONG function */\r
+            ul = strtoul(p, &pend, 0);\r
+            if (p != pend)\r
+            {\r
+               RpnOp.Type = RpnOpImmediate;\r
+               RpnOp.CharacterOffset = CharacterOffset;\r
+               RpnOp.Data.Immediate = (ULONGLONG)ul;\r
+               CharacterOffset += pend - p;\r
+               p = pend;\r
+            }\r
+            else\r
+            {\r
+               CONST_STRCPY(ErrMsg, "Operand expected");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = CharacterOffset;\r
+               return FALSE;\r
+            }\r
+         }\r
+\r
+         /* Push operand */\r
+         if (!RpnpPushStack(Stack, &RpnOp))\r
+         {\r
+            CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+      }\r
+      else if (i == 0)\r
+      {\r
+         if (p[0] == '(' || p[0] == '[') /* subexpression */\r
+         {\r
+            if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,\r
+                                     ErrOffset, ErrMsg))\r
+            {\r
+               return FALSE;\r
+            }\r
+            else if (pend == p + 1)\r
+            {\r
+               CONST_STRCPY(ErrMsg, "Expression expected");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = CharacterOffset + 1;\r
+               return FALSE;\r
+            }\r
+\r
+            if (p[0] == '[') /* dereference */\r
+            {\r
+               ASSERT(MemorySize == 1 || MemorySize == 2 ||\r
+                      MemorySize == 4 || MemorySize == 8);\r
+               if (pend[0] != ']')\r
+               {\r
+                  CONST_STRCPY(ErrMsg, "']' expected");\r
+                  if (ErrOffset != NULL)\r
+                     *ErrOffset = CharacterOffset + (pend - p);\r
+                  return FALSE;\r
+               }\r
+               RpnOp.Type = RpnOpDereference;\r
+               RpnOp.CharacterOffset = CharacterOffset;\r
+               RpnOp.Data.DerefMemorySize = MemorySize;\r
+               if (!RpnpPushStack(Stack, &RpnOp))\r
+               {\r
+                  CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+                  if (ErrOffset != NULL)\r
+                     *ErrOffset = -1;\r
+                  return FALSE;\r
+               }\r
+            }\r
+            else /* p[0] == '(' */\r
+            {\r
+               if (pend[0] != ')')\r
+               {\r
+                  CONST_STRCPY(ErrMsg, "')' expected");\r
+                  if (ErrOffset != NULL)\r
+                     *ErrOffset = CharacterOffset + (pend - p);\r
+                  return FALSE;\r
+               }\r
+            }\r
+\r
+            /* Push a "nop" to prevent popping of the + operator (which would\r
+             * result in (10+10)/2 beeing evaluated as 15)\r
+             */\r
+            RpnOp.Type = RpnOpNop;\r
+            if (!RpnpPushStack(Stack, &RpnOp))\r
+            {\r
+               CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = -1;\r
+               return FALSE;\r
+            }\r
+\r
+            /* Skip closing brace/bracket */\r
+            pend++;\r
+            \r
+            CharacterOffset += pend - p;\r
+            p = pend;\r
+         }\r
+         else if (First && p[0] == '-') /* Allow expressions like "- eax" */\r
+         {\r
+            RpnOp.Type = RpnOpImmediate;\r
+            RpnOp.CharacterOffset = CharacterOffset;\r
+            RpnOp.Data.Immediate = 0;\r
+            if (!RpnpPushStack(Stack, &RpnOp))\r
+            {\r
+               CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = -1;\r
+               return FALSE;\r
+            }\r
+         }\r
+         else\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Operand expected");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = CharacterOffset;\r
+            return FALSE;\r
+         }\r
+      }\r
+      else\r
+      {\r
+         CONST_STRCPY(ErrMsg, "strcspn() failed");\r
+         if (ErrOffset != NULL)\r
+            *ErrOffset = -1;\r
+         return FALSE;\r
+      }\r
+\r
+      if (!First)\r
+      {\r
+         /* Push operator */\r
+         RpnOp.CharacterOffset = OperatorOffset;\r
+         RpnOp.Type = RpnOpBinaryOperator;\r
+         IsComparativeOp = FALSE;\r
+         switch (*Operator)\r
+         {\r
+         case '+':\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorAdd;\r
+            break;\r
+\r
+         case '-':\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorSub;\r
+            break;\r
+\r
+         case '*':\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorMul;\r
+            break;\r
+\r
+         case '/':\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorDiv;\r
+            break;\r
+\r
+         case '%':\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorMod;\r
+            break;\r
+\r
+         case '=':\r
+            ASSERT(Operator[1] == '=');\r
+            IsComparativeOp = TRUE;\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorEquals;\r
+            break;\r
+            \r
+         case '!':\r
+            ASSERT(Operator[1] == '=');\r
+            IsComparativeOp = TRUE;\r
+            RpnOp.Data.BinaryOperator = RpnBinaryOperatorNotEquals;\r
+            break;\r
+\r
+         case '<':\r
+            IsComparativeOp = TRUE;\r
+            if (Operator[1] == '=')\r
+               RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThanOrEquals;\r
+            else\r
+               RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThan;\r
+            break;\r
+\r
+         case '>':\r
+            IsComparativeOp = TRUE;\r
+            if (Operator[1] == '=')\r
+               RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThanOrEquals;\r
+            else\r
+               RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThan;\r
+            break;\r
+\r
+         default:\r
+            ASSERT(0);\r
+            break;\r
+         }\r
+         if (IsComparativeOp)\r
+         {\r
+            if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))\r
+            {\r
+               CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = -1;\r
+               return FALSE;\r
+            }\r
+            memcpy(&ComparativeOp, &RpnOp, sizeof(RPN_OP));\r
+            ComparativeOpFilled = TRUE;\r
+         }\r
+         else if (!RpnpPushStack(Stack, &RpnOp))\r
+         {\r
+            CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+\r
+         /* Push popped operator */\r
+         if (HavePoppedOperator)\r
+         {\r
+            if (!RpnpPushStack(Stack, &PoppedOperator))\r
+            {\r
+               CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+               if (ErrOffset != NULL)\r
+                  *ErrOffset = -1;\r
+               return FALSE;\r
+            }\r
+         }\r
+      }\r
+      \r
+      First = FALSE;\r
+   }\r
+   \r
+//end_of_expression:\r
+\r
+   if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))\r
+   {\r
+      CONST_STRCPY(ErrMsg, "RPN op stack overflow");\r
+      if (ErrOffset != NULL)\r
+         *ErrOffset = -1;\r
+      return FALSE;\r
+   }\r
+\r
+   /* Skip whitespace */\r
+   while (isspace(*p))\r
+   {\r
+      p++;\r
+      CharacterOffset++;\r
+   }\r
+\r
+   if (End != NULL)\r
+      *End = p;\r
+   \r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Evaluates the RPN op stack and returns the result.\r
+ *\r
+ * \param Stack      Pointer to a RPN_STACK structure.\r
+ * \param TrapFrame  Register values.\r
+ * \param Result     Pointer to an ULONG to store the result into.\r
+ * \param ErrOffset  On failure this is set to the character offset at which the error occoured.\r
+ * \param ErrMsg     Buffer which receives an error message on failure (128 bytes)\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure.\r
+ */\r
+STATIC BOOLEAN\r
+RpnpEvaluateStack(\r
+   IN  PRPN_STACK Stack,\r
+   IN  PKDB_KTRAP_FRAME TrapFrame,\r
+   OUT PULONGLONG Result,\r
+   OUT PLONG ErrOffset  OPTIONAL,\r
+   OUT PCHAR ErrMsg  OPTIONAL)\r
+{\r
+   ULONGLONG ValueStack[RPN_VALUE_STACK_SIZE];\r
+   ULONG ValueStackPointer = 0;\r
+   ULONG index;\r
+   ULONGLONG ull;\r
+   ULONG ul;\r
+   USHORT us;\r
+   UCHAR uc;\r
+   PVOID p;\r
+   BOOLEAN Ok;\r
+#ifdef DEBUG_RPN\r
+   ULONG ValueStackPointerMax = 0;\r
+#endif\r
+\r
+   ASSERT(Stack != NULL);\r
+   ASSERT(TrapFrame != NULL);\r
+   ASSERT(Result != NULL);\r
+\r
+   for (index = 0; index < Stack->Sp; index++)\r
+   {\r
+      PRPN_OP Op = Stack->Ops + index;\r
+\r
+#ifdef DEBUG_RPN\r
+      ValueStackPointerMax = max(ValueStackPointerMax, ValueStackPointer);\r
+#endif\r
+\r
+      switch (Op->Type)\r
+      {\r
+      case RpnOpNop:\r
+         /* No operation */\r
+         break;\r
+         \r
+      case RpnOpImmediate:\r
+         if (ValueStackPointer == RPN_VALUE_STACK_SIZE)\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Value stack overflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+         ValueStack[ValueStackPointer++] = Op->Data.Immediate;\r
+         break;\r
+\r
+      case RpnOpRegister:\r
+         if (ValueStackPointer == RPN_VALUE_STACK_SIZE)\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Value stack overflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+         ul = Op->Data.Register;\r
+         p = (PVOID)((ULONG_PTR)TrapFrame + RegisterToTrapFrame[ul].Offset);\r
+         switch (RegisterToTrapFrame[ul].Size)\r
+         {\r
+         case 1: ull = (ULONGLONG)(*(PUCHAR)p); break;\r
+         case 2: ull = (ULONGLONG)(*(PUSHORT)p); break;\r
+         case 4: ull = (ULONGLONG)(*(PULONG)p); break;\r
+         case 8: ull = (ULONGLONG)(*(PULONGLONG)p); break;\r
+         default: ASSERT(0); return FALSE; break;\r
+         }\r
+         ValueStack[ValueStackPointer++] = ull;\r
+         break;\r
+\r
+      case RpnOpDereference:\r
+         if (ValueStackPointer < 1)\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Value stack underflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+\r
+         /* FIXME: Print a warning when address is out of range */\r
+         p = (PVOID)(ULONG_PTR)ValueStack[ValueStackPointer - 1];\r
+         Ok = FALSE;\r
+         switch (Op->Data.DerefMemorySize)\r
+         {\r
+         case 1:\r
+            if (NT_SUCCESS(KdbpSafeReadMemory(&uc, p, sizeof (uc))))\r
+            {\r
+               Ok = TRUE;\r
+               ull = (ULONGLONG)uc;\r
+            }\r
+            break;\r
+         case 2:\r
+            if (NT_SUCCESS(KdbpSafeReadMemory(&us, p, sizeof (us))))\r
+            {\r
+               Ok = TRUE;\r
+               ull = (ULONGLONG)us;\r
+            }\r
+            break;\r
+         case 4:\r
+            if (NT_SUCCESS(KdbpSafeReadMemory(&ul, p, sizeof (ul))))\r
+            {\r
+               Ok = TRUE;\r
+               ull = (ULONGLONG)ul;\r
+            }\r
+            break;\r
+         case 8:\r
+            if (NT_SUCCESS(KdbpSafeReadMemory(&ull, p, sizeof (ull))))\r
+            {\r
+               Ok = TRUE;\r
+            }\r
+            break;\r
+         default:\r
+            ASSERT(0);\r
+            return FALSE;\r
+            break;\r
+         }\r
+         if (!Ok)\r
+         {\r
+            _snprintf(ErrMsg, 128, "Couldn't access memory at 0x%lx", (ULONG)p);\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = Op->CharacterOffset;\r
+            return FALSE;\r
+         }\r
+         ValueStack[ValueStackPointer - 1] = ull;\r
+         break;\r
+\r
+      case RpnOpBinaryOperator:\r
+         if (ValueStackPointer < 2)\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Value stack underflow");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = -1;\r
+            return FALSE;\r
+         }\r
+         ValueStackPointer--;\r
+         ull = ValueStack[ValueStackPointer];\r
+         if (ull == 0 && (Op->Data.BinaryOperator == RpnBinaryOperatorDiv ||\r
+                          Op->Data.BinaryOperator == RpnBinaryOperatorDiv))\r
+         {\r
+            CONST_STRCPY(ErrMsg, "Devision by zero");\r
+            if (ErrOffset != NULL)\r
+               *ErrOffset = Op->CharacterOffset;\r
+            return FALSE;\r
+         }\r
+         ull = Op->Data.BinaryOperator(ValueStack[ValueStackPointer - 1], ull);\r
+         ValueStack[ValueStackPointer - 1] = ull;\r
+         break;\r
+\r
+      default:\r
+         ASSERT(0);\r
+         return FALSE;\r
+      }\r
+   }\r
+#ifdef DEBUG_RPN\r
+   DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax);\r
+#endif\r
+   if (ValueStackPointer != 1)\r
+   {\r
+      CONST_STRCPY(ErrMsg, "Stack not empty after evaluation");\r
+      if (ErrOffset != NULL)\r
+         *ErrOffset = -1;\r
+      return FALSE;\r
+   }\r
+   \r
+   *Result = ValueStack[0];\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Evaluates the given expression\r
+ *\r
+ * \param Expression  Expression to evaluate.\r
+ * \param TrapFrame   Register values.\r
+ * \param Result      Variable which receives the result on success.\r
+ * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)\r
+ * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)\r
+ *\r
+ * \retval TRUE   Success.\r
+ * \retval FALSE  Failure.\r
+ */\r
+BOOLEAN\r
+KdbpRpnEvaluateExpression(\r
+   IN  PCHAR Expression,\r
+   IN  PKDB_KTRAP_FRAME TrapFrame,\r
+   OUT PULONGLONG Result,\r
+   OUT PLONG ErrOffset  OPTIONAL,\r
+   OUT PCHAR ErrMsg  OPTIONAL)\r
+{\r
+   PRPN_STACK Stack = (PRPN_STACK)&RpnStack;\r
+   \r
+   ASSERT(Expression != NULL);\r
+   ASSERT(TrapFrame != NULL);\r
+   ASSERT(Result != NULL);\r
+\r
+   /* Clear the stack and parse the expression */\r
+   RpnpClearStack(Stack);\r
+   if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))\r
+   {\r
+      return FALSE;\r
+   }\r
+#ifdef DEBUG_RPN\r
+   RpnpDumpStack(Stack);\r
+#endif\r
+\r
+   /* Evaluate the stack */\r
+   if (!RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg))\r
+   {\r
+      return FALSE;\r
+   }\r
+\r
+   return TRUE;\r
+}\r
+\r
+/*!\brief Parses the given expression and returns a "handle" to it.\r
+ *\r
+ * \param Expression  Expression to evaluate.\r
+ * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)\r
+ * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)\r
+ *\r
+ * \returns "Handle" for the expression, NULL on failure.\r
+ *\r
+ * \sa KdbpRpnEvaluateExpression\r
+ */\r
+PVOID\r
+KdbpRpnParseExpression(\r
+   IN  PCHAR Expression,\r
+   OUT PLONG ErrOffset  OPTIONAL,\r
+   OUT PCHAR ErrMsg  OPTIONAL)\r
+{\r
+   LONG Size;\r
+   PRPN_STACK Stack = (PRPN_STACK)&RpnStack;\r
+   PRPN_STACK NewStack;\r
+\r
+   ASSERT(Expression != NULL);\r
+\r
+   /* Clear the stack and parse the expression */\r
+   RpnpClearStack(Stack);\r
+   if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))\r
+   {\r
+      return FALSE;\r
+   }\r
+#ifdef DEBUG_RPN\r
+   RpnpDumpStack(Stack);\r
+#endif\r
+\r
+   /* Duplicate the stack and return a pointer/handle to it */\r
+   ASSERT(Stack->Sp >= 1);\r
+   Size = sizeof (RPN_STACK) + (RTL_FIELD_SIZE(RPN_STACK, Ops[0]) * (Stack->Sp - 1));\r
+   NewStack = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_KDBG);\r
+   if (NewStack == NULL)\r
+   {\r
+      CONST_STRCPY(ErrMsg, "Out of memory");\r
+      if (ErrOffset != NULL)\r
+         *ErrOffset = -1;\r
+      return NULL;\r
+   }\r
+   memcpy(NewStack, Stack, Size);\r
+   NewStack->Size = NewStack->Sp;\r
+   \r
+   return NewStack;\r
+}\r
+\r
+/*!\brief Evaluates the given expression and returns the result.\r
+ *\r
+ * \param Expression  Expression "handle" returned by KdbpRpnParseExpression.\r
+ * \param TrapFrame   Register values.\r
+ * \param Result      Variable which receives the result on success.\r
+ * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)\r
+ * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)\r
+ *\r
+ * \returns "Handle" for the expression, NULL on failure.\r
+ *\r
+ * \sa KdbpRpnParseExpression\r
+ */\r
+BOOLEAN\r
+KdbpRpnEvaluateParsedExpression(\r
+   IN  PVOID Expression,\r
+   IN  PKDB_KTRAP_FRAME TrapFrame,\r
+   OUT PULONGLONG Result,\r
+   OUT PLONG ErrOffset  OPTIONAL,\r
+   OUT PCHAR ErrMsg  OPTIONAL)\r
+{\r
+   PRPN_STACK Stack = (PRPN_STACK)Expression;\r
+\r
+   ASSERT(Expression != NULL);\r
+   ASSERT(TrapFrame != NULL);\r
+   ASSERT(Result != NULL);\r
+\r
+   /* Evaluate the stack */\r
+   return RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg);\r
+}\r
+\r
index a9804e3..71376dd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id:$
+/* $Id$
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -62,7 +62,7 @@ VOID KbdDisableMouse()
 }
 
 CHAR
-KdbTryGetCharKeyboard(PULONG ScanCode)
+KdbpTryGetCharKeyboard(PULONG ScanCode)
 {
     static byte_t last_key = 0;
     static byte_t shift = 0;
@@ -305,7 +305,7 @@ static char keymap[128][2] = {
  * Yes, this is horrible.
  */
 ULONG
-KdbTryGetCharKeyboard(VOID)
+KdbpTryGetCharKeyboard(VOID)
 {
        static unsigned shift_state, ctrl_state, meta_state;
        unsigned scan_code, ch;
index 3223a77..0d28c00 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id:$
+/* $Id$
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -20,7 +20,7 @@ extern KD_PORT_INFORMATION LogPortInfo;
 
 
 CHAR
-KdbTryGetCharSerial()
+KdbpTryGetCharSerial()
 {
   UCHAR Result;
 
diff --git a/reactos/ntoskrnl/dbg/kdb_string.c b/reactos/ntoskrnl/dbg/kdb_string.c
new file mode 100644 (file)
index 0000000..773acce
--- /dev/null
@@ -0,0 +1,123 @@
+/*\r
+ *  ReactOS kernel\r
+ *  Copyright (C) 2005 ReactOS Team\r
+ *\r
+ *  This program is free software; you can redistribute it and/or modify\r
+ *  it under the terms of the GNU General Public License as published by\r
+ *  the Free Software Foundation; either version 2 of the License, or\r
+ *  (at your option) any later version.\r
+ *\r
+ *  This program is distributed in the hope that it will be useful,\r
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *  GNU General Public License for more details.\r
+ *\r
+ *  You should have received a copy of the GNU General Public License\r
+ *  along with this program; if not, write to the Free Software\r
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+/* $Id$\r
+ *\r
+ * PROJECT:         ReactOS kernel\r
+ * FILE:            ntoskrnl/dbg/kdb_string.c\r
+ * PURPOSE:         Kernel debugger string functions\r
+ * PROGRAMMER:      Gregor Anich (blight@blight.eu.org)\r
+ * UPDATE HISTORY:\r
+ *                  Created 17/01/2005\r
+ */\r
+\r
+/* INCLUDES ******************************************************************/\r
+#include <ntoskrnl.h>\r
+\r
+/* FUNCTIONS *****************************************************************/\r
+\r
+#if 0\r
+int\r
+_stricmp(\r
+   const char *s1,\r
+   const char *s2)\r
+{\r
+   char c1, c2;\r
+   for (;;)\r
+   {\r
+      c1 = tolower(*s1++);\r
+      c2 = tolower(*s2++);\r
+      if (c1 < c2)\r
+         return -1;\r
+      else if (c1 > c2)\r
+         return 1;\r
+      if (c1 == '\0')\r
+         break;\r
+   }\r
+   return 0;\r
+}\r
+#endif /* unused */\r
+\r
+/*\r
+ * Convert a string to an unsigned long integer.\r
+ *\r
+ * Ignores `locale' stuff.  Assumes that the upper and lower case\r
+ * alphabets and digits are each contiguous.\r
+ */\r
+unsigned long\r
+strtoul(const char *nptr, char **endptr, int base)\r
+{\r
+  const char *s = nptr;\r
+  unsigned long acc;\r
+  int c;\r
+  unsigned long cutoff;\r
+  int neg = 0, any, cutlim;\r
+\r
+  /*\r
+   * See strtol for comments as to the logic used.\r
+   */\r
+  do {\r
+    c = *s++;\r
+  } while (isspace(c));\r
+  if (c == '-')\r
+  {\r
+    neg = 1;\r
+    c = *s++;\r
+  }\r
+  else if (c == '+')\r
+    c = *s++;\r
+  if ((base == 0 || base == 16) &&\r
+      c == '0' && (*s == 'x' || *s == 'X'))\r
+  {\r
+    c = s[1];\r
+    s += 2;\r
+    base = 16;\r
+  }\r
+  if (base == 0)\r
+    base = c == '0' ? 8 : 10;\r
+  cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;\r
+  cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;\r
+  for (acc = 0, any = 0;; c = *s++)\r
+  {\r
+    if (isdigit(c))\r
+      c -= '0';\r
+    else if (isalpha(c))\r
+      c -= isupper(c) ? 'A' - 10 : 'a' - 10;\r
+    else\r
+      break;\r
+    if (c >= base)\r
+      break;\r
+    if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))\r
+      any = -1;\r
+    else {\r
+      any = 1;\r
+      acc *= base;\r
+      acc += c;\r
+    }\r
+  }\r
+  if (any < 0)\r
+  {\r
+    acc = ULONG_MAX;\r
+  }\r
+  else if (neg)\r
+    acc = -acc;\r
+  if (endptr != 0)\r
+    *endptr = any ? (char *)s - 1 : (char *)nptr;\r
+  return acc;\r
+}\r
+\r
index 618711e..c95259e 100644 (file)
@@ -243,12 +243,12 @@ KdbSymPrintAddress(IN PVOID Address)
                                        FunctionName);
   if (NT_SUCCESS(Status))
     {
-      DbgPrint("<%ws: %x (%s:%d (%s))>",
+      DbgPrint("<%ws:%x (%s:%d (%s))>",
                Info.Name, RelativeAddress, FileName, LineNumber, FunctionName);
     }
   else
     {
-      DbgPrint("<%ws: %x>", Info.Name, RelativeAddress);
+      DbgPrint("<%ws:%x>", Info.Name, RelativeAddress);
     }
 
   return TRUE;
@@ -541,7 +541,7 @@ KdbSymFreeProcessSymbols(IN PEPROCESS Process)
   CurrentProcess = PsGetCurrentProcess();
   if (CurrentProcess != Process)
   {
-    KeAttachProcess(&Process->Pcb);
+    KeAttachProcess(EPROCESS_TO_KPROCESS(Process));
   }
   Peb = Process->Peb;
   ASSERT(Peb);
index 06612b5..252ed8c 100644 (file)
 #define KTRAP_FRAME_RESERVED9      (0x8A)
 #define KTRAP_FRAME_SIZE           (0x8C)
 
+#define X86_EFLAGS_TF           0x00000100 /* Trap flag */
 #define X86_EFLAGS_IF           0x00000200 /* Interrupt Enable flag */
 #define X86_EFLAGS_IOPL         0x00003000 /* I/O Privilege Level bits */
 #define X86_EFLAGS_NT           0x00004000 /* Nested Task flag */
+#define X86_EFLAGS_RF           0x00010000 /* Resume flag */
 #define X86_EFLAGS_VM           0x00020000 /* Virtual Mode */
 #define X86_EFLAGS_ID           0x00200000 /* CPUID detection flag */
 
index 4594dd4..f61149d 100644 (file)
@@ -98,9 +98,6 @@ KdGdbDebugPrint (LPSTR Message);
 VOID
 KdDebugPrint (LPSTR Message);
 
-VOID
-KdbCreateThreadHook(PCONTEXT Context);
-
 KD_CONTINUE_TYPE
 KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
                         PCONTEXT Context,
@@ -118,7 +115,7 @@ VOID KdPrintMda(PCH pch);
 # define KDB_CREATE_THREAD_HOOK(CONTEXT)       do { } while (0)
 #else
 # define KDB_LOADUSERMODULE_HOOK(LDRMOD)       KdbSymLoadUserModuleSymbols(LDRMOD)
-# define KDB_DELETEPROCESS_HOOK(PROCESS)       KdbSymFreeProcessSymbols(PROCESS)
+# define KDB_DELETEPROCESS_HOOK(PROCESS)       KdbDeleteProcessHook(PROCESS)
 # define KDB_LOADDRIVER_HOOK(FILENAME, MODULE) KdbSymLoadDriverSymbols(FILENAME, MODULE)
 # define KDB_UNLOADDRIVER_HOOK(MODULE)         KdbSymUnloadDriverSymbols(MODULE)
 # define KDB_LOADERINIT_HOOK(NTOS, HAL)                KdbSymInit(NTOS, HAL)
@@ -126,6 +123,9 @@ VOID KdPrintMda(PCH pch);
 /*#define KDB_CREATE_THREAD_HOOK(CONTEXT) \
         KdbCreateThreadHook(CONTEXT)
 */
+VOID
+KdbDeleteProcessHook(IN PEPROCESS Process);
+
 VOID
 KdbSymLoadUserModuleSymbols(IN PLDR_MODULE LdrModule);
 
@@ -155,7 +155,7 @@ KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
                          KPROCESSOR_MODE PreviousMode,
                           PCONTEXT Context,
                           PKTRAP_FRAME TrapFrame,
-                         BOOLEAN HandleAlways);
+                         BOOLEAN FirstChance);
 
 #endif /* KDBG || DBG */
 
index 1d4ca92..70deaaf 100644 (file)
@@ -81,7 +81,7 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
 
 #ifdef KDBG
              Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
-                                                 Context, Tf, FALSE);
+                                                 Context, Tf, TRUE);
               if (Action == kdContinue)
                 {
                   return;
@@ -131,7 +131,7 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
 
 #ifdef KDBG
          Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
-                                             Context, Tf, TRUE);
+                                             Context, Tf, FALSE);
           if (Action == kdContinue)
             {
               return;
@@ -147,7 +147,7 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
          /* PreviousMode == KernelMode */
 #ifdef KDBG
          Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
-                                             Context, Tf, FALSE);
+                                             Context, Tf, TRUE);
           if (Action == kdContinue)
             {
               return;
@@ -168,7 +168,7 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
                     ExceptionRecord->ExceptionAddress );
 #ifdef KDBG
               Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
-                                                  Context, Tf, TRUE);
+                                                  Context, Tf, FALSE);
               if (Action == kdContinue)
                 {
                   return;
index 280720d..5e24374 100644 (file)
@@ -26,7 +26,9 @@
 
 /* INCLUDES ******************************************************************/
        
+#include <roscfg.h>
 #include <ddk/status.h>
+#include <internal/i386/ke.h>
 #include <internal/i386/segment.h>
 #include <internal/ps.h>
 #include <ddk/defines.h>
@@ -74,6 +76,29 @@ _KiTrapRet:
        popl    %edi
        popl    %esi
        popl    %ebx
+
+#ifdef DBG
+        /*
+         * Cleanup the stack which was used to setup a trapframe with SS:ESP when called
+         * from kmode.
+         */
+        movw    0xC(%esp), %bp             /* Get CS from trapframe */
+        cmpw    $KERNEL_CS, %bp
+        jne     0f
+
+        /* Copy EBP, CS:EIP and EFLAGS from the trapframe back onto the top of our stack. */
+        movl    0x00(%esp), %ebp            /* EBP */
+        movl    %ebp, 0x24(%esp)
+        movl    0x08(%esp), %ebp            /* EIP */
+        movl    %ebp, 0x2C(%esp)
+        movl    0x0C(%esp), %ebp            /* CS */
+        movl    %ebp, 0x30(%esp)
+        movl    0x10(%esp), %ebp            /* EFLAGS */
+        movl    %ebp, 0x34(%esp)
+
+        addl    $0x24, %esp
+0:
+#endif /* DBG */
        popl    %ebp
        addl    $0x4, %esp  /* Ignore error code */
                
@@ -81,10 +106,32 @@ _KiTrapRet:
 
 .globl _KiTrapProlog
 _KiTrapProlog: 
+#ifdef DBG
+        /*
+         * If we were called from kmode we start setting up a new trapframe (with SS:ESP at the end)
+         */
+        movw    0x14(%esp), %bx             /* Get old CS */
+        cmpw    $KERNEL_CS, %bx
+        
+        jne     0f
+
+        leal    0x1C(%esp), %ebp
+        pushl   %ss                          /* Old SS */
+        pushl   %ebp                         /* Old ESP */
+        pushl   0x20(%esp)                   /* Old EFLAGS */
+        pushl   0x20(%esp)                   /* Old CS */
+        pushl   0x20(%esp)                   /* Old EIP */
+        pushl   0x20(%esp)                   /* ErrorCode */
+        pushl   0x20(%esp)                   /* Ebp */
+        pushl   0x20(%esp)                   /* Ebx */
+        pushl   0x20(%esp)                   /* Esi */
+0:
+#endif /* DBG */
+
        pushl   %edi
        pushl   %fs
 
-       /* 
+       /*
         * Check that the PCR exists, very early in the boot process it may 
         * not 
         */
index a97577f..4555f23 100644 (file)
@@ -45,6 +45,10 @@ _Ki386ContextSwitch:
  *     Thread = Thread to switch to
  *     OldThread = Thread to switch from
  */
+#ifdef KDBG
+       jmp     SaveTrapFrameForKDB
+SaveTrapFrameForKDB_Return:
+#endif
        pushl   %ebp
        movl    %esp, %ebp
 
@@ -218,3 +222,128 @@ _Ki386ContextSwitch:
        ret
 .endfunc
 
+
+
+#ifdef KDBG
+
+SaveTrapFrameForKDB:
+       /*
+        * Set up a trap frame.
+        */
+                               /* Ss - space already reserved by return EIP */
+       pushl   %esp            /* Esp */
+       pushfl                  /* Eflags */
+       pushl   %cs             /* Cs */
+       pushl   12(%esp)        /* Eip */
+       movl    %ss, 16(%esp)   /* Save Ss */
+       pushl   $0              /* ErrorCode */
+       pushl   %ebp            /* Ebp */
+       pushl   %ebx            /* Ebx */
+       pushl   %esi            /* Esi */
+       pushl   %edi            /* Edi */
+       pushl   %fs             /* Fs */
+       pushl   $0              /* ExceptionList */
+       pushl   $0              /* PreviousMode */
+       pushl   %eax            /* Eax */
+       pushl   %ecx            /* Ecx */
+       pushl   %edx            /* Edx */
+       pushl   %ds             /* Ds */
+       pushl   %es             /* Es */
+       pushl   %gs             /* Gs */
+       movl    %dr7, %eax
+       pushl   %eax            /* Dr7 */
+       /* Clear breakpoint enables in dr7. */
+       andl    $~0xffff, %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 */
+       pushl   $0xffffffff     /* DebugArgMark (Exception number) */
+       pushl   0x60(%esp)      /* DebugEip */
+       pushl   %ebp            /* DebugEbp */
+
+       movl    %esp, %ebp      /* Save pointer to new TrapFrame */
+
+       /* Save the old trapframe and set pointer to the new one */
+       movl    0x80(%esp), %ebx        /* Get pointer to OldThread */
+       pushl   KTHREAD_TRAP_FRAME(%ebx)
+       movl    %ebp, KTHREAD_TRAP_FRAME(%ebx)
+
+       /* Copy the arguments which were passed to Ki386ContextSwitch */
+       pushl   0x80(%ebp)              /* OldThread */
+       pushl   0x7c(%ebp)              /* NewThread */
+       pushl   $RestoreTrapFrameForKDB /* Return address */
+
+       /* Restore clobbered registers */
+       movl    KTRAP_FRAME_EBX(%ebp), %ebx
+       movl    KTRAP_FRAME_EBP(%ebp), %ebp
+
+       /* Return */
+       jmp     SaveTrapFrameForKDB_Return
+
+
+RestoreTrapFrameForKDB:
+       addl    $8, %esp                /* Remove NewThread and OldThread arguments from the stack */
+       movl    0x84(%esp), %ebx        /* Get pointer to OldThread */
+
+       /* Restore the old trapframe */
+       popl    KTHREAD_TRAP_FRAME(%ebx)
+        
+       /*
+        * Pop unused portions of the trap frame:
+        *   DebugEbp
+        *   DebugEip
+        *   DebugArgMark
+        *   DebugPointer
+        *   TempCs
+        *   TempEip
+        *   Dr0-3
+        *   Dr6-7
+        */
+       addl    $(12*4), %esp
+
+       /*
+        * 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 */
+
+        /* Remove SS:ESP from the stack */
+       movl    16(%esp), %ebp
+       movl    %ebp, 24(%esp)
+       movl    12(%esp), %ebp
+       movl    %ebp, 20(%esp)
+       movl    8(%esp), %ebp
+       movl    %ebp, 16(%esp)
+
+       popl    %ebp            /* Ebp */
+       addl    $12, %esp       /* ErrorCode and SS:ESP */
+
+       /*
+        * Return to the caller.
+        */
+       iret
+
+#endif /* KDBG */
+
index 40b352f..c490cc5 100644 (file)
@@ -236,10 +236,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
   Thread->Alerted[0] = 0;
   Thread->Alerted[1] = 0;
   Thread->Iopl = 0;
-  /*
-   * FIXME: Think how this might work
-   */
-  Thread->NpxState = 0;
+  Thread->NpxState = NPX_STATE_INVALID;
   
   Thread->Saturation = 0;
   Thread->Priority = Process->BasePriority; 
@@ -262,7 +259,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
   Thread->DecrementCount = 0;
   Thread->PriorityDecrement = 0;
   Thread->Quantum = Process->ThreadQuantum;
-  memset(Thread->WaitBlock, 0, sizeof(KWAIT_BLOCK)*4);
+  RtlZeroMemory(Thread->WaitBlock, sizeof(KWAIT_BLOCK)*4);
   Thread->LegoData = 0; 
   Thread->UserAffinity = Process->Affinity;
   Thread->SystemAffinityActive = 0;
@@ -271,7 +268,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
   Thread->ServiceTable = KeServiceDescriptorTable;
   Thread->Queue = NULL;
   KeInitializeSpinLock(&Thread->ApcQueueLock);
-  memset(&Thread->Timer, 0, sizeof(KTIMER));
+  RtlZeroMemory(&Thread->Timer, sizeof(KTIMER));
   KeInitializeTimer(&Thread->Timer);
   Thread->QueueListEntry.Flink = NULL;
   Thread->QueueListEntry.Blink = NULL;
@@ -291,7 +288,7 @@ KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First)
   Thread->PreviousMode = KernelMode;
   Thread->KernelTime = 0;
   Thread->UserTime = 0;
-  memset(&Thread->SavedApcState, 0, sizeof(KAPC_STATE));
+  RtlZeroMemory(&Thread->SavedApcState, sizeof(KAPC_STATE));
    
   Thread->ApcStateIndex = OriginalApcEnvironment;
   Thread->ApcQueueable = TRUE;
index eef694b..572925d 100644 (file)
@@ -697,6 +697,7 @@ ExpInitializeExecutive(VOID)
   }
 
 #if defined(KDBG) || defined(DBG)
+  KdbInit();
   KdbInitProfiling2();
 #endif /* KDBG */
 
index 455fd63..d6ee975 100644 (file)
@@ -120,7 +120,7 @@ NtCallbackReturn (PVOID             Result,
       else
        {
          *CallerResultLength = min(ResultLength, *CallerResultLength);
-         memcpy(*CallerResult, Result, *CallerResultLength);
+         RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
        }
     }
 
@@ -131,9 +131,9 @@ NtCallbackReturn (PVOID             Result,
   if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
       ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentKPCR()->PrcbData.NpxThread)
     {
-      memcpy((char*)InitialStack - sizeof(FX_SAVE_AREA),
-             (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
-             sizeof(FX_SAVE_AREA));
+      RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
+                    (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
+                    sizeof(FX_SAVE_AREA));
     }
   Thread->Tcb.InitialStack = InitialStack;
   Thread->Tcb.StackBase = StackBase;
@@ -289,11 +289,11 @@ NtW32Call (IN ULONG RoutineIndex,
       AssignedStack = CONTAINING_RECORD(StackEntry, NTW32CALL_CALLBACK_STACK,
                                        ListEntry);
       NewStack = AssignedStack->BaseAddress;
-      memset(NewStack, 0, StackSize);
+      RtlZeroMemory(NewStack, StackSize);
     }
   /* FIXME: Need to check whether we were interrupted from v86 mode. */
-  memcpy((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA),
-         Thread->Tcb.TrapFrame, sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
+  RtlCopyMemory((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA),
+                Thread->Tcb.TrapFrame, sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
   NewFrame = (PKTRAP_FRAME)((char*)NewStack + StackSize - sizeof(KTRAP_FRAME) - sizeof(FX_SAVE_AREA));
   /* We need the stack pointer to remain 4-byte aligned */
   NewFrame->Esp -= (((ArgumentLength + 3) & (~ 0x3)) + (4 * sizeof(ULONG)));
@@ -303,7 +303,7 @@ NtW32Call (IN ULONG RoutineIndex,
   UserEsp[1] = RoutineIndex;
   UserEsp[2] = (ULONG)&UserEsp[4];
   UserEsp[3] = ArgumentLength;
-  memcpy((PVOID)&UserEsp[4], Argument, ArgumentLength);
+  RtlCopyMemory((PVOID)&UserEsp[4], Argument, ArgumentLength);
 
   /* Switch to the new environment and return to user-mode. */
   KeRaiseIrql(HIGH_LEVEL, &oldIrql);
@@ -319,9 +319,9 @@ NtW32Call (IN ULONG RoutineIndex,
   if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
       ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentKPCR()->PrcbData.NpxThread)
     {
-      memcpy((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA),
-             (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA),
-             sizeof(FX_SAVE_AREA));
+      RtlCopyMemory((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA),
+                    (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA),
+                    sizeof(FX_SAVE_AREA));
     }
   Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)NewStack + StackSize;
   Thread->Tcb.StackLimit = (ULONG)NewStack;