https://git.reactos.org/?p=reactos.git;a=commitdiff;h=84e32e4e90109b3bce75dd...
commit 84e32e4e90109b3bce75ddb3eee2d3dfc42ab4be Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Sun Nov 27 19:58:56 2022 +0100 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Fri Jan 6 18:57:32 2023 +0100
[NTOS:KD] Revisit KdSendPacket() and KdReceivePacket() for DBGKD_DEBUG_IO. (#4914)
- Use SAL2 annotations. - KdSendPacket(): Validate DEBUG_IO API call. - KdReceivePacket(): Take the LengthOfStringRead into account; use KdbpReadCommand() to read the input, so that correct line edition is available (backspace, etc.) --- ntoskrnl/kd/kdio.c | 163 ++++++++++++++++++++-------------------------------- ntoskrnl/kdbg/kdb.h | 5 ++ 2 files changed, 68 insertions(+), 100 deletions(-)
diff --git a/ntoskrnl/kd/kdio.c b/ntoskrnl/kd/kdio.c index 3f39e20c173..45733e0b3ca 100644 --- a/ntoskrnl/kd/kdio.c +++ b/ntoskrnl/kd/kdio.c @@ -37,7 +37,7 @@ CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0}; static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = ""; static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
-const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024; +const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; PCHAR KdpDmesgBuffer = NULL; volatile ULONG KdpDmesgCurrentPosition = 0; volatile ULONG KdpDmesgFreeBytes = 0; @@ -576,18 +576,34 @@ extern STRING KdbPromptString; VOID NTAPI KdSendPacket( - IN ULONG PacketType, - IN PSTRING MessageHeader, - IN PSTRING MessageData, - IN OUT PKD_CONTEXT Context) + _In_ ULONG PacketType, + _In_ PSTRING MessageHeader, + _In_opt_ PSTRING MessageData, + _Inout_ PKD_CONTEXT Context) { if (PacketType == PACKET_TYPE_KD_DEBUG_IO) { - PSTRING Output = MessageData; + ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber; PLIST_ENTRY CurrentEntry; PKD_DISPATCH_TABLE CurrentTable;
- if (!KdpDebugMode.Value) return; + /* Validate API call */ + if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO)) + return; + if ((ApiNumber != DbgKdPrintStringApi) && + (ApiNumber != DbgKdGetStringApi)) + { + return; + } + if (!MessageData) + return; + + /* NOTE: MessageData->Length should be equal to + * DebugIo.u.PrintString.LengthOfString, or to + * DebugIo.u.GetString.LengthOfPromptString */ + + if (!KdpDebugMode.Value) + return;
/* Call the registered handlers */ CurrentEntry = KdProviders.Flink; @@ -599,7 +615,7 @@ KdSendPacket( KdProvidersList);
/* Call it */ - CurrentTable->KdpPrintRoutine(Output->Buffer, Output->Length); + CurrentTable->KdpPrintRoutine(MessageData->Buffer, MessageData->Length);
/* Next Table */ CurrentEntry = CurrentEntry->Flink; @@ -672,20 +688,17 @@ KdSendPacket( KDSTATUS NTAPI KdReceivePacket( - IN ULONG PacketType, - OUT PSTRING MessageHeader, - OUT PSTRING MessageData, - OUT PULONG DataLength, - IN OUT PKD_CONTEXT Context) + _In_ ULONG PacketType, + _Out_ PSTRING MessageHeader, + _Out_ PSTRING MessageData, + _Out_ PULONG DataLength, + _Inout_ PKD_CONTEXT Context) { #ifdef KDBG - KIRQL OldIrql; - STRING StringChar; - CHAR Response; - USHORT i; - ULONG DummyScanCode; - CHAR MessageBuffer[100]; + STRING NewLine = RTL_CONSTANT_STRING("\n"); STRING ResponseString; + PDBGKD_DEBUG_IO DebugIo; + CHAR MessageBuffer[512]; #endif
if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE) @@ -724,99 +737,49 @@ KdReceivePacket( return KdPacketTimedOut;
#ifdef KDBG - ResponseString.Buffer = MessageBuffer; - ResponseString.Length = 0; - ResponseString.MaximumLength = min(sizeof(MessageBuffer), MessageData->MaximumLength); - StringChar.Buffer = &Response; - StringChar.Length = StringChar.MaximumLength = sizeof(Response); - - /* Display the string and print a new line for log neatness */ - *StringChar.Buffer = '\n'; - KdpPrintString(&StringChar); + DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
- /* Print the kdb prompt */ - KdpPrintString(&KdbPromptString); + /* Validate API call */ + if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO)) + return KdPacketNeedsResend; + if (DebugIo->ApiNumber != DbgKdGetStringApi) + return KdPacketNeedsResend;
- // TODO: Use an improved KdbpReadCommand() function for our purposes. + /* NOTE: We cannot use directly MessageData->Buffer here as it points + * to the temporary KdpMessageBuffer scratch buffer that is being + * shared with all the possible I/O KD operations that may happen. */ + ResponseString.Buffer = MessageBuffer; + ResponseString.Length = 0; + ResponseString.MaximumLength = min(sizeof(MessageBuffer), + MessageData->MaximumLength); + ResponseString.MaximumLength = min(ResponseString.MaximumLength, + DebugIo->u.GetString.LengthOfStringRead);
- /* Acquire the printing spinlock without waiting at raised IRQL */ - OldIrql = KdbpAcquireLock(&KdpSerialSpinLock); + /* 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> "
if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) KbdDisableMouse();
- /* Loop the whole string */ - for (i = 0; i < ResponseString.MaximumLength; i++) - { - /* Check if this is serial debugging mode */ - if (KdbDebugState & KD_DEBUG_KDSERIAL) - { - /* Get the character from serial */ - do - { - Response = KdbpTryGetCharSerial(MAXULONG); - } while (Response == -1); - } - else - { - /* Get the response from the keyboard */ - do - { - Response = KdbpTryGetCharKeyboard(&DummyScanCode, MAXULONG); - } while (Response == -1); - } - - /* Check for return */ - if (Response == '\r') - { - /* - * We might need to discard the next '\n'. - * Wait a bit to make sure we receive it. - */ - KeStallExecutionProcessor(100000); - - /* Check the mode */ - if (KdbDebugState & KD_DEBUG_KDSERIAL) - { - /* Read and discard the next character, if any */ - KdbpTryGetCharSerial(5); - } - else - { - /* Read and discard the next character, if any */ - KdbpTryGetCharKeyboard(&DummyScanCode, 5); - } - - /* - * Null terminate the output string -- documentation states that - * DbgPrompt does not null terminate, but it does - */ - *(PCHAR)(ResponseString.Buffer + i) = 0; - break; - } - - /* Write it back and print it to the log */ - *(PCHAR)(ResponseString.Buffer + i) = Response; - KdbpReleaseLock(&KdpSerialSpinLock, OldIrql); - KdpPrintString(&StringChar); - OldIrql = KdbpAcquireLock(&KdpSerialSpinLock); - } - - /* Release the spinlock */ - KdbpReleaseLock(&KdpSerialSpinLock, OldIrql); - - /* Print a new line */ - *StringChar.Buffer = '\n'; - KdpPrintString(&StringChar); - - /* Return the length */ - RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, i); - *DataLength = i; + /* Read a line of user input and retrieve the length. + * The output string is NULL-terminated -- documentation states + * that DbgPrompt() does not NULL-terminate, but it does. */ + *DataLength = KdbpReadCommand(ResponseString.Buffer, + ResponseString.MaximumLength);
if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) KbdEnableMouse();
+ /* Return the length */ + *DataLength = min(*DataLength, DebugIo->u.GetString.LengthOfStringRead); + MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = *DataLength; + + /* Only now we can copy back the data into MessageData->Buffer */ + RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength); #endif + return KdPacketReceived; }
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h index d78e2696cdd..8d1e9af2a47 100644 --- a/ntoskrnl/kdbg/kdb.h +++ b/ntoskrnl/kdbg/kdb.h @@ -98,6 +98,11 @@ KdbpCliMainLoop( VOID KdbpCliInterpretInitFile(VOID);
+SIZE_T +KdbpReadCommand( + _Out_ PCHAR Buffer, + _In_ SIZE_T Size); + VOID KdbpPager( _In_ PCHAR Buffer,