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