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