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