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