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