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 #define KD_PRINT_MAX_BYTES 512 17 18 /* FUNCTIONS *****************************************************************/ 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 USHORT 216 NTAPI 217 KdpPrompt( 218 _In_reads_bytes_(PromptLength) PCHAR PromptString, 219 _In_ USHORT PromptLength, 220 _Out_writes_bytes_(MaximumResponseLength) PCHAR ResponseString, 221 _In_ USHORT MaximumResponseLength, 222 _In_ KPROCESSOR_MODE PreviousMode, 223 _In_ PKTRAP_FRAME TrapFrame, 224 _In_ PKEXCEPTION_FRAME ExceptionFrame) 225 { 226 STRING PromptBuffer, ResponseBuffer; 227 BOOLEAN Enable, Resend; 228 PCHAR SafeResponseString; 229 CHAR CapturedPrompt[KD_PRINT_MAX_BYTES]; 230 CHAR SafeResponseBuffer[KD_PRINT_MAX_BYTES]; 231 232 /* Normalize the lengths */ 233 PromptLength = min(PromptLength, 234 sizeof(CapturedPrompt)); 235 MaximumResponseLength = min(MaximumResponseLength, 236 sizeof(SafeResponseBuffer)); 237 238 /* Check if we need to verify the string */ 239 if (PreviousMode != KernelMode) 240 { 241 /* Handle user-mode buffers safely */ 242 _SEH2_TRY 243 { 244 /* Probe and capture the prompt */ 245 ProbeForRead(PromptString, PromptLength, 1); 246 KdpMoveMemory(CapturedPrompt, PromptString, PromptLength); 247 PromptString = CapturedPrompt; 248 249 /* Probe and make room for the response */ 250 ProbeForWrite(ResponseString, MaximumResponseLength, 1); 251 SafeResponseString = SafeResponseBuffer; 252 } 253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 254 { 255 /* Bad string pointer, bail out */ 256 _SEH2_YIELD(return 0); 257 } 258 _SEH2_END; 259 } 260 else 261 { 262 SafeResponseString = ResponseString; 263 } 264 265 /* Setup the prompt and response buffers */ 266 PromptBuffer.Buffer = PromptString; 267 PromptBuffer.Length = PromptBuffer.MaximumLength = PromptLength; 268 ResponseBuffer.Buffer = SafeResponseString; 269 ResponseBuffer.Length = 0; 270 ResponseBuffer.MaximumLength = MaximumResponseLength; 271 272 /* Log the print */ 273 //KdLogDbgPrint(&PromptBuffer); 274 275 /* Enter the debugger */ 276 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); 277 278 /* Enter prompt loop */ 279 do 280 { 281 /* Send the prompt and receive the response */ 282 Resend = KdpPromptString(&PromptBuffer, &ResponseBuffer); 283 284 /* Loop while we need to resend */ 285 } while (Resend); 286 287 /* Exit the debugger */ 288 KdExitDebugger(Enable); 289 290 /* Copy back the response if required */ 291 if (PreviousMode != KernelMode) 292 { 293 _SEH2_TRY 294 { 295 /* Safely copy back the response to user mode */ 296 KdpMoveMemory(ResponseString, 297 ResponseBuffer.Buffer, 298 ResponseBuffer.Length); 299 } 300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 301 { 302 /* String became invalid after we exited, fail */ 303 _SEH2_YIELD(return 0); 304 } 305 _SEH2_END; 306 } 307 308 /* Return the number of characters received */ 309 return ResponseBuffer.Length; 310 } 311 312 static 313 NTSTATUS 314 NTAPI 315 KdpPrintFromUser( 316 _In_ ULONG ComponentId, 317 _In_ ULONG Level, 318 _In_reads_bytes_(Length) PCHAR String, 319 _In_ USHORT Length, 320 _In_ KPROCESSOR_MODE PreviousMode, 321 _In_ PKTRAP_FRAME TrapFrame, 322 _In_ PKEXCEPTION_FRAME ExceptionFrame, 323 _Out_ PBOOLEAN Handled) 324 { 325 CHAR CapturedString[KD_PRINT_MAX_BYTES]; 326 327 ASSERT(PreviousMode == UserMode); 328 ASSERT(Length <= sizeof(CapturedString)); 329 330 /* Capture user-mode buffers */ 331 _SEH2_TRY 332 { 333 /* Probe and capture the string */ 334 ProbeForRead(String, Length, 1); 335 KdpMoveMemory(CapturedString, String, Length); 336 String = CapturedString; 337 } 338 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 339 { 340 /* Bad string pointer, bail out */ 341 _SEH2_YIELD(return STATUS_ACCESS_VIOLATION); 342 } 343 _SEH2_END; 344 345 /* Now go through the kernel-mode code path */ 346 return KdpPrint(ComponentId, 347 Level, 348 String, 349 Length, 350 KernelMode, 351 TrapFrame, 352 ExceptionFrame, 353 Handled); 354 } 355 356 NTSTATUS 357 NTAPI 358 KdpPrint( 359 _In_ ULONG ComponentId, 360 _In_ ULONG Level, 361 _In_reads_bytes_(Length) PCHAR String, 362 _In_ USHORT Length, 363 _In_ KPROCESSOR_MODE PreviousMode, 364 _In_ PKTRAP_FRAME TrapFrame, 365 _In_ PKEXCEPTION_FRAME ExceptionFrame, 366 _Out_ PBOOLEAN Handled) 367 { 368 NTSTATUS Status; 369 BOOLEAN Enable; 370 STRING OutputString; 371 372 if (NtQueryDebugFilterState(ComponentId, Level) == (NTSTATUS)FALSE) 373 { 374 /* Mask validation failed */ 375 *Handled = TRUE; 376 return STATUS_SUCCESS; 377 } 378 379 /* Assume failure */ 380 *Handled = FALSE; 381 382 /* Normalize the length */ 383 Length = min(Length, KD_PRINT_MAX_BYTES); 384 385 /* Check if we need to verify the string */ 386 if (PreviousMode != KernelMode) 387 { 388 /* This case requires a 512 byte stack buffer. 389 * We don't want to use that much stack in the kernel case, but we 390 * can't use _alloca due to PSEH. So the buffer exists in this 391 * helper function instead. 392 */ 393 return KdpPrintFromUser(ComponentId, 394 Level, 395 String, 396 Length, 397 PreviousMode, 398 TrapFrame, 399 ExceptionFrame, 400 Handled); 401 } 402 403 /* Setup the output string */ 404 OutputString.Buffer = String; 405 OutputString.Length = OutputString.MaximumLength = Length; 406 407 /* Log the print */ 408 //KdLogDbgPrint(&OutputString); 409 410 /* Check for a debugger */ 411 if (KdDebuggerNotPresent) 412 { 413 /* Fail */ 414 *Handled = TRUE; 415 return STATUS_DEVICE_NOT_CONNECTED; 416 } 417 418 /* Enter the debugger */ 419 Enable = KdEnterDebugger(TrapFrame, ExceptionFrame); 420 421 /* Print the string */ 422 if (KdpPrintString(&OutputString)) 423 { 424 /* User pressed CTRL-C, breakpoint on return */ 425 Status = STATUS_BREAKPOINT; 426 } 427 else 428 { 429 /* String was printed */ 430 Status = STATUS_SUCCESS; 431 } 432 433 /* Exit the debugger and return */ 434 KdExitDebugger(Enable); 435 *Handled = TRUE; 436 return Status; 437 } 438 439 VOID 440 __cdecl 441 KdpDprintf( 442 _In_ PCHAR Format, 443 ...) 444 { 445 STRING String; 446 USHORT Length; 447 va_list ap; 448 CHAR Buffer[100]; 449 450 /* Format the string */ 451 va_start(ap, Format); 452 Length = (USHORT)_vsnprintf(Buffer, 453 sizeof(Buffer), 454 Format, 455 ap); 456 va_end(ap); 457 458 /* Set it up */ 459 String.Buffer = Buffer; 460 String.Length = String.MaximumLength = Length; 461 462 /* Send it to the debugger directly */ 463 KdpPrintString(&String); 464 } 465