reactos/ntoskrnl/kdbg/kdb_print.c
Hermès Bélusca-Maïto 2046a17ef4
[NTOS:KD:KDBG] Integration into KD framework (Part 1/3)
Split KdSendPacket and KdReceivePacket into those that manipulate the
KDBG state proper (reside in kdbg/kdbg.c), and those that deal only with
debug input/output that will reside in a KDTERM "KD Terminal Driver" DLL.

Based on some previous preparatory work by Hervé Poussineau in PR #4600.
(Equivalents of commits 5162bf106 and partly e9bcf7275.)
2023-08-31 16:07:51 +02:00

201 lines
5.1 KiB
C

/*
* PROJECT: ReactOS KDBG Kernel Debugger
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: IO interface for KDBG. Provides local KDBG versions
* of KdpPrintString, KdpPromptString and KdpDprintf.
* COPYRIGHT: Copyright 2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "kdb.h"
/* FUNCTIONS *****************************************************************/
static KD_CONTEXT KdbgKdContext;
#undef KdSendPacket
#define pKdSendPacket KdSendPacket
#undef KdReceivePacket
#define pKdReceivePacket KdReceivePacket
static VOID
KdbPrintStringWorker(
_In_ const CSTRING* Output,
_In_ ULONG ApiNumber,
_Inout_ PDBGKD_DEBUG_IO DebugIo,
_Inout_ PSTRING Header,
_Inout_ PSTRING Data)
{
USHORT Length;
C_ASSERT(PACKET_MAX_SIZE >= sizeof(*DebugIo));
ASSERT((ApiNumber == DbgKdPrintStringApi) ||
(ApiNumber == DbgKdGetStringApi));
/* Make sure we don't exceed the KD Packet size */
Length = min(Output->Length, PACKET_MAX_SIZE - sizeof(*DebugIo));
/* Build the packet header */
DebugIo->ApiNumber = ApiNumber;
DebugIo->ProcessorLevel = 0; // (USHORT)KeProcessorLevel;
DebugIo->Processor = KeGetCurrentPrcb()->Number;
if (ApiNumber == DbgKdPrintStringApi)
DebugIo->u.PrintString.LengthOfString = Length;
else // if (ApiNumber == DbgKdGetStringApi)
DebugIo->u.GetString.LengthOfPromptString = Length;
Header->Length = sizeof(*DebugIo);
Header->Buffer = (PCHAR)DebugIo;
/* Build the data */
Data->Length = Length;
Data->Buffer = (PCHAR)Output->Buffer;
/* Send the packet */
/* IO packet: call KdTerm */
pKdSendPacket(PACKET_TYPE_KD_DEBUG_IO, Header, Data, &KdbgKdContext);
}
VOID
KdbPrintString(
_In_ const CSTRING* Output)
{
DBGKD_DEBUG_IO DebugIo;
STRING Header, Data;
KdbPrintStringWorker(Output, DbgKdPrintStringApi,
&DebugIo, &Header, &Data);
}
static BOOLEAN
KdbPromptStringWorker(
_In_ const CSTRING* PromptString,
_Inout_ PSTRING ResponseString)
{
DBGKD_DEBUG_IO DebugIo;
STRING Header, Data;
ULONG Length;
KDSTATUS Status;
/* Print the prompt */
// DebugIo.u.GetString.LengthOfPromptString = Length;
DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength;
KdbPrintStringWorker(PromptString, DbgKdGetStringApi,
&DebugIo, &Header, &Data);
/* Set the maximum lengths for the receive */
Header.MaximumLength = sizeof(DebugIo);
Data.MaximumLength = ResponseString->MaximumLength;
/* Build the data */
Data.Buffer = ResponseString->Buffer;
/* Enter receive loop */
do
{
/* Get our reply */
/* IO packet: call KdTerm */
Status = pKdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
&Header,
&Data,
&Length,
&KdbgKdContext);
/* Return TRUE if we need to resend */
if (Status == KdPacketNeedsResend)
return TRUE;
/* Loop until we succeed */
} while (Status != KdPacketReceived);
/* Don't copy back a larger response than there is room for */
Length = min(Length, ResponseString->MaximumLength);
/* We've got the string back; return the length */
ResponseString->Length = (USHORT)Length;
/* Success; we don't need to resend */
return FALSE;
}
USHORT
KdbPromptString(
_In_ const CSTRING* PromptString,
_Inout_ PSTRING ResponseString)
{
/* Enter prompt loop: send the prompt and receive the response */
ResponseString->Length = 0;
while (KdbPromptStringWorker(PromptString, ResponseString))
{
/* Loop while we need to resend */
}
return ResponseString->Length;
}
VOID
KdbPutsN(
_In_ PCCH String,
_In_ USHORT Length)
{
CSTRING Output;
Output.Buffer = String;
Output.Length = Output.MaximumLength = Length;
KdbPrintString(&Output);
}
VOID
KdbPuts(
_In_ PCSTR String)
{
KdbPutsN(String, (USHORT)strnlen(String, MAXUSHORT - sizeof(ANSI_NULL)));
}
VOID
__cdecl
KdbPrintf(
_In_ PCSTR Format,
...)
{
va_list ap;
SIZE_T Length;
CHAR Buffer[1024];
/* Format the string */
va_start(ap, Format);
Length = _vsnprintf(Buffer,
sizeof(Buffer),
Format,
ap);
Length = min(Length, MAXUSHORT - sizeof(ANSI_NULL));
va_end(ap);
/* Send it to the debugger directly */
KdbPutsN(Buffer, (USHORT)Length);
}
SIZE_T
KdbPrompt(
_In_ PCSTR Prompt,
_Out_ PCHAR Buffer,
_In_ SIZE_T Size)
{
CSTRING PromptString;
STRING ResponseBuffer;
PromptString.Buffer = Prompt;
PromptString.Length = PromptString.MaximumLength =
(USHORT)strnlen(Prompt, MAXUSHORT - sizeof(ANSI_NULL));
ResponseBuffer.Buffer = Buffer;
ResponseBuffer.Length = 0;
ResponseBuffer.MaximumLength = (USHORT)min(Size, MAXUSHORT);
return KdbPromptString(&PromptString, &ResponseBuffer);
}
/* EOF */