xref: /reactos/ntoskrnl/kdbg/kdb_print.c (revision 3c797b31)
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