[NTOS:KDBG] Isolate terminal and input-related routines from the rest of KDBG. (#5188)

This is done in preparation for moving all this functionality in a
separate KDTERM "KD Terminal Driver" DLL.

Additionally:

- Flush the terminal input before sending ANSI escape sequences.

- In KDBG pager, always use the correct reading-key function (the
  same used also for reading keys for a line of user input), and not
  the simplistic two-call KdbpGetCharSerial + KdbpTryGetCharSerial
  that would split the \r \n across calls.

- Call KdbpGetCommandLineSettings() in KdbInitialize() at BootPhase 0,
  which is indirectly called by KdDebuggerInitialize0(). And fix its
  command-line parsing too.
This commit is contained in:
Hermès Bélusca-Maïto 2023-03-29 02:06:35 +02:00
parent 56bf3969cd
commit 35180b3ad2
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
9 changed files with 407 additions and 266 deletions

View file

@ -26,6 +26,11 @@ KdIoPrintf(
_In_ PCSTR Format,
...);
SIZE_T
KdIoReadLine(
_Out_ PCHAR Buffer,
_In_ SIZE_T Size);
/* INIT ROUTINES *************************************************************/

View file

@ -9,14 +9,42 @@
#include <ntoskrnl.h>
#include "kd.h"
#include "kdterminal.h"
#define NDEBUG
#include <debug.h>
/* PUBLIC FUNCTIONS *********************************************************/
static VOID
KdpGetTerminalSettings(
_In_ PCSTR p1)
{
#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
while (p1 && *p1)
{
/* Skip leading whitespace */
while (*p1 == ' ') ++p1;
if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
{
p1 += CONST_STR_LEN("KDSERIAL");
KdbDebugState |= KD_DEBUG_KDSERIAL;
KdpDebugMode.Serial = TRUE;
}
else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
{
p1 += CONST_STR_LEN("KDNOECHO");
KdbDebugState |= KD_DEBUG_KDNOECHO;
}
/* Move on to the next option */
p1 = strchr(p1, ' ');
}
}
static PCHAR
NTAPI
KdpGetDebugMode(
_In_ PCHAR Currentp2)
{
@ -95,10 +123,8 @@ KdDebuggerInitialize0(
/* Upcase it */
_strupr(CommandLine);
#ifdef KDBG
/* Get the KDBG Settings */
KdbpGetCommandLineSettings(CommandLine);
#endif
/* Get terminal settings */
KdpGetTerminalSettings(CommandLine);
/* Get the port */
Port = strstr(CommandLine, "DEBUGPORT");

View file

@ -36,72 +36,23 @@ KdIoReadLine(
PCHAR Orig = Buffer;
ULONG ScanCode = 0;
CHAR Key;
static CHAR NextKey = ANSI_NULL;
BOOLEAN EchoOn;
BOOLEAN EchoOn = !(KdbDebugState & KD_DEBUG_KDNOECHO);
LONG CmdHistIndex = -1; // Start at end of history.
/* Flush the input buffer */
KdpFlushTerminalInput();
/* Bail out if the buffer is zero-sized */
if (Size == 0)
return 0;
EchoOn = ((KdbDebugState & KD_DEBUG_KDNOECHO) == 0);
for (;;)
{
ScanCode = 0;
if (KdbDebugState & KD_DEBUG_KDSERIAL)
{
Key = (!NextKey ? KdbpGetCharSerial() : NextKey);
NextKey = ANSI_NULL;
if (Key == KEY_ESC) /* ESC */
{
Key = KdbpGetCharSerial();
if (Key == '[')
{
Key = KdbpGetCharSerial();
switch (Key)
{
case 'A':
ScanCode = KEY_SCAN_UP;
break;
case 'B':
ScanCode = KEY_SCAN_DOWN;
break;
case 'C':
break;
case 'D':
break;
}
}
}
}
else
{
Key = (!NextKey ? KdbpGetCharKeyboard(&ScanCode) : NextKey);
NextKey = ANSI_NULL;
}
Key = KdpReadTermKey(&ScanCode);
/* Check for return or newline */
if ((Key == '\r') || (Key == '\n'))
{
if (Key == '\r')
{
/*
* We might need to discard the next '\n' which most clients
* should send after \r. Wait a bit to make sure we receive it.
*/
KeStallExecutionProcessor(100000);
if (KdbDebugState & KD_DEBUG_KDSERIAL)
NextKey = KdbpTryGetCharSerial(5);
else
NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5);
if (NextKey == '\n' || NextKey == -1) /* \n or no response at all */
NextKey = ANSI_NULL;
}
*Buffer = ANSI_NULL;
KdIoPuts("\n");
return (SIZE_T)(Buffer - Orig);

276
ntoskrnl/kd/kdterminal.c Normal file
View file

@ -0,0 +1,276 @@
/*
* PROJECT: ReactOS KDBG Kernel Debugger Terminal Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: KD Terminal Management
* COPYRIGHT: Copyright 2005 Gregor Anich <blight@blight.eu.org>
* Copyright 2022-2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "kdterminal.h"
#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
CHAR
KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
#define KdbpGetCharSerial() KdbpTryGetCharSerial(0)
CHAR
KdbpTryGetCharSerial(
_In_ ULONG Retry);
VOID
KdbpSendCommandSerial(
_In_ PCSTR Command);
/* GLOBALS *******************************************************************/
/* KD Controlling Terminal */
ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
SIZE KdTermSize = {0,0};
BOOLEAN KdTermConnected = FALSE;
BOOLEAN KdTermSerial = FALSE;
BOOLEAN KdTermReportsSize = TRUE;
static CHAR KdTermNextKey = ANSI_NULL; /* 1-character input queue buffer */
/* FUNCTIONS *****************************************************************/
/**
* @brief Initializes the controlling terminal.
*
* @return
* TRUE if the controlling terminal is serial and detected
* as being connected, or FALSE if not.
**/
BOOLEAN
KdpInitTerminal(VOID)
{
/* Determine whether the controlling terminal is a serial terminal:
* serial output is enabled *and* KDSERIAL is set (i.e. user input
* through serial). */
KdTermSerial =
#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
/* Flush the input buffer */
KdpFlushTerminalInput();
if (KdTermSerial)
{
ULONG Length;
/* Enable line-wrap */
KdbpSendCommandSerial("\x1b[?7h");
/*
* 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.
*/
KdbpSendCommandSerial("\x1b[c");
KeStallExecutionProcessor(100000);
Length = 0;
for (;;)
{
/* Verify we get an answer, but don't care about it */
if (KdbpTryGetCharSerial(5000) == -1)
break;
++Length;
}
/* Terminal is connected (TRUE) or not connected (FALSE) */
KdTermConnected = (Length > 0);
}
else
{
/* Terminal is not serial, assume it's *not* connected */
KdTermConnected = FALSE;
}
return KdTermConnected;
}
BOOLEAN
KdpUpdateTerminalSize(
_Out_ PSIZE TermSize)
{
static CHAR Buffer[128];
CHAR c;
LONG NumberOfCols = -1; // Or initialize to TermSize->cx ??
LONG NumberOfRows = -1; // Or initialize to TermSize->cy ??
/* Retrieve the size of the controlling terminal only when it is serial */
if (KdTermConnected && KdTermSerial && KdTermReportsSize)
{
/* Flush the input buffer */
KdpFlushTerminalInput();
/* Try to query the terminal size. A reply looks like "\x1b[8;24;80t" */
KdTermReportsSize = FALSE;
KdbpSendCommandSerial("\x1b[18t");
KeStallExecutionProcessor(100000);
c = KdbpTryGetCharSerial(5000);
if (c == KEY_ESC)
{
c = KdbpTryGetCharSerial(5000);
if (c == '[')
{
ULONG Length = 0;
for (;;)
{
c = KdbpTryGetCharSerial(5000);
if (c == -1)
break;
Buffer[Length++] = c;
if (isalpha(c) || Length >= (sizeof(Buffer) - 1))
break;
}
Buffer[Length] = ANSI_NULL;
if (Buffer[0] == '8' && Buffer[1] == ';')
{
SIZE_T i;
for (i = 2; (i < Length) && (Buffer[i] != ';'); i++);
if (Buffer[i] == ';')
{
Buffer[i++] = ANSI_NULL;
/* Number of rows is now at Buffer + 2
* and number of columns at Buffer + i */
NumberOfRows = strtoul(Buffer + 2, NULL, 0);
NumberOfCols = strtoul(Buffer + i, NULL, 0);
KdTermReportsSize = TRUE;
}
}
}
/* Clear further characters */
while (KdbpTryGetCharSerial(5000) != -1);
}
}
if (NumberOfCols <= 0)
{
/* Set the number of columns to the default */
if (KdpDebugMode.Screen && !KdTermSerial)
NumberOfCols = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
else
NumberOfCols = 80;
}
if (NumberOfRows <= 0)
{
/* Set the number of rows to the default */
if (KdpDebugMode.Screen && !KdTermSerial)
NumberOfRows = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ + 1));
else
NumberOfRows = 24;
}
TermSize->cx = NumberOfCols;
TermSize->cy = NumberOfRows;
// KdIoPrintf("Cols/Rows: %dx%d\n", TermSize->cx, TermSize->cy);
return KdTermReportsSize;
}
/**
* @brief Flushes terminal input (either serial or PS/2).
**/
VOID
KdpFlushTerminalInput(VOID)
{
KdTermNextKey = ANSI_NULL;
if (KdbDebugState & KD_DEBUG_KDSERIAL)
{
while (KdbpTryGetCharSerial(1) != -1);
}
else
{
ULONG ScanCode;
while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
}
}
/**
* @brief
* Reads one character from the terminal. This function returns
* a scan code even when reading is done from a serial terminal.
**/
CHAR
KdpReadTermKey(
_Out_ PULONG ScanCode)
{
CHAR Key;
*ScanCode = 0;
if (KdbDebugState & KD_DEBUG_KDSERIAL)
{
Key = (!KdTermNextKey ? KdbpGetCharSerial() : KdTermNextKey);
KdTermNextKey = ANSI_NULL;
if (Key == KEY_ESC) /* ESC */
{
Key = KdbpGetCharSerial();
if (Key == '[')
{
Key = KdbpGetCharSerial();
switch (Key)
{
case 'A':
*ScanCode = KEY_SCAN_UP;
break;
case 'B':
*ScanCode = KEY_SCAN_DOWN;
break;
case 'C':
break;
case 'D':
break;
}
}
}
}
else
{
Key = (!KdTermNextKey ? KdbpGetCharKeyboard(ScanCode) : KdTermNextKey);
KdTermNextKey = ANSI_NULL;
}
/* Check for return */
if (Key == '\r')
{
/*
* We might need to discard the next '\n' which most clients
* should send after \r. Wait a bit to make sure we receive it.
*/
KeStallExecutionProcessor(100000);
if (KdbDebugState & KD_DEBUG_KDSERIAL)
KdTermNextKey = KdbpTryGetCharSerial(5);
else
KdTermNextKey = KdbpTryGetCharKeyboard(ScanCode, 5);
if (KdTermNextKey == '\n' || KdTermNextKey == -1) /* \n or no response at all */
KdTermNextKey = ANSI_NULL;
}
return Key;
}
/* EOF */

View file

@ -21,9 +21,40 @@
#define KEYSC_HOME 0x0047
#define KEYSC_ARROWUP 0x0048 // == KEY_SCAN_UP
SIZE_T
KdIoReadLine(
_Out_ PCHAR Buffer,
_In_ SIZE_T Size);
typedef struct _SIZE
{
LONG cx;
LONG cy;
} SIZE, *PSIZE;
/* KD Controlling Terminal */
/* These values MUST be nonzero, they're used as bit masks */
typedef enum _KDB_OUTPUT_SETTINGS
{
KD_DEBUG_KDSERIAL = 1,
KD_DEBUG_KDNOECHO = 2
} KDB_OUTPUT_SETTINGS;
extern ULONG KdbDebugState;
extern SIZE KdTermSize;
extern BOOLEAN KdTermConnected;
extern BOOLEAN KdTermSerial;
extern BOOLEAN KdTermReportsSize;
BOOLEAN
KdpInitTerminal(VOID);
BOOLEAN
KdpUpdateTerminalSize(
_Out_ PSIZE TermSize);
VOID
KdpFlushTerminalInput(VOID);
CHAR
KdpReadTermKey(
_Out_ PULONG ScanCode);
/* EOF */

View file

@ -49,7 +49,6 @@ static BOOLEAN KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleSte
LONG KdbLastBreakPointNr = -1; /* Index of the breakpoint which cause KDB to be entered */
ULONG KdbNumSingleSteps = 0; /* How many single steps to do */
BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */
ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered because of single step */
PEPROCESS KdbCurrentProcess = NULL; /* The current process context in which KDB runs */
PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered */
@ -1624,33 +1623,24 @@ continue_execution:
}
VOID
NTAPI
KdbpGetCommandLineSettings(
PCHAR p1)
_In_ PCSTR p1)
{
#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
while (p1 && (p1 = strchr(p1, ' ')))
while (p1 && *p1)
{
/* Skip other spaces */
/* Skip leading whitespace */
while (*p1 == ' ') ++p1;
if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
{
p1 += CONST_STR_LEN("KDSERIAL");
KdbDebugState |= KD_DEBUG_KDSERIAL;
KdpDebugMode.Serial = TRUE;
}
else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
{
p1 += CONST_STR_LEN("KDNOECHO");
KdbDebugState |= KD_DEBUG_KDNOECHO;
}
else if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
{
p1 += CONST_STR_LEN("FIRSTCHANCE");
KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
}
/* Move on to the next option */
p1 = strchr(p1, ' ');
}
}

View file

@ -51,12 +51,6 @@ typedef enum _KDB_ENTER_CONDITION
KdbEnterFromUmode
} KDB_ENTER_CONDITION;
/* These values MUST be nonzero. They're used as bit masks. */
typedef enum _KDB_OUTPUT_SETTINGS
{
KD_DEBUG_KDSERIAL = 1,
KD_DEBUG_KDNOECHO = 2
} KDB_OUTPUT_SETTINGS;
/* FUNCTIONS *****************************************************************/
@ -187,7 +181,6 @@ extern LONG KdbLastBreakPointNr;
extern ULONG KdbNumSingleSteps;
extern BOOLEAN KdbSingleStepOver;
extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
extern ULONG KdbDebugState;
LONG
KdbpGetNextBreakPointNr(
@ -252,8 +245,8 @@ KdbpAttachToProcess(
PVOID ProcessId);
VOID
NTAPI
KdbpGetCommandLineSettings(PCHAR p1);
KdbpGetCommandLineSettings(
_In_ PCSTR p1);
KD_CONTINUE_TYPE
KdbEnterDebuggerException(IN PEXCEPTION_RECORD64 ExceptionRecord,
@ -289,19 +282,6 @@ KdbpSafeWriteMemory(OUT PVOID Dest,
IN PVOID Src,
IN ULONG Bytes);
#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
CHAR
KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
#define KdbpGetCharSerial() KdbpTryGetCharSerial(0)
CHAR
KdbpTryGetCharSerial(
_In_ ULONG Retry);
VOID
KdbpSendCommandSerial(
_In_ PCSTR Command);
VOID
KbdDisableMouse(VOID);

View file

@ -131,8 +131,6 @@ static ULONG KdbNumberOfRowsPrinted = 0;
static ULONG KdbNumberOfColsPrinted = 0;
static BOOLEAN KdbOutputAborted = FALSE;
static BOOLEAN KdbRepeatLastCommand = FALSE;
static LONG KdbNumberOfRowsTerminal = -1;
static LONG KdbNumberOfColsTerminal = -1;
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
BOOLEAN KdbpBugCheckRequested = FALSE;
@ -2786,26 +2784,35 @@ memrchr(const void *s, int c, size_t n)
return NULL;
}
/*!\brief Calculate pointer position for N lines upper of current position.
/**
* @brief Calculate pointer position for N lines above the current position.
*
* \param Buffer Characters buffer to operate on.
* \param BufLength Buffer size.
* Calculate pointer position for N lines above the current displaying
* position within the given buffer. Used by KdbpPager().
*
* \note Calculate pointer position for N lines upper of current displaying
* position within the given buffer.
* @param[in] Buffer
* Character buffer to operate on.
*
* Used by KdbpPager().
* Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
*/
* @param[in] BufLength
* Size of the buffer.
*
* @param[in] pCurPos
* Current position within the buffer.
*
* @return Beginning of the previous page of text.
*
* @note N lines count is hardcoded to the terminal's number of rows.
**/
static PCHAR
CountOnePageUp(
_In_ PCCH Buffer,
_In_ ULONG BufLength,
_In_ PCCH pCurPos)
_In_ PCCH pCurPos,
_In_ const SIZE* TermSize)
{
PCCH p;
// p0 is initial guess of Page Start
ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
ULONG p0len = TermSize->cx * TermSize->cy;
PCCH p0 = pCurPos - p0len;
PCCH prev_p = p0, p1;
ULONG j;
@ -2817,7 +2824,7 @@ CountOnePageUp(
p = memrchr(p0, '\n', p0len);
if (!p)
p = p0;
for (j = KdbNumberOfRowsTerminal; j--; )
for (j = TermSize->cy; j--; )
{
int linesCnt;
p1 = memrchr(p0, '\n', p-p0);
@ -2830,7 +2837,7 @@ CountOnePageUp(
p = p0;
break;
}
linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
linesCnt = (TermSize->cx+prev_p-p-2) / TermSize->cx;
if (linesCnt > 1)
j -= linesCnt-1;
}
@ -2874,27 +2881,23 @@ KdpFilterEscapes(
* 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).
* Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
VOID
static VOID
KdbpPagerInternal(
_In_ PCHAR Buffer,
_In_ ULONG BufLength,
_In_ BOOLEAN DoPage)
{
static CHAR InBuffer[128];
static BOOLEAN TerminalInitialized = FALSE;
static BOOLEAN TerminalConnected = FALSE;
static BOOLEAN TerminalReportsSize = TRUE;
CHAR c;
ULONG ScanCode;
PCHAR p;
ULONG Length;
SIZE_T i;
LONG RowsPrintedByTerminal;
if (BufLength == 0)
return;
return;
/* Check if the user has aborted output of the current command */
if (KdbOutputAborted)
@ -2904,117 +2907,13 @@ KdbpPagerInternal(
if (!TerminalInitialized)
{
TerminalInitialized = TRUE;
/* Enable line-wrap */
KdbpSendCommandSerial("\x1b[?7h");
/*
* 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.
*/
KdbpSendCommandSerial("\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;
++Length;
}
if (Length > 0)
TerminalConnected = TRUE;
KdpInitTerminal();
}
/* Get number of rows and columns in terminal */
if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
/* Refresh terminal size each time when number of rows printed is 0 */
(KdbNumberOfRowsPrinted) == 0)
/* Refresh terminal size each time when number of rows printed is 0 */
if (KdbNumberOfRowsPrinted == 0)
{
/* 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;
KdbpSendCommandSerial("\x1b[18t");
KeStallExecutionProcessor(100000);
c = KdbpTryGetCharSerial(5000);
if (c == KEY_ESC)
{
c = KdbpTryGetCharSerial(5000);
if (c == '[')
{
Length = 0;
for (;;)
{
c = KdbpTryGetCharSerial(5000);
if (c == -1)
break;
InBuffer[Length++] = c;
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 (InBuffer[i] == ';')
{
InBuffer[i++] = '\0';
/* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */
KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0);
KdbNumberOfColsTerminal = strtoul(InBuffer + i, NULL, 0);
TerminalReportsSize = TRUE;
}
}
}
/* Clear further characters */
while ((c = KdbpTryGetCharSerial(5000)) != -1);
}
}
if (KdbNumberOfRowsTerminal <= 0)
{
/* Set number of rows to the default */
if (KdpDebugMode.Screen && !SerialTerminal)
KdbNumberOfRowsTerminal = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ + 1));
else
KdbNumberOfRowsTerminal = 24;
}
if (KdbNumberOfColsTerminal <= 0)
{
/* Set number of cols to the default */
if (KdpDebugMode.Screen && !SerialTerminal)
KdbNumberOfColsTerminal = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
else
KdbNumberOfColsTerminal = 80;
}
// KdpDprintf("Cols/Rows: %dx%d\n",
// KdbNumberOfColsTerminal, KdbNumberOfRowsTerminal);
KdpUpdateTerminalSize(&KdTermSize);
}
/* Loop through the strings */
@ -3041,7 +2940,7 @@ KdbpPagerInternal(
/* 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;
RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdTermSize.cx;
else
RowsPrintedByTerminal = 0;
@ -3051,9 +2950,10 @@ KdbpPagerInternal(
//KdpDprintf("!%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)
if (KdTermSize.cy > 0 &&
(LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdTermSize.cy)
{
/* Disable the repetition of previous command with long many-page output */
KdbRepeatLastCommand = FALSE;
if (KdbNumberOfColsPrinted > 0)
@ -3069,21 +2969,7 @@ KdbpPagerInternal(
}
RowsPrintedByTerminal++;
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);
}
c = KdpReadTermKey(&ScanCode);
if (DoPage)
{
@ -3106,13 +2992,13 @@ KdbpPagerInternal(
if (ScanCode == KEYSC_END || c == 'e')
{
PCHAR pBufEnd = Buffer + BufLength;
p = CountOnePageUp(Buffer, BufLength, pBufEnd);
p = CountOnePageUp(Buffer, BufLength, pBufEnd, &KdTermSize);
i = strcspn(p, "\n");
}
else if (ScanCode == KEYSC_PAGEUP ||
ScanCode == KEYSC_ARROWUP || c == 'u')
{
p = CountOnePageUp(Buffer, BufLength, p);
p = CountOnePageUp(Buffer, BufLength, p, &KdTermSize);
i = strcspn(p, "\n");
}
else if (ScanCode == KEYSC_HOME || c == 'h')
@ -3139,11 +3025,10 @@ KdbpPagerInternal(
/* Remove escape sequences from the line if there is no terminal connected */
// FIXME: Dangerous operation since we modify the source string!!
if (!TerminalConnected)
if (!KdTermConnected)
KdpFilterEscapes(p);
/* Print the current line */
// KdpDprintf(p);
KdpDprintf("%s", p);
/* Restore not null char with saved */
@ -3178,7 +3063,7 @@ KdbpPagerInternal(
* 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).
* Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
*/
VOID
KdbpPager(
@ -3408,17 +3293,6 @@ KdbpCliMainLoop(
KdbpPrint("\n");
}
/* Flush the input buffer */
if (KdbDebugState & KD_DEBUG_KDSERIAL)
{
while (KdbpTryGetCharSerial(1) != -1);
}
else
{
ULONG ScanCode;
while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
}
/* Main loop */
do
{
@ -3687,6 +3561,13 @@ KdbInitialize(
/* Write out the functions that we support for now */
DispatchTable->KdpPrintRoutine = KdbDebugPrint;
/* Check if we have a command line */
if (KeLoaderBlock && KeLoaderBlock->LoadOptions)
{
/* Get the KDBG Settings */
KdbpGetCommandLineSettings(KeLoaderBlock->LoadOptions);
}
/* Register for BootPhase 1 initialization and as a Provider */
DispatchTable->KdpInitRoutine = KdbInitialize;
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);

View file

@ -415,7 +415,8 @@ if(NOT _WINKD_)
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdmain.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdprompt.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdps2kbd.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c)
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdterminal.c)
else()
add_definitions(-D_WINKD_)