xref: /reactos/ntoskrnl/kd/kdmain.c (revision 41203c9b)
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 */
492