[NTOSKRNL] Implement ObSetDirectoryDeviceMap
[reactos.git] / ntoskrnl / kd / kdmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/kd/kdmain.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 KdPitchDebugger = TRUE;
21 BOOLEAN KdIgnoreUmExceptions = FALSE;
22 KD_CONTEXT KdpContext;
23 ULONG Kd_WIN2000_Mask;
24 LONG KdpTimeSlipPending;
25 KDDEBUGGER_DATA64 KdDebuggerDataBlock;
26 VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
27
28 typedef struct
29 {
30 ULONG ComponentId;
31 ULONG Level;
32 } KD_COMPONENT_DATA;
33 #define MAX_KD_COMPONENT_TABLE_ENTRIES 128
34 KD_COMPONENT_DATA KdpComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
35 ULONG KdComponentTableEntries = 0;
36
37 ULONG Kd_DEFAULT_MASK = 1 << DPFLTR_ERROR_LEVEL;
38
39 /* PRIVATE FUNCTIONS *********************************************************/
40
41 ULONG
42 NTAPI
43 KdpServiceDispatcher(ULONG Service,
44 PVOID Buffer1,
45 ULONG Buffer1Length,
46 KPROCESSOR_MODE PreviousMode)
47 {
48 ULONG Result = 0;
49
50 switch (Service)
51 {
52 case BREAKPOINT_PRINT: /* DbgPrint */
53 Result = KdpPrintString(Buffer1, Buffer1Length, PreviousMode);
54 break;
55
56 #if DBG
57 case ' soR': /* ROS-INTERNAL */
58 {
59 switch ((ULONG_PTR)Buffer1)
60 {
61 case DumpAllThreads:
62 PspDumpThreads(TRUE);
63 break;
64
65 case DumpUserThreads:
66 PspDumpThreads(FALSE);
67 break;
68
69 case KdSpare3:
70 MmDumpArmPfnDatabase(FALSE);
71 break;
72
73 default:
74 break;
75 }
76 break;
77 }
78
79 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
80 /* Register a debug callback */
81 case 'CsoR':
82 {
83 switch (Buffer1Length)
84 {
85 case ID_Win32PreServiceHook:
86 KeWin32PreServiceHook = Buffer1;
87 break;
88
89 case ID_Win32PostServiceHook:
90 KeWin32PostServiceHook = Buffer1;
91 break;
92
93 }
94 break;
95 }
96 #endif
97
98 /* Special case for stack frame dumps */
99 case 'DsoR':
100 {
101 KeRosDumpStackFrames((PULONG)Buffer1, Buffer1Length);
102 break;
103 }
104
105 #if defined(KDBG)
106 /* Register KDBG CLI callback */
107 case 'RbdK':
108 {
109 Result = KdbRegisterCliCallback(Buffer1, Buffer1Length);
110 break;
111 }
112 #endif /* KDBG */
113 #endif /* DBG */
114 default:
115 DPRINT1("Invalid debug service call!\n");
116 HalDisplayString("Invalid debug service call!\r\n");
117 break;
118 }
119
120 return Result;
121 }
122
123 BOOLEAN
124 NTAPI
125 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
126 IN PKEXCEPTION_FRAME ExceptionFrame,
127 IN PEXCEPTION_RECORD ExceptionRecord,
128 IN PCONTEXT Context,
129 IN KPROCESSOR_MODE PreviousMode,
130 IN BOOLEAN SecondChance)
131 {
132 KD_CONTINUE_TYPE Return = kdHandleException;
133 ULONG ExceptionCommand = ExceptionRecord->ExceptionInformation[0];
134
135 /* Check if this was a breakpoint due to DbgPrint or Load/UnloadSymbols */
136 if ((ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) &&
137 (ExceptionRecord->NumberParameters > 0) &&
138 ((ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS) ||
139 (ExceptionCommand == BREAKPOINT_UNLOAD_SYMBOLS) ||
140 (ExceptionCommand == BREAKPOINT_COMMAND_STRING) ||
141 (ExceptionCommand == BREAKPOINT_PRINT) ||
142 (ExceptionCommand == BREAKPOINT_PROMPT)))
143 {
144 /* Check if this is a debug print */
145 if (ExceptionCommand == BREAKPOINT_PRINT)
146 {
147 /* Print the string */
148 KdpServiceDispatcher(BREAKPOINT_PRINT,
149 (PVOID)ExceptionRecord->ExceptionInformation[1],
150 ExceptionRecord->ExceptionInformation[2],
151 PreviousMode);
152
153 /* Return success */
154 KeSetContextReturnRegister(Context, STATUS_SUCCESS);
155 }
156 #ifdef KDBG
157 else if (ExceptionCommand == BREAKPOINT_LOAD_SYMBOLS)
158 {
159 PKD_SYMBOLS_INFO SymbolsInfo;
160 KD_SYMBOLS_INFO CapturedSymbolsInfo;
161 PLDR_DATA_TABLE_ENTRY LdrEntry;
162
163 SymbolsInfo = (PKD_SYMBOLS_INFO)ExceptionRecord->ExceptionInformation[2];
164 if (PreviousMode != KernelMode)
165 {
166 _SEH2_TRY
167 {
168 ProbeForRead(SymbolsInfo,
169 sizeof(*SymbolsInfo),
170 1);
171 RtlCopyMemory(&CapturedSymbolsInfo,
172 SymbolsInfo,
173 sizeof(*SymbolsInfo));
174 SymbolsInfo = &CapturedSymbolsInfo;
175 }
176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
177 {
178 SymbolsInfo = NULL;
179 }
180 _SEH2_END;
181 }
182
183 if (SymbolsInfo != NULL)
184 {
185 /* Load symbols. Currently implemented only for KDBG! */
186 if (KdbpSymFindModule(SymbolsInfo->BaseOfDll, NULL, -1, &LdrEntry))
187 {
188 KdbSymProcessSymbols(LdrEntry);
189 }
190 }
191 }
192 else if (ExceptionCommand == BREAKPOINT_PROMPT)
193 {
194 ULONG ReturnValue;
195 LPSTR OutString;
196 USHORT OutStringLength;
197
198 /* Get the response string and length */
199 OutString = (LPSTR)Context->Ebx;
200 OutStringLength = (USHORT)Context->Edi;
201
202 /* Call KDBG */
203 ReturnValue = KdpPrompt((LPSTR)ExceptionRecord->
204 ExceptionInformation[1],
205 (USHORT)ExceptionRecord->
206 ExceptionInformation[2],
207 OutString,
208 OutStringLength,
209 PreviousMode,
210 TrapFrame,
211 ExceptionFrame);
212
213 /* Return the number of characters that we received */
214 Context->Eax = ReturnValue;
215 }
216 #endif
217
218 /* This we can handle: simply bump the Program Counter */
219 KeSetContextPc(Context, KeGetContextPc(Context) + KD_BREAKPOINT_SIZE);
220 return TRUE;
221 }
222
223 #ifdef KDBG
224 /* Check if this is an assertion failure */
225 if (ExceptionRecord->ExceptionCode == STATUS_ASSERTION_FAILURE)
226 {
227 /* Bump EIP to the instruction following the int 2C */
228 Context->Eip += 2;
229 }
230 #endif
231
232 /* Get out of here if the Debugger isn't connected */
233 if (KdDebuggerNotPresent) return FALSE;
234
235 #ifdef KDBG
236 /* Call KDBG if available */
237 Return = KdbEnterDebuggerException(ExceptionRecord,
238 PreviousMode,
239 Context,
240 TrapFrame,
241 !SecondChance);
242 #else /* not KDBG */
243 if (WrapperInitRoutine)
244 {
245 /* Call GDB */
246 Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
247 Context,
248 TrapFrame);
249 }
250 #endif /* not KDBG */
251
252 /* Debugger didn't handle it, please handle! */
253 if (Return == kdHandleException) return FALSE;
254
255 /* Debugger handled it */
256 return TRUE;
257 }
258
259 BOOLEAN
260 NTAPI
261 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord,
262 IN PCONTEXT Context,
263 IN KPROCESSOR_MODE PreviousMode)
264 {
265 /* KDBG has its own mechanism for ignoring user mode exceptions */
266 return FALSE;
267 }
268
269 /* PUBLIC FUNCTIONS *********************************************************/
270
271 VOID
272 NTAPI
273 KdUpdateDataBlock(VOID)
274 {
275 }
276
277 /*
278 * @implemented
279 */
280 BOOLEAN
281 NTAPI
282 KdRefreshDebuggerNotPresent(VOID)
283 {
284 UNIMPLEMENTED;
285
286 /* Just return whatever was set previously -- FIXME! */
287 return KdDebuggerNotPresent;
288 }
289
290 /*
291 * @implemented
292 */
293 NTSTATUS
294 NTAPI
295 KdDisableDebugger(VOID)
296 {
297 KIRQL OldIrql;
298
299 /* Raise IRQL */
300 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
301
302 /* TODO: Disable any breakpoints */
303
304 /* Disable the Debugger */
305 KdDebuggerEnabled = FALSE;
306 SharedUserData->KdDebuggerEnabled = FALSE;
307
308 /* Lower the IRQL */
309 KeLowerIrql(OldIrql);
310
311 /* Return success */
312 return STATUS_SUCCESS;
313 }
314
315 NTSTATUS
316 NTAPI
317 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
318 {
319 return STATUS_ACCESS_DENIED;
320 }
321
322 /*
323 * @implemented
324 */
325 NTSTATUS
326 NTAPI
327 KdEnableDebugger(VOID)
328 {
329 KIRQL OldIrql;
330
331 /* Raise IRQL */
332 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
333
334 /* TODO: Re-enable any breakpoints */
335
336 /* Enable the Debugger */
337 KdDebuggerEnabled = TRUE;
338 SharedUserData->KdDebuggerEnabled = TRUE;
339
340 /* Lower the IRQL */
341 KeLowerIrql(OldIrql);
342
343 /* Return success */
344 return STATUS_SUCCESS;
345 }
346
347 /*
348 * @implemented
349 */
350 BOOLEAN
351 NTAPI
352 KdPollBreakIn(VOID)
353 {
354 return FALSE;
355 }
356
357 /*
358 * @unimplemented
359 */
360 NTSTATUS
361 NTAPI
362 KdPowerTransition(ULONG PowerState)
363 {
364 UNIMPLEMENTED;
365 return STATUS_NOT_IMPLEMENTED;
366 }
367
368 /*
369 * @unimplemented
370 */
371 NTSTATUS
372 NTAPI
373 KdChangeOption(IN KD_OPTION Option,
374 IN ULONG InBufferLength OPTIONAL,
375 IN PVOID InBuffer,
376 IN ULONG OutBufferLength OPTIONAL,
377 OUT PVOID OutBuffer,
378 OUT PULONG OutBufferRequiredLength OPTIONAL)
379 {
380 UNIMPLEMENTED;
381 return STATUS_NOT_IMPLEMENTED;
382 }
383
384
385 NTSTATUS
386 NTAPI
387 NtQueryDebugFilterState(IN ULONG ComponentId,
388 IN ULONG Level)
389 {
390 ULONG i;
391
392 /* Convert Level to mask if it isn't already one */
393 if (Level < 32)
394 Level = 1 << Level;
395
396 /* Check if it is not the default component */
397 if (ComponentId != MAXULONG)
398 {
399 /* No, search for an existing entry in the table */
400 for (i = 0; i < KdComponentTableEntries; i++)
401 {
402 /* Check if it is the right component */
403 if (ComponentId == KdpComponentTable[i].ComponentId)
404 {
405 /* Check if mask are matching */
406 return (Level & KdpComponentTable[i].Level) ? TRUE : FALSE;
407 }
408 }
409 }
410
411 /* Entry not found in the table, use default mask */
412 return (Level & Kd_DEFAULT_MASK) ? TRUE : FALSE;
413 }
414
415 NTSTATUS
416 NTAPI
417 NtSetDebugFilterState(IN ULONG ComponentId,
418 IN ULONG Level,
419 IN BOOLEAN State)
420 {
421 ULONG i;
422
423 /* Convert Level to mask if it isn't already one */
424 if (Level < 32)
425 Level = 1 << Level;
426 Level &= ~DPFLTR_MASK;
427
428 /* Check if it is the default component */
429 if (ComponentId == MAXULONG)
430 {
431 /* Yes, modify the default mask */
432 if (State)
433 Kd_DEFAULT_MASK |= Level;
434 else
435 Kd_DEFAULT_MASK &= ~Level;
436
437 return STATUS_SUCCESS;
438 }
439
440 /* Search for an existing entry */
441 for (i = 0; i < KdComponentTableEntries; i++ )
442 {
443 if (ComponentId == KdpComponentTable[i].ComponentId)
444 break;
445 }
446
447 /* Check if we have found an existing entry */
448 if (i == KdComponentTableEntries)
449 {
450 /* Check if we have enough space in the table */
451 if (i == MAX_KD_COMPONENT_TABLE_ENTRIES)
452 return STATUS_INVALID_PARAMETER_1;
453
454 /* Add a new entry */
455 ++KdComponentTableEntries;
456 KdpComponentTable[i].ComponentId = ComponentId;
457 KdpComponentTable[i].Level = Kd_DEFAULT_MASK;
458 }
459
460 /* Update entry table */
461 if (State)
462 KdpComponentTable[i].Level |= Level;
463 else
464 KdpComponentTable[i].Level &= ~Level;
465
466 return STATUS_SUCCESS;
467 }
468
469 /*
470 * @unimplemented
471 */
472 NTSTATUS
473 NTAPI
474 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
475 IN PVOID InputBuffer,
476 IN ULONG InputBufferLength,
477 OUT PVOID OutputBuffer,
478 IN ULONG OutputBufferLength,
479 IN OUT PULONG ReturnLength,
480 IN KPROCESSOR_MODE PreviousMode)
481 {
482 /* HACK */
483 return KdpServiceDispatcher(Command,
484 InputBuffer,
485 InputBufferLength,
486 PreviousMode);
487 }
488
489 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
490
491 /* EOF */