Fix merge r65567.
[reactos.git] / ntoskrnl / kd / kdmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/kdinit.c
5 * PURPOSE: Kernel Debugger Initialization
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <debug.h>
13
14 /* VARIABLES ***************************************************************/
15
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);
26
27 typedef struct
28 {
29 ULONG ComponentId;
30 ULONG Level;
31 } KD_COMPONENT_DATA;
32 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
33 KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
34 ULONG KdComponentTableEntries = 0;
35
36 ULONG Kd_DEFAULT_MASK = 1 << DPFLTR_ERROR_LEVEL;
37
38 /* PRIVATE FUNCTIONS *********************************************************/
39
40 ULONG
41 NTAPI
42 KdpServiceDispatcher(ULONG Service,
43 PVOID Buffer1,
44 ULONG Buffer1Length)
45 {
46 ULONG Result = 0;
47
48 switch (Service)
49 {
50 case BREAKPOINT_PRINT: /* DbgPrint */
51 Result = KdpPrintString(Buffer1, Buffer1Length);
52 break;
53
54 #if DBG
55 case ' soR': /* ROS-INTERNAL */
56 {
57 switch ((ULONG_PTR)Buffer1)
58 {
59 case DumpAllThreads:
60 PspDumpThreads(TRUE);
61 break;
62
63 case DumpUserThreads:
64 PspDumpThreads(FALSE);
65 break;
66
67 case KdSpare3:
68 MmDumpArmPfnDatabase(FALSE);
69 break;
70
71 default:
72 break;
73 }
74 break;
75 }
76
77 /* Register a debug callback */
78 case 'CsoR':
79 {
80 switch (Buffer1Length)
81 {
82 case ID_Win32PreServiceHook:
83 KeWin32PreServiceHook = Buffer1;
84 break;
85
86 case ID_Win32PostServiceHook:
87 KeWin32PostServiceHook = Buffer1;
88 break;
89
90 }
91 break;
92 }
93
94 /* Special case for stack frame dumps */
95 case 'DsoR':
96 {
97 KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length);
98 break;
99 }
100
101 #if KDBG
102 /* Register KDBG CLI callback */
103 case 'RbdK':
104 {
105 Result = KdbRegisterCliCallback(Buffer1, Buffer1Length);
106 break;
107 }
108 #endif /* KDBG */
109 #endif /* DBG */
110 default:
111 DPRINT1("Invalid debug service call!\n");
112 HalDisplayString("Invalid debug service call!\r\n");
113 break;
114 }
115
116 return Result;
117 }
118
119 BOOLEAN
120 NTAPI
121 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
122 IN PKEXCEPTION_FRAME ExceptionFrame,
123 IN PEXCEPTION_RECORD ExceptionRecord,
124 IN PCONTEXT Context,
125 IN KPROCESSOR_MODE PreviousMode,
126 IN BOOLEAN SecondChance)
127 {
128 KD_CONTINUE_TYPE Return = kdHandleException;
129 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
130
131 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
132 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
133 (ExceptionRecord->NumberParameters > 0) &&
134 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
135 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
136 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
137 (ExceptionCommand == BREAKPOINT_PRINT) ||
138 (ExceptionCommand == BREAKPOINT_PROMPT)))
139 {
140 /* Check if this is a debug print */
141 if (ExceptionCommand == BREAKPOINT_PRINT)
142 {
143 /* Print the string */
144 KdpServiceDispatcher(BREAKPOINT_PRINT,
145 (PVOID)ExceptionRecord->ExceptionInformation[1],
146 ExceptionRecord->ExceptionInformation[2]);
147
148 /* Return success */
149 KeSetContextReturnRegister(Context, STATUS_SUCCESS);
150 }
151 #ifdef KDBG
152 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
153 {
154 PLDR_DATA_TABLE_ENTRY LdrEntry;
155
156 /* Load symbols. Currently implemented only for KDBG! */
157 if(KdbpSymFindModule(((PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2])->BaseOfDll, NULL, -1, &LdrEntry))
158 KdbSymProcessSymbols(LdrEntry);
159 }
160 else if (ExceptionCommand == BREAKPOINT_PROMPT)
161 {
162 ULONG ReturnValue;
163 LPSTR OutString;
164 USHORT OutStringLength;
165
166 /* Get the response string and length */
167 OutString = (LPSTR)Context->Ebx;
168 OutStringLength = (USHORT)Context->Edi;
169
170 /* Call KDBG */
171 ReturnValue = KdpPrompt((LPSTR)ExceptionRecord->
172 ExceptionInformation[1],
173 (USHORT)ExceptionRecord->
174 ExceptionInformation[2],
175 OutString,
176 OutStringLength);
177
178 /* Return the number of characters that we received */
179 Context->Eax = ReturnValue;
180 }
181 #endif
182
183 /* This we can handle: simply bump the Program Counter */
184 KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE);
185 return TRUE;
186 }
187
188 #ifdef KDBG
189 /* Check if this is an assertion failure */
190 if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE)
191 {
192 /* Bump EIP to the instruction following the int 2C */
193 Context->Eip += 2;
194 }
195 #endif
196
197 /* Get out of here if the Debugger isn't connected */
198 if (KdDebuggerNotPresent) return FALSE;
199
200 #ifdef KDBG
201 /* Call KDBG if available */
202 Return = KdbEnterDebuggerException(ExceptionRecord,
203 PreviousMode,
204 Context,
205 TrapFrame,
206 !SecondChance);
207 #else /* not KDBG */
208 if (WrapperInitRoutine)
209 {
210 /* Call GDB */
211 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
212 Context,
213 TrapFrame);
214 }
215 #endif /* not KDBG */
216
217 /* Debugger didn't handle it, please handle! */
218 if (Return == kdHandleException) return FALSE;
219
220 /* Debugger handled it */
221 return TRUE;
222 }
223
224 BOOLEAN
225 NTAPI
226 KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
227 IN PEXCEPTION_RECORD ExceptionRecord,
228 IN PCONTEXT Context)
229 {
230 KD_CONTINUE_TYPE Return = kdDoNotHandleException;
231
232 /* Get out of here if the Debugger isn't connected */
233 if (KdDebuggerNotPresent) return FALSE;
234
235 /* FIXME:
236 * Right now, the GDB wrapper seems to handle exceptions differntly
237 * from KDGB and both are called at different times, while the GDB
238 * one is only called once and that's it. I don't really have the knowledge
239 * to fix the GDB stub, so until then, we'll be using this hack
240 */
241 if (WrapperInitRoutine)
242 {
243 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
244 Context,
245 TrapFrame);
246 }
247
248 /* Debugger didn't handle it, please handle! */
249 if (Return == kdHandleException) return FALSE;
250
251 /* Debugger handled it */
252 return TRUE;
253 }
254
255 BOOLEAN
256 NTAPI
257 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord,
258 IN PCONTEXT Context,
259 IN KPROCESSOR_MODE PreviousMode)
260 {
261 /* KDBG has its own mechanism for ignoring user mode exceptions */
262 return FALSE;
263 }
264
265 /* PUBLIC FUNCTIONS *********************************************************/
266
267 /*
268 * @implemented
269 */
270 BOOLEAN
271 NTAPI
272 KdRefreshDebuggerNotPresent(VOID)
273 {
274 UNIMPLEMENTED;
275
276 /* Just return whatever was set previously -- FIXME! */
277 return KdDebuggerNotPresent;
278 }
279
280 /*
281 * @implemented
282 */
283 NTSTATUS
284 NTAPI
285 KdDisableDebugger(VOID)
286 {
287 KIRQL OldIrql;
288
289 /* Raise IRQL */
290 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
291
292 /* TODO: Disable any breakpoints */
293
294 /* Disable the Debugger */
295 KdDebuggerEnabled = FALSE;
296
297 /* Lower the IRQL */
298 KeLowerIrql(OldIrql);
299
300 /* Return success */
301 return STATUS_SUCCESS;
302 }
303
304 /*
305 * @implemented
306 */
307 NTSTATUS
308 NTAPI
309 KdEnableDebugger(VOID)
310 {
311 KIRQL OldIrql;
312
313 /* Raise IRQL */
314 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
315
316 /* TODO: Re-enable any breakpoints */
317
318 /* Enable the Debugger */
319 KdDebuggerEnabled = TRUE;
320
321 /* Lower the IRQL */
322 KeLowerIrql(OldIrql);
323
324 /* Return success */
325 return STATUS_SUCCESS;
326 }
327
328 /*
329 * @implemented
330 */
331 BOOLEAN
332 NTAPI
333 KdPollBreakIn(VOID)
334 {
335 return KdpBreakPending;
336 }
337
338 /*
339 * @unimplemented
340 */
341 NTSTATUS
342 NTAPI
343 KdPowerTransition(ULONG PowerState)
344 {
345 UNIMPLEMENTED;
346 return STATUS_NOT_IMPLEMENTED;
347 }
348
349 /*
350 * @unimplemented
351 */
352 NTSTATUS
353 NTAPI
354 KdChangeOption(IN KD_OPTION Option,
355 IN ULONG InBufferLength OPTIONAL,
356 IN PVOID InBuffer,
357 IN ULONG OutBufferLength OPTIONAL,
358 OUT PVOID OutBuffer,
359 OUT PULONG OutBufferRequiredLength OPTIONAL)
360 {
361 UNIMPLEMENTED;
362 return STATUS_NOT_IMPLEMENTED;
363 }
364
365
366 NTSTATUS
367 NTAPI
368 NtQueryDebugFilterState(IN ULONG ComponentId,
369 IN ULONG Level)
370 {
371 ULONG i;
372
373 /* Convert Level to mask if it isn't already one */
374 if (Level < 32)
375 Level = 1 << Level;
376
377 /* Check if it is not the default component */
378 if (ComponentId != DPFLTR_DEFAULT_ID)
379 {
380 /* No, search for an existing entry in the table */
381 for (i = 0; i < KdComponentTableEntries; i++)
382 {
383 /* Check if it is the right component */
384 if (ComponentId == KdComponentTable[i].ComponentId)
385 {
386 /* Check if mask are matching */
387 return (Level & KdComponentTable[i].Level) ? TRUE : FALSE;
388 }
389 }
390 }
391
392 /* Entry not found in the table, use default mask */
393 return (Level & Kd_DEFAULT_MASK) ? TRUE : FALSE;
394 }
395
396 NTSTATUS
397 NTAPI
398 NtSetDebugFilterState(IN ULONG ComponentId,
399 IN ULONG Level,
400 IN BOOLEAN State)
401 {
402 ULONG i;
403
404 /* Convert Level to mask if it isn't already one */
405 if (Level < 32)
406 Level = 1 << Level;
407 Level &= ~DPFLTR_MASK;
408
409 /* Check if it is the default component */
410 if (ComponentId == DPFLTR_DEFAULT_ID)
411 {
412 /* Yes, modify the default mask */
413 if (State)
414 Kd_DEFAULT_MASK |= Level;
415 else
416 Kd_DEFAULT_MASK &= ~Level;
417
418 return STATUS_SUCCESS;
419 }
420
421 /* Search for an existing entry */
422 for (i = 0; i < KdComponentTableEntries; i++ )
423 {
424 if (ComponentId == KdComponentTable[i].ComponentId)
425 break;
426 }
427
428 /* Check if we have found an existing entry */
429 if (i == KdComponentTableEntries)
430 {
431 /* Check if we have enough space in the table */
432 if (i == MAX_KD_COMPONENT_TABLE_ENTRIES)
433 return STATUS_INVALID_PARAMETER_1;
434
435 /* Add a new entry */
436 ++KdComponentTableEntries;
437 KdComponentTable[i].ComponentId = ComponentId;
438 KdComponentTable[i].Level = Kd_DEFAULT_MASK;
439 }
440
441 /* Update entry table */
442 if (State)
443 KdComponentTable[i].Level |= Level;
444 else
445 KdComponentTable[i].Level &= ~Level;
446
447 return STATUS_SUCCESS;
448 }
449
450 /*
451 * @unimplemented
452 */
453 NTSTATUS
454 NTAPI
455 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
456 IN PVOID InputBuffer,
457 IN ULONG InputBufferLength,
458 OUT PVOID OutputBuffer,
459 IN ULONG OutputBufferLength,
460 IN OUT PULONG ReturnLength,
461 IN KPROCESSOR_MODE PreviousMode)
462 {
463 /* HACK */
464 return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
465 }
466
467 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
468
469 /* EOF */