xref: /reactos/ntoskrnl/kd/kdmain.c (revision d8c6ef5e)
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 
281     /* We'll manually dump the stack for the user... */
282     KeRosDumpStackFrames(NULL, 0);
283 #endif /* not KDBG */
284 
285     /* Debugger didn't handle it, please handle! */
286     if (Return == kdHandleException) return FALSE;
287 
288     /* Debugger handled it */
289     return TRUE;
290 }
291 
292 BOOLEAN
293 NTAPI
294 KdIsThisAKdTrap(IN PEXCEPTION_RECORD ExceptionRecord,
295                 IN PCONTEXT Context,
296                 IN KPROCESSOR_MODE PreviousMode)
297 {
298     /* KDBG has its own mechanism for ignoring user mode exceptions */
299     return FALSE;
300 }
301 
302 /* PUBLIC FUNCTIONS *********************************************************/
303 
304 VOID
305 NTAPI
306 KdUpdateDataBlock(VOID)
307 {
308 }
309 
310 BOOLEAN
311 NTAPI
312 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
313                 IN PKEXCEPTION_FRAME ExceptionFrame)
314 {
315     return FALSE;
316 }
317 
318 VOID
319 NTAPI
320 KdExitDebugger(IN BOOLEAN Enable)
321 {
322 }
323 
324 /*
325  * @implemented
326  */
327 BOOLEAN
328 NTAPI
329 KdRefreshDebuggerNotPresent(VOID)
330 {
331     UNIMPLEMENTED;
332 
333     /* Just return whatever was set previously -- FIXME! */
334     return KdDebuggerNotPresent;
335 }
336 
337 /*
338  * @implemented
339  */
340 NTSTATUS
341 NTAPI
342 KdDisableDebugger(VOID)
343 {
344     KIRQL OldIrql;
345 
346     /* Raise IRQL */
347     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
348 
349     /* TODO: Disable any breakpoints */
350 
351     /* Disable the Debugger */
352     KdDebuggerEnabled = FALSE;
353     SharedUserData->KdDebuggerEnabled = FALSE;
354 
355     /* Lower the IRQL */
356     KeLowerIrql(OldIrql);
357 
358     /* Return success */
359     return STATUS_SUCCESS;
360 }
361 
362 NTSTATUS
363 NTAPI
364 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
365 {
366     return STATUS_ACCESS_DENIED;
367 }
368 
369 /*
370  * @implemented
371  */
372 NTSTATUS
373 NTAPI
374 KdEnableDebugger(VOID)
375 {
376     KIRQL OldIrql;
377 
378     /* Raise IRQL */
379     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
380 
381     /* TODO: Re-enable any breakpoints */
382 
383     /* Enable the Debugger */
384     KdDebuggerEnabled = TRUE;
385     SharedUserData->KdDebuggerEnabled = TRUE;
386 
387     /* Lower the IRQL */
388     KeLowerIrql(OldIrql);
389 
390     /* Return success */
391     return STATUS_SUCCESS;
392 }
393 
394 /*
395  * @implemented
396  */
397 BOOLEAN
398 NTAPI
399 KdPollBreakIn(VOID)
400 {
401     return FALSE;
402 }
403 
404 /*
405  * @unimplemented
406  */
407 NTSTATUS
408 NTAPI
409 KdPowerTransition(ULONG PowerState)
410 {
411     UNIMPLEMENTED;
412     return STATUS_NOT_IMPLEMENTED;
413 }
414 
415 /*
416  * @unimplemented
417  */
418 NTSTATUS
419 NTAPI
420 KdChangeOption(IN KD_OPTION Option,
421                IN ULONG InBufferLength OPTIONAL,
422                IN PVOID InBuffer,
423                IN ULONG OutBufferLength OPTIONAL,
424                OUT PVOID OutBuffer,
425                OUT PULONG OutBufferRequiredLength OPTIONAL)
426 {
427     UNIMPLEMENTED;
428     return STATUS_NOT_IMPLEMENTED;
429 }
430 
431 /*
432  * @unimplemented
433  */
434 NTSTATUS
435 NTAPI
436 KdSystemDebugControl(IN SYSDBG_COMMAND Command,
437                      IN PVOID InputBuffer,
438                      IN ULONG InputBufferLength,
439                      OUT PVOID OutputBuffer,
440                      IN ULONG OutputBufferLength,
441                      IN OUT PULONG ReturnLength,
442                      IN KPROCESSOR_MODE PreviousMode)
443 {
444     /* HACK */
445     return KdpServiceDispatcher(Command,
446                                 InputBuffer,
447                                 InputBufferLength,
448                                 PreviousMode);
449 }
450 
451 PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
452 
453  /* EOF */
454