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