https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ffb05406e6f4a408df857…
commit ffb05406e6f4a408df8577c4b3472f0a0972d77e
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Nov 23 23:24:59 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Thu Nov 24 01:18:18 2022 +0100
[NTOS:KD64] Implement KdLogDbgPrint() for the WinDbg !dbgprint command.
See this command's documentation:
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-dbgprint
and the section "DbgPrint buffer and the debugger"
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/reading-…
for more details.
- Loosely implement the function, based on our existing circular printout
buffers in kdio.c.
- Enable its usage in the KdpPrint() and KdpPrompt() functions.
Notice that this function will *only* capture the strings being sent **to**
the debugger, and not the strings the debugger itself produce. (This means
that we cannot use the KdPrintCircularBuffer as a replacement for our
KDBG dmesg one, for example...)
How to test:
Run ReactOS under WinDbg, and use the !dbgprint command to view the
buffer. You can also use the Memory Window, place yourself at the
address pointed by KdPrintCircularBuffer and KdPrintWritePointer, and
read its contents.
What you should observe:
Prior notice: The circular buffer in debug builds of ReactOS and Windows
is 0x8000 bytes large. In release builds, its size is down to 0x1000.
1- When you start e.g. the 2nd-stage GUI installation of ReactOS, going
past the initial "devices installation" and letting it stabilize on
the Welcome page, break into WinDbg and run the !dbgprint command. You
should notice that the end of its output is weirdly truncated, compared
to what has been actually emitted to the debug output. Comparing this
with the actual contents of the circular buffer (via Memory Window),
shows that the buffer contents is actually correct.
2- Copy all the text that has been output by the !dbgprint command and
paste it in an editor; count the number of all characters appearing +
newlines (only CR or LF), and observe that this number is "mysteriously"
equal to 16384 == 0x4000.
3- Continue running ReactOS installation for a little while, breaking back
back into WinDbg and looking at !dbgprint again. Its output seems to be
still stopping at the same place as before (but the actual buffer memory
contents shows otherwise). Continue running ROS installation, and break
into the debugger when ROS is about to restart. You should now observe
that the dbgprint buffer rolled over:
dd nt!KdPrintRolloverCount shows 1.
Carefully analysing the output of !dbgprint, however, you will notice
that it looks a bit garbage-y: the first part of the output is actually
truncated after 16384 characters, then you get a second part of the
buffer showing what ReactOS was printing while shutting down. Then
you get again what was shown at the top of the !dbgprint output.
(Of course, comparing with the actual contents of the circular buffer
in memory shows that its contents are fine...)
The reason of these strange observations, is because there is an intrinsic
bug in the !dbgprint command implementation (in kdexts.dll). Essentially,
it displays the contents of the circular buffer in two single dprintf()
calls: one for the "older" (bottom) part of the buffer:
[WritePointer, EndOfBuffer]
and one for the "newer" (upper) part of the buffer:
[CircularBuffer, WritePointer[ .
The first aspect of the bug (causing observation 3), is that those two
parts are not necessarily NULL-terminated strings (especially after
rollover), so for example, displaying the upper part of the buffer, will
potentially also display part of the buffer's bottom part.
The second aspect of the bug (explaining observations 1 and 2), is due
to the implementation of the dprintf() function (callback in dbgenv.dll).
There, it uses a fixed-sized buffer of size 0x4000 == 16384 characters.
Since the output of the circular buffer is not done by little chunks,
but by the two large parts, if any of those are larger than 0x4000 they
get truncated on display.
(This last observation is confirmed in a completely different context by
https://community.osr.com/discussion/112439/dprintf-s-max-string-length .)
---
ntoskrnl/include/internal/kd64.h | 13 ++++++
ntoskrnl/kd64/kddata.c | 1 +
ntoskrnl/kd64/kdprint.c | 91 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/ntoskrnl/include/internal/kd64.h b/ntoskrnl/include/internal/kd64.h
index d12d10fde1e..9c8670ab557 100644
--- a/ntoskrnl/include/internal/kd64.h
+++ b/ntoskrnl/include/internal/kd64.h
@@ -523,6 +523,11 @@ NTAPI
KdpPrintString(
_In_ PSTRING Output);
+VOID
+NTAPI
+KdLogDbgPrint(
+ _In_ PSTRING String);
+
//
// Global KD Data
//
@@ -558,7 +563,15 @@ extern LARGE_INTEGER KdTimerStop, KdTimerStart, KdTimerDifference;
extern CHAR KdpMessageBuffer[KDP_MSG_BUFFER_SIZE];
extern CHAR KdpPathBuffer[KDP_MSG_BUFFER_SIZE];
+
extern CHAR KdPrintDefaultCircularBuffer[KD_DEFAULT_LOG_BUFFER_SIZE];
+extern PCHAR KdPrintWritePointer;
+extern ULONG KdPrintRolloverCount;
+extern PCHAR KdPrintCircularBuffer;
+extern ULONG KdPrintBufferSize;
+extern ULONG KdPrintBufferChanges;
+extern KSPIN_LOCK KdpPrintSpinLock;
+
extern BREAKPOINT_ENTRY KdpBreakpointTable[KD_BREAKPOINT_MAX];
extern KD_BREAKPOINT_TYPE KdpBreakpointInstruction;
extern BOOLEAN KdpOweBreakpoint;
diff --git a/ntoskrnl/kd64/kddata.c b/ntoskrnl/kd64/kddata.c
index 6e99c18d374..7111d287d0a 100644
--- a/ntoskrnl/kd64/kddata.c
+++ b/ntoskrnl/kd64/kddata.c
@@ -136,6 +136,7 @@ ULONG KdPrintRolloverCount;
PCHAR KdPrintCircularBuffer = KdPrintDefaultCircularBuffer;
ULONG KdPrintBufferSize = sizeof(KdPrintDefaultCircularBuffer);
ULONG KdPrintBufferChanges = 0;
+KSPIN_LOCK KdpPrintSpinLock;
//
// Debug Filter Masks
diff --git a/ntoskrnl/kd64/kdprint.c b/ntoskrnl/kd64/kdprint.c
index 83e2e2f3840..c6089b534b4 100644
--- a/ntoskrnl/kd64/kdprint.c
+++ b/ntoskrnl/kd64/kdprint.c
@@ -17,6 +17,93 @@
/* FUNCTIONS *****************************************************************/
+KIRQL
+NTAPI
+KdpAcquireLock(
+ _In_ PKSPIN_LOCK SpinLock)
+{
+ KIRQL OldIrql;
+
+ /* Acquire the spinlock without waiting at raised IRQL */
+ while (TRUE)
+ {
+ /* Loop until the spinlock becomes available */
+ while (!KeTestSpinLock(SpinLock));
+
+ /* Spinlock is free, raise IRQL to high level */
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ /* Try to get the spinlock */
+ if (KeTryToAcquireSpinLockAtDpcLevel(SpinLock))
+ break;
+
+ /* Someone else got the spinlock, lower IRQL back */
+ KeLowerIrql(OldIrql);
+ }
+
+ return OldIrql;
+}
+
+VOID
+NTAPI
+KdpReleaseLock(
+ _In_ PKSPIN_LOCK SpinLock,
+ _In_ KIRQL OldIrql)
+{
+ /* Release the spinlock */
+ KiReleaseSpinLock(SpinLock);
+ // KeReleaseSpinLockFromDpcLevel(SpinLock);
+
+ /* Restore the old IRQL */
+ KeLowerIrql(OldIrql);
+}
+
+VOID
+NTAPI
+KdLogDbgPrint(
+ _In_ PSTRING String)
+{
+ SIZE_T Length, Remaining;
+ KIRQL OldIrql;
+
+ /* If the string is empty, bail out */
+ if (!String->Buffer || (String->Length == 0))
+ return;
+
+ /* If no log buffer available, bail out */
+ if (!KdPrintCircularBuffer /*|| (KdPrintBufferSize == 0)*/)
+ return;
+
+ /* Acquire the log spinlock without waiting at raised IRQL */
+ OldIrql = KdpAcquireLock(&KdpPrintSpinLock);
+
+ Length = min(String->Length, KdPrintBufferSize);
+ Remaining = KdPrintCircularBuffer + KdPrintBufferSize - KdPrintWritePointer;
+
+ if (Length < Remaining)
+ {
+ KdpMoveMemory(KdPrintWritePointer, String->Buffer, Length);
+ KdPrintWritePointer += Length;
+ }
+ else
+ {
+ KdpMoveMemory(KdPrintWritePointer, String->Buffer, Remaining);
+ Length -= Remaining;
+ if (Length > 0)
+ KdpMoveMemory(KdPrintCircularBuffer, String->Buffer + Remaining, Length);
+
+ KdPrintWritePointer = KdPrintCircularBuffer + Length;
+
+ /* Got a rollover, update count (handle wrapping, must always be >= 1) */
+ ++KdPrintRolloverCount;
+ if (KdPrintRolloverCount == 0)
+ ++KdPrintRolloverCount;
+ }
+
+ /* Release the spinlock */
+ KdpReleaseLock(&KdpPrintSpinLock, OldIrql);
+}
+
BOOLEAN
NTAPI
KdpPrintString(
@@ -270,7 +357,7 @@ KdpPrompt(
ResponseBuffer.MaximumLength = MaximumResponseLength;
/* Log the print */
- //KdLogDbgPrint(&PromptBuffer);
+ KdLogDbgPrint(&PromptBuffer);
/* Enter the debugger */
Enable = KdEnterDebugger(TrapFrame, ExceptionFrame);
@@ -405,7 +492,7 @@ KdpPrint(
OutputString.Length = OutputString.MaximumLength = Length;
/* Log the print */
- //KdLogDbgPrint(&OutputString);
+ KdLogDbgPrint(&OutputString);
/* Check for a debugger */
if (KdDebuggerNotPresent)
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1847474aaa1fbfd438607…
commit 1847474aaa1fbfd438607c78cefba2ee3d4085e5
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Nov 23 06:02:13 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Thu Nov 24 01:18:11 2022 +0100
[PSDK] Clarify the FIXME comment about this mysterious warning.h (here for WDK compatibility).
---
sdk/include/psdk/warning.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sdk/include/psdk/warning.h b/sdk/include/psdk/warning.h
index 0d60f0f834b..60b5b15a78f 100644
--- a/sdk/include/psdk/warning.h
+++ b/sdk/include/psdk/warning.h
@@ -1,5 +1,5 @@
-/* FIXME
- here we putting #pragma warning and disable or enable them
- I known gcc and msvc using diffent pragma and I do not known
- the gcc pragma well to achive msvs and gcc compatible with this */
\ No newline at end of file
+/* FIXME - For WDK compatibility.
+ Here #pragma warning are placed and are disabled or enabled.
+ GCC and MSVC use different pragmas so a compatible list for
+ these remains to be found. */
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=edb7575faa0be6c9f19a2…
commit edb7575faa0be6c9f19a2632f15e95f96ab2f54d
Author: Marcin Jabłoński <nnxcomputing(a)gmail.com>
AuthorDate: Tue Nov 22 21:52:18 2022 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Nov 22 23:52:18 2022 +0300
[NTOS:KE/x64] Implement KeDisconnectInterrupt() for amd64 (#4883)
Choose the correct element of the KiUnexpectedRange array,
depending on the interrupt vector, the same way as here:
https://github.com/reactos/reactos/blob/a2c6af0da4acbba9c254d003e9d9f4ea6e0…
And guard KeConnectInterrupt() execution with dispatcher lock.
CORE-14922
---
ntoskrnl/ke/amd64/interrupt.c | 86 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 76 insertions(+), 10 deletions(-)
diff --git a/ntoskrnl/ke/amd64/interrupt.c b/ntoskrnl/ke/amd64/interrupt.c
index a1e66da4dde..bf74eb2722c 100644
--- a/ntoskrnl/ke/amd64/interrupt.c
+++ b/ntoskrnl/ke/amd64/interrupt.c
@@ -17,8 +17,8 @@
#include <debug.h>
extern UCHAR KiInterruptDispatchTemplate[16];
-extern UCHAR KiUnexpectedRange[];
-extern UCHAR KiUnexpectedRangeEnd[];
+extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256];
+extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRangeEnd[];
void KiInterruptDispatch(void);
@@ -82,6 +82,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
{
PVOID CurrentHandler;
PKINTERRUPT ConnectedInterrupt;
+ KIRQL OldIrql;
ASSERT(Interrupt->Vector >= PRIMARY_VECTOR_BASE);
ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
@@ -93,6 +94,10 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Check if its already connected */
if (Interrupt->Connected) return TRUE;
+ /* Set the system affinity and acquire the dispatcher lock */
+ KeSetSystemAffinityThread(1ULL << Interrupt->Number);
+ OldIrql = KiAcquireDispatcherLock();
+
/* Query the current handler */
CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
@@ -118,7 +123,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Didn't work, restore old handler */
DPRINT1("HalEnableSystemInterrupt failed\n");
KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
- return FALSE;
+ goto Cleanup;
}
}
else
@@ -131,7 +136,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
(ConnectedInterrupt->ShareVector == 0) ||
(Interrupt->Mode != ConnectedInterrupt->Mode))
{
- return FALSE;
+ goto Cleanup;
}
/* Insert the new interrupt into the connected interrupt's list */
@@ -142,21 +147,82 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Mark as connected */
Interrupt->Connected = TRUE;
- return TRUE;
+Cleanup:
+ /* Release the dispatcher lock and restore the thread affinity */
+ KiReleaseDispatcherLock(OldIrql);
+ KeRevertToUserAffinityThread();
+ return Interrupt->Connected;
}
BOOLEAN
NTAPI
KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
{
- /* If the interrupt wasn't connected, there's nothing to do */
- if (!Interrupt->Connected)
+ KIRQL OldIrql;
+ PVOID VectorHandler, UnexpectedHandler;
+ PKINTERRUPT VectorFirstInterrupt, NextInterrupt;
+ PLIST_ENTRY HandlerHead;
+
+ /* Set the system affinity and acquire the dispatcher lock */
+ KeSetSystemAffinityThread(1ULL << Interrupt->Number);
+ OldIrql = KiAcquireDispatcherLock();
+
+ /* Check if the interrupt was connected - otherwise there's nothing to do */
+ if (Interrupt->Connected)
{
- return FALSE;
+ /* Get the handler for this interrupt vector */
+ VectorHandler = KeQueryInterruptHandler(Interrupt->Vector);
+
+ /* Get the first interrupt for this handler */
+ VectorFirstInterrupt = CONTAINING_RECORD(VectorHandler, KINTERRUPT, DispatchCode);
+
+ /* The first interrupt list entry is the interrupt list head */
+ HandlerHead = &VectorFirstInterrupt->InterruptListEntry;
+
+ /* If the list is empty, this is the only interrupt for this vector */
+ if (IsListEmpty(HandlerHead))
+ {
+ /* If the list is empty, and the head is not from this interrupt,
+ * this interrupt is somehow incorrectly connected */
+ ASSERT(VectorFirstInterrupt == Interrupt);
+
+ UnexpectedHandler = &KiUnexpectedRange[Interrupt->Vector]._Op_push;
+
+ /* This is the only interrupt, the handler can be disconnected */
+ HalDisableSystemInterrupt(Interrupt->Vector, Interrupt->Irql);
+ KeRegisterInterruptHandler(Interrupt->Vector, UnexpectedHandler);
+ }
+ /* If the interrupt to be disconnected is the list head, but some others follow */
+ else if (VectorFirstInterrupt == Interrupt)
+ {
+ /* Relocate the head to the next element */
+ HandlerHead = HandlerHead->Flink;
+ RemoveTailList(HandlerHead);
+
+ /* Get the next interrupt from the list head */
+ NextInterrupt = CONTAINING_RECORD(HandlerHead,
+ KINTERRUPT,
+ InterruptListEntry);
+
+ /* Set the next interrupt as the handler for this vector */
+ KeRegisterInterruptHandler(Interrupt->Vector,
+ NextInterrupt->DispatchCode);
+ }
+ /* If the interrupt to be disconnected is not the list head */
+ else
+ {
+ /* Remove the to be disconnected interrupt from the interrupt list */
+ RemoveEntryList(&Interrupt->InterruptListEntry);
+ }
+
+ /* Mark as not connected */
+ Interrupt->Connected = FALSE;
}
- UNIMPLEMENTED;
- __debugbreak();
+ /* Release the dispatcher lock and restore the thread affinity */
+ KiReleaseDispatcherLock(OldIrql);
+ KeRevertToUserAffinityThread();
+
return TRUE;
}
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d15f12614397d14264e67…
commit d15f12614397d14264e676aed343d1b56937efcd
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Tue Nov 22 01:49:16 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Nov 22 02:10:55 2022 +0100
[NTOS:KDBG] Fix the ANSI escape sequences used to get terminal characteristics when printing with paging.
- Line-wrapping is enabled with 'ESC[?7h' (the '?' was forgotten).
Notice that the following reference also shows it wrong:
https://www.cse.psu.edu/~kxc104/class/cse472/09s/hw/hw7/vt100ansi.htm
- Terminal type is actually queried with 'ESC Z' (VT52-compatible), or
with 'ESC[c' (VT100-compatible). The antediluvian CTRL-E ('\x05')
control code gives instead a user-configurable (usually empty) string,
so it's not reliable.
Also, we don't really care about the returned result, we just need to
know that one has been sent.
Cross-checked with online documentation:
* "Digital VT100 User Guide" (EK-VT100-UG-001) (1st edition, August 1978,
reviewed November 1978).
* https://www.real-world-systems.com/docs/ANSIcode.html
* https://geoffg.net/Downloads/Terminal/TerminalEscapeCodes.pdf
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
* https://en.wikipedia.org/wiki/Enquiry_character
- Retrieve the size of the *controlling terminal* with escape sequences
only when it's a serial one: serial output is enabled *and* KDSERIAL
is set (i.e. user input through serial). See code for the actual logic
(the corresponding truth table is left as an exercise for the reader).
- Fix also a "Buffer" vs. "InBuffer" mismatch, that caused the whole
code to fail.
- For fallback terminal size values, use meaningful ones when SCREEN
is instead the controlling "terminal" (based on full-size BOOTVID
values).
- When echoing read characters during line-cooking, do direct output by
using KdpDprintf() instead of going through the heavy KdbpPrint() function.
This fixes some input artifacts like: 1. extra slowdowns due to
querying terminal size at each keypress, and 2. getting obnoxious
"--- Press q to abort ..." prompts in the middle of typing a long
comamnd because you are at the very bottom of the screen.
---
ntoskrnl/kdbg/kdb_cli.c | 85 +++++++++++++++++++++++++++++--------------------
1 file changed, 51 insertions(+), 34 deletions(-)
diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c
index 806ace30fb2..ac4e70b7fbc 100644
--- a/ntoskrnl/kdbg/kdb_cli.c
+++ b/ntoskrnl/kdbg/kdb_cli.c
@@ -2923,27 +2923,28 @@ KdbpPagerInternal(
{
TerminalInitialized = TRUE;
- KdpDprintf("\x1b[7h"); /* Enable linewrap */
+ /* Enable line-wrap */
+ KdpDprintf("\x1b[?7h");
- /* Query terminal type */
- /*DbgPrint("\x1b[Z");*/
- KdpDprintf("\x05");
-
- Length = 0;
+ /*
+ * Query terminal type.
+ * Historically it was done with CTRL-E ('\x05'), however nowadays
+ * terminals respond to it with an empty (or a user-configurable)
+ * string. Instead, use the VT52-compatible 'ESC Z' sequence or the
+ * VT100-compatible 'ESC[c' one.
+ */
+ KdpDprintf("\x1b[c");
KeStallExecutionProcessor(100000);
+ Length = 0;
for (;;)
{
+ /* Verify we get an answer, but don't care about it */
c = KdbpTryGetCharSerial(5000);
if (c == -1)
break;
-
- InBuffer[Length++] = c;
- if (Length >= (sizeof(InBuffer) - 1))
- break;
+ ++Length;
}
-
- InBuffer[Length] = '\0';
if (Length > 0)
TerminalConnected = TRUE;
}
@@ -2953,21 +2954,34 @@ KdbpPagerInternal(
/* Refresh terminal size each time when number of rows printed is 0 */
(KdbNumberOfRowsPrinted) == 0)
{
- if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize)
+ /* Retrieve the size of the serial terminal only when it is the
+ * controlling terminal: serial output is enabled *and* KDSERIAL
+ * is set (i.e. user input through serial). */
+ BOOLEAN SerialTerminal =
+#if 0
+ // Old logic where KDSERIAL also enables serial output.
+ (KdbDebugState & KD_DEBUG_KDSERIAL) ||
+ (KdpDebugMode.Serial && !KdpDebugMode.Screen);
+#else
+ // New logic where KDSERIAL does not necessarily enable serial output.
+ KdpDebugMode.Serial &&
+ ((KdbDebugState & KD_DEBUG_KDSERIAL) || !KdpDebugMode.Screen);
+#endif
+
+ if (SerialTerminal && TerminalConnected && TerminalReportsSize)
{
/* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */
TerminalReportsSize = FALSE;
- KeStallExecutionProcessor(100000);
KdpDprintf("\x1b[18t");
- c = KdbpTryGetCharSerial(5000);
+ KeStallExecutionProcessor(100000);
+ c = KdbpTryGetCharSerial(5000);
if (c == KEY_ESC)
{
c = KdbpTryGetCharSerial(5000);
if (c == '[')
{
Length = 0;
-
for (;;)
{
c = KdbpTryGetCharSerial(5000);
@@ -2978,15 +2992,15 @@ KdbpPagerInternal(
if (isalpha(c) || Length >= (sizeof(InBuffer) - 1))
break;
}
-
InBuffer[Length] = '\0';
+
if (InBuffer[0] == '8' && InBuffer[1] == ';')
{
for (i = 2; (i < Length) && (InBuffer[i] != ';'); i++);
- if (Buffer[i] == ';')
+ if (InBuffer[i] == ';')
{
- Buffer[i++] = '\0';
+ InBuffer[i++] = '\0';
/* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */
KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0);
@@ -3003,19 +3017,22 @@ KdbpPagerInternal(
if (KdbNumberOfRowsTerminal <= 0)
{
/* Set number of rows to the default */
- if (!DoPage)
- KdbNumberOfRowsTerminal = 23; //Mna.: for SCREEN debugport
+ if (KdpDebugMode.Screen && !SerialTerminal)
+ KdbNumberOfRowsTerminal = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ + 1));
else
KdbNumberOfRowsTerminal = 24;
}
- else if (KdbNumberOfColsTerminal <= 0)
+ if (KdbNumberOfColsTerminal <= 0)
{
/* Set number of cols to the default */
- if (!DoPage)
- KdbNumberOfColsTerminal = 75; //Mna.: for SCREEN debugport
+ if (KdpDebugMode.Screen && !SerialTerminal)
+ KdbNumberOfColsTerminal = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
else
KdbNumberOfColsTerminal = 80;
}
+
+ // KdpDprintf("Cols/Rows: %dx%d\n",
+ // KdbNumberOfColsTerminal, KdbNumberOfRowsTerminal);
}
/* Loop through the strings */
@@ -3398,7 +3415,7 @@ KdbpReadCommand(
if (NextKey == '\n' || NextKey == -1) /* \n or no response at all */
NextKey = '\0';
- KdbpPrint("\n");
+ KdpDprintf("\n");
/*
* Repeat the last command if the user presses enter. Reduces the
@@ -3425,9 +3442,9 @@ KdbpReadCommand(
*Buffer = 0;
if (EchoOn)
- KdbpPrint("%c %c", KEY_BS, KEY_BS);
+ KdpDprintf("%c %c", KEY_BS, KEY_BS);
else
- KdbpPrint(" %c", KEY_BS);
+ KdpDprintf(" %c", KEY_BS);
}
}
else if (ScanCode == KEY_SCAN_UP)
@@ -3459,16 +3476,16 @@ KdbpReadCommand(
*Buffer = 0;
if (EchoOn)
- KdbpPrint("%c %c", KEY_BS, KEY_BS);
+ KdpDprintf("%c %c", KEY_BS, KEY_BS);
else
- KdbpPrint(" %c", KEY_BS);
+ KdpDprintf(" %c", KEY_BS);
}
i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);
memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);
Orig[i] = '\0';
Buffer = Orig + i;
- KdbpPrint("%s", Orig);
+ KdpDprintf("%s", Orig);
}
}
else if (ScanCode == KEY_SCAN_DOWN)
@@ -3488,23 +3505,23 @@ KdbpReadCommand(
*Buffer = 0;
if (EchoOn)
- KdbpPrint("%c %c", KEY_BS, KEY_BS);
+ KdpDprintf("%c %c", KEY_BS, KEY_BS);
else
- KdbpPrint(" %c", KEY_BS);
+ KdpDprintf(" %c", KEY_BS);
}
i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);
memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);
Orig[i] = '\0';
Buffer = Orig + i;
- KdbpPrint("%s", Orig);
+ KdpDprintf("%s", Orig);
}
}
}
else
{
if (EchoOn)
- KdbpPrint("%c", Key);
+ KdpDprintf("%c", Key);
*Buffer = Key;
Buffer++;
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9337ea6a3c6b93837a02c…
commit 9337ea6a3c6b93837a02ca83dd2d8899d40d7072
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Mon Nov 21 16:35:47 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Nov 22 02:10:54 2022 +0100
[NTOS:KDBG] Deduplicate code between KdbpPrint() and KdbpPager().
---
ntoskrnl/kdbg/kdb.h | 9 +-
ntoskrnl/kdbg/kdb_cli.c | 548 ++++++++++++++++++------------------------------
2 files changed, 207 insertions(+), 350 deletions(-)
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h
index 542cc398f11..d78e2696cdd 100644
--- a/ntoskrnl/kdbg/kdb.h
+++ b/ntoskrnl/kdbg/kdb.h
@@ -98,10 +98,15 @@ KdbpCliMainLoop(
VOID
KdbpCliInterpretInitFile(VOID);
+VOID
+KdbpPager(
+ _In_ PCHAR Buffer,
+ _In_ ULONG BufLength);
+
VOID
KdbpPrint(
- IN PCHAR Format,
- IN ... OPTIONAL);
+ _In_ PSTR Format,
+ _In_ ...);
VOID
KdbpPrintUnicodeString(
diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c
index e044572691d..806ace30fb2 100644
--- a/ntoskrnl/kdbg/kdb_cli.c
+++ b/ntoskrnl/kdbg/kdb_cli.c
@@ -2526,12 +2526,6 @@ KdbpCmdReboot(
return FALSE;
}
-
-VOID
-KdbpPager(
- IN PCHAR Buffer,
- IN ULONG BufLength);
-
/*!\brief Display debug messages on screen, with paging.
*
* Keys for per-page view: Home, End, PageUp, Arrow Up, PageDown,
@@ -2787,266 +2781,9 @@ KdbpCmdHelp(
return TRUE;
}
-/*!\brief Prints the given string with printf-like formatting.
- *
- * \param Format Format of the string/arguments.
- * \param ... Variable number of arguments matching the format specified in \a Format.
- *
- * \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.
- * Prints maximum 4096 chars, because of its buffer size.
- * Uses KdpDPrintf internally (NOT DbgPrint!). Callers must already hold the debugger lock.
- */
-VOID
-KdbpPrint(
- IN PCHAR Format,
- IN ... OPTIONAL)
-{
- static CHAR Buffer[4096];
- static BOOLEAN TerminalInitialized = FALSE;
- static BOOLEAN TerminalConnected = FALSE;
- static BOOLEAN TerminalReportsSize = TRUE;
- CHAR c = '\0';
- PCHAR p, p2;
- ULONG Length;
- SIZE_T i, j;
- LONG RowsPrintedByTerminal;
- ULONG ScanCode;
- va_list ap;
-
- /* Check if the user has aborted output of the current command */
- if (KdbOutputAborted)
- return;
-
- /* Initialize the terminal */
- if (!TerminalInitialized)
- {
- KdpDprintf("\x1b[7h"); /* Enable linewrap */
-
- /* Query terminal type */
- /*DbgPrint("\x1b[Z");*/
- KdpDprintf("\x05");
-
- TerminalInitialized = TRUE;
- Length = 0;
- KeStallExecutionProcessor(100000);
-
- for (;;)
- {
- c = KdbpTryGetCharSerial(5000);
- if (c == -1)
- break;
-
- Buffer[Length++] = c;
- if (Length >= (sizeof(Buffer) - 1))
- break;
- }
-
- Buffer[Length] = '\0';
- if (Length > 0)
- TerminalConnected = TRUE;
- }
-
- /* Get number of rows and columns in terminal */
- if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
- (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */
- {
- if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize)
- {
- /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */
- TerminalReportsSize = FALSE;
- KeStallExecutionProcessor(100000);
- KdpDprintf("\x1b[18t");
- c = KdbpTryGetCharSerial(5000);
-
- if (c == KEY_ESC)
- {
- c = KdbpTryGetCharSerial(5000);
- if (c == '[')
- {
- Length = 0;
-
- for (;;)
- {
- c = KdbpTryGetCharSerial(5000);
- if (c == -1)
- break;
-
- Buffer[Length++] = c;
- if (isalpha(c) || Length >= (sizeof(Buffer) - 1))
- break;
- }
-
- Buffer[Length] = '\0';
- if (Buffer[0] == '8' && Buffer[1] == ';')
- {
- for (i = 2; (i < Length) && (Buffer[i] != ';'); i++);
-
- if (Buffer[i] == ';')
- {
- Buffer[i++] = '\0';
-
- /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */
- KdbNumberOfRowsTerminal = strtoul(Buffer + 2, NULL, 0);
- KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0);
- TerminalReportsSize = TRUE;
- }
- }
- }
- /* Clear further characters */
- while ((c = KdbpTryGetCharSerial(5000)) != -1);
- }
- }
-
- if (KdbNumberOfRowsTerminal <= 0)
- {
- /* Set number of rows to the default. */
- KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport
- }
- else if (KdbNumberOfColsTerminal <= 0)
- {
- /* Set number of cols to the default. */
- KdbNumberOfColsTerminal = 75; //80; //Mna.: 75 for SCREEN debugport
- }
- }
-
- /* Get the string */
- va_start(ap, Format);
- Length = _vsnprintf(Buffer, sizeof(Buffer) - 1, Format, ap);
- Buffer[Length] = '\0';
- va_end(ap);
-
- p = Buffer;
- while (p[0] != '\0')
- {
- i = strcspn(p, "\n");
-
- /* Calculate the number of lines which will be printed in the terminal
- * when outputting the current line
- */
- if (i > 0)
- RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal;
- else
- RowsPrintedByTerminal = 0;
-
- if (p[i] == '\n')
- RowsPrintedByTerminal++;
-
- /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/
-
- /* Display a prompt if we printed one screen full of text */
- if (KdbNumberOfRowsTerminal > 0 &&
- (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
- {
- KdbRepeatLastCommand = FALSE;
-
- if (KdbNumberOfColsPrinted > 0)
- KdpDprintf("\n");
-
- KdpDprintf("--- Press q to abort, any other key to continue ---");
- RowsPrintedByTerminal++; /* added by Mna. */
-
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- c = KdbpGetCharSerial();
- else
- c = KdbpGetCharKeyboard(&ScanCode);
-
- if (c == '\r')
- {
- /* Try to read '\n' which might follow '\r' - if \n is not received here
- * it will be interpreted as "return" when the next command should be read.
- */
- if (KdbDebugState & KD_DEBUG_KDSERIAL)
- c = KdbpTryGetCharSerial(5);
- else
- c = KdbpTryGetCharKeyboard(&ScanCode, 5);
- }
-
- KdpDprintf("\n");
- if (c == 'q')
- {
- KdbOutputAborted = TRUE;
- return;
- }
-
- KdbNumberOfRowsPrinted = 0;
- KdbNumberOfColsPrinted = 0;
- }
-
- /* Insert a NUL after the line and print only the current line. */
- if (p[i] == '\n' && p[i + 1] != '\0')
- {
- c = p[i + 1];
- p[i + 1] = '\0';
- }
- else
- {
- c = '\0';
- }
-
- /* Remove escape sequences from the line if there's no terminal connected */
- if (!TerminalConnected)
- {
- while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */
- {
- size_t len = strlen(p2);
- if (p2[1] == '[')
- {
- j = 2;
- while (!isalpha(p2[j++]));
- memmove(p2, p2 + j, len + 1 - j);
- }
- else
- {
- memmove(p2, p2 + 1, len);
- }
- }
- }
-
- KdpDprintf("%s", p);
-
- if (c != '\0')
- p[i + 1] = c;
-
- /* Set p to the start of the next line and
- * remember the number of rows/cols printed
- */
- p += i;
- if (p[0] == '\n')
- {
- p++;
- KdbNumberOfColsPrinted = 0;
- }
- else
- {
- ASSERT(p[0] == '\0');
- KdbNumberOfColsPrinted += i;
- }
-
- KdbNumberOfRowsPrinted += RowsPrintedByTerminal;
- }
-}
-
-VOID
-KdbpPrintUnicodeString(
- _In_ PCUNICODE_STRING String)
-{
- ULONG i;
-
- if ((String == NULL) || (String->Buffer == NULL))
- {
- KdbpPrint("<NULL>");
- return;
- }
-
- for (i = 0; i < String->Length / sizeof(WCHAR); i++)
- {
- KdbpPrint("%c", (CHAR)String->Buffer[i]);
- }
-}
-/** memrchr(), explicitly defined, since was absent in MinGW of RosBE. */
/*
+ * memrchr(), explicitly defined, since absent in the CRT.
* Reverse memchr()
* Find the last occurrence of 'c' in the buffer 's' of size 'n'.
*/
@@ -3078,14 +2815,17 @@ memrchr(const void *s, int c, size_t n)
* Used by KdbpPager().
* Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
*/
-PCHAR
-CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
+static PCHAR
+CountOnePageUp(
+ _In_ PCCH Buffer,
+ _In_ ULONG BufLength,
+ _In_ PCCH pCurPos)
{
- PCHAR p;
+ PCCH p;
// p0 is initial guess of Page Start
ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
- PCHAR p0 = pCurPos - p0len;
- PCHAR prev_p = p0, p1;
+ PCCH p0 = pCurPos - p0len;
+ PCCH prev_p = p0, p1;
ULONG j;
if (pCurPos < Buffer)
@@ -3093,7 +2833,7 @@ CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
ASSERT(pCurPos <= Buffer + BufLength);
p = memrchr(p0, '\n', p0len);
- if (NULL == p)
+ if (!p)
p = p0;
for (j = KdbNumberOfRowsTerminal; j--; )
{
@@ -3101,10 +2841,10 @@ CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
p1 = memrchr(p0, '\n', p-p0);
prev_p = p;
p = p1;
- if (NULL == p)
+ if (!p)
{
p = prev_p;
- if (NULL == p)
+ if (!p)
p = p0;
break;
}
@@ -3113,9 +2853,33 @@ CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
j -= linesCnt-1;
}
- ASSERT(p != 0);
+ ASSERT(p != NULL);
++p;
- return p;
+ return (PCHAR)p;
+}
+
+static VOID
+KdpFilterEscapes(
+ _Inout_ PSTR String)
+{
+ PCHAR p;
+ SIZE_T i;
+ size_t len;
+
+ while ((p = strrchr(String, '\x1b'))) /* Look for escape character */
+ {
+ len = strlen(p);
+ if (p[1] == '[')
+ {
+ i = 2;
+ while (!isalpha(p[i++]));
+ memmove(p, p + i, len + 1 - i);
+ }
+ else
+ {
+ memmove(p, p + 1, len);
+ }
+ }
}
/*!\brief Prints the given string with, page by page.
@@ -3126,27 +2890,28 @@ CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
* \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.
*
* Note: BufLength should be greater then (KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal).
- *
*/
VOID
-KdbpPager(
- IN PCHAR Buffer,
- IN ULONG BufLength)
+KdbpPagerInternal(
+ _In_ PCHAR Buffer,
+ _In_ ULONG BufLength,
+ _In_ BOOLEAN DoPage)
{
- static CHAR InBuffer[4096];
+ static CHAR InBuffer[128];
static BOOLEAN TerminalInitialized = FALSE;
static BOOLEAN TerminalConnected = FALSE;
static BOOLEAN TerminalReportsSize = TRUE;
- CHAR c = '\0';
- PCHAR p, p2;
+ CHAR c;
+ ULONG ScanCode;
+ PCHAR p;
ULONG Length;
- SIZE_T i, j;
+ SIZE_T i;
LONG RowsPrintedByTerminal;
- ULONG ScanCode;
- if( BufLength == 0)
+ if (BufLength == 0)
return;
/* Check if the user has aborted output of the current command */
@@ -3156,13 +2921,14 @@ KdbpPager(
/* Initialize the terminal */
if (!TerminalInitialized)
{
+ TerminalInitialized = TRUE;
+
KdpDprintf("\x1b[7h"); /* Enable linewrap */
/* Query terminal type */
/*DbgPrint("\x1b[Z");*/
KdpDprintf("\x05");
- TerminalInitialized = TRUE;
Length = 0;
KeStallExecutionProcessor(100000);
@@ -3184,7 +2950,8 @@ KdbpPager(
/* Get number of rows and columns in terminal */
if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
- (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */
+ /* Refresh terminal size each time when number of rows printed is 0 */
+ (KdbNumberOfRowsPrinted) == 0)
{
if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize)
{
@@ -3235,36 +3002,45 @@ KdbpPager(
if (KdbNumberOfRowsTerminal <= 0)
{
- /* Set number of rows to the default. */
- KdbNumberOfRowsTerminal = 24;
+ /* Set number of rows to the default */
+ if (!DoPage)
+ KdbNumberOfRowsTerminal = 23; //Mna.: for SCREEN debugport
+ else
+ KdbNumberOfRowsTerminal = 24;
}
else if (KdbNumberOfColsTerminal <= 0)
{
- /* Set number of cols to the default. */
- KdbNumberOfColsTerminal = 80;
+ /* Set number of cols to the default */
+ if (!DoPage)
+ KdbNumberOfColsTerminal = 75; //Mna.: for SCREEN debugport
+ else
+ KdbNumberOfColsTerminal = 80;
}
}
- /* Get the string */
+ /* Loop through the strings */
p = Buffer;
-
while (p[0] != '\0')
{
- if ( p > Buffer+BufLength)
+ if (DoPage)
{
- KdpDprintf("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer+BufLength));
- return;
+ if (p > Buffer + BufLength)
+ {
+ KdpDprintf("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer + BufLength));
+ return;
+ }
}
i = strcspn(p, "\n");
- // Are we out of buffer?
- if (p + i > Buffer + BufLength)
- // Leaving pager function:
- break;
+ if (DoPage)
+ {
+ /* Are we out of buffer? */
+ if (p + i > Buffer + BufLength)
+ break; // Leaving pager function
+ }
- /* Calculate the number of lines which will be printed in the terminal
- * when outputting the current line.
- */
+ /* Calculate the number of lines which will be printed in
+ * the terminal when outputting the current line. */
if (i > 0)
RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal;
else
@@ -3273,7 +3049,7 @@ KdbpPager(
if (p[i] == '\n')
RowsPrintedByTerminal++;
- /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/
+ //KdpDprintf("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);
/* Display a prompt if we printed one screen full of text */
if (KdbNumberOfRowsTerminal > 0 &&
@@ -3284,7 +3060,14 @@ KdbpPager(
if (KdbNumberOfColsPrinted > 0)
KdpDprintf("\n");
- KdpDprintf("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---");
+ if (DoPage)
+ {
+ KdpDprintf("--- 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++;
if (KdbDebugState & KD_DEBUG_KDSERIAL)
@@ -3303,41 +3086,52 @@ KdbpPager(
c = KdbpTryGetCharKeyboard(&ScanCode, 5);
}
- //DbgPrint("\n"); //Consize version: don't show pressed key
- KdpDprintf(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key
-
- if (c == 'q')
- {
- KdbOutputAborted = TRUE;
- return;
- }
- if ( ScanCode == KEYSC_END || c=='e')
+ if (DoPage)
{
- PCHAR pBufEnd = Buffer + BufLength;
- p = CountOnePageUp(Buffer, BufLength, pBufEnd);
- i = strcspn(p, "\n");
+ //KdpDprintf("\n"); // Concise version: don't show pressed key
+ KdpDprintf(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key
}
- else if (ScanCode == KEYSC_PAGEUP || c=='u')
+ else
{
- p = CountOnePageUp(Buffer, BufLength, p);
- i = strcspn(p, "\n");
+ KdpDprintf("\n");
}
- else if (ScanCode == KEYSC_HOME || c=='h')
+
+ if (c == 'q')
{
- p = Buffer;
- i = strcspn(p, "\n");
+ KdbOutputAborted = TRUE;
+ return;
}
- else if (ScanCode == KEYSC_ARROWUP)
+
+ if (DoPage)
{
- p = CountOnePageUp(Buffer, BufLength, p);
- i = strcspn(p, "\n");
+ if (ScanCode == KEYSC_END || c == 'e')
+ {
+ PCHAR pBufEnd = Buffer + BufLength;
+ p = CountOnePageUp(Buffer, BufLength, pBufEnd);
+ i = strcspn(p, "\n");
+ }
+ else if (ScanCode == KEYSC_PAGEUP || c == 'u')
+ {
+ p = CountOnePageUp(Buffer, BufLength, p);
+ i = strcspn(p, "\n");
+ }
+ else if (ScanCode == KEYSC_HOME || c == 'h')
+ {
+ p = Buffer;
+ i = strcspn(p, "\n");
+ }
+ else if (ScanCode == KEYSC_ARROWUP)
+ {
+ p = CountOnePageUp(Buffer, BufLength, p);
+ i = strcspn(p, "\n");
+ }
}
KdbNumberOfRowsPrinted = 0;
KdbNumberOfColsPrinted = 0;
}
- /* Insert a NUL after the line and print only the current line. */
+ /* Insert a NUL after the line and print only the current line */
if (p[i] == '\n' && p[i + 1] != '\0')
{
c = p[i + 1];
@@ -3348,35 +3142,21 @@ KdbpPager(
c = '\0';
}
- /* Remove escape sequences from the line if there's no terminal connected */
+ /* Remove escape sequences from the line if there is no terminal connected */
+ // FIXME: Dangerous operation since we modify the source string!!
if (!TerminalConnected)
- {
- while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */
- {
- size_t len = strlen(p2);
- if (p2[1] == '[')
- {
- j = 2;
- while (!isalpha(p2[j++]));
- memmove(p2, p2 + j, len + 1 - j);
- }
- else
- {
- memmove(p2, p2 + 1, len);
- }
- }
- }
+ KdpFilterEscapes(p);
- // The main printing of the current line:
- KdpDprintf(p);
+ /* Print the current line */
+ // KdpDprintf(p);
+ KdpDprintf("%s", p);
- // restore not null char with saved:
+ /* Restore not null char with saved */
if (c != '\0')
p[i + 1] = c;
/* Set p to the start of the next line and
- * remember the number of rows/cols printed
- */
+ * remember the number of rows/cols printed */
p += i;
if (p[0] == '\n')
{
@@ -3393,6 +3173,78 @@ KdbpPager(
}
}
+/*!\brief Prints the given string with, page by page.
+ *
+ * \param Buffer Characters buffer to print.
+ * \param BufferLen Buffer size.
+ *
+ * \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.
+ *
+ * Note: BufLength should be greater then (KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal).
+ */
+VOID
+KdbpPager(
+ _In_ PCHAR Buffer,
+ _In_ ULONG BufLength)
+{
+ /* Call the internal function */
+ KdbpPagerInternal(Buffer, BufLength, TRUE);
+}
+
+/*!\brief Prints the given string with printf-like formatting.
+ *
+ * \param Format Format of the string/arguments.
+ * \param ... Variable number of arguments matching the format specified in \a Format.
+ *
+ * \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.
+ * Prints maximum 4096 chars, because of its buffer size.
+ */
+VOID
+KdbpPrint(
+ _In_ PSTR Format,
+ _In_ ...)
+{
+ static CHAR Buffer[4096];
+ ULONG Length;
+ va_list ap;
+
+ /* Check if the user has aborted output of the current command */
+ if (KdbOutputAborted)
+ return;
+
+ /* Build the string */
+ va_start(ap, Format);
+ Length = _vsnprintf(Buffer, sizeof(Buffer) - 1, Format, ap);
+ Buffer[Length] = '\0';
+ va_end(ap);
+
+ /* Actually print it */
+ KdbpPagerInternal(Buffer, Length, FALSE);
+}
+
+VOID
+KdbpPrintUnicodeString(
+ _In_ PCUNICODE_STRING String)
+{
+ ULONG i;
+
+ if ((String == NULL) || (String->Buffer == NULL))
+ {
+ KdbpPrint("<NULL>");
+ return;
+ }
+
+ for (i = 0; i < String->Length / sizeof(WCHAR); i++)
+ {
+ KdbpPrint("%c", (CHAR)String->Buffer[i]);
+ }
+}
+
+
/*!\brief Appends a command to the command history
*
* \param Command Pointer to the command to append to the history.