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