$(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
$(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
static DWORD ctrlKeyState;
static PKINTERRUPT KbdInterrupt;
static KDPC KbdDpc;
+static PIO_WORKITEM KbdWorkItem = NULL;
static BOOLEAN AlreadyOpened = FALSE;
/*
}
+/*
+ * 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
*/
{
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);
IoStartNextPacket(DeviceObject,FALSE);
}
+
static BOOLEAN STDCALL
KeyboardHandler(PKINTERRUPT Interrupt,
PVOID Context)
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);
}
KbdClearInput();
KeyboardConnectInterrupt(DeviceObject);
KeInitializeDpc(&KbdDpc,KbdDpcRoutine,NULL);
+ KbdWorkItem = IoAllocateWorkItem(DeviceObject);
+ if (KbdWorkItem == NULL)
+ {
+ DPRINT("Warning: Couldn't allocate work item!\n");
+ }
return 0;
}
--- /dev/null
+# 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
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
-/* $Id:$
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
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];
}
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;
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;
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;
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.
#else
mode_64bit = 0;
priv.orig_sizeflag = AFLAG | DFLAG;
- intel_syntax = 0;
+ /*intel_syntax = 0;*/
#endif
if (intel_syntax)
#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 */
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 */
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.
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
-
--- /dev/null
+ .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
--- /dev/null
+ .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
#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);
}
+
+#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];
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
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
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;
-};
--- /dev/null
+/*\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
--- /dev/null
+/*\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
-/* $Id:$
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
}
CHAR
-KdbTryGetCharKeyboard(PULONG ScanCode)
+KdbpTryGetCharKeyboard(PULONG ScanCode)
{
static byte_t last_key = 0;
static byte_t shift = 0;
* Yes, this is horrible.
*/
ULONG
-KdbTryGetCharKeyboard(VOID)
+KdbpTryGetCharKeyboard(VOID)
{
static unsigned shift_state, ctrl_state, meta_state;
unsigned scan_code, ch;
-/* $Id:$
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
CHAR
-KdbTryGetCharSerial()
+KdbpTryGetCharSerial()
{
UCHAR Result;
--- /dev/null
+/*\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
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;
CurrentProcess = PsGetCurrentProcess();
if (CurrentProcess != Process)
{
- KeAttachProcess(&Process->Pcb);
+ KeAttachProcess(EPROCESS_TO_KPROCESS(Process));
}
Peb = Process->Peb;
ASSERT(Peb);
#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 */
VOID
KdDebugPrint (LPSTR Message);
-VOID
-KdbCreateThreadHook(PCONTEXT Context);
-
KD_CONTINUE_TYPE
KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
PCONTEXT Context,
# 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)
/*#define KDB_CREATE_THREAD_HOOK(CONTEXT) \
KdbCreateThreadHook(CONTEXT)
*/
+VOID
+KdbDeleteProcessHook(IN PEPROCESS Process);
+
VOID
KdbSymLoadUserModuleSymbols(IN PLDR_MODULE LdrModule);
KPROCESSOR_MODE PreviousMode,
PCONTEXT Context,
PKTRAP_FRAME TrapFrame,
- BOOLEAN HandleAlways);
+ BOOLEAN FirstChance);
#endif /* KDBG || DBG */
#ifdef KDBG
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
- Context, Tf, FALSE);
+ Context, Tf, TRUE);
if (Action == kdContinue)
{
return;
#ifdef KDBG
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
- Context, Tf, TRUE);
+ Context, Tf, FALSE);
if (Action == kdContinue)
{
return;
/* PreviousMode == KernelMode */
#ifdef KDBG
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
- Context, Tf, FALSE);
+ Context, Tf, TRUE);
if (Action == kdContinue)
{
return;
ExceptionRecord->ExceptionAddress );
#ifdef KDBG
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
- Context, Tf, TRUE);
+ Context, Tf, FALSE);
if (Action == kdContinue)
{
return;
/* 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>
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 */
.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
*/
* Thread = Thread to switch to
* OldThread = Thread to switch from
*/
+#ifdef KDBG
+ jmp SaveTrapFrameForKDB
+SaveTrapFrameForKDB_Return:
+#endif
pushl %ebp
movl %esp, %ebp
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 */
+
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;
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;
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;
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;
}
#if defined(KDBG) || defined(DBG)
+ KdbInit();
KdbInitProfiling2();
#endif /* KDBG */
else
{
*CallerResultLength = min(ResultLength, *CallerResultLength);
- memcpy(*CallerResult, Result, *CallerResultLength);
+ RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
}
}
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;
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)));
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);
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;