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