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