-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: ntoskrnl/dbg/kdb.c
- * PURPOSE: Kernel debugger
- *
- * PROGRAMMERS: David Welch (welch@mcmail.com)
+ * FILE: ntoskrnl/kdbg/kdb.c
+ * PURPOSE: Kernel Debugger
+ *
+ * PROGRAMMERS: Gregor Anich
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
-#include <internal/kdb.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
/* TYPES *********************************************************************/
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. */
-
+ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
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 */
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;
+extern BOOLEAN KdbpBugCheckRequested;
/* Array of conditions when to enter KDB */
STATIC KDB_ENTER_CONDITION KdbEnterConditions[][2] =
{
/* First chance Last chance */
{ KdbDoNotEnter, KdbEnterFromKmode }, /* Zero devide */
- { KdbEnterAlways, KdbDoNotEnter }, /* Debug trap */
+ { KdbEnterFromKmode, KdbDoNotEnter }, /* Debug trap */
{ KdbDoNotEnter, KdbEnterAlways }, /* NMI */
{ KdbEnterFromKmode, KdbDoNotEnter }, /* INT3 */
{ KdbDoNotEnter, KdbEnterFromKmode }, /* Overflow */
};
/* Exception descriptions */
-STATIC CONST PCHAR ExceptionNrToString[] =
+STATIC CONST CHAR *ExceptionNrToString[] =
{
"Divide Error",
"Debug Trap",
"SIMD Fault"
};
+ULONG
+NTAPI
+KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame);
+
+ULONG
+NTAPI
+KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame);
+
+VOID
+NTAPI
+KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Ss);
+
+VOID
+NTAPI
+KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG Esp);
+
+/* ROS Internal. Please deprecate */
+NTHALAPI
+VOID
+NTAPI
+HalReleaseDisplayOwnership(
+ VOID
+);
+
/* FUNCTIONS *****************************************************************/
+STATIC VOID
+KdbpTrapFrameToKdbTrapFrame(PKTRAP_FRAME TrapFrame, PKDB_KTRAP_FRAME KdbTrapFrame)
+{
+ ULONG TrapCr0, TrapCr2, TrapCr3, TrapCr4;
+
+ /* Copy the TrapFrame only up to Eflags and zero the rest*/
+ RtlCopyMemory(&KdbTrapFrame->Tf, TrapFrame, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp));
+ RtlZeroMemory((PVOID)((ULONG_PTR)&KdbTrapFrame->Tf + FIELD_OFFSET(KTRAP_FRAME, HardwareEsp)),
+ sizeof (KTRAP_FRAME) - FIELD_OFFSET(KTRAP_FRAME, HardwareEsp));
+
+#ifndef _MSC_VER
+ asm volatile(
+ "movl %%cr0, %0" "\n\t"
+ "movl %%cr2, %1" "\n\t"
+ "movl %%cr3, %2" "\n\t"
+ "movl %%cr4, %3" "\n\t"
+ : "=r"(TrapCr0), "=r"(TrapCr2),
+ "=r"(TrapCr3), "=r"(TrapCr4));
+#else
+ __asm
+ {
+ mov eax, cr0;
+ mov TrapCr0, eax;
+
+ mov eax, cr2;
+ mov TrapCr2, eax;
+
+ mov eax, cr3;
+ mov TrapCr3, eax;
+/* FIXME: What's the problem with cr4? */
+ //mov eax, cr4;
+ //mov TrapCr4, eax;
+ }
+#endif
+
+ KdbTrapFrame->Cr0 = TrapCr0;
+ KdbTrapFrame->Cr2 = TrapCr2;
+ KdbTrapFrame->Cr3 = TrapCr3;
+ KdbTrapFrame->Cr4 = TrapCr4;
+
+ KdbTrapFrame->Tf.HardwareEsp = KiEspFromTrapFrame(TrapFrame);
+ KdbTrapFrame->Tf.HardwareSegSs = (USHORT)(KiSsFromTrapFrame(TrapFrame) & 0xFFFF);
+
+
+ /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
+}
+
+STATIC VOID
+KdbpKdbTrapFrameToTrapFrame(PKDB_KTRAP_FRAME KdbTrapFrame, PKTRAP_FRAME TrapFrame)
+{
+ /* Copy the TrapFrame only up to Eflags and zero the rest*/
+ RtlCopyMemory(TrapFrame, &KdbTrapFrame->Tf, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp));
+
+ /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
+
+ KiSsToTrapFrame(TrapFrame, KdbTrapFrame->Tf.HardwareSegSs);
+ KiEspToTrapFrame(TrapFrame, KdbTrapFrame->Tf.HardwareEsp);
+
+ /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */
+}
+
+STATIC VOID
+KdbpKdbTrapFrameFromKernelStack(PVOID KernelStack,
+ PKDB_KTRAP_FRAME KdbTrapFrame)
+{
+ ULONG_PTR *StackPtr;
+
+ RtlZeroMemory(KdbTrapFrame, sizeof(KDB_KTRAP_FRAME));
+ StackPtr = (ULONG_PTR *) KernelStack;
+ KdbTrapFrame->Tf.Ebp = StackPtr[3];
+ KdbTrapFrame->Tf.Edi = StackPtr[4];
+ KdbTrapFrame->Tf.Esi = StackPtr[5];
+ KdbTrapFrame->Tf.Ebx = StackPtr[6];
+ KdbTrapFrame->Tf.Eip = StackPtr[7];
+ KdbTrapFrame->Tf.HardwareEsp = (ULONG) (StackPtr + 8);
+ KdbTrapFrame->Tf.HardwareSegSs = KGDT_R0_DATA;
+ KdbTrapFrame->Tf.SegCs = KGDT_R0_CODE;
+ KdbTrapFrame->Tf.SegDs = KGDT_R0_DATA;
+ KdbTrapFrame->Tf.SegEs = KGDT_R0_DATA;
+ KdbTrapFrame->Tf.SegGs = KGDT_R0_DATA;
+
+ /* FIXME: what about the other registers??? */
+}
+
/*!\brief Overwrites the instruction at \a Address with \a NewInst and stores
* the old instruction in *OldInst.
*
/* 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);
+ KeStackAttachProcess(&Process->Pcb, &ApcState);
}
/* Make the page writeable if it is read only. */
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)
{
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)
{
KdbpShouldStepOverInstruction(ULONG_PTR Eip)
{
UCHAR Mem[3];
- INT i = 0;
+ ULONG i = 0;
if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
{
- KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Eip);
+ KdbpPrint("Couldn't access memory at 0x%p\n", Eip);
return FALSE;
}
BOOLEAN
KdbpStepIntoInstruction(ULONG_PTR Eip)
{
- struct __attribute__((packed)) {
- USHORT Limit;
- ULONG Base;
- } Idtr;
+ KDESCRIPTOR Idtr = {0};
UCHAR Mem[2];
INT IntVect;
ULONG IntDesc[2];
/* Read memory */
if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
{
- /*KdbpPrint("Couldn't access memory at 0x%x\n", (UINT)Eip);*/
+ /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
return FALSE;
}
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 */
+ else if (Mem[0] == 0xce && KdbCurrentTrapFrame->Tf.EFlags & (1<<11)) /* 1 << 11 is the overflow flag */
IntVect = 4;
else
return FALSE;
}
/* Read the interrupt descriptor table register */
- asm volatile("sidt %0" : : "m"(Idtr));
+ Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR)&Idtr.Limit);
if (IntVect >= (Idtr.Limit + 1) / 8)
{
/*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
/* 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));*/
+ /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
return FALSE;
}
-
+
/* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
if ((IntDesc[1] & (1 << 15)) == 0) /* not present */
{
{
return FALSE;
}
-
+
bp = KdbBreakPoints + BreakPointNr;
if (Address != NULL)
*Address = bp->Address;
IN KDB_ACCESS_TYPE AccessType OPTIONAL,
IN PCHAR ConditionExpression OPTIONAL,
IN BOOLEAN Global,
- OUT PULONG BreakPointNumber OPTIONAL)
+ OUT PLONG BreakPointNr OPTIONAL)
{
LONG i;
PVOID Condition;
{
if ((Address % Size) != 0)
{
- KdbpPrint("Address (0x%x) must be aligned to a multiple of the size (%d)\n", Address, Size);
+ KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address, Size);
return STATUS_UNSUCCESSFUL;
}
if (AccessType == KdbAccessExec && Size != 1)
{
return STATUS_UNSUCCESSFUL;
}
-
+
/* Parse conditon expression string and duplicate it */
if (ConditionExpression != NULL)
{
}
else
{
- for (i = 0; i < RTL_NUMBER_OF(KdbBreakPoints); i++)
+ for (i = 0; i < (LONG)RTL_NUMBER_OF(KdbBreakPoints); i++)
{
if (KdbBreakPoints[i].Type == KdbBreakPointNone)
break;
}
}
- ASSERT(i < RTL_NUMBER_OF(KdbBreakPoints));
-
+ ASSERT(i < (LONG)RTL_NUMBER_OF(KdbBreakPoints));
+
/* Set the breakpoint */
ASSERT(KdbCurrentProcess != NULL);
KdbBreakPoints[i].Type = Type;
KdbBreakPoints[i].Data.Hw.AccessType = AccessType;
}
KdbBreakPointCount++;
-
+
if (Type != KdbBreakPointTemporary)
KdbpPrint("Breakpoint %d inserted.\n", i);
KdbpEnableBreakPoint(i, NULL);
/* Return the breakpoint number */
- if (BreakPointNumber != NULL)
- *BreakPointNumber = i;
+ if (BreakPointNr != NULL)
+ *BreakPointNr = i;
return STATUS_SUCCESS;
}
KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr);
BreakPoint->Type = KdbBreakPointNone;
KdbBreakPointCount--;
-
+
return TRUE;
}
*/
STATIC LONG
KdbpIsBreakPointOurs(
- IN ULONG ExpNr,
+ IN NTSTATUS ExceptionCode,
IN PKTRAP_FRAME TrapFrame)
{
- INT i;
- ASSERT(ExpNr == 1 || ExpNr == 3);
+ ULONG i;
+ ASSERT(ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT);
- if (ExpNr == 3) /* Software interrupt */
+ if (ExceptionCode == STATUS_BREAKPOINT) /* Software interrupt */
{
ULONG_PTR BpEip = (ULONG_PTR)TrapFrame->Eip - 1; /* Get EIP of INT3 instruction */
for (i = 0; i < KdbSwBreakPointCount; i++)
}
}
}
- else if (ExpNr == 1) /* Hardware interrupt */
+ else if (ExceptionCode == STATUS_SINGLE_STEP) /* Hardware interrupt */
{
UCHAR DebugReg;
for (i = 0; i < KdbHwBreakPointCount; i++)
}
}
}
-
+
return -1;
}
KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
return FALSE;
}
-
+
if (BreakPoint->Enabled == TRUE)
{
KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr);
0xCC, &BreakPoint->Data.SavedInstruction);
if (!NT_SUCCESS(Status))
{
- KdbpPrint("Couldn't access memory at 0x%x\n", BreakPoint->Address);
+ KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint->Address);
return FALSE;
}
KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint;
IN LONG BreakPointNr OPTIONAL,
IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL)
{
- INT i;
+ ULONG i;
NTSTATUS Status;
-
+
if (BreakPointNr < 0)
{
ASSERT(BreakPoint != NULL);
KdbpPrint("Couldn't restore original instruction.\n");
return FALSE;
}
-
+
for (i = 0; i < KdbSwBreakPointCount; i++)
{
if (KdbSwBreakPoints[i] == BreakPoint)
break;
}
}
- if (i != -1) /* not found */
+ if (i != (ULONG)-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)
break;
}
}
- if (i != -1) /* not found */
+ if (i != (ULONG)-1) /* not found */
ASSERT(0);
}
IN BOOLEAN FirstChance,
OUT KDB_ENTER_CONDITION *Condition)
{
- if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions))
+ if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions))
return FALSE;
*Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1];
{
if (ExceptionNr < 0)
{
- for (ExceptionNr = 0; ExceptionNr < RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++)
+ for (ExceptionNr = 0; ExceptionNr < (LONG)RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++)
{
if (ExceptionNr == 1 || ExceptionNr == 8 ||
ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */
}
else
{
- if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions) ||
+ if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions) ||
ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */
ExceptionNr == 9 || ExceptionNr == 15) /* trap or reserved exceptions */
{
/* Get a pointer to the thread */
if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread)))
{
- KdbpPrint("Invalid thread id: 0x%08x\n", (UINT)ThreadId);
+ KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG)ThreadId);
return FALSE;
}
Process = Thread->ThreadsProcess;
if (KeIsExecutingDpc() && Process != KdbCurrentProcess)
{
KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
+ ObDereferenceObject(Thread);
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));
+ /* Actually, we can't save the context, there's no guarantee that there
+ * was a trap frame */
}
else
{
/* 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));
+ /* The thread we're attaching to isn't the thread on which we entered
+ * kdb and so the thread we're attaching to is not running. There
+ * is no guarantee that it actually has a trap frame. So we have to
+ * peek directly at the registers which were saved on the stack when the
+ * thread was preempted in the scheduler */
+ KdbpKdbTrapFrameFromKernelStack(Thread->Tcb.KernelStack,
+ &KdbThreadTrapFrame);
KdbCurrentTrapFrame = &KdbThreadTrapFrame;
}
else /* Switching back to original thread */
}
if (KdbOriginalProcess != Process)
{
- KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process), &KdbApcState);
+ KeStackAttachProcess(&Process->Pcb, &KdbApcState);
}
KdbCurrentProcess = Process;
}
+ ObDereferenceObject(Thread);
return TRUE;
}
/* Get a pointer to the process */
if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
{
- KdbpPrint("Invalid process id: 0x%08x\n", (UINT)ProcessId);
+ KdbpPrint("Invalid process id: 0x%08x\n", (ULONG)ProcessId);
return FALSE;
}
Entry = Process->ThreadListHead.Flink;
+ ObDereferenceObject(Process);
if (Entry == &KdbCurrentProcess->ThreadListHead)
{
- KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (UINT)ProcessId);
+ KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (ULONG)ProcessId);
return FALSE;
}
*/
STATIC VOID
KdbpInternalEnter()
-{
+{
PETHREAD Thread;
PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
ULONG SavedStackLimit;
-
+
KbdDisableMouse();
- if (KdDebugState & KD_DEBUG_SCREEN)
+ if (KdpDebugMode.Screen)
{
- HalReleaseDisplayOwnership();
+ InbvAcquireDisplayOwnership();
}
/* Call the interface's main loop on a different stack */
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);*/
+ /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/
- KdbpStackSwitchAndCall(Thread->Tcb.KernelStack, KdbpCallMainLoop);
+ KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - sizeof(ULONG), KdbpCallMainLoop);
Thread->Tcb.InitialStack = SavedInitialStack;
Thread->Tcb.StackBase = SavedStackBase;
KbdEnableMouse();
}
+STATIC ULONG
+KdbpGetExceptionNumberFromStatus(IN NTSTATUS ExceptionCode)
+{
+ ULONG Ret;
+
+ switch (ExceptionCode)
+ {
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ Ret = 0;
+ break;
+ case STATUS_SINGLE_STEP:
+ Ret = 1;
+ break;
+ case STATUS_BREAKPOINT:
+ Ret = 3;
+ break;
+ case STATUS_INTEGER_OVERFLOW:
+ Ret = 4;
+ break;
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ Ret = 5;
+ break;
+ case STATUS_ILLEGAL_INSTRUCTION:
+ Ret = 6;
+ break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ Ret = 7;
+ break;
+ case STATUS_STACK_OVERFLOW:
+ Ret = 12;
+ break;
+ case STATUS_ACCESS_VIOLATION:
+ Ret = 14;
+ break;
+ case STATUS_DATATYPE_MISALIGNMENT:
+ Ret = 17;
+ break;
+ case STATUS_FLOAT_MULTIPLE_TRAPS:
+ Ret = 18;
+ break;
+
+ default:
+ Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1;
+ break;
+ }
+
+ return Ret;
+}
+
/*!\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 Context Context, IN/OUT parameter.
* \param TrapFrame Exception TrapFrame.
* \param FirstChance TRUE when called before exception frames were serached,
* FALSE for the second call.
KdbEnterDebuggerException(
IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
IN KPROCESSOR_MODE PreviousMode,
- IN PCONTEXT Context OPTIONAL,
+ IN PCONTEXT Context,
IN OUT PKTRAP_FRAME TrapFrame,
IN BOOLEAN FirstChance)
{
- ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
KDB_ENTER_CONDITION EnterCondition;
KD_CONTINUE_TYPE ContinueType = kdHandleException;
PKDB_BREAKPOINT BreakPoint;
- ULONG ul;
+ ULONG ExpNr;
ULONGLONG ull;
BOOLEAN Resume = FALSE;
BOOLEAN EnterConditionMet = TRUE;
ULONG OldEflags;
+ NTSTATUS ExceptionCode;
+
+ ExceptionCode = (ExceptionRecord != NULL ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT);
KdbCurrentProcess = PsGetCurrentProcess();
/* Set continue type to kdContinue for single steps and breakpoints */
- if (ExpNr == 1 || ExpNr == 3)
+ if (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT)
ContinueType = kdContinue;
/* Check if we should handle the exception. */
- ul = min(ExpNr, RTL_NUMBER_OF(KdbEnterConditions) - 1);
- EnterCondition = KdbEnterConditions[ul][FirstChance ? 0 : 1];
+ /* FIXME - won't get all exceptions here :( */
+ ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode);
+ EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1];
if (EnterCondition == KdbDoNotEnter ||
- (EnterCondition == KdbEnterFromUmode && PreviousMode != UserMode) ||
+ (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) ||
(EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
{
EnterConditionMet = FALSE;
KdbLastBreakPointNr = -1;
KdbEnteredOnSingleStep = FALSE;
- if (FirstChance && (ExpNr == 1 || ExpNr == 3) &&
- (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExpNr, TrapFrame)) >= 0)
+ if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) &&
+ (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, TrapFrame)) >= 0)
{
BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
- if (ExpNr == 3)
+ if (ExceptionCode == STATUS_BREAKPOINT)
{
- /*
- * 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);
+ KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
+ KeBugCheck(0); // FIXME: Proper bugcode!
}
}
{
Resume = TRUE; /* Set the resume flag when continuing execution */
}
-
+
/*
* 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
else if (BreakPoint->Type == KdbBreakPointTemporary &&
BreakPoint->Process == KdbCurrentProcess)
{
- ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) == 0);
-
+ ASSERT((TrapFrame->EFlags & EFLAGS_TF) == 0);
+
/*
* Delete the temporary breakpoint which was used to step over or into the instruction.
*/
if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
(!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
{
- TrapFrame->Eflags |= X86_EFLAGS_TF;
+ Context->EFlags |= EFLAGS_TF;
}
goto continue_execution; /* return */
}
else if (BreakPoint->Type == KdbBreakPointSoftware ||
BreakPoint->Type == KdbBreakPointTemporary)
{
- ASSERT(ExpNr == 3);
- TrapFrame->Eflags |= X86_EFLAGS_TF;
+ ASSERT(ExceptionCode == STATUS_BREAKPOINT);
+ Context->EFlags |= EFLAGS_TF;
KdbBreakPointToReenable = BreakPoint;
}
-
+
/*
* Make sure that the breakpoint should be triggered in this context
*/
{
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));
+ KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
ull = 0;
if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
if (BreakPoint->Type == KdbBreakPointSoftware)
{
- DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
- KdbLastBreakPointNr, TrapFrame->Cs & 0xffff, TrapFrame->Eip);
+ KdbpPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
+ KdbLastBreakPointNr, TrapFrame->SegCs & 0xffff, TrapFrame->Eip);
}
else if (BreakPoint->Type == KdbBreakPointHardware)
{
- DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
+ KdbpPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
KdbLastBreakPointNr,
(BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
}
}
- else if (ExpNr == 1)
+ else if (ExceptionCode == STATUS_SINGLE_STEP)
{
/* Silently ignore a debugger initiated single step. */
if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable != NULL)
if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
&BreakPoint->Data.SavedInstruction)))
{
- DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
+ KdbpPrint("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;
+ Context->EFlags &= ~EFLAGS_TF;
goto continue_execution; /* return */
}
/* Check if we expect a single step */
if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
{
- /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
+ /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/
if (--KdbNumSingleSteps > 0)
{
if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
(!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
{
- TrapFrame->Eflags &= ~X86_EFLAGS_TF;
+ Context->EFlags &= ~EFLAGS_TF;
}
else
{
- TrapFrame->Eflags |= X86_EFLAGS_TF;
+ Context->EFlags |= EFLAGS_TF;
}
- goto continue_execution; /* return */
+ goto continue_execution; /* return */
}
-
- TrapFrame->Eflags &= ~X86_EFLAGS_TF;
- KdbEnteredOnSingleStep = TRUE;
+ else
+ {
+ Context->EFlags &= ~EFLAGS_TF;
+ KdbEnteredOnSingleStep = TRUE;
+ }
}
else
{
if (!EnterConditionMet)
{
- return ContinueType;
+ return kdHandleException;
}
- DbgPrint("Entered debugger on unexpected debug trap!\n");
+ KdbpPrint("Entered debugger on unexpected debug trap!\n");
}
}
- else if (ExpNr == 3)
+ else if (ExceptionCode == STATUS_BREAKPOINT)
{
if (KdbInitFileBuffer != NULL)
{
}
if (!EnterConditionMet)
{
- return ContinueType;
+ return kdHandleException;
}
- DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
- TrapFrame->Cs & 0xffff, TrapFrame->Eip - 1);
+ KdbpPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
+ TrapFrame->SegCs & 0xffff, TrapFrame->Eip - 1);
}
else
{
- CONST PCHAR ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
+ CONST CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
(ExceptionNrToString[ExpNr]) :
("Unknown/User defined exception");
return ContinueType;
}
- DbgPrint("Entered debugger on %s-chance exception number %d (%s)\n",
- FirstChance ? "first" : "last", ExpNr, ExceptionString);
- if (ExpNr == 14)
+ KdbpPrint("Entered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n",
+ FirstChance ? "first" : "last", ExceptionCode, ExceptionString);
+ if (ExceptionCode == STATUS_ACCESS_VIOLATION &&
+ ExceptionRecord != NULL && ExceptionRecord->NumberParameters != 0)
{
/* 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");
+ ULONG_PTR TrapCr2;
+ ULONG Err;
+#ifdef __GNUC__
+ asm volatile("movl %%cr2, %0" : "=r"(TrapCr2));
+#elif _MSC_VER
+ __asm mov eax, cr2;
+ __asm mov TrapCr2, eax;
+#else
+#error Unknown compiler for inline assembler
+#endif
+
+ Err = TrapFrame->ErrCode;
+ KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2, (Err & (1 << 1)) ? "written" : "read");
if ((Err & (1 << 0)) == 0)
- DbgPrint("Page not present.\n");
+ KdbpPrint("Page not present.\n");
else
{
if ((Err & (1 << 3)) != 0)
- DbgPrint("Reserved bits in page directory set.\n");
+ KdbpPrint("Reserved bits in page directory set.\n");
else
- DbgPrint("Page protection violation.\n");
+ KdbpPrint("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));
+ KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
/* Enter critical section */
Ke386SaveFlags(OldEflags);
- Ke386DisableInterrupts();
+ _disable();
/* Exception inside the debugger? Game over. */
if (InterlockedIncrement(&KdbEntryCount) > 1)
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;*/
+ ASSERT((KdbCurrentTrapFrame->Tf.EFlags & EFLAGS_TF) == 0);
+ /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/
}
else
{
- KdbCurrentTrapFrame->Tf.Eflags |= X86_EFLAGS_TF;
+ Context->EFlags |= EFLAGS_TF;
}
}
- /* Save the current thread's trapframe */
- if (KdbCurrentTrapFrame == &KdbThreadTrapFrame)
- {
- RtlCopyMemory(KdbCurrentThread->Tcb.TrapFrame, KdbCurrentTrapFrame, sizeof (KTRAP_FRAME));
- }
+ /* We can't update the current thread's trapframe 'cause it might not
+ have one */
/* Detach from attached process */
if (KdbCurrentProcess != KdbOriginalProcess)
}
/* 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
+ KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame);
/* Decrement the entry count */
InterlockedDecrement(&KdbEntryCount);
/* Leave critical section */
Ke386RestoreFlags(OldEflags);
+ /* Check if user requested a bugcheck */
+ if (KdbpBugCheckRequested)
+ {
+ /* Clear the flag and bugcheck the system */
+ KdbpBugCheckRequested = FALSE;
+ KeBugCheck(MANUALLY_INITIATED_CRASH);
+ }
+
continue_execution:
/* Clear debug status */
- if (ExpNr == 1 || ExpNr == 3) /* FIXME: Why clear DR6 on INT3? */
+ if (ExceptionCode == STATUS_BREAKPOINT) /* 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;
+ TrapFrame->EFlags |= EFLAGS_RF;
}
-
+
/* Clear dr6 status flags. */
TrapFrame->Dr6 &= ~0x0000e00f;
+ /* Skip the current instruction */
+ Context->Eip++;
}
return ContinueType;
}
-VOID
-KdbInit()
-{
- KdbpCliInit();
-}
-
VOID
KdbDeleteProcessHook(IN PEPROCESS Process)
{
KdbSymFreeProcessSymbols(Process);
-
+
/* FIXME: Delete breakpoints for process */
}
VOID
-KdbModuleLoaded(IN PUNICODE_STRING Name)
+NTAPI
+KdbpGetCommandLineSettings(PCHAR p1)
{
- KdbpCliModuleLoaded(Name);
+ PCHAR p2;
+
+ while (p1 && (p2 = strchr(p1, ' ')))
+ {
+ p2++;
+
+ if (!_strnicmp(p2, "KDSERIAL", 8))
+ {
+ p2 += 8;
+ KdbDebugState |= KD_DEBUG_KDSERIAL;
+ KdpDebugMode.Serial = TRUE;
+ }
+ else if (!_strnicmp(p2, "KDNOECHO", 8))
+ {
+ p2 += 8;
+ KdbDebugState |= KD_DEBUG_KDNOECHO;
+ }
+
+ p1 = p2;
+ }
}
+NTSTATUS
+KdbpSafeReadMemory(OUT PVOID Dest,
+ IN PVOID Src,
+ IN ULONG Bytes)
+{
+ BOOLEAN Result = TRUE;
+
+ switch (Bytes)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest);
+ break;
+ default:
+ {
+ ULONG_PTR Start, End, Write;
+ for (Start = (ULONG_PTR)Src,
+ End = Start + Bytes,
+ Write = (ULONG_PTR)Dest;
+ Result && (Start < End);
+ Start++, Write++)
+ if (!KdpSafeReadMemory(Start, 1, (PVOID)Write))
+ Result = FALSE;
+ break;
+ }
+ }
+
+ return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
+}
+NTSTATUS
+KdbpSafeWriteMemory(OUT PVOID Dest,
+ IN PVOID Src,
+ IN ULONG Bytes)
+{
+ BOOLEAN Result = TRUE;
+ ULONG_PTR Start, End, Write;
+
+ for (Start = (ULONG_PTR)Src,
+ End = Start + Bytes,
+ Write = (ULONG_PTR)Dest;
+ Result && (Start < End);
+ Start++, Write++)
+ if (!KdpSafeWriteMemory(Write, 1, *((PCHAR)Start)))
+ Result = FALSE;
+
+ return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
+}