Sync to trunk head (r42241)
[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 KiEnableTimerWatchdog = FALSE;
20 BOOLEAN KdBreakAfterSymbolLoad = FALSE;
21 BOOLEAN KdpBreakPending;
22 BOOLEAN KdPitchDebugger = TRUE;
23 VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
24
25 typedef struct
26 {
27 ULONG ComponentId;
28 ULONG Level;
29 } KD_COMPONENT_DATA;
30 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
31 KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
32 ULONG KdComponentTableEntries = 0;
33
34 ULONG Kd_DEFAULT_MASK = 1 << DPFLTR_ERROR_LEVEL;
35
36 /* PRIVATE FUNCTIONS *********************************************************/
37
38 ULONG
39 NTAPI
40 KdpServiceDispatcher(ULONG Service,
41 PVOID Buffer1,
42 ULONG Buffer1Length)
43 {
44 ULONG Result = 0;
45
46 switch (Service)
47 {
48 case BREAKPOINT_PRINT: /* DbgPrint */
49 Result = KdpPrintString(Buffer1, Buffer1Length);
50 break;
51
52 #if DBG
53 case TAG('R', 'o', 's', ' '): /* ROS-INTERNAL */
54 {
55 switch ((ULONG_PTR)Buffer1)
56 {
57 case DumpNonPagedPool:
58 MiDebugDumpNonPagedPool(FALSE);
59 break;
60
61 case ManualBugCheck:
62 KeBugCheck(MANUALLY_INITIATED_CRASH);
63 break;
64
65 case DumpNonPagedPoolStats:
66 MiDebugDumpNonPagedPoolStats(FALSE);
67 break;
68
69 case DumpNewNonPagedPool:
70 MiDebugDumpNonPagedPool(TRUE);
71 break;
72
73 case DumpNewNonPagedPoolStats:
74 MiDebugDumpNonPagedPoolStats(TRUE);
75 break;
76
77 case DumpAllThreads:
78 PspDumpThreads(TRUE);
79 break;
80
81 case DumpUserThreads:
82 PspDumpThreads(FALSE);
83 break;
84
85 case EnterDebugger:
86 DbgBreakPoint();
87 break;
88
89 case ThatsWhatSheSaid:
90 MmDumpPfnDatabase();
91 break;
92
93 default:
94 break;
95 }
96 break;
97 }
98
99 /* Special case for stack frame dumps */
100 case TAG('R', 'o', 's', 'D'):
101 {
102 KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length);
103 break;
104 }
105 #endif
106 default:
107 HalDisplayString ("Invalid debug service call!\n");
108 break;
109 }
110
111 return Result;
112 }
113
114 BOOLEAN
115 NTAPI
116 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
117 IN PKEXCEPTION_FRAME ExceptionFrame,
118 IN PEXCEPTION_RECORD ExceptionRecord,
119 IN PCONTEXT Context,
120 IN KPROCESSOR_MODE PreviousMode,
121 IN BOOLEAN SecondChance)
122 {
123 KD_CONTINUE_TYPE Return = kdHandleException;
124 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
125 #ifdef _M_IX86
126 ULONG EipOld;
127 #endif
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 {
137 /* Check if this is a debug print */
138 if (ExceptionCommand == BREAKPOINT_PRINT)
139 {
140 /* Print the string */
141 KdpServiceDispatcher(BREAKPOINT_PRINT,
142 (PVOID)ExceptionRecord->ExceptionInformation[1],
143 ExceptionRecord->ExceptionInformation[2]);
144 #ifdef _M_IX86
145 Context->Eax = STATUS_SUCCESS;
146 #elif _M_ARM
147 Context->R0 = STATUS_SUCCESS;
148 #else
149 #error Please be portable when modifying code
150 #endif
151 }
152 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
153 {
154 /* Load symbols. Currently implemented only for KDBG! */
155 KDB_SYMBOLFILE_HOOK((PANSI_STRING)ExceptionRecord->ExceptionInformation[1],
156 (PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2]);
157 }
158
159 /* This we can handle: simply bump EIP */
160 #ifdef _M_IX86
161 Context->Eip++;
162 #elif _M_ARM
163 Context->Pc += sizeof(ULONG);
164 #endif
165 return TRUE;
166 }
167
168 /* Get out of here if the Debugger isn't connected */
169 if (KdDebuggerNotPresent) return FALSE;
170
171 /* Save old EIP value */
172 #ifdef _M_IX86
173 EipOld = Context->Eip;
174 #endif
175
176 #ifdef KDBG
177 /* Call KDBG if available */
178 Return = KdbEnterDebuggerException(ExceptionRecord,
179 PreviousMode,
180 Context,
181 TrapFrame,
182 !SecondChance);
183 #else /* not KDBG */
184 if (WrapperInitRoutine)
185 {
186 /* Call GDB */
187 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
188 Context,
189 TrapFrame);
190 }
191 #endif /* not KDBG */
192
193 /* Bump EIP over int 3 if debugger did not already change it */
194 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
195 {
196 //DPRINT1("Address: %p. Return: %d\n", EipOld, Return);
197 }
198
199 /* Debugger didn't handle it, please handle! */
200 if (Return == kdHandleException) return FALSE;
201
202 /* Debugger handled it */
203 return TRUE;
204 }
205
206 BOOLEAN
207 NTAPI
208 KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
209 IN PEXCEPTION_RECORD ExceptionRecord,
210 IN PCONTEXT Context)
211 {
212 KD_CONTINUE_TYPE Return = kdDoNotHandleException;
213
214 /* Get out of here if the Debugger isn't connected */
215 if (KdDebuggerNotPresent) return FALSE;
216
217 /* FIXME:
218 * Right now, the GDB wrapper seems to handle exceptions differntly
219 * from KDGB and both are called at different times, while the GDB
220 * one is only called once and that's it. I don't really have the knowledge
221 * to fix the GDB stub, so until then, we'll be using this hack
222 */
223 if (WrapperInitRoutine)
224 {
225 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
226 Context,
227 TrapFrame);
228 }
229
230 /* Debugger didn't handle it, please handle! */
231 if (Return == kdHandleException) return FALSE;
232
233 /* Debugger handled it */
234 return TRUE;
235 }
236
237 /* PUBLIC FUNCTIONS *********************************************************/
238
239 /*
240 * @implemented
241 */
242 BOOLEAN
243 NTAPI
244 KdRefreshDebuggerNotPresent(VOID)
245 {
246 UNIMPLEMENTED;
247
248 /* Just return whatever was set previously -- FIXME! */
249 return KdDebuggerNotPresent;
250 }
251
252 /*
253 * @implemented
254 */
255 NTSTATUS
256 NTAPI
257 KdDisableDebugger(VOID)
258 {
259 KIRQL OldIrql;
260
261 /* Raise IRQL */
262 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
263
264 /* TODO: Disable any breakpoints */
265
266 /* Disable the Debugger */
267 KdDebuggerEnabled = FALSE;
268
269 /* Lower the IRQL */
270 KeLowerIrql(OldIrql);
271
272 /* Return success */
273 return STATUS_SUCCESS;
274 }
275
276 /*
277 * @implemented
278 */
279 NTSTATUS
280 NTAPI
281 KdEnableDebugger(VOID)
282 {
283 KIRQL OldIrql;
284
285 /* Raise IRQL */
286 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
287
288 /* TODO: Re-enable any breakpoints */
289
290 /* Enable the Debugger */
291 KdDebuggerEnabled = TRUE;
292
293 /* Lower the IRQL */
294 KeLowerIrql(OldIrql);
295
296 /* Return success */
297 return STATUS_SUCCESS;
298 }
299
300 /*
301 * @implemented
302 */
303 BOOLEAN
304 NTAPI
305 KdPollBreakIn(VOID)
306 {
307 return KdpBreakPending;
308 }
309
310 /*
311 * @unimplemented
312 */
313 NTSTATUS
314 NTAPI
315 KdPowerTransition(ULONG PowerState)
316 {
317 UNIMPLEMENTED;
318 return STATUS_NOT_IMPLEMENTED;
319 }
320
321 /*
322 * @unimplemented
323 */
324 NTSTATUS
325 NTAPI
326 KdChangeOption(IN KD_OPTION Option,
327 IN ULONG InBufferLength OPTIONAL,
328 IN PVOID InBuffer,
329 IN ULONG OutBufferLength OPTIONAL,
330 OUT PVOID OutBuffer,
331 OUT PULONG OutBufferRequiredLength OPTIONAL)
332 {
333 UNIMPLEMENTED;
334 return STATUS_NOT_IMPLEMENTED;
335 }
336
337
338 NTSTATUS
339 NTAPI
340 NtQueryDebugFilterState(IN ULONG ComponentId,
341 IN ULONG Level)
342 {
343 ULONG i;
344
345 /* Convert Level to mask if it isn't already one */
346 if (Level < 32)
347 Level = 1 << Level;
348
349 /* Check if it is not the default component */
350 if (ComponentId != DPFLTR_DEFAULT_ID)
351 {
352 /* No, search for an existing entry in the table */
353 for (i = 0; i < KdComponentTableEntries; i++)
354 {
355 /* Check if it is the right component */
356 if (ComponentId == KdComponentTable[i].ComponentId)
357 {
358 /* Check if mask are matching */
359 return (Level & KdComponentTable[i].Level) != 0;
360 }
361 }
362 }
363
364 /* Entry not found in the table, use default mask */
365 return (Level & Kd_DEFAULT_MASK) != 0;
366 }
367
368 NTSTATUS
369 NTAPI
370 NtSetDebugFilterState(IN ULONG ComponentId,
371 IN ULONG Level,
372 IN BOOLEAN State)
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 Level &= ~DPFLTR_MASK;
380
381 /* Check if it is the default component */
382 if (ComponentId == DPFLTR_DEFAULT_ID)
383 {
384 /* Yes, modify the default mask */
385 if (State)
386 Kd_DEFAULT_MASK |= Level;
387 else
388 Kd_DEFAULT_MASK &= ~Level;
389
390 return STATUS_SUCCESS;
391 }
392
393 /* Search for an existing entry */
394 for (i = 0; i < KdComponentTableEntries; i++ )
395 {
396 if (ComponentId == KdComponentTable[i].ComponentId)
397 break;
398 }
399
400 /* Check if we have found an existing entry */
401 if (i == KdComponentTableEntries)
402 {
403 /* Check if we have enough space in the table */
404 if (i == MAX_KD_COMPONENT_TABLE_ENTRIES)
405 return STATUS_INVALID_PARAMETER_1;
406
407 /* Add a new entry */
408 ++KdComponentTableEntries;
409 KdComponentTable[i].ComponentId = ComponentId;
410 KdComponentTable[i].Level = Kd_DEFAULT_MASK;
411 }
412
413 /* Update entry table */
414 if (State)
415 KdComponentTable[i].Level |= Level;
416 else
417 KdComponentTable[i].Level &= ~Level;
418
419 return STATUS_SUCCESS;
420 }
421
422 /*
423 * @unimplemented
424 */
425 NTSTATUS
426 NTAPI
427 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
428 IN PVOID InputBuffer,
429 IN ULONG InputBufferLength,
430 OUT PVOID OutputBuffer,
431 IN ULONG OutputBufferLength,
432 IN OUT PULONG ReturnLength,
433 IN KPROCESSOR_MODE PreviousMode)
434 {
435 /* HACK */
436 return KdpServiceDispatcher(Command, InputBuffer, InputBufferLength);
437 }
438
439 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
440
441 /* EOF */