* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/kd/kdinit.c
- * PURPOSE: Kernel Debugger Initializtion
+ * PURPOSE: Kernel Debugger Initialization
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
/* VARIABLES ***************************************************************/
-BOOLEAN EXPORTED KdDebuggerEnabled = FALSE;
-BOOLEAN EXPORTED KdEnteredDebugger = FALSE;
-BOOLEAN EXPORTED KdDebuggerNotPresent = TRUE;
-BOOLEAN EXPORTED KiEnableTimerWatchdog = FALSE;
-ULONG EXPORTED KiBugCheckData;
-BOOLEAN KdpBreakPending;
-VOID STDCALL PspDumpThreads(BOOLEAN SystemThreads);
+BOOLEAN KdDebuggerEnabled = FALSE;
+BOOLEAN KdEnteredDebugger = FALSE;
+BOOLEAN KdDebuggerNotPresent = TRUE;
+BOOLEAN KdBreakAfterSymbolLoad = FALSE;
+BOOLEAN KdpBreakPending = FALSE;
+BOOLEAN KdPitchDebugger = TRUE;
+BOOLEAN KdIgnoreUmExceptions = FALSE;
+VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
+
+typedef struct
+{
+ ULONG ComponentId;
+ ULONG Level;
+} KD_COMPONENT_DATA;
+#define MAX_KD_COMPONENT_TABLE_ENTRIES 128
+KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
+ULONG KdComponentTableEntries = 0;
+
+ULONG Kd_DEFAULT_MASK = 1 << DPFLTR_ERROR_LEVEL;
/* PRIVATE FUNCTIONS *********************************************************/
ULONG
-STDCALL
+NTAPI
KdpServiceDispatcher(ULONG Service,
- PVOID Context1,
- PVOID Context2)
+ PVOID Buffer1,
+ ULONG Buffer1Length)
{
ULONG Result = 0;
switch (Service)
{
- case 1: /* DbgPrint */
- Result = KdpPrintString ((PANSI_STRING)Context1);
+ case BREAKPOINT_PRINT: /* DbgPrint */
+ Result = KdpPrintString(Buffer1, Buffer1Length);
break;
- case TAG('R', 'o', 's', ' '): /* ROS-INTERNAL */
+#if DBG
+ case ' soR': /* ROS-INTERNAL */
{
- switch ((ULONG)Context1)
+ switch ((ULONG_PTR)Buffer1)
{
- case DumpNonPagedPool:
- MiDebugDumpNonPagedPool(FALSE);
- break;
-
case ManualBugCheck:
- KEBUGCHECK(MANUALLY_INITIATED_CRASH);
- break;
-
- case DumpNonPagedPoolStats:
- MiDebugDumpNonPagedPoolStats(FALSE);
- break;
-
- case DumpNewNonPagedPool:
- MiDebugDumpNonPagedPool(TRUE);
- break;
-
- case DumpNewNonPagedPoolStats:
- MiDebugDumpNonPagedPoolStats(TRUE);
+ KeBugCheck(MANUALLY_INITIATED_CRASH);
break;
case DumpAllThreads:
case EnterDebugger:
DbgBreakPoint();
break;
+
+ case ThatsWhatSheSaid:
+ MmDumpPfnDatabase();
+ break;
default:
break;
}
+ break;
}
+ /* Special case for stack frame dumps */
+ case 'DsoR':
+ {
+ KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length);
+ break;
+ }
+#endif
default:
HalDisplayString ("Invalid debug service call!\n");
break;
return Result;
}
-KD_CONTINUE_TYPE
-STDCALL
-KdpEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
- KPROCESSOR_MODE PreviousMode,
- PCONTEXT Context,
- PKTRAP_FRAME TrapFrame,
- BOOLEAN FirstChance,
- BOOLEAN Gdb)
+BOOLEAN
+NTAPI
+KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context,
+ IN KPROCESSOR_MODE PreviousMode,
+ IN BOOLEAN SecondChance)
+{
+ KD_CONTINUE_TYPE Return = kdHandleException;
+ ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
+
+ /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
+ if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
+ (ExceptionRecord->NumberParameters > 0) &&
+ ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
+ (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
+ (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
+ (ExceptionCommand == BREAKPOINT_PRINT) ||
+ (ExceptionCommand == BREAKPOINT_PROMPT)))
+ {
+ /* Check if this is a debug print */
+ if (ExceptionCommand == BREAKPOINT_PRINT)
+ {
+ /* Print the string */
+ KdpServiceDispatcher(BREAKPOINT_PRINT,
+ (PVOID)ExceptionRecord->ExceptionInformation[1],
+ ExceptionRecord->ExceptionInformation[2]);
+
+ /* Return success */
+ KeSetContextReturnRegister(Context, STATUS_SUCCESS);
+ }
+#ifdef KDBG
+ else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
+ {
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+
+ /* Load symbols. Currently implemented only for KDBG! */
+ if(KdbpSymFindModule(((PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2])->BaseOfDll, NULL, -1, &LdrEntry))
+ KdbSymProcessSymbols(LdrEntry);
+ }
+ else if (ExceptionCommand == BREAKPOINT_PROMPT)
+ {
+ ULONG ReturnValue;
+ LPSTR OutString;
+ USHORT OutStringLength;
+
+ /* Get the response string and length */
+ OutString = (LPSTR)Context->Ebx;
+ OutStringLength = (USHORT)Context->Edi;
+
+ /* Call KDBG */
+ ReturnValue = KdpPrompt((LPSTR)ExceptionRecord->
+ ExceptionInformation[1],
+ (USHORT)ExceptionRecord->
+ ExceptionInformation[2],
+ OutString,
+ OutStringLength);
+
+ /* Return the number of characters that we received */
+ Context->Eax = ReturnValue;
+ }
+#endif
+
+ /* This we can handle: simply bump the Program Counter */
+ KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE);
+ return TRUE;
+ }
+
+#ifdef KDBG
+ /* Check if this is an assertion failure */
+ if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE)
+ {
+ /* Warn about it */
+ DbgPrint("\n!!! Assertion Failure at Address 0x%p !!!\n\n",
+ (PVOID)Context->Eip);
+
+ /* Bump EIP to the instruction following the int 2C and return */
+ Context->Eip += 2;
+ return TRUE;
+ }
+#endif
+
+ /* Get out of here if the Debugger isn't connected */
+ if (KdDebuggerNotPresent) return FALSE;
+
+#ifdef KDBG
+ /* Call KDBG if available */
+ Return = KdbEnterDebuggerException(ExceptionRecord,
+ PreviousMode,
+ Context,
+ TrapFrame,
+ !SecondChance);
+#else /* not KDBG */
+ if (WrapperInitRoutine)
+ {
+ /* Call GDB */
+ Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
+ Context,
+ TrapFrame);
+ }
+#endif /* not KDBG */
+
+ /* Debugger didn't handle it, please handle! */
+ if (Return == kdHandleException) return FALSE;
+
+ /* Debugger handled it */
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context)
{
- /* Get out of here if the Debugger isn't enabled */
- if (!KdDebuggerEnabled) return kdHandleException;
+ KD_CONTINUE_TYPE Return = kdDoNotHandleException;
+
+ /* Get out of here if the Debugger isn't connected */
+ if (KdDebuggerNotPresent) return FALSE;
/* FIXME:
* Right now, the GDB wrapper seems to handle exceptions differntly
* one is only called once and that's it. I don't really have the knowledge
* to fix the GDB stub, so until then, we'll be using this hack
*/
- if (Gdb)
+ if (WrapperInitRoutine)
{
- /* Call the registered wrapper */
- if (WrapperInitRoutine) return WrapperTable.
- KdpExceptionRoutine(ExceptionRecord,
- Context,
- TrapFrame);
+ Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
+ Context,
+ TrapFrame);
}
- /* Call KDBG if available */
- return KdbEnterDebuggerException(ExceptionRecord,
- PreviousMode,
- Context,
- TrapFrame,
- FirstChance);
+ /* Debugger didn't handle it, please handle! */
+ if (Return == kdHandleException) return FALSE;
+
+ /* Debugger handled it */
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PCONTEXT Context,
+ IN KPROCESSOR_MODE PreviousMode)
+{
+ /* KDBG has its own mechanism for ignoring user mode exceptions */
+ return FALSE;
}
/* PUBLIC FUNCTIONS *********************************************************/
/*
* @implemented
*/
-VOID
-STDCALL
+BOOLEAN
+NTAPI
+KdRefreshDebuggerNotPresent(VOID)
+{
+ UNIMPLEMENTED;
+
+ /* Just return whatever was set previously -- FIXME! */
+ return KdDebuggerNotPresent;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
KdDisableDebugger(VOID)
{
KIRQL OldIrql;
/* Lower the IRQL */
KeLowerIrql(OldIrql);
+
+ /* Return success */
+ return STATUS_SUCCESS;
}
/*
* @implemented
*/
-VOID
-STDCALL
+NTSTATUS
+NTAPI
KdEnableDebugger(VOID)
{
KIRQL OldIrql;
/* Lower the IRQL */
KeLowerIrql(OldIrql);
+
+ /* Return success */
+ return STATUS_SUCCESS;
}
/*
* @implemented
*/
BOOLEAN
-STDCALL
+NTAPI
KdPollBreakIn(VOID)
{
return KdpBreakPending;
}
/*
- * @implemented
+ * @unimplemented
*/
-VOID
-STDCALL
-KeEnterKernelDebugger(VOID)
+NTSTATUS
+NTAPI
+KdPowerTransition(ULONG PowerState)
{
- HalDisplayString("\n\n *** Entered kernel debugger ***\n");
-
- /* Set the Variable */
- KdEnteredDebugger = TRUE;
-
- /* Halt the CPU */
- for (;;) Ke386HaltProcessor();
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
-STDCALL
-KdPowerTransition(ULONG PowerState)
+NTAPI
+KdChangeOption(IN KD_OPTION Option,
+ IN ULONG InBufferLength OPTIONAL,
+ IN PVOID InBuffer,
+ IN ULONG OutBufferLength OPTIONAL,
+ OUT PVOID OutBuffer,
+ OUT PULONG OutBufferRequiredLength OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
+
+NTSTATUS
+NTAPI
+NtQueryDebugFilterState(IN ULONG ComponentId,
+ IN ULONG Level)
+{
+ ULONG i;
+
+ /* Convert Level to mask if it isn't already one */
+ if (Level < 32)
+ Level = 1 << Level;
+
+ /* Check if it is not the default component */
+ if (ComponentId != DPFLTR_DEFAULT_ID)
+ {
+ /* No, search for an existing entry in the table */
+ for (i = 0; i < KdComponentTableEntries; i++)
+ {
+ /* Check if it is the right component */
+ if (ComponentId == KdComponentTable[i].ComponentId)
+ {
+ /* Check if mask are matching */
+ return (Level & KdComponentTable[i].Level) ? TRUE : FALSE;
+ }
+ }
+ }
+
+ /* Entry not found in the table, use default mask */
+ return (Level & Kd_DEFAULT_MASK) ? TRUE : FALSE;
+}
+
+NTSTATUS
+NTAPI
+NtSetDebugFilterState(IN ULONG ComponentId,
+ IN ULONG Level,
+ IN BOOLEAN State)
+{
+ ULONG i;
+
+ /* Convert Level to mask if it isn't already one */
+ if (Level < 32)
+ Level = 1 << Level;
+ Level &= ~DPFLTR_MASK;
+
+ /* Check if it is the default component */
+ if (ComponentId == DPFLTR_DEFAULT_ID)
+ {
+ /* Yes, modify the default mask */
+ if (State)
+ Kd_DEFAULT_MASK |= Level;
+ else
+ Kd_DEFAULT_MASK &= ~Level;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Search for an existing entry */
+ for (i = 0; i < KdComponentTableEntries; i++ )
+ {
+ if (ComponentId == KdComponentTable[i].ComponentId)
+ break;
+ }
+
+ /* Check if we have found an existing entry */
+ if (i == KdComponentTableEntries)
+ {
+ /* Check if we have enough space in the table */
+ if (i == MAX_KD_COMPONENT_TABLE_ENTRIES)
+ return STATUS_INVALID_PARAMETER_1;
+
+ /* Add a new entry */
+ ++KdComponentTableEntries;
+ KdComponentTable[i].ComponentId = ComponentId;
+ KdComponentTable[i].Level = Kd_DEFAULT_MASK;
+ }
+
+ /* Update entry table */
+ if (State)
+ KdComponentTable[i].Level |= Level;
+ else
+ KdComponentTable[i].Level &= ~Level;
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KdSystemDebugControl(IN SYSDBG_COMMAND Command,
+ IN PVOID InputBuffer,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer,
+ IN ULONG OutputBufferLength,
+ IN OUT PULONG ReturnLength,
+ IN KPROCESSOR_MODE PreviousMode)
+{
+ /* HACK */
+ return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
+}
+
+PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
+
/* EOF */