2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/kdinit.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 VOID NTAPI
PspDumpThreads(BOOLEAN SystemThreads
);
30 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
31 KD_COMPONENT_DATA KdComponentTable
[MAX_KD_COMPONENT_TABLE_ENTRIES
];
32 ULONG KdComponentTableEntries
= 0;
34 ULONG Kd_DEFAULT_MASK
= 1 << DPFLTR_ERROR_LEVEL
;
36 /* PRIVATE FUNCTIONS *********************************************************/
40 KdpServiceDispatcher(ULONG Service
,
48 case BREAKPOINT_PRINT
: /* DbgPrint */
49 Result
= KdpPrintString(Buffer1
, Buffer1Length
);
53 case ' soR': /* ROS-INTERNAL */
55 switch ((ULONG
)Buffer1
)
58 KeBugCheck(MANUALLY_INITIATED_CRASH
);
66 PspDumpThreads(FALSE
);
73 case ThatsWhatSheSaid
:
83 /* Special case for stack frame dumps */
86 KeRosDumpStackFrames((PULONG
)Buffer1
, Buffer1Length
);
91 HalDisplayString ("Invalid debug service call!\n");
100 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame
,
101 IN PKEXCEPTION_FRAME ExceptionFrame
,
102 IN PEXCEPTION_RECORD ExceptionRecord
,
104 IN KPROCESSOR_MODE PreviousMode
,
105 IN BOOLEAN SecondChance
)
107 KD_CONTINUE_TYPE Return
= kdHandleException
;
108 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
110 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
111 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
112 (ExceptionRecord
->NumberParameters
> 0) &&
113 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
114 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
115 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
116 (ExceptionCommand
== BREAKPOINT_PRINT
) ||
117 (ExceptionCommand
== BREAKPOINT_PROMPT
)))
119 /* Check if this is a debug print */
120 if (ExceptionCommand
== BREAKPOINT_PRINT
)
122 /* Print the string */
123 KdpServiceDispatcher(BREAKPOINT_PRINT
,
124 (PVOID
)ExceptionRecord
->ExceptionInformation
[1],
125 ExceptionRecord
->ExceptionInformation
[2]);
128 KeSetContextReturnRegister(Context
, STATUS_SUCCESS
);
131 else if (ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
)
133 PLDR_DATA_TABLE_ENTRY LdrEntry
;
135 /* Load symbols. Currently implemented only for KDBG! */
136 if(KdbpSymFindModule(((PKD_SYMBOLS_INFO
)ExceptionRecord
->ExceptionInformation
[2])->BaseOfDll
, NULL
, -1, &LdrEntry
))
137 KdbSymProcessSymbols(LdrEntry
);
139 else if (ExceptionCommand
== BREAKPOINT_PROMPT
)
143 USHORT OutStringLength
;
145 /* Get the response string and length */
146 OutString
= (LPSTR
)Context
->Ebx
;
147 OutStringLength
= (USHORT
)Context
->Edi
;
150 ReturnValue
= KdpPrompt((LPSTR
)ExceptionRecord
->
151 ExceptionInformation
[1],
152 (USHORT
)ExceptionRecord
->
153 ExceptionInformation
[2],
157 /* Return the number of characters that we received */
158 Context
->Eax
= ReturnValue
;
162 /* This we can handle: simply bump the Program Counter */
163 KeSetContextPc(Context
, KeGetContextPc(Context
) + KD_BREAKPOINT_SIZE
);
168 /* Check if this is an assertion failure */
169 if (ExceptionRecord
->ExceptionCode
== STATUS_ASSERTION_FAILURE
)
172 DbgPrint("\n!!! Assertion Failure at Address 0x%p !!!\n\n",
173 (PVOID
)Context
->Eip
);
175 /* Bump EIP to the instruction following the int 2C and return */
181 /* Get out of here if the Debugger isn't connected */
182 if (KdDebuggerNotPresent
) return FALSE
;
185 /* Call KDBG if available */
186 Return
= KdbEnterDebuggerException(ExceptionRecord
,
192 if (WrapperInitRoutine
)
195 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
199 #endif /* not KDBG */
201 /* Debugger didn't handle it, please handle! */
202 if (Return
== kdHandleException
) return FALSE
;
204 /* Debugger handled it */
210 KdpCallGdb(IN PKTRAP_FRAME TrapFrame
,
211 IN PEXCEPTION_RECORD ExceptionRecord
,
214 KD_CONTINUE_TYPE Return
= kdDoNotHandleException
;
216 /* Get out of here if the Debugger isn't connected */
217 if (KdDebuggerNotPresent
) return FALSE
;
220 * Right now, the GDB wrapper seems to handle exceptions differntly
221 * from KDGB and both are called at different times, while the GDB
222 * one is only called once and that's it. I don't really have the knowledge
223 * to fix the GDB stub, so until then, we'll be using this hack
225 if (WrapperInitRoutine
)
227 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
232 /* Debugger didn't handle it, please handle! */
233 if (Return
== kdHandleException
) return FALSE
;
235 /* Debugger handled it */
241 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
243 IN KPROCESSOR_MODE PreviousMode
)
245 /* KDBG has its own mechanism for ignoring user mode exceptions */
249 /* PUBLIC FUNCTIONS *********************************************************/
256 KdRefreshDebuggerNotPresent(VOID
)
260 /* Just return whatever was set previously -- FIXME! */
261 return KdDebuggerNotPresent
;
269 KdDisableDebugger(VOID
)
274 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
276 /* TODO: Disable any breakpoints */
278 /* Disable the Debugger */
279 KdDebuggerEnabled
= FALSE
;
282 KeLowerIrql(OldIrql
);
285 return STATUS_SUCCESS
;
293 KdEnableDebugger(VOID
)
298 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
300 /* TODO: Re-enable any breakpoints */
302 /* Enable the Debugger */
303 KdDebuggerEnabled
= TRUE
;
306 KeLowerIrql(OldIrql
);
309 return STATUS_SUCCESS
;
319 return KdpBreakPending
;
327 KdPowerTransition(ULONG PowerState
)
330 return STATUS_NOT_IMPLEMENTED
;
338 KdChangeOption(IN KD_OPTION Option
,
339 IN ULONG InBufferLength OPTIONAL
,
341 IN ULONG OutBufferLength OPTIONAL
,
343 OUT PULONG OutBufferRequiredLength OPTIONAL
)
346 return STATUS_NOT_IMPLEMENTED
;
352 NtQueryDebugFilterState(IN ULONG ComponentId
,
357 /* Convert Level to mask if it isn't already one */
361 /* Check if it is not the default component */
362 if (ComponentId
!= DPFLTR_DEFAULT_ID
)
364 /* No, search for an existing entry in the table */
365 for (i
= 0; i
< KdComponentTableEntries
; i
++)
367 /* Check if it is the right component */
368 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
370 /* Check if mask are matching */
371 return (Level
& KdComponentTable
[i
].Level
) != 0;
376 /* Entry not found in the table, use default mask */
377 return (Level
& Kd_DEFAULT_MASK
) != 0;
382 NtSetDebugFilterState(IN ULONG ComponentId
,
388 /* Convert Level to mask if it isn't already one */
391 Level
&= ~DPFLTR_MASK
;
393 /* Check if it is the default component */
394 if (ComponentId
== DPFLTR_DEFAULT_ID
)
396 /* Yes, modify the default mask */
398 Kd_DEFAULT_MASK
|= Level
;
400 Kd_DEFAULT_MASK
&= ~Level
;
402 return STATUS_SUCCESS
;
405 /* Search for an existing entry */
406 for (i
= 0; i
< KdComponentTableEntries
; i
++ )
408 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
412 /* Check if we have found an existing entry */
413 if (i
== KdComponentTableEntries
)
415 /* Check if we have enough space in the table */
416 if (i
== MAX_KD_COMPONENT_TABLE_ENTRIES
)
417 return STATUS_INVALID_PARAMETER_1
;
419 /* Add a new entry */
420 ++KdComponentTableEntries
;
421 KdComponentTable
[i
].ComponentId
= ComponentId
;
422 KdComponentTable
[i
].Level
= Kd_DEFAULT_MASK
;
425 /* Update entry table */
427 KdComponentTable
[i
].Level
|= Level
;
429 KdComponentTable
[i
].Level
&= ~Level
;
431 return STATUS_SUCCESS
;
439 KdSystemDebugControl(IN SYSDBG_COMMAND Command
,
440 IN PVOID InputBuffer
,
441 IN ULONG InputBufferLength
,
442 OUT PVOID OutputBuffer
,
443 IN ULONG OutputBufferLength
,
444 IN OUT PULONG ReturnLength
,
445 IN KPROCESSOR_MODE PreviousMode
)
448 return KdpServiceDispatcher(Command
, InputBuffer
, InputBufferLength
);
451 PKDEBUG_ROUTINE KiDebugRoutine
= KdpEnterDebuggerException
;