[NTOS:KDBG] Introduce local versions of KdpPrintString, KdpDprintf and KdpPromptString...

... since the original ones are internal to the kernel and won't be
available once KDBG is moved out of it.

Use these functions in the pager/prompt support.
This commit is contained in:
Hermès Bélusca-Maïto 2023-03-29 19:38:10 +02:00
parent fdf4814ebb
commit f620ce7705
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
5 changed files with 259 additions and 38 deletions

View file

@ -597,7 +597,7 @@ KdIoPrintf(
}
extern STRING KdbPromptString;
extern const CSTRING KdbPromptStr;
VOID
NTAPI
@ -706,7 +706,6 @@ KdReceivePacket(
_Inout_ PKD_CONTEXT Context)
{
#ifdef KDBG
STRING NewLine = RTL_CONSTANT_STRING("\n");
STRING ResponseString;
PDBGKD_DEBUG_IO DebugIo;
CHAR MessageBuffer[512];
@ -768,8 +767,8 @@ KdReceivePacket(
/* The prompt string has been printed by KdSendPacket; go to
* new line and print the kdb prompt -- for SYSREG2 support. */
KdpPrintString(&NewLine);
KdpPrintString(&KdbPromptString); // Alternatively, use "Input> "
KdIoPrintString("\n", 1);
KdIoPuts(KdbPromptStr.Buffer); // Alternatively, use "Input> "
if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
KbdDisableMouse();

View file

@ -287,3 +287,36 @@ KbdDisableMouse(VOID);
VOID
KbdEnableMouse(VOID);
/* From kdb_print.c */
VOID
KdbPrintString(
_In_ const CSTRING* Output);
USHORT
KdbPromptString(
_In_ const CSTRING* PromptString,
_Inout_ PSTRING ResponseString);
VOID
KdbPutsN(
_In_ PCCH String,
_In_ USHORT Length);
VOID
KdbPuts(
_In_ PCSTR String);
VOID
__cdecl
KdbPrintf(
_In_ PCSTR Format,
...);
SIZE_T
KdbPrompt(
_In_ PCSTR Prompt,
_Out_ PCHAR Buffer,
_In_ SIZE_T Size);

View file

@ -145,7 +145,7 @@ static volatile ULONG KdbDmesgTotalWritten = 0;
static volatile BOOLEAN KdbpIsInDmesgMode = FALSE;
static KSPIN_LOCK KdpDmesgLogSpinLock;
STRING KdbPromptString = RTL_CONSTANT_STRING("kdb:> ");
const CSTRING KdbPromptStr = RTL_CONSTANT_STRING("kdb:> ");
//
// Debug Filter Component Table
@ -491,7 +491,7 @@ KdbpCmdEvalExpression(
}
/* Evaluate the expression */
Ok = KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result);
Ok = KdbpEvaluateExpression(Argv[1], KdbPromptStr.Length + (Argv[1]-Argv[0]), &Result);
if (Ok)
{
if (Result > 0x00000000ffffffffLL)
@ -849,7 +849,7 @@ KdbpCmdDisassembleX(
/* Evaluate the expression */
if (Argc > 1)
{
if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
if (!KdbpEvaluateExpression(Argv[1], KdbPromptStr.Length + (Argv[1]-Argv[0]), &Result))
return TRUE;
if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
@ -1271,7 +1271,7 @@ KdbpCmdBackTrace(
Argv[1]++;
/* Evaluate the expression */
if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
if (!KdbpEvaluateExpression(Argv[1], KdbPromptStr.Length + (Argv[1]-Argv[0]), &Result))
return TRUE;
if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
@ -1680,7 +1680,7 @@ KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[])
/* Evaluate the address expression */
if (!KdbpEvaluateExpression(Argv[AddressArgIndex],
KdbPromptString.Length + (Argv[AddressArgIndex]-Argv[0]),
KdbPromptStr.Length + (Argv[AddressArgIndex]-Argv[0]),
&Result))
{
return TRUE;
@ -2046,7 +2046,7 @@ KdbpCmdMod(
Argv[Argc][strlen(Argv[Argc])] = ' ';
/* Evaluate the expression */
if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
if (!KdbpEvaluateExpression(Argv[1], KdbPromptStr.Length + (Argv[1]-Argv[0]), &Result))
{
return TRUE;
}
@ -2880,7 +2880,7 @@ KdpFilterEscapes(
* \note Doesn't correctly handle \\t and terminal escape sequences when calculating the
* number of lines required to print a single line from the Buffer in the terminal.
* Maximum length of buffer is limited only by memory size.
* Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold the debugger lock.
* Uses KdbPrintf internally.
*
* Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
@ -2925,7 +2925,7 @@ KdbpPagerInternal(
{
if (p > Buffer + BufLength)
{
KdpDprintf("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer + BufLength));
KdbPrintf("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer + BufLength));
return;
}
}
@ -2948,39 +2948,33 @@ KdbpPagerInternal(
if (p[i] == '\n')
RowsPrintedByTerminal++;
//KdpDprintf("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);
//KdbPrintf("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);
/* Display a prompt if we printed one screen full of text */
if (KdTermSize.cy > 0 &&
(LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdTermSize.cy)
{
PCSTR Prompt;
/* Disable the repetition of previous command with long many-page output */
KdbRepeatLastCommand = FALSE;
if (KdbNumberOfColsPrinted > 0)
KdpDprintf("\n");
KdbPuts("\n");
if (DoPage)
{
KdpDprintf("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---");
}
Prompt = "--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---";
else
{
KdpDprintf("--- Press q to abort, any other key to continue ---");
}
RowsPrintedByTerminal++;
Prompt = "--- Press q to abort, any other key to continue ---";
KdbPuts(Prompt);
c = KdpReadTermKey(&ScanCode);
if (DoPage)
{
//KdpDprintf("\n"); // Concise version: don't show pressed key
KdpDprintf(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key
}
if (DoPage) // Show pressed key
KdbPrintf(" '%c'/scan=%04x\n", c, ScanCode);
else
{
KdpDprintf("\n");
}
KdbPuts("\n");
RowsPrintedByTerminal++;
if (c == 'q')
{
@ -3030,7 +3024,7 @@ KdbpPagerInternal(
KdpFilterEscapes(p);
/* Print the current line */
KdpDprintf("%s", p);
KdbPuts(p);
/* Restore not null char with saved */
if (c != '\0')
@ -3062,7 +3056,7 @@ KdbpPagerInternal(
* \note Doesn't correctly handle \\t and terminal escape sequences when calculating the
* number of lines required to print a single line from the Buffer in the terminal.
* Maximum length of buffer is limited only by memory size.
* Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold the debugger lock.
* Uses KdbPrintf internally.
*
* Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
@ -3300,15 +3294,18 @@ KdbpCliMainLoop(
/* Reset the number of rows/cols printed */
KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;
/* Print the prompt */
KdpDprintf(KdbPromptString.Buffer);
/*
* Read a command. Repeat the last one if the user pressed Enter.
* Print the prompt and read a command.
* Repeat the last one if the user pressed Enter.
* This reduces the risk of RSI when single-stepping!
*/
CmdLen = KdIoReadLine(Command, sizeof(Command));
if (CmdLen > 0) // i.e. (*Command != ANSI_NULL)
CmdLen = KdbPrompt(KdbPromptStr.Buffer, Command, sizeof(Command));
if (CmdLen == 0)
{
/* Nothing received but the user didn't press Enter, retry */
continue;
}
else if (CmdLen > 1) // i.e. (*Command != ANSI_NULL)
{
/* Save this new last command */
KdbRepeatLastCommand = TRUE;

191
ntoskrnl/kdbg/kdb_print.c Normal file
View file

@ -0,0 +1,191 @@
/*
* 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 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 */
KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, Header, Data, &KdpContext);
}
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 */
Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
&Header,
&Data,
&Length,
&KdpContext);
/* 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 */

View file

@ -407,6 +407,7 @@ if(NOT _WINKD_)
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cli.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cmdhist.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_expr.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_print.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_symbols.c)
endif()