mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[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:
parent
56bf3969cd
commit
35180b3ad2
9 changed files with 407 additions and 266 deletions
|
@ -26,6 +26,11 @@ KdIoPrintf(
|
|||
_In_ PCSTR Format,
|
||||
...);
|
||||
|
||||
SIZE_T
|
||||
KdIoReadLine(
|
||||
_Out_ PCHAR Buffer,
|
||||
_In_ SIZE_T Size);
|
||||
|
||||
|
||||
/* INIT ROUTINES *************************************************************/
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
276
ntoskrnl/kd/kdterminal.c
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_)
|
||||
|
|
Loading…
Reference in a new issue