mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
[NTOSKRNL]
Minas Abrahamyan (minas \dot/ subs \at/ gmail \dot/ com): - Allow to view already shown, logged debug messages on the screen (bug #6018). svn path=/trunk/; revision=52556
This commit is contained in:
parent
5b90950500
commit
e462a7a6d3
2 changed files with 535 additions and 5 deletions
|
@ -33,7 +33,15 @@ ULONG KdpPort;
|
|||
CHAR KdpScreenLineBuffer[KdpScreenLineLenght + 1] = "";
|
||||
ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
|
||||
|
||||
/* DEBUG LOG FUNCTIONS *******************************************************/
|
||||
const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024;
|
||||
PCHAR KdpDmesgBuffer = NULL;
|
||||
volatile ULONG KdpDmesgCurrentPosition = 0;
|
||||
volatile ULONG KdpDmesgFreeBytes = 0;
|
||||
volatile ULONG KdbDmesgTotalWritten = 0;
|
||||
KSPIN_LOCK KdpDmesgLogSpinLock;
|
||||
extern volatile BOOLEAN KdbpIsInDmesgMode;
|
||||
|
||||
/* FILE DEBUG LOG FUNCTIONS **************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
|
@ -49,8 +57,14 @@ KdpLoggerThread(PVOID Context)
|
|||
KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
|
||||
|
||||
/* Bug */
|
||||
/* Keep KdpCurrentPosition and KdpFreeBytes values in local
|
||||
* variables to avoid their possible change from Producer part,
|
||||
* KdpPrintToLogFile function
|
||||
*/
|
||||
end = KdpCurrentPosition;
|
||||
num = KdpFreeBytes;
|
||||
|
||||
/* Now securely calculate values, based on local variables */
|
||||
beg = (end + num) % KdpBufferSize;
|
||||
num = KdpBufferSize - num;
|
||||
|
||||
|
@ -148,6 +162,7 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
|
|||
IO_STATUS_BLOCK Iosb;
|
||||
HANDLE ThreadHandle;
|
||||
KPRIORITY Priority;
|
||||
SIZE_T MemSizeMBs;
|
||||
|
||||
if (!KdpDebugMode.File) return;
|
||||
|
||||
|
@ -175,6 +190,8 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
|
|||
/* Display separator + ReactOS version at start of the debug log */
|
||||
DPRINT1("---------------------------------------------------------------\n");
|
||||
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
|
||||
MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
|
||||
DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
|
||||
}
|
||||
else if (BootPhase == 2)
|
||||
{
|
||||
|
@ -276,6 +293,7 @@ NTAPI
|
|||
KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||
ULONG BootPhase)
|
||||
{
|
||||
SIZE_T MemSizeMBs;
|
||||
if (!KdpDebugMode.Serial) return;
|
||||
|
||||
if (BootPhase == 0)
|
||||
|
@ -301,6 +319,8 @@ KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
|||
/* Display separator + ReactOS version at start of the debug log */
|
||||
DPRINT1("-----------------------------------------------------\n");
|
||||
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
|
||||
MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
|
||||
DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
|
||||
DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
|
||||
DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
|
||||
KeLoaderBlock->NtHalPathName,
|
||||
|
@ -315,11 +335,19 @@ KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
|||
|
||||
/* SCREEN FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* Screen debug logger function KdpScreenPrint() writes text messages into
|
||||
* KdpDmesgBuffer, using it as a circular buffer. KdpDmesgBuffer contents could
|
||||
* be later (re)viewed using dmesg command of kdbg. KdpScreenPrint() protects
|
||||
* KdpDmesgBuffer from simultaneous writes by use of KdpDmesgLogSpinLock.
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
KdpScreenPrint(LPSTR Message,
|
||||
ULONG Length)
|
||||
{
|
||||
ULONG beg, end, num;
|
||||
KIRQL OldIrql;
|
||||
PCHAR pch = (PCHAR) Message;
|
||||
|
||||
while (*pch)
|
||||
|
@ -354,16 +382,74 @@ KdpScreenPrint(LPSTR Message,
|
|||
KdpScreenLineBuffer[0] = '\0';
|
||||
KdpScreenLineLength = KdpScreenLineBufferPos = 0;
|
||||
}
|
||||
|
||||
|
||||
++pch;
|
||||
}
|
||||
|
||||
|
||||
/* Print buffered characters */
|
||||
if(KdpScreenLineBufferPos != KdpScreenLineLength)
|
||||
{
|
||||
HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
|
||||
KdpScreenLineBufferPos = KdpScreenLineLength;
|
||||
}
|
||||
|
||||
/* Dmesg: store Message in the buffer to show it later */
|
||||
if (KdbpIsInDmesgMode)
|
||||
return;
|
||||
|
||||
if (KdpDmesgBuffer == NULL)
|
||||
return;
|
||||
|
||||
/* Acquire the printing spinlock without waiting at raised IRQL */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Wait when the spinlock becomes available */
|
||||
while (!KeTestSpinLock(&KdpDmesgLogSpinLock));
|
||||
|
||||
/* Spinlock was free, raise IRQL */
|
||||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||||
|
||||
/* Try to get the spinlock */
|
||||
if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDmesgLogSpinLock))
|
||||
break;
|
||||
|
||||
/* Someone else got the spinlock, lower IRQL back */
|
||||
KeLowerIrql(OldIrql);
|
||||
}
|
||||
|
||||
/* Invariant: always_true(KdpDmesgFreeBytes == KdpDmesgBufferSize);
|
||||
* set num to min(KdpDmesgFreeBytes, Length).
|
||||
*/
|
||||
num = (Length < KdpDmesgFreeBytes) ? Length : KdpDmesgFreeBytes;
|
||||
beg = KdpDmesgCurrentPosition;
|
||||
if (num != 0)
|
||||
{
|
||||
end = (beg + num) % KdpDmesgBufferSize;
|
||||
if (end > beg)
|
||||
{
|
||||
RtlCopyMemory(KdpDmesgBuffer + beg, Message, Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlCopyMemory(KdpDmesgBuffer + beg, Message, KdpDmesgBufferSize - beg);
|
||||
RtlCopyMemory(KdpDmesgBuffer, Message + (KdpDmesgBufferSize - beg), end);
|
||||
}
|
||||
KdpDmesgCurrentPosition = end;
|
||||
|
||||
/* Counting the total bytes written */
|
||||
KdbDmesgTotalWritten += num;
|
||||
}
|
||||
|
||||
/* Release spinlock */
|
||||
KiReleaseSpinLock(&KdpDmesgLogSpinLock);
|
||||
|
||||
/* Lower IRQL */
|
||||
KeLowerIrql(OldIrql);
|
||||
|
||||
/* Optional step(?): find out a way to notify about buffer exhaustion,
|
||||
* and possibly fall into kbd to use dmesg command: user will read
|
||||
* debug messages before they will be wiped over by next writes.
|
||||
*/
|
||||
}
|
||||
|
||||
VOID
|
||||
|
@ -371,6 +457,7 @@ NTAPI
|
|||
KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||
ULONG BootPhase)
|
||||
{
|
||||
SIZE_T MemSizeMBs;
|
||||
if (!KdpDebugMode.Screen) return;
|
||||
|
||||
if (BootPhase == 0)
|
||||
|
@ -382,6 +469,30 @@ KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
|||
/* Register as a Provider */
|
||||
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
||||
}
|
||||
else if (BootPhase == 1)
|
||||
{
|
||||
/* Allocate a buffer for dmesg log buffer. +1 for terminating null,
|
||||
* see kdbp_cli.c:KdbpCmdDmesg()/2
|
||||
*/
|
||||
KdpDmesgBuffer = ExAllocatePool(NonPagedPool, KdpDmesgBufferSize + 1);
|
||||
RtlZeroMemory(KdpDmesgBuffer, KdpDmesgBufferSize + 1);
|
||||
KdpDmesgFreeBytes = KdpDmesgBufferSize;
|
||||
KdbDmesgTotalWritten = 0;
|
||||
|
||||
/* Initialize spinlock */
|
||||
KeInitializeSpinLock(&KdpDmesgLogSpinLock);
|
||||
|
||||
/* Display separator + ReactOS version at start of the debug log */
|
||||
DPRINT1("-----------------------------------------------------\n");
|
||||
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
|
||||
MemSizeMBs = MmNumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
|
||||
DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
|
||||
DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
|
||||
DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
|
||||
KeLoaderBlock->NtHalPathName,
|
||||
KeLoaderBlock->ArcHalDeviceName,
|
||||
KeLoaderBlock->NtBootPathName);
|
||||
}
|
||||
else if (BootPhase == 2)
|
||||
{
|
||||
HalDisplayString("\n Screen debugging enabled\n\n");
|
||||
|
|
|
@ -42,6 +42,13 @@
|
|||
#define KEY_SCAN_UP 72
|
||||
#define KEY_SCAN_DOWN 80
|
||||
|
||||
/* Scan codes of keyboard keys: */
|
||||
#define KEYSC_END 0x004f
|
||||
#define KEYSC_PAGEUP 0x0049
|
||||
#define KEYSC_PAGEDOWN 0x0051
|
||||
#define KEYSC_HOME 0x0047
|
||||
#define KEYSC_ARROWUP 0x0048
|
||||
|
||||
#define KDB_ENTER_CONDITION_TO_STRING(cond) \
|
||||
((cond) == KdbDoNotEnter ? "never" : \
|
||||
((cond) == KdbEnterAlways ? "always" : \
|
||||
|
@ -81,6 +88,7 @@ static BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]);
|
|||
static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]);
|
||||
static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]);
|
||||
static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);
|
||||
static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]);
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
|
@ -101,6 +109,17 @@ static LONG KdbNumberOfColsTerminal = -1;
|
|||
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
|
||||
BOOLEAN KdbpBugCheckRequested = FALSE;
|
||||
|
||||
/* Vars for dmesg */
|
||||
/* defined here, used in ../kd/kdio.c: */
|
||||
volatile BOOLEAN KdbpIsInDmesgMode = FALSE;
|
||||
|
||||
/* defined in ../kd/kdio.c, declare here: */
|
||||
extern const ULONG KdpDmesgBufferSize;
|
||||
extern PCHAR KdpDmesgBuffer;
|
||||
extern volatile ULONG KdpDmesgCurrentPosition;
|
||||
extern volatile ULONG KdpDmesgFreeBytes;
|
||||
extern volatile ULONG KdbDmesgTotalWritten;
|
||||
|
||||
static const struct
|
||||
{
|
||||
PCHAR Name;
|
||||
|
@ -150,6 +169,8 @@ static const struct
|
|||
{ "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck },
|
||||
{ "filter", "filter [error|warning|trace|info|level]+|-[componentname|default]", "Enable/disable debug channels", KdbpCmdFilter },
|
||||
{ "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet },
|
||||
{ "dmesg", "dmesg", "Display debug messages on screen, with navigation on pages.", KdbpCmdDmesg },
|
||||
{ "kmsg", "kmsg", "Kernel dmesg. Alias for dmesg.", KdbpCmdDmesg },
|
||||
{ "help", "help", "Display help screen.", KdbpCmdHelp }
|
||||
};
|
||||
|
||||
|
@ -1895,6 +1916,58 @@ KdbpCmdBugCheck(
|
|||
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,
|
||||
* all others are as PageDown.
|
||||
*/
|
||||
static BOOLEAN
|
||||
KdbpCmdDmesg(
|
||||
ULONG Argc,
|
||||
PCHAR Argv[])
|
||||
{
|
||||
ULONG beg, end;
|
||||
|
||||
KdbpIsInDmesgMode = TRUE; /* Toggle logging flag */
|
||||
if (!KdpDmesgBuffer)
|
||||
{
|
||||
KdbpPrint("Dmesg: error, buffer is not allocated! /DEBUGPORT=SCREEN kernel param required for dmesg.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
KdbpPrint("*** Dmesg *** TotalWritten=%lu, BufferSize=%lu, CurrentPosition=%lu\n",
|
||||
KdbDmesgTotalWritten, KdpDmesgBufferSize, KdpDmesgCurrentPosition);
|
||||
|
||||
// Pass data to the pager:
|
||||
end = KdpDmesgCurrentPosition;
|
||||
beg = (end + KdpDmesgFreeBytes) % KdpDmesgBufferSize;
|
||||
|
||||
// no roll-overs, and overwritten=lost bytes
|
||||
if (KdbDmesgTotalWritten <= KdpDmesgBufferSize)
|
||||
{
|
||||
// show buffer (KdpDmesgBuffer + beg, num)
|
||||
KdbpPager(KdpDmesgBuffer, KdpDmesgCurrentPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// show 2 buffers: (KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg)
|
||||
// and: (KdpDmesgBuffer, end)
|
||||
KdbpPager(KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg);
|
||||
KdbpPrint("*** Dmesg: buffer rollup ***\n");
|
||||
KdbpPager(KdpDmesgBuffer, end);
|
||||
}
|
||||
KdbpPrint("*** Dmesg: end of output ***\n");
|
||||
|
||||
KdbpIsInDmesgMode = FALSE; /* Toggle logging flag */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*!\brief Sets or displays a config variables value.
|
||||
*/
|
||||
static BOOLEAN
|
||||
|
@ -2110,6 +2183,7 @@ KdbpCmdHelp(
|
|||
*
|
||||
* \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(
|
||||
|
@ -2215,12 +2289,12 @@ KdbpPrint(
|
|||
if (KdbNumberOfRowsTerminal <= 0)
|
||||
{
|
||||
/* Set number of rows to the default. */
|
||||
KdbNumberOfRowsTerminal = 24;
|
||||
KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport
|
||||
}
|
||||
else if (KdbNumberOfColsTerminal <= 0)
|
||||
{
|
||||
/* Set number of cols to the default. */
|
||||
KdbNumberOfColsTerminal = 80;
|
||||
KdbNumberOfColsTerminal = 75; //80; //Mna.: 75 for SCREEN debugport
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2256,6 +2330,7 @@ KdbpPrint(
|
|||
DbgPrint("\n");
|
||||
|
||||
DbgPrint("--- Press q to abort, any other key to continue ---");
|
||||
RowsPrintedByTerminal++; /* added by Mna. */
|
||||
|
||||
if (KdbDebugState & KD_DEBUG_KDSERIAL)
|
||||
c = KdbpGetCharSerial();
|
||||
|
@ -2337,6 +2412,350 @@ KdbpPrint(
|
|||
}
|
||||
}
|
||||
|
||||
/** memrchr(), explicitly defined, since was absent in MinGW of RosBE. */
|
||||
/*
|
||||
* Reverse memchr()
|
||||
* Find the last occurrence of 'c' in the buffer 's' of size 'n'.
|
||||
*/
|
||||
void *
|
||||
memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
const unsigned char *cp;
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
cp = (unsigned char *)s + n;
|
||||
do
|
||||
{
|
||||
if (*(--cp) == (unsigned char)c)
|
||||
return (void *)cp;
|
||||
} while (--n != 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!\brief Calculate pointer position for N lines upper of current position.
|
||||
*
|
||||
* \param Buffer Characters buffer to operate on.
|
||||
* \param BufLength Buffer size.
|
||||
*
|
||||
* \note Calculate pointer position for N lines upper of current displaying
|
||||
* position within the given buffer.
|
||||
*
|
||||
* Used by KdbpPager().
|
||||
* Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
|
||||
*/
|
||||
PCHAR
|
||||
CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
|
||||
{
|
||||
PCHAR p;
|
||||
// p0 is initial guess of Page Start
|
||||
ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
|
||||
PCHAR p0 = pCurPos - p0len;
|
||||
PCHAR prev_p = p0, p1;
|
||||
ULONG j;
|
||||
|
||||
if (pCurPos < Buffer)
|
||||
pCurPos = Buffer;
|
||||
ASSERT(pCurPos <= Buffer + BufLength);
|
||||
|
||||
p = memrchr(p0, '\n', p0len);
|
||||
if (NULL == p)
|
||||
p = p0;
|
||||
for (j = KdbNumberOfRowsTerminal; j--; )
|
||||
{
|
||||
p1 = memrchr(p0, '\n', p-p0);
|
||||
prev_p = p;
|
||||
p = p1;
|
||||
if (NULL == p)
|
||||
{
|
||||
p = prev_p;
|
||||
if (NULL == p)
|
||||
p = p0;
|
||||
break;
|
||||
}
|
||||
int linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
|
||||
if (linesCnt > 1)
|
||||
j -= linesCnt-1;
|
||||
}
|
||||
|
||||
ASSERT(p != 0);
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*!\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.
|
||||
*
|
||||
* Note: BufLength should be greater then (KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal).
|
||||
*
|
||||
*/
|
||||
VOID
|
||||
KdbpPager(
|
||||
IN PCHAR Buffer,
|
||||
IN ULONG BufLength)
|
||||
{
|
||||
static CHAR InBuffer[4096];
|
||||
static BOOLEAN TerminalInitialized = FALSE;
|
||||
static BOOLEAN TerminalConnected = FALSE;
|
||||
static BOOLEAN TerminalReportsSize = TRUE;
|
||||
CHAR c = '\0';
|
||||
PCHAR p, p2;
|
||||
ULONG Length;
|
||||
ULONG i, j;
|
||||
LONG RowsPrintedByTerminal;
|
||||
ULONG ScanCode;
|
||||
|
||||
if( BufLength == 0)
|
||||
return;
|
||||
|
||||
/* Check if the user has aborted output of the current command */
|
||||
if (KdbOutputAborted)
|
||||
return;
|
||||
|
||||
/* Initialize the terminal */
|
||||
if (!TerminalInitialized)
|
||||
{
|
||||
DbgPrint("\x1b[7h"); /* Enable linewrap */
|
||||
|
||||
/* Query terminal type */
|
||||
/*DbgPrint("\x1b[Z");*/
|
||||
DbgPrint("\x05");
|
||||
|
||||
TerminalInitialized = TRUE;
|
||||
Length = 0;
|
||||
KeStallExecutionProcessor(100000);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
c = KdbpTryGetCharSerial(5000);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
InBuffer[Length++] = c;
|
||||
if (Length >= (sizeof (InBuffer) - 1))
|
||||
break;
|
||||
}
|
||||
|
||||
InBuffer[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);
|
||||
DbgPrint("\x1b[18t");
|
||||
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 (Buffer[i] == ';')
|
||||
{
|
||||
Buffer[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. */
|
||||
KdbNumberOfRowsTerminal = 24;
|
||||
}
|
||||
else if (KdbNumberOfColsTerminal <= 0)
|
||||
{
|
||||
/* Set number of cols to the default. */
|
||||
KdbNumberOfColsTerminal = 80;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the string */
|
||||
p = Buffer;
|
||||
|
||||
while (p[0] != '\0')
|
||||
{
|
||||
if ( p > Buffer+BufLength)
|
||||
{
|
||||
DbgPrint("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;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (KdbNumberOfColsPrinted > 0)
|
||||
DbgPrint("\n");
|
||||
|
||||
DbgPrint("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---");
|
||||
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);
|
||||
}
|
||||
|
||||
//DbgPrint("\n"); //Consize version: don't show pressed key
|
||||
DbgPrint(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key
|
||||
|
||||
if (c == 'q')
|
||||
{
|
||||
KdbOutputAborted = TRUE;
|
||||
return;
|
||||
}
|
||||
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. */
|
||||
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 */
|
||||
{
|
||||
if (p2[1] == '[')
|
||||
{
|
||||
j = 2;
|
||||
while (!isalpha(p2[j++]));
|
||||
strcpy(p2, p2 + j);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(p2, p2 + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The main printing of the current line:
|
||||
DbgPrint(p);
|
||||
|
||||
// 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
|
||||
*/
|
||||
p += i;
|
||||
if (p[0] == '\n')
|
||||
{
|
||||
p++;
|
||||
KdbNumberOfColsPrinted = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(p[0] == '\0');
|
||||
KdbNumberOfColsPrinted += i;
|
||||
}
|
||||
|
||||
KdbNumberOfRowsPrinted += RowsPrintedByTerminal;
|
||||
}
|
||||
}
|
||||
|
||||
/*!\brief Appends a command to the command history
|
||||
*
|
||||
* \param Command Pointer to the command to append to the history.
|
||||
|
|
Loading…
Reference in a new issue