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