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
,
45 KPROCESSOR_MODE PreviousMode
)
51 case BREAKPOINT_PRINT
: /* DbgPrint */
52 Result
= KdpPrintString(Buffer1
, Buffer1Length
, PreviousMode
);
56 case ' soR': /* ROS-INTERNAL */
58 switch ((ULONG_PTR
)Buffer1
)
65 PspDumpThreads(FALSE
);
69 MmDumpArmPfnDatabase(FALSE
);
78 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
79 /* Register a debug callback */
82 switch (Buffer1Length
)
84 case ID_Win32PreServiceHook
:
85 KeWin32PreServiceHook
= Buffer1
;
88 case ID_Win32PostServiceHook
:
89 KeWin32PostServiceHook
= Buffer1
;
97 /* Special case for stack frame dumps */
100 KeRosDumpStackFrames((PULONG
)Buffer1
, Buffer1Length
);
105 /* Register KDBG CLI callback */
108 Result
= KdbRegisterCliCallback(Buffer1
, Buffer1Length
);
114 DPRINT1("Invalid debug service call!\n");
115 HalDisplayString("Invalid debug service call!\r\n");
124 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame
,
125 IN PKEXCEPTION_FRAME ExceptionFrame
,
126 IN PEXCEPTION_RECORD ExceptionRecord
,
128 IN KPROCESSOR_MODE PreviousMode
,
129 IN BOOLEAN SecondChance
)
131 KD_CONTINUE_TYPE Return
= kdHandleException
;
132 ULONG ExceptionCommand
= ExceptionRecord
->ExceptionInformation
[0];
134 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
135 if ((ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
) &&
136 (ExceptionRecord
->NumberParameters
> 0) &&
137 ((ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
) ||
138 (ExceptionCommand
== BREAKPOINT_UNLOAD_SYMBOLS
) ||
139 (ExceptionCommand
== BREAKPOINT_COMMAND_STRING
) ||
140 (ExceptionCommand
== BREAKPOINT_PRINT
) ||
141 (ExceptionCommand
== BREAKPOINT_PROMPT
)))
143 /* Check if this is a debug print */
144 if (ExceptionCommand
== BREAKPOINT_PRINT
)
146 /* Print the string */
147 KdpServiceDispatcher(BREAKPOINT_PRINT
,
148 (PVOID
)ExceptionRecord
->ExceptionInformation
[1],
149 ExceptionRecord
->ExceptionInformation
[2],
153 KeSetContextReturnRegister(Context
, STATUS_SUCCESS
);
156 else if (ExceptionCommand
== BREAKPOINT_LOAD_SYMBOLS
)
158 PKD_SYMBOLS_INFO SymbolsInfo
;
159 KD_SYMBOLS_INFO CapturedSymbolsInfo
;
160 PLDR_DATA_TABLE_ENTRY LdrEntry
;
162 SymbolsInfo
= (PKD_SYMBOLS_INFO
)ExceptionRecord
->ExceptionInformation
[2];
163 if (PreviousMode
!= KernelMode
)
167 ProbeForRead(SymbolsInfo
,
168 sizeof(*SymbolsInfo
),
170 RtlCopyMemory(&CapturedSymbolsInfo
,
172 sizeof(*SymbolsInfo
));
173 SymbolsInfo
= &CapturedSymbolsInfo
;
175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
182 if (SymbolsInfo
!= NULL
)
184 /* Load symbols. Currently implemented only for KDBG! */
185 if (KdbpSymFindModule(SymbolsInfo
->BaseOfDll
, NULL
, -1, &LdrEntry
))
187 KdbSymProcessSymbols(LdrEntry
);
191 else if (ExceptionCommand
== BREAKPOINT_PROMPT
)
195 USHORT OutStringLength
;
197 /* Get the response string and length */
198 OutString
= (LPSTR
)Context
->Ebx
;
199 OutStringLength
= (USHORT
)Context
->Edi
;
202 ReturnValue
= KdpPrompt((LPSTR
)ExceptionRecord
->
203 ExceptionInformation
[1],
204 (USHORT
)ExceptionRecord
->
205 ExceptionInformation
[2],
210 /* Return the number of characters that we received */
211 Context
->Eax
= ReturnValue
;
215 /* This we can handle: simply bump the Program Counter */
216 KeSetContextPc(Context
, KeGetContextPc(Context
) + KD_BREAKPOINT_SIZE
);
221 /* Check if this is an assertion failure */
222 if (ExceptionRecord
->ExceptionCode
== STATUS_ASSERTION_FAILURE
)
224 /* Bump EIP to the instruction following the int 2C */
229 /* Get out of here if the Debugger isn't connected */
230 if (KdDebuggerNotPresent
) return FALSE
;
233 /* Call KDBG if available */
234 Return
= KdbEnterDebuggerException(ExceptionRecord
,
240 if (WrapperInitRoutine
)
243 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
247 #endif /* not KDBG */
249 /* Debugger didn't handle it, please handle! */
250 if (Return
== kdHandleException
) return FALSE
;
252 /* Debugger handled it */
258 KdpCallGdb(IN PKTRAP_FRAME TrapFrame
,
259 IN PEXCEPTION_RECORD ExceptionRecord
,
262 KD_CONTINUE_TYPE Return
= kdDoNotHandleException
;
264 /* Get out of here if the Debugger isn't connected */
265 if (KdDebuggerNotPresent
) return FALSE
;
268 * Right now, the GDB wrapper seems to handle exceptions differntly
269 * from KDGB and both are called at different times, while the GDB
270 * one is only called once and that's it. I don't really have the knowledge
271 * to fix the GDB stub, so until then, we'll be using this hack
273 if (WrapperInitRoutine
)
275 Return
= WrapperTable
.KdpExceptionRoutine(ExceptionRecord
,
280 /* Debugger didn't handle it, please handle! */
281 if (Return
== kdHandleException
) return FALSE
;
283 /* Debugger handled it */
289 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord
,
291 IN KPROCESSOR_MODE PreviousMode
)
293 /* KDBG has its own mechanism for ignoring user mode exceptions */
297 /* PUBLIC FUNCTIONS *********************************************************/
304 KdRefreshDebuggerNotPresent(VOID
)
308 /* Just return whatever was set previously -- FIXME! */
309 return KdDebuggerNotPresent
;
317 KdDisableDebugger(VOID
)
322 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
324 /* TODO: Disable any breakpoints */
326 /* Disable the Debugger */
327 KdDebuggerEnabled
= FALSE
;
328 SharedUserData
->KdDebuggerEnabled
= FALSE
;
331 KeLowerIrql(OldIrql
);
334 return STATUS_SUCCESS
;
342 KdEnableDebugger(VOID
)
347 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
349 /* TODO: Re-enable any breakpoints */
351 /* Enable the Debugger */
352 KdDebuggerEnabled
= TRUE
;
353 SharedUserData
->KdDebuggerEnabled
= TRUE
;
356 KeLowerIrql(OldIrql
);
359 return STATUS_SUCCESS
;
369 return KdpBreakPending
;
377 KdPowerTransition(ULONG PowerState
)
380 return STATUS_NOT_IMPLEMENTED
;
388 KdChangeOption(IN KD_OPTION Option
,
389 IN ULONG InBufferLength OPTIONAL
,
391 IN ULONG OutBufferLength OPTIONAL
,
393 OUT PULONG OutBufferRequiredLength OPTIONAL
)
396 return STATUS_NOT_IMPLEMENTED
;
402 NtQueryDebugFilterState(IN ULONG ComponentId
,
407 /* Convert Level to mask if it isn't already one */
411 /* Check if it is not the default component */
412 if (ComponentId
!= MAXULONG
)
414 /* No, search for an existing entry in the table */
415 for (i
= 0; i
< KdComponentTableEntries
; i
++)
417 /* Check if it is the right component */
418 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
420 /* Check if mask are matching */
421 return (Level
& KdComponentTable
[i
].Level
) ? TRUE
: FALSE
;
426 /* Entry not found in the table, use default mask */
427 return (Level
& Kd_DEFAULT_MASK
) ? TRUE
: FALSE
;
432 NtSetDebugFilterState(IN ULONG ComponentId
,
438 /* Convert Level to mask if it isn't already one */
441 Level
&= ~DPFLTR_MASK
;
443 /* Check if it is the default component */
444 if (ComponentId
== MAXULONG
)
446 /* Yes, modify the default mask */
448 Kd_DEFAULT_MASK
|= Level
;
450 Kd_DEFAULT_MASK
&= ~Level
;
452 return STATUS_SUCCESS
;
455 /* Search for an existing entry */
456 for (i
= 0; i
< KdComponentTableEntries
; i
++ )
458 if (ComponentId
== KdComponentTable
[i
].ComponentId
)
462 /* Check if we have found an existing entry */
463 if (i
== KdComponentTableEntries
)
465 /* Check if we have enough space in the table */
466 if (i
== MAX_KD_COMPONENT_TABLE_ENTRIES
)
467 return STATUS_INVALID_PARAMETER_1
;
469 /* Add a new entry */
470 ++KdComponentTableEntries
;
471 KdComponentTable
[i
].ComponentId
= ComponentId
;
472 KdComponentTable
[i
].Level
= Kd_DEFAULT_MASK
;
475 /* Update entry table */
477 KdComponentTable
[i
].Level
|= Level
;
479 KdComponentTable
[i
].Level
&= ~Level
;
481 return STATUS_SUCCESS
;
489 KdSystemDebugControl(IN SYSDBG_COMMAND Command
,
490 IN PVOID InputBuffer
,
491 IN ULONG InputBufferLength
,
492 OUT PVOID OutputBuffer
,
493 IN ULONG OutputBufferLength
,
494 IN OUT PULONG ReturnLength
,
495 IN KPROCESSOR_MODE PreviousMode
)
498 return KdpServiceDispatcher(Command
,
504 PKDEBUG_ROUTINE KiDebugRoutine
= KdpEnterDebuggerException
;