xref: /reactos/ntoskrnl/kdbg/kdb_print.c (revision 2046a17e)
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
KdbPrintStringWorker(_In_ const CSTRING * Output,_In_ ULONG ApiNumber,_Inout_ PDBGKD_DEBUG_IO DebugIo,_Inout_ PSTRING Header,_Inout_ PSTRING Data)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
KdbPrintString(_In_ const CSTRING * Output)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
KdbPromptStringWorker(_In_ const CSTRING * PromptString,_Inout_ PSTRING ResponseString)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
KdbPromptString(_In_ const CSTRING * PromptString,_Inout_ PSTRING ResponseString)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
KdbPutsN(_In_ PCCH String,_In_ USHORT Length)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
KdbPuts(_In_ PCSTR String)152 KdbPuts(
153     _In_ PCSTR String)
154 {
155     KdbPutsN(String, (USHORT)strnlen(String, MAXUSHORT - sizeof(ANSI_NULL)));
156 }
157 
158 VOID
159 __cdecl
KdbPrintf(_In_ PCSTR Format,...)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
KdbPrompt(_In_ PCSTR Prompt,_Out_ PCHAR Buffer,_In_ SIZE_T Size)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