1 /* 2 * PROJECT: ReactOS KDBG Kernel Debugger 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: IO interface for KDBG. Provides local KDBG versions 5 * of KdpPrintString, KdpPromptString and KdpDprintf. 6 * COPYRIGHT: Copyright 2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #include "kdb.h" 13 14 /* FUNCTIONS *****************************************************************/ 15 16 static VOID 17 KdbPrintStringWorker( 18 _In_ const CSTRING* Output, 19 _In_ ULONG ApiNumber, 20 _Inout_ PDBGKD_DEBUG_IO DebugIo, 21 _Inout_ PSTRING Header, 22 _Inout_ PSTRING Data) 23 { 24 USHORT Length; 25 C_ASSERT(PACKET_MAX_SIZE >= sizeof(*DebugIo)); 26 27 ASSERT((ApiNumber == DbgKdPrintStringApi) || 28 (ApiNumber == DbgKdGetStringApi)); 29 30 /* Make sure we don't exceed the KD Packet size */ 31 Length = min(Output->Length, PACKET_MAX_SIZE - sizeof(*DebugIo)); 32 33 /* Build the packet header */ 34 DebugIo->ApiNumber = ApiNumber; 35 DebugIo->ProcessorLevel = 0; // (USHORT)KeProcessorLevel; 36 DebugIo->Processor = KeGetCurrentPrcb()->Number; 37 38 if (ApiNumber == DbgKdPrintStringApi) 39 DebugIo->u.PrintString.LengthOfString = Length; 40 else // if (ApiNumber == DbgKdGetStringApi) 41 DebugIo->u.GetString.LengthOfPromptString = Length; 42 43 Header->Length = sizeof(*DebugIo); 44 Header->Buffer = (PCHAR)DebugIo; 45 46 /* Build the data */ 47 Data->Length = Length; 48 Data->Buffer = (PCHAR)Output->Buffer; 49 50 /* Send the packet */ 51 KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, Header, Data, &KdpContext); 52 } 53 54 VOID 55 KdbPrintString( 56 _In_ const CSTRING* Output) 57 { 58 DBGKD_DEBUG_IO DebugIo; 59 STRING Header, Data; 60 61 KdbPrintStringWorker(Output, DbgKdPrintStringApi, 62 &DebugIo, &Header, &Data); 63 } 64 65 static BOOLEAN 66 KdbPromptStringWorker( 67 _In_ const CSTRING* PromptString, 68 _Inout_ PSTRING ResponseString) 69 { 70 DBGKD_DEBUG_IO DebugIo; 71 STRING Header, Data; 72 ULONG Length; 73 KDSTATUS Status; 74 75 /* Print the prompt */ 76 // DebugIo.u.GetString.LengthOfPromptString = Length; 77 DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength; 78 KdbPrintStringWorker(PromptString, DbgKdGetStringApi, 79 &DebugIo, &Header, &Data); 80 81 /* Set the maximum lengths for the receive */ 82 Header.MaximumLength = sizeof(DebugIo); 83 Data.MaximumLength = ResponseString->MaximumLength; 84 /* Build the data */ 85 Data.Buffer = ResponseString->Buffer; 86 87 /* Enter receive loop */ 88 do 89 { 90 /* Get our reply */ 91 Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO, 92 &Header, 93 &Data, 94 &Length, 95 &KdpContext); 96 97 /* Return TRUE if we need to resend */ 98 if (Status == KdPacketNeedsResend) 99 return TRUE; 100 101 /* Loop until we succeed */ 102 } while (Status != KdPacketReceived); 103 104 /* Don't copy back a larger response than there is room for */ 105 Length = min(Length, ResponseString->MaximumLength); 106 107 /* We've got the string back; return the length */ 108 ResponseString->Length = (USHORT)Length; 109 110 /* Success; we don't need to resend */ 111 return FALSE; 112 } 113 114 USHORT 115 KdbPromptString( 116 _In_ const CSTRING* PromptString, 117 _Inout_ PSTRING ResponseString) 118 { 119 /* Enter prompt loop: send the prompt and receive the response */ 120 ResponseString->Length = 0; 121 while (KdbPromptStringWorker(PromptString, ResponseString)) 122 { 123 /* Loop while we need to resend */ 124 } 125 return ResponseString->Length; 126 } 127 128 129 VOID 130 KdbPutsN( 131 _In_ PCCH String, 132 _In_ USHORT Length) 133 { 134 CSTRING Output; 135 136 Output.Buffer = String; 137 Output.Length = Output.MaximumLength = Length; 138 KdbPrintString(&Output); 139 } 140 141 VOID 142 KdbPuts( 143 _In_ PCSTR String) 144 { 145 KdbPutsN(String, (USHORT)strnlen(String, MAXUSHORT - sizeof(ANSI_NULL))); 146 } 147 148 VOID 149 __cdecl 150 KdbPrintf( 151 _In_ PCSTR Format, 152 ...) 153 { 154 va_list ap; 155 SIZE_T Length; 156 CHAR Buffer[1024]; 157 158 /* Format the string */ 159 va_start(ap, Format); 160 Length = _vsnprintf(Buffer, 161 sizeof(Buffer), 162 Format, 163 ap); 164 Length = min(Length, MAXUSHORT - sizeof(ANSI_NULL)); 165 va_end(ap); 166 167 /* Send it to the debugger directly */ 168 KdbPutsN(Buffer, (USHORT)Length); 169 } 170 171 SIZE_T 172 KdbPrompt( 173 _In_ PCSTR Prompt, 174 _Out_ PCHAR Buffer, 175 _In_ SIZE_T Size) 176 { 177 CSTRING PromptString; 178 STRING ResponseBuffer; 179 180 PromptString.Buffer = Prompt; 181 PromptString.Length = PromptString.MaximumLength = 182 (USHORT)strnlen(Prompt, MAXUSHORT - sizeof(ANSI_NULL)); 183 184 ResponseBuffer.Buffer = Buffer; 185 ResponseBuffer.Length = 0; 186 ResponseBuffer.MaximumLength = (USHORT)min(Size, MAXUSHORT); 187 188 return KdbPromptString(&PromptString, &ResponseBuffer); 189 } 190 191 /* EOF */ 192