2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/kdmain.c
5 * PURPOSE: Kernel Debugger Initialization
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
14 /* VARIABLES ***************************************************************/
16 BOOLEAN KdDebuggerEnabled
= FALSE
;
17 BOOLEAN KdEnteredDebugger
= FALSE
;
18 BOOLEAN KdDebuggerNotPresent
= TRUE
;
19 BOOLEAN KdBreakAfterSymbolLoad
= FALSE
;
20 BOOLEAN KdpBreakPending
= FALSE
;
21 BOOLEAN KdPitchDebugger
= TRUE
;
22 BOOLEAN KdIgnoreUmExceptions
= FALSE
;
23 KD_CONTEXT KdpContext
;
24 ULONG Kd_WIN2000_Mask
;
25 VOID NTAPI
PspDumpThreads(BOOLEAN SystemThreads
);
32 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
33 KD_COMPONENT_DATA KdComponentTable
[MAX_KD_COMPONENT_TABLE_ENTRIES
];
34 ULONG KdComponentTableEntries
= 0;
36 ULONG Kd_DEFAULT_MASK
= 1 << DPFLTR_ERROR_LEVEL
;
38 /* PRIVATE FUNCTIONS *********************************************************/
42 KdpServiceDispatcher(ULONG Service
,
50 case BREAKPOINT_PRINT
: /* DbgPrint */
51 Result
= KdpPrintString(Buffer1
, Buffer1Length
);
55 case ' soR': /* ROS-INTERNAL */
57 switch ((ULONG_PTR
)Buffer1
)
64 PspDumpThreads(FALSE
);
68 MmDumpArmPfnDatabase(FALSE
);
77 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
78 /* Register a debug callback */
81 switch (Buffer1Length
)
83 case ID_Win32PreServiceHook
:
84 KeWin32PreServiceHook
= Buffer1
;
87 case ID_Win32PostServiceHook
:
88 KeWin32PostServiceHook
= Buffer1
;
96 /* Special case for stack frame dumps */
99 KeRosDumpStackFrames((PULONG
)Buffer1
, Buffer1Length
);
104 /* Register KDBG CLI callback */
107 Result
= KdbRegisterCliCallback(Buffer1
, Buffer1Length
);
113 DPRINT1("Invalid debug service call!\n");
114 HalDisplayString("Invalid debug service call!\r\n");
123 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame
,
124 IN PKEXCEPTION_FRAME ExceptionFrame
,
125 IN PEXCEPTION_RECORD ExceptionRecord
,
127 IN KPROCESSOR_MODE PreviousMode
,
128 IN BOOLEAN SecondChance
)
130 KD_CONTINUE_TYPE Return
= kdHandleException
;
131 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
133 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
134 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
135 (ExceptionRecord
->NumberParameters
> 0) &&
136 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
137 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
138 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
139 (ExceptionCommand
== BREAKPOINT_PRINT
) ||
140 (ExceptionCommand
== BREAKPOINT_PROMPT
)))
142 /* Check if this is a debug print */
143 if (ExceptionCommand
== BREAKPOINT_PRINT
)
145 /* Print the string */
146 KdpServiceDispatcher(BREAKPOINT_PRINT
,
147 (PVOID
)ExceptionRecord
->ExceptionInformation
[1],
148 ExceptionRecord
->ExceptionInformation
[2]);
151 KeSetContextReturnRegister(Context
, STATUS_SUCCESS
);
154 else if (ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
)
156 PLDR_DATA_TABLE_ENTRY LdrEntry
;
158 /* Load symbols. Currently implemented only for KDBG! */
159 if(KdbpSymFindModule(((PKD_SYMBOLS_INFO
)ExceptionRecord
->ExceptionInformation
[2])->BaseOfDll
, NULL
, -1, &LdrEntry
))
160 KdbSymProcessSymbols(LdrEntry
);
162 else if (ExceptionCommand
== BREAKPOINT_PROMPT
)
166 USHORT OutStringLength
;
168 /* Get the response string and length */
169 OutString
= (LPSTR
)Context
->Ebx
;
170 OutStringLength
= (USHORT
)Context
->Edi
;
173 ReturnValue
= KdpPrompt((LPSTR
)ExceptionRecord
->
174 ExceptionInformation
[1],
175 (USHORT
)ExceptionRecord
->
176 ExceptionInformation
[2],
180 /* Return the number of characters that we received */
181 Context
->Eax
= ReturnValue
;
185 /* This we can handle: simply bump the Program Counter */
186 KeSetContextPc(Context
, KeGetContextPc(Context
) + KD_BREAKPOINT_SIZE
);
191 /* Check if this is an assertion failure */
192 if (ExceptionRecord
->ExceptionCode
== STATUS_ASSERTION_FAILURE
)
194 /* Bump EIP to the instruction following the int 2C */
199 /* Get out of here if the Debugger isn't connected */
200 if (KdDebuggerNotPresent
) return FALSE
;
203 /* Call KDBG if available */
204 Return
= KdbEnterDebuggerException(ExceptionRecord
,
210 if (WrapperInitRoutine
)
213 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
217 #endif /* not KDBG */
219 /* Debugger didn't handle it, please handle! */
220 if (Return
== kdHandleException
) return FALSE
;
222 /* Debugger handled it */
228 KdpCallGdb(IN PKTRAP_FRAME TrapFrame
,
229 IN PEXCEPTION_RECORD ExceptionRecord
,
232 KD_CONTINUE_TYPE Return
= kdDoNotHandleException
;
234 /* Get out of here if the Debugger isn't connected */
235 if (KdDebuggerNotPresent
) return FALSE
;
238 * Right now, the GDB wrapper seems to handle exceptions differntly
239 * from KDGB and both are called at different times, while the GDB
240 * one is only called once and that's it. I don't really have the knowledge
241 * to fix the GDB stub, so until then, we'll be using this hack
243 if (WrapperInitRoutine
)
245 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
250 /* Debugger didn't handle it, please handle! */
251 if (Return
== kdHandleException
) return FALSE
;
253 /* Debugger handled it */
259 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
261 IN KPROCESSOR_MODE PreviousMode
)
263 /* KDBG has its own mechanism for ignoring user mode exceptions */
267 /* PUBLIC FUNCTIONS *********************************************************/
274 KdRefreshDebuggerNotPresent(VOID
)
278 /* Just return whatever was set previously -- FIXME! */
279 return KdDebuggerNotPresent
;
287 KdDisableDebugger(VOID
)
292 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
294 /* TODO: Disable any breakpoints */
296 /* Disable the Debugger */
297 KdDebuggerEnabled
= FALSE
;
298 SharedUserData
->KdDebuggerEnabled
= FALSE
;
301 KeLowerIrql(OldIrql
);
304 return STATUS_SUCCESS
;
312 KdEnableDebugger(VOID
)
317 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
319 /* TODO: Re-enable any breakpoints */
321 /* Enable the Debugger */
322 KdDebuggerEnabled
= TRUE
;
323 SharedUserData
->KdDebuggerEnabled
= TRUE
;
326 KeLowerIrql(OldIrql
);
329 return STATUS_SUCCESS
;
339 return KdpBreakPending
;
347 KdPowerTransition(ULONG PowerState
)
350 return STATUS_NOT_IMPLEMENTED
;
358 KdChangeOption(IN KD_OPTION Option
,
359 IN ULONG InBufferLength OPTIONAL
,
361 IN ULONG OutBufferLength OPTIONAL
,
363 OUT PULONG OutBufferRequiredLength OPTIONAL
)
366 return STATUS_NOT_IMPLEMENTED
;
372 NtQueryDebugFilterState(IN ULONG ComponentId
,
377 /* Convert Level to mask if it isn't already one */
381 /* Check if it is not the default component */
382 if (ComponentId
!= MAXULONG
)
384 /* No, search for an existing entry in the table */
385 for (i
= 0; i
< KdComponentTableEntries
; i
++)
387 /* Check if it is the right component */
388 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
390 /* Check if mask are matching */
391 return (Level
& KdComponentTable
[i
].Level
) ? TRUE
: FALSE
;
396 /* Entry not found in the table, use default mask */
397 return (Level
& Kd_DEFAULT_MASK
) ? TRUE
: FALSE
;
402 NtSetDebugFilterState(IN ULONG ComponentId
,
408 /* Convert Level to mask if it isn't already one */
411 Level
&= ~DPFLTR_MASK
;
413 /* Check if it is the default component */
414 if (ComponentId
== MAXULONG
)
416 /* Yes, modify the default mask */
418 Kd_DEFAULT_MASK
|= Level
;
420 Kd_DEFAULT_MASK
&= ~Level
;
422 return STATUS_SUCCESS
;
425 /* Search for an existing entry */
426 for (i
= 0; i
< KdComponentTableEntries
; i
++ )
428 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
432 /* Check if we have found an existing entry */
433 if (i
== KdComponentTableEntries
)
435 /* Check if we have enough space in the table */
436 if (i
== MAX_KD_COMPONENT_TABLE_ENTRIES
)
437 return STATUS_INVALID_PARAMETER_1
;
439 /* Add a new entry */
440 ++KdComponentTableEntries
;
441 KdComponentTable
[i
].ComponentId
= ComponentId
;
442 KdComponentTable
[i
].Level
= Kd_DEFAULT_MASK
;
445 /* Update entry table */
447 KdComponentTable
[i
].Level
|= Level
;
449 KdComponentTable
[i
].Level
&= ~Level
;
451 return STATUS_SUCCESS
;
459 KdSystemDebugControl(IN SYSDBG_COMMAND Command
,
460 IN PVOID InputBuffer
,
461 IN ULONG InputBufferLength
,
462 OUT PVOID OutputBuffer
,
463 IN ULONG OutputBufferLength
,
464 IN OUT PULONG ReturnLength
,
465 IN KPROCESSOR_MODE PreviousMode
)
468 return KdpServiceDispatcher(Command
, InputBuffer
, InputBufferLength
);
471 PKDEBUG_ROUTINE KiDebugRoutine
= KdpEnterDebuggerException
;