- There is no need for the i8042 driver to use a hacked KdSystemDebugControl call...
[reactos.git] / reactos / 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 #endif
101 default:
102 HalDisplayString ("Invalid debug service call!\n");
103 break;
104 }
105
106 return Result;
107 }
108
109 BOOLEAN
110 NTAPI
111 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
112 IN PKEXCEPTION_FRAME ExceptionFrame,
113 IN PEXCEPTION_RECORD ExceptionRecord,
114 IN PCONTEXT Context,
115 IN KPROCESSOR_MODE PreviousMode,
116 IN BOOLEAN SecondChance)
117 {
118 KD_CONTINUE_TYPE Return = kdHandleException;
119 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
120
121 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
122 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
123 (ExceptionRecord->NumberParameters > 0) &&
124 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
125 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
126 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
127 (ExceptionCommand == BREAKPOINT_PRINT) ||
128 (ExceptionCommand == BREAKPOINT_PROMPT)))
129 {
130 /* Check if this is a debug print */
131 if (ExceptionCommand == BREAKPOINT_PRINT)
132 {
133 /* Print the string */
134 KdpServiceDispatcher(BREAKPOINT_PRINT,
135 (PVOID)ExceptionRecord->ExceptionInformation[1],
136 ExceptionRecord->ExceptionInformation[2]);
137
138 /* Return success */
139 KeSetContextReturnRegister(Context, STATUS_SUCCESS);
140 }
141 #ifdef KDBG
142 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
143 {
144 PLDR_DATA_TABLE_ENTRY LdrEntry;
145
146 /* Load symbols. Currently implemented only for KDBG! */
147 if(KdbpSymFindModule(((PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2])->BaseOfDll, NULL, -1, &LdrEntry))
148 KdbSymProcessSymbols(LdrEntry);
149 }
150 else if (ExceptionCommand == BREAKPOINT_PROMPT)
151 {
152 ULONG ReturnValue;
153 LPSTR OutString;
154 USHORT OutStringLength;
155
156 /* Get the response string and length */
157 OutString = (LPSTR)Context->Ebx;
158 OutStringLength = (USHORT)Context->Edi;
159
160 /* Call KDBG */
161 ReturnValue = KdpPrompt((LPSTR)ExceptionRecord->
162 ExceptionInformation[1],
163 (USHORT)ExceptionRecord->
164 ExceptionInformation[2],
165 OutString,
166 OutStringLength);
167
168 /* Return the number of characters that we received */
169 Context->Eax = ReturnValue;
170 }
171 #endif
172
173 /* This we can handle: simply bump the Program Counter */
174 KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE);
175 return TRUE;
176 }
177
178 #ifdef KDBG
179 /* Check if this is an assertion failure */
180 if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE)
181 {
182 /* Warn about it */
183 DbgPrint("\n!!! Assertion Failure at Address 0x%p !!!\n\n",
184 (PVOID)Context->Eip);
185
186 /* Bump EIP to the instruction following the int 2C and return */
187 Context->Eip += 2;
188 return TRUE;
189 }
190 #endif
191
192 /* Get out of here if the Debugger isn't connected */
193 if (KdDebuggerNotPresent) return FALSE;
194
195 #ifdef KDBG
196 /* Call KDBG if available */
197 Return = KdbEnterDebuggerException(ExceptionRecord,
198 PreviousMode,
199 Context,
200 TrapFrame,
201 !SecondChance);
202 #else /* not KDBG */
203 if (WrapperInitRoutine)
204 {
205 /* Call GDB */
206 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
207 Context,
208 TrapFrame);
209 }
210 #endif /* not KDBG */
211
212 /* Debugger didn't handle it, please handle! */
213 if (Return == kdHandleException) return FALSE;
214
215 /* Debugger handled it */
216 return TRUE;
217 }
218
219 BOOLEAN
220 NTAPI
221 KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
222 IN PEXCEPTION_RECORD ExceptionRecord,
223 IN PCONTEXT Context)
224 {
225 KD_CONTINUE_TYPE Return = kdDoNotHandleException;
226
227 /* Get out of here if the Debugger isn't connected */
228 if (KdDebuggerNotPresent) return FALSE;
229
230 /* FIXME:
231 * Right now, the GDB wrapper seems to handle exceptions differntly
232 * from KDGB and both are called at different times, while the GDB
233 * one is only called once and that's it. I don't really have the knowledge
234 * to fix the GDB stub, so until then, we'll be using this hack
235 */
236 if (WrapperInitRoutine)
237 {
238 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
239 Context,
240 TrapFrame);
241 }
242
243 /* Debugger didn't handle it, please handle! */
244 if (Return == kdHandleException) return FALSE;
245
246 /* Debugger handled it */
247 return TRUE;
248 }
249
250 BOOLEAN
251 NTAPI
252 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord,
253 IN PCONTEXT Context,
254 IN KPROCESSOR_MODE PreviousMode)
255 {
256 /* KDBG has its own mechanism for ignoring user mode exceptions */
257 return FALSE;
258 }
259
260 /* PUBLIC FUNCTIONS *********************************************************/
261
262 /*
263 * @implemented
264 */
265 BOOLEAN
266 NTAPI
267 KdRefreshDebuggerNotPresent(VOID)
268 {
269 UNIMPLEMENTED;
270
271 /* Just return whatever was set previously -- FIXME! */
272 return KdDebuggerNotPresent;
273 }
274
275 /*
276 * @implemented
277 */
278 NTSTATUS
279 NTAPI
280 KdDisableDebugger(VOID)
281 {
282 KIRQL OldIrql;
283
284 /* Raise IRQL */
285 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
286
287 /* TODO: Disable any breakpoints */
288
289 /* Disable the Debugger */
290 KdDebuggerEnabled = FALSE;
291
292 /* Lower the IRQL */
293 KeLowerIrql(OldIrql);
294
295 /* Return success */
296 return STATUS_SUCCESS;
297 }
298
299 /*
300 * @implemented
301 */
302 NTSTATUS
303 NTAPI
304 KdEnableDebugger(VOID)
305 {
306 KIRQL OldIrql;
307
308 /* Raise IRQL */
309 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
310
311 /* TODO: Re-enable any breakpoints */
312
313 /* Enable the Debugger */
314 KdDebuggerEnabled = TRUE;
315
316 /* Lower the IRQL */
317 KeLowerIrql(OldIrql);
318
319 /* Return success */
320 return STATUS_SUCCESS;
321 }
322
323 /*
324 * @implemented
325 */
326 BOOLEAN
327 NTAPI
328 KdPollBreakIn(VOID)
329 {
330 return KdpBreakPending;
331 }
332
333 /*
334 * @unimplemented
335 */
336 NTSTATUS
337 NTAPI
338 KdPowerTransition(ULONG PowerState)
339 {
340 UNIMPLEMENTED;
341 return STATUS_NOT_IMPLEMENTED;
342 }
343
344 /*
345 * @unimplemented
346 */
347 NTSTATUS
348 NTAPI
349 KdChangeOption(IN KD_OPTION Option,
350 IN ULONG InBufferLength OPTIONAL,
351 IN PVOID InBuffer,
352 IN ULONG OutBufferLength OPTIONAL,
353 OUT PVOID OutBuffer,
354 OUT PULONG OutBufferRequiredLength OPTIONAL)
355 {
356 UNIMPLEMENTED;
357 return STATUS_NOT_IMPLEMENTED;
358 }
359
360
361 NTSTATUS
362 NTAPI
363 NtQueryDebugFilterState(IN ULONG ComponentId,
364 IN ULONG Level)
365 {
366 ULONG i;
367
368 /* Convert Level to mask if it isn't already one */
369 if (Level < 32)
370 Level = 1 << Level;
371
372 /* Check if it is not the default component */
373 if (ComponentId != DPFLTR_DEFAULT_ID)
374 {
375 /* No, search for an existing entry in the table */
376 for (i = 0; i < KdComponentTableEntries; i++)
377 {
378 /* Check if it is the right component */
379 if (ComponentId == KdComponentTable[i].ComponentId)
380 {
381 /* Check if mask are matching */
382 return (Level & KdComponentTable[i].Level) ? TRUE : FALSE;
383 }
384 }
385 }
386
387 /* Entry not found in the table, use default mask */
388 return (Level & Kd_DEFAULT_MASK) ? TRUE : FALSE;
389 }
390
391 NTSTATUS
392 NTAPI
393 NtSetDebugFilterState(IN ULONG ComponentId,
394 IN ULONG Level,
395 IN BOOLEAN State)
396 {
397 ULONG i;
398
399 /* Convert Level to mask if it isn't already one */
400 if (Level < 32)
401 Level = 1 << Level;
402 Level &= ~DPFLTR_MASK;
403
404 /* Check if it is the default component */
405 if (ComponentId == DPFLTR_DEFAULT_ID)
406 {
407 /* Yes, modify the default mask */
408 if (State)
409 Kd_DEFAULT_MASK |= Level;
410 else
411 Kd_DEFAULT_MASK &= ~Level;
412
413 return STATUS_SUCCESS;
414 }
415
416 /* Search for an existing entry */
417 for (i = 0; i < KdComponentTableEntries; i++ )
418 {
419 if (ComponentId == KdComponentTable[i].ComponentId)
420 break;
421 }
422
423 /* Check if we have found an existing entry */
424 if (i == KdComponentTableEntries)
425 {
426 /* Check if we have enough space in the table */
427 if (i == MAX_KD_COMPONENT_TABLE_ENTRIES)
428 return STATUS_INVALID_PARAMETER_1;
429
430 /* Add a new entry */
431 ++KdComponentTableEntries;
432 KdComponentTable[i].ComponentId = ComponentId;
433 KdComponentTable[i].Level = Kd_DEFAULT_MASK;
434 }
435
436 /* Update entry table */
437 if (State)
438 KdComponentTable[i].Level |= Level;
439 else
440 KdComponentTable[i].Level &= ~Level;
441
442 return STATUS_SUCCESS;
443 }
444
445 /*
446 * @unimplemented
447 */
448 NTSTATUS
449 NTAPI
450 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
451 IN PVOID InputBuffer,
452 IN ULONG InputBufferLength,
453 OUT PVOID OutputBuffer,
454 IN ULONG OutputBufferLength,
455 IN OUT PULONG ReturnLength,
456 IN KPROCESSOR_MODE PreviousMode)
457 {
458 /* HACK */
459 return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
460 }
461
462 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
463
464 /* EOF */