xref: /reactos/ntoskrnl/kd64/kdprint.c (revision bd712186)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/kd64/kdprint.c
5  * PURPOSE:         KD64 Trap Handler Routines
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  *                  Stefan Ginsberg (stefan.ginsberg@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 #ifdef _WINKD_
19 
20 BOOLEAN
21 NTAPI
22 KdpPrintString(
23     _In_ PSTRING Output)
24 {
25     STRING Data, Header;
26     DBGKD_DEBUG_IO DebugIo;
27     USHORT Length;
28 
29     /* Copy the string */
30     KdpMoveMemory(KdpMessageBuffer,
31                   Output->Buffer,
32                   Output->Length);
33 
34     /* Make sure we don't exceed the KD Packet size */
35     Length = Output->Length;
36     if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
37     {
38         /* Normalize length */
39         Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
40     }
41 
42     /* Build the packet header */
43     DebugIo.ApiNumber = DbgKdPrintStringApi;
44     DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
45     DebugIo.Processor = KeGetCurrentPrcb()->Number;
46     DebugIo.u.PrintString.LengthOfString = Length;
47     Header.Length = sizeof(DBGKD_DEBUG_IO);
48     Header.Buffer = (PCHAR)&DebugIo;
49 
50     /* Build the data */
51     Data.Length = Length;
52     Data.Buffer = KdpMessageBuffer;
53 
54     /* Send the packet */
55     KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
56 
57     /* Check if the user pressed CTRL+C */
58     return KdpPollBreakInWithPortLock();
59 }
60 
61 BOOLEAN
62 NTAPI
63 KdpPromptString(
64     _In_ PSTRING PromptString,
65     _In_ PSTRING ResponseString)
66 {
67     STRING Data, Header;
68     DBGKD_DEBUG_IO DebugIo;
69     ULONG Length;
70     KDSTATUS Status;
71 
72     /* Copy the string to the message buffer */
73     KdpMoveMemory(KdpMessageBuffer,
74                   PromptString->Buffer,
75                   PromptString->Length);
76 
77     /* Make sure we don't exceed the KD Packet size */
78     Length = PromptString->Length;
79     if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
80     {
81         /* Normalize length */
82         Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
83     }
84 
85     /* Build the packet header */
86     DebugIo.ApiNumber = DbgKdGetStringApi;
87     DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
88     DebugIo.Processor = KeGetCurrentPrcb()->Number;
89     DebugIo.u.GetString.LengthOfPromptString = Length;
90     DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength;
91     Header.Length = sizeof(DBGKD_DEBUG_IO);
92     Header.Buffer = (PCHAR)&DebugIo;
93 
94     /* Build the data */
95     Data.Length = Length;
96     Data.Buffer = KdpMessageBuffer;
97 
98     /* Send the packet */
99     KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
100 
101     /* Set the maximum lengths for the receive */
102     Header.MaximumLength = sizeof(DBGKD_DEBUG_IO);
103     Data.MaximumLength = sizeof(KdpMessageBuffer);
104 
105     /* Enter receive loop */
106     do
107     {
108         /* Get our reply */
109         Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
110                                  &Header,
111                                  &Data,
112                                  &Length,
113                                  &KdpContext);
114 
115         /* Return TRUE if we need to resend */
116         if (Status == KdPacketNeedsResend) return TRUE;
117 
118     /* Loop until we succeed */
119     } while (Status != KdPacketReceived);
120 
121     /* Don't copy back a larger response than there is room for */
122     Length = min(Length,
123                  ResponseString->MaximumLength);
124 
125     /* Copy back the string and return the length */
126     KdpMoveMemory(ResponseString->Buffer,
127                   KdpMessageBuffer,
128                   Length);
129     ResponseString->Length = (USHORT)Length;
130 
131     /* Success; we don't need to resend */
132     return FALSE;
133 }
134 
135 VOID
136 NTAPI
137 KdpCommandString(IN PSTRING NameString,
138                  IN PSTRING CommandString,
139                  IN KPROCESSOR_MODE PreviousMode,
140                  IN PCONTEXT ContextRecord,
141                  IN PKTRAP_FRAME TrapFrame,
142                  IN PKEXCEPTION_FRAME ExceptionFrame)
143 {
144     BOOLEAN Enable;
145     PKPRCB Prcb = KeGetCurrentPrcb();
146 
147     /* Check if we need to do anything */
148     if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return;
149 
150     /* Enter the debugger */
151     Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
152 
153     /* Save the CPU Control State and save the context */
154     KiSaveProcessorControlState(&Prcb->ProcessorState);
155     KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
156                   ContextRecord,
157                   sizeof(CONTEXT));
158 
159     /* Send the command string to the debugger */
160     KdpReportCommandStringStateChange(NameString,
161                                       CommandString,
162                                       &Prcb->ProcessorState.ContextFrame);
163 
164     /* Restore the processor state */
165     KdpMoveMemory(ContextRecord,
166                   &Prcb->ProcessorState.ContextFrame,
167                   sizeof(CONTEXT));
168     KiRestoreProcessorControlState(&Prcb->ProcessorState);
169 
170     /* Exit the debugger and return */
171     KdExitDebugger(Enable);
172 }
173 
174 VOID
175 NTAPI
176 KdpSymbol(IN PSTRING DllPath,
177           IN PKD_SYMBOLS_INFO SymbolInfo,
178           IN BOOLEAN Unload,
179           IN KPROCESSOR_MODE PreviousMode,
180           IN PCONTEXT ContextRecord,
181           IN PKTRAP_FRAME TrapFrame,
182           IN PKEXCEPTION_FRAME ExceptionFrame)
183 {
184     BOOLEAN Enable;
185     PKPRCB Prcb = KeGetCurrentPrcb();
186 
187     /* Check if we need to do anything */
188     if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return;
189 
190     /* Enter the debugger */
191     Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
192 
193     /* Save the CPU Control State and save the context */
194     KiSaveProcessorControlState(&Prcb->ProcessorState);
195     KdpMoveMemory(&Prcb->ProcessorState.ContextFrame,
196                   ContextRecord,
197                   sizeof(CONTEXT));
198 
199     /* Report the new state */
200     KdpReportLoadSymbolsStateChange(DllPath,
201                                     SymbolInfo,
202                                     Unload,
203                                     &Prcb->ProcessorState.ContextFrame);
204 
205     /* Restore the processor state */
206     KdpMoveMemory(ContextRecord,
207                   &Prcb->ProcessorState.ContextFrame,
208                   sizeof(CONTEXT));
209     KiRestoreProcessorControlState(&Prcb->ProcessorState);
210 
211     /* Exit the debugger and return */
212     KdExitDebugger(Enable);
213 }
214 
215 #else
216 
217 extern
218 BOOLEAN
219 NTAPI
220 KdpPrintString(
221     _In_ PSTRING Output);
222 
223 extern
224 BOOLEAN
225 NTAPI
226 KdpPromptString(
227     _In_ PSTRING PromptString,
228     _In_ PSTRING ResponseString);
229 
230 #endif // _WINKD_
231 
232 USHORT
233 NTAPI
234 KdpPrompt(
235     _In_reads_bytes_(PromptLength) PCHAR PromptString,
236     _In_ USHORT PromptLength,
237     _Out_writes_bytes_(MaximumResponseLength) PCHAR ResponseString,
238     _In_ USHORT MaximumResponseLength,
239     _In_ KPROCESSOR_MODE PreviousMode,
240     _In_ PKTRAP_FRAME TrapFrame,
241     _In_ PKEXCEPTION_FRAME ExceptionFrame)
242 {
243     STRING PromptBuffer, ResponseBuffer;
244     BOOLEAN Enable, Resend;
245     PCHAR SafeResponseString;
246     CHAR CapturedPrompt[512];
247     CHAR SafeResponseBuffer[512];
248 
249     /* Normalize the lengths */
250     PromptLength = min(PromptLength,
251                        sizeof(CapturedPrompt));
252     MaximumResponseLength = min(MaximumResponseLength,
253                                 sizeof(SafeResponseBuffer));
254 
255     /* Check if we need to verify the string */
256     if (PreviousMode != KernelMode)
257     {
258         /* Handle user-mode buffers safely */
259         _SEH2_TRY
260         {
261             /* Probe and capture the prompt */
262             ProbeForRead(PromptString, PromptLength, 1);
263             KdpMoveMemory(CapturedPrompt, PromptString, PromptLength);
264             PromptString = CapturedPrompt;
265 
266             /* Probe and make room for the response */
267             ProbeForWrite(ResponseString, MaximumResponseLength, 1);
268             SafeResponseString = SafeResponseBuffer;
269         }
270         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
271         {
272             /* Bad string pointer, bail out */
273             _SEH2_YIELD(return 0);
274         }
275         _SEH2_END;
276     }
277     else
278     {
279         SafeResponseString = ResponseString;
280     }
281 
282     /* Setup the prompt and response buffers */
283     PromptBuffer.Buffer = PromptString;
284     PromptBuffer.Length = PromptBuffer.MaximumLength = PromptLength;
285     ResponseBuffer.Buffer = SafeResponseString;
286     ResponseBuffer.Length = 0;
287     ResponseBuffer.MaximumLength = MaximumResponseLength;
288 
289     /* Log the print */
290     //KdLogDbgPrint(&PromptBuffer);
291 
292     /* Enter the debugger */
293     Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
294 
295     /* Enter prompt loop */
296     do
297     {
298         /* Send the prompt and receive the response */
299         Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer);
300 
301     /* Loop while we need to resend */
302     } while (Resend);
303 
304     /* Exit the debugger */
305     KdExitDebugger(Enable);
306 
307     /* Copy back the response if required */
308     if (PreviousMode != KernelMode)
309     {
310         _SEH2_TRY
311         {
312             /* Safely copy back the response to user mode */
313             KdpMoveMemory(ResponseString,
314                           ResponseBuffer.Buffer,
315                           ResponseBuffer.Length);
316         }
317         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
318         {
319             /* String became invalid after we exited, fail */
320             _SEH2_YIELD(return 0);
321         }
322         _SEH2_END;
323     }
324 
325     /* Return the number of characters received */
326     return ResponseBuffer.Length;
327 }
328 
329 NTSTATUS
330 NTAPI
331 KdpPrint(
332     _In_ ULONG ComponentId,
333     _In_ ULONG Level,
334     _In_reads_bytes_(Length) PCHAR String,
335     _In_ USHORT Length,
336     _In_ KPROCESSOR_MODE PreviousMode,
337     _In_ PKTRAP_FRAME TrapFrame,
338     _In_ PKEXCEPTION_FRAME ExceptionFrame,
339     _Out_ PBOOLEAN Handled)
340 {
341     NTSTATUS Status;
342     BOOLEAN Enable;
343     STRING OutputString;
344     CHAR CapturedString[512];
345 
346     if (NtQueryDebugFilterState(ComponentId, Level) == (NTSTATUS)FALSE)
347     {
348         /* Mask validation failed */
349         *Handled = TRUE;
350         return STATUS_SUCCESS;
351     }
352 
353     /* Assume failure */
354     *Handled = FALSE;
355 
356     /* Normalize the length */
357     Length = min(Length, sizeof(CapturedString));
358 
359     /* Check if we need to verify the string */
360     if (PreviousMode != KernelMode)
361     {
362         /* Capture user-mode buffers */
363         _SEH2_TRY
364         {
365             /* Probe and capture the string */
366             ProbeForRead(String, Length, 1);
367             KdpMoveMemory(CapturedString, String, Length);
368             String = CapturedString;
369         }
370         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
371         {
372             /* Bad string pointer, bail out */
373             _SEH2_YIELD(return STATUS_ACCESS_VIOLATION);
374         }
375         _SEH2_END;
376     }
377 
378     /* Setup the output string */
379     OutputString.Buffer = String;
380     OutputString.Length = OutputString.MaximumLength = Length;
381 
382     /* Log the print */
383     //KdLogDbgPrint(&OutputString);
384 
385     /* Check for a debugger */
386     if (KdDebuggerNotPresent)
387     {
388         /* Fail */
389         *Handled = TRUE;
390         return STATUS_DEVICE_NOT_CONNECTED;
391     }
392 
393     /* Enter the debugger */
394     Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
395 
396     /* Print the string */
397     if (KdpPrintString(&OutputString))
398     {
399         /* User pressed CTRL-C, breakpoint on return */
400         Status = STATUS_BREAKPOINT;
401     }
402     else
403     {
404         /* String was printed */
405         Status = STATUS_SUCCESS;
406     }
407 
408     /* Exit the debugger and return */
409     KdExitDebugger(Enable);
410     *Handled = TRUE;
411     return Status;
412 }
413 
414 VOID
415 __cdecl
416 KdpDprintf(
417     _In_ PCHAR Format,
418     ...)
419 {
420     STRING String;
421     USHORT Length;
422     va_list ap;
423     CHAR Buffer[100];
424 
425     /* Format the string */
426     va_start(ap, Format);
427     Length = (USHORT)_vsnprintf(Buffer,
428                                 sizeof(Buffer),
429                                 Format,
430                                 ap);
431     va_end(ap);
432 
433     /* Set it up */
434     String.Buffer = Buffer;
435     String.Length = String.MaximumLength = Length;
436 
437     /* Send it to the debugger directly */
438     KdpPrintString(&String);
439 }
440