"<@Christoph_vW> please commit something" -- aye sir
[reactos.git] / reactos / ntoskrnl / kd64 / kdprint.c
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 = Output->Length;
25
26 /* Copy the string */
27 RtlMoveMemory(KdpMessageBuffer, Output->Buffer, Length);
28
29 /* Make sure we don't exceed the KD Packet size */
30 if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
31 {
32 /* Normalize length */
33 Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
34 }
35
36 /* Build the packet header */
37 DebugIo.ApiNumber = DbgKdPrintStringApi;
38 DebugIo.ProcessorLevel = KeProcessorLevel;
39 DebugIo.Processor = KeGetCurrentPrcb()->Number;
40 DebugIo.u.PrintString.LengthOfString = Length;
41 Header.Length = sizeof(DBGKD_DEBUG_IO);
42 Header.Buffer = (PCHAR)&DebugIo;
43
44 /* Build the data */
45 Data.Length = Length;
46 Data.Buffer = KdpMessageBuffer;
47
48 /* Send the packet */
49 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
50
51 /* Check if the user pressed CTRL+C */
52 return KdpPollBreakInWithPortLock();
53 }
54
55 BOOLEAN
56 NTAPI
57 KdpPromptString(IN PSTRING PromptString,
58 IN PSTRING ResponseString)
59 {
60 STRING Data, Header;
61 DBGKD_DEBUG_IO DebugIo;
62 ULONG Length = PromptString->Length;
63 KDSTATUS Status;
64
65 /* Copy the string to the message buffer */
66 RtlCopyMemory(KdpMessageBuffer,
67 PromptString->Buffer,
68 PromptString->Length);
69
70 /* Make sure we don't exceed the KD Packet size */
71 if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
72 {
73 /* Normalize length */
74 Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
75 }
76
77 /* Build the packet header */
78 DebugIo.ApiNumber = DbgKdGetStringApi;
79 DebugIo.ProcessorLevel = KeProcessorLevel;
80 DebugIo.Processor = KeGetCurrentPrcb()->Number;
81 DebugIo.u.GetString.LengthOfPromptString = Length;
82 DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength;
83 Header.Length = sizeof(DBGKD_DEBUG_IO);
84 Header.Buffer = (PCHAR)&DebugIo;
85
86 /* Build the data */
87 Data.Length = PromptString->Length;
88 Data.Buffer = KdpMessageBuffer;
89
90 /* Send the packet */
91 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);
92
93 /* Set the maximum lengths for the receive */
94 Header.MaximumLength = sizeof(DBGKD_DEBUG_IO);
95 Data.MaximumLength = sizeof(KdpMessageBuffer);
96
97 /* Enter receive loop */
98 do
99 {
100 /* Get our reply */
101 Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
102 &Header,
103 &Data,
104 &Length,
105 &KdpContext);
106
107 /* Return TRUE if we need to resend */
108 if (Status == KdPacketNeedsResend) return TRUE;
109
110 /* Loop until we succeed */
111 } while (Status != KdPacketReceived);
112
113 /* Don't copy back a larger response than there is room for */
114 Length = min(Length, ResponseString->MaximumLength);
115
116 /* Copy back the string and return the length */
117 RtlCopyMemory(ResponseString->Buffer, KdpMessageBuffer, Length);
118 ResponseString->Length = Length;
119
120 /* Success; we don't need to resend */
121 return FALSE;
122 }
123
124 VOID
125 NTAPI
126 KdpCommandString(IN ULONG Length,
127 IN LPSTR String,
128 IN KPROCESSOR_MODE PreviousMode,
129 IN PCONTEXT ContextRecord,
130 IN PKTRAP_FRAME TrapFrame,
131 IN PKEXCEPTION_FRAME ExceptionFrame)
132 {
133 /* FIXME */
134 KdpDprintf("KdpCommandString called\n");
135 while (TRUE);
136 }
137
138 VOID
139 NTAPI
140 KdpSymbol(IN PSTRING DllPath,
141 IN PKD_SYMBOLS_INFO DllBase,
142 IN BOOLEAN Unload,
143 IN KPROCESSOR_MODE PreviousMode,
144 IN PCONTEXT ContextRecord,
145 IN PKTRAP_FRAME TrapFrame,
146 IN PKEXCEPTION_FRAME ExceptionFrame)
147 {
148 BOOLEAN Entered;
149 PKPRCB Prcb = KeGetCurrentPrcb();
150 ULONG Status;
151
152 /* Check if we need to do anything */
153 if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return;
154
155 /* Enter the debugger */
156 Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);
157
158 /* Save the CPU Control State and save the context */
159 KiSaveProcessorControlState(&Prcb->ProcessorState);
160 RtlCopyMemory(&Prcb->ProcessorState.ContextFrame,
161 ContextRecord,
162 sizeof(CONTEXT));
163
164 /* Report the new state */
165 Status = KdpReportLoadSymbolsStateChange(DllPath,
166 DllBase,
167 Unload,
168 &Prcb->ProcessorState.
169 ContextFrame);
170
171 /* Now restore the processor state, manually again. */
172 RtlCopyMemory(ContextRecord,
173 &Prcb->ProcessorState.ContextFrame,
174 sizeof(CONTEXT));
175 KiRestoreProcessorControlState(&Prcb->ProcessorState);
176
177 /* Exit the debugger and clear the CTRL-C state */
178 KdExitDebugger(Entered);
179 }
180
181 USHORT
182 NTAPI
183 KdpPrompt(IN LPSTR PromptString,
184 IN USHORT PromptLength,
185 OUT LPSTR ResponseString,
186 IN USHORT MaximumResponseLength,
187 IN KPROCESSOR_MODE PreviousMode,
188 IN PKTRAP_FRAME TrapFrame,
189 IN PKEXCEPTION_FRAME ExceptionFrame)
190 {
191 STRING PromptBuffer, ResponseBuffer;
192 BOOLEAN Entered, Resend;
193
194 /* Normalize the lengths */
195 PromptLength = min(PromptLength, 512);
196 MaximumResponseLength = min(MaximumResponseLength, 512);
197
198 /* Check if we need to verify the string */
199 if (PreviousMode != KernelMode)
200 {
201 /* FIXME: Handle user-mode */
202 }
203
204 /* Setup the prompt and response buffers */
205 PromptBuffer.Buffer = PromptString;
206 PromptBuffer.Length = PromptLength;
207 ResponseBuffer.Buffer = ResponseString;
208 ResponseBuffer.Length = 0;
209 ResponseBuffer.MaximumLength = MaximumResponseLength;
210
211 /* Log the print */
212 //KdLogDbgPrint(&PromptBuffer);
213
214 /* Enter the debugger */
215 Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);
216
217 /* Enter prompt loop */
218 do
219 {
220 /* Send the prompt and receive the response */
221 Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer);
222
223 /* Loop while we need to resend */
224 } while (Resend);
225
226 /* Exit the debugger */
227 KdExitDebugger(Entered);
228
229 /* Return the number of characters received */
230 return ResponseBuffer.Length;
231 }
232
233 NTSTATUS
234 NTAPI
235 KdpPrint(IN ULONG ComponentId,
236 IN ULONG ComponentMask,
237 IN LPSTR String,
238 IN USHORT Length,
239 IN KPROCESSOR_MODE PreviousMode,
240 IN PKTRAP_FRAME TrapFrame,
241 IN PKEXCEPTION_FRAME ExceptionFrame,
242 OUT PBOOLEAN Status)
243 {
244 NTSTATUS ReturnStatus;
245 BOOLEAN Entered;
246 ANSI_STRING AnsiString;
247
248 /* Assume failure */
249 *Status = FALSE;
250
251 /* Validate the mask */
252 if (ComponentMask < 0x20) ComponentMask = 1 << ComponentMask;
253 if (!(Kd_WIN2000_Mask & ComponentMask) ||
254 ((ComponentId < KdComponentTableSize) &&
255 !(*KdComponentTable[ComponentId] & ComponentMask)))
256 {
257 /* Mask validation failed */
258 *Status = TRUE;
259 return FALSE;
260 }
261
262 /* Normalize the length */
263 Length = min(Length, 512);
264
265 /* Check if we need to verify the buffer */
266 if (PreviousMode != KernelMode)
267 {
268 /* FIXME: Support user-mode */
269 }
270
271 /* Setup the ANSI string */
272 AnsiString.Buffer = String;
273 AnsiString.Length = Length;
274
275 /* Log the print */
276 //KdLogDbgPrint(&AnsiString);
277
278 /* Check for a debugger */
279 if (KdDebuggerNotPresent)
280 {
281 /* Fail */
282 *Status = TRUE;
283 return STATUS_DEVICE_NOT_CONNECTED;
284 }
285
286 /* Enter the debugger */
287 Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);
288
289 /* Print the string */
290 if (KdpPrintString(&AnsiString))
291 {
292 /* User pressed CTRL-C, breakpoint on return */
293 ReturnStatus = STATUS_BREAKPOINT;
294 }
295 else
296 {
297 /* String was printed */
298 ReturnStatus = STATUS_SUCCESS;
299 }
300
301 /* Exit the debugger and return */
302 KdExitDebugger(Entered);
303 *Status = TRUE;
304 return ReturnStatus;
305 }
306
307 VOID
308 __cdecl
309 KdpDprintf(IN PCHAR Format,
310 ...)
311 {
312 STRING String;
313 CHAR Buffer[100];
314 USHORT Length;
315 va_list ap;
316
317 /* Format the string */
318 va_start(ap, Format);
319 Length = (USHORT)_vsnprintf(Buffer,
320 sizeof(Buffer),
321 Format,
322 ap);
323
324 /* Set it up */
325 String.Buffer = Buffer;
326 String.Length = Length + 1;
327
328 /* Send it to the debugger directly */
329 KdpPrintString(&String);
330 va_end(ap);
331 }