mirror of
https://github.com/reactos/reactos.git
synced 2024-12-31 19:42:51 +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] = "";
|
CHAR KdpScreenLineBuffer[KdpScreenLineLenght + 1] = "";
|
||||||
ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
|
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -49,8 +57,14 @@ KdpLoggerThread(PVOID Context)
|
||||||
KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
|
KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
|
||||||
|
|
||||||
/* Bug */
|
/* Bug */
|
||||||
|
/* Keep KdpCurrentPosition and KdpFreeBytes values in local
|
||||||
|
* variables to avoid their possible change from Producer part,
|
||||||
|
* KdpPrintToLogFile function
|
||||||
|
*/
|
||||||
end = KdpCurrentPosition;
|
end = KdpCurrentPosition;
|
||||||
num = KdpFreeBytes;
|
num = KdpFreeBytes;
|
||||||
|
|
||||||
|
/* Now securely calculate values, based on local variables */
|
||||||
beg = (end + num) % KdpBufferSize;
|
beg = (end + num) % KdpBufferSize;
|
||||||
num = KdpBufferSize - num;
|
num = KdpBufferSize - num;
|
||||||
|
|
||||||
|
@ -148,6 +162,7 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
IO_STATUS_BLOCK Iosb;
|
IO_STATUS_BLOCK Iosb;
|
||||||
HANDLE ThreadHandle;
|
HANDLE ThreadHandle;
|
||||||
KPRIORITY Priority;
|
KPRIORITY Priority;
|
||||||
|
SIZE_T MemSizeMBs;
|
||||||
|
|
||||||
if (!KdpDebugMode.File) return;
|
if (!KdpDebugMode.File) return;
|
||||||
|
|
||||||
|
@ -175,6 +190,8 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
/* Display separator + ReactOS version at start of the debug log */
|
/* Display separator + ReactOS version at start of the debug log */
|
||||||
DPRINT1("---------------------------------------------------------------\n");
|
DPRINT1("---------------------------------------------------------------\n");
|
||||||
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\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)
|
else if (BootPhase == 2)
|
||||||
{
|
{
|
||||||
|
@ -276,6 +293,7 @@ NTAPI
|
||||||
KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
ULONG BootPhase)
|
ULONG BootPhase)
|
||||||
{
|
{
|
||||||
|
SIZE_T MemSizeMBs;
|
||||||
if (!KdpDebugMode.Serial) return;
|
if (!KdpDebugMode.Serial) return;
|
||||||
|
|
||||||
if (BootPhase == 0)
|
if (BootPhase == 0)
|
||||||
|
@ -301,6 +319,8 @@ KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
/* Display separator + ReactOS version at start of the debug log */
|
/* Display separator + ReactOS version at start of the debug log */
|
||||||
DPRINT1("-----------------------------------------------------\n");
|
DPRINT1("-----------------------------------------------------\n");
|
||||||
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\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("Command Line: %s\n", KeLoaderBlock->LoadOptions);
|
||||||
DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
|
DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
|
||||||
KeLoaderBlock->NtHalPathName,
|
KeLoaderBlock->NtHalPathName,
|
||||||
|
@ -315,11 +335,19 @@ KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
|
|
||||||
/* SCREEN FUNCTIONS **********************************************************/
|
/* 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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
KdpScreenPrint(LPSTR Message,
|
KdpScreenPrint(LPSTR Message,
|
||||||
ULONG Length)
|
ULONG Length)
|
||||||
{
|
{
|
||||||
|
ULONG beg, end, num;
|
||||||
|
KIRQL OldIrql;
|
||||||
PCHAR pch = (PCHAR) Message;
|
PCHAR pch = (PCHAR) Message;
|
||||||
|
|
||||||
while (*pch)
|
while (*pch)
|
||||||
|
@ -354,16 +382,74 @@ KdpScreenPrint(LPSTR Message,
|
||||||
KdpScreenLineBuffer[0] = '\0';
|
KdpScreenLineBuffer[0] = '\0';
|
||||||
KdpScreenLineLength = KdpScreenLineBufferPos = 0;
|
KdpScreenLineLength = KdpScreenLineBufferPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++pch;
|
++pch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print buffered characters */
|
/* Print buffered characters */
|
||||||
if(KdpScreenLineBufferPos != KdpScreenLineLength)
|
if(KdpScreenLineBufferPos != KdpScreenLineLength)
|
||||||
{
|
{
|
||||||
HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
|
HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
|
||||||
KdpScreenLineBufferPos = KdpScreenLineLength;
|
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
|
VOID
|
||||||
|
@ -371,6 +457,7 @@ NTAPI
|
||||||
KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
ULONG BootPhase)
|
ULONG BootPhase)
|
||||||
{
|
{
|
||||||
|
SIZE_T MemSizeMBs;
|
||||||
if (!KdpDebugMode.Screen) return;
|
if (!KdpDebugMode.Screen) return;
|
||||||
|
|
||||||
if (BootPhase == 0)
|
if (BootPhase == 0)
|
||||||
|
@ -382,6 +469,30 @@ KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
||||||
/* Register as a Provider */
|
/* Register as a Provider */
|
||||||
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
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)
|
else if (BootPhase == 2)
|
||||||
{
|
{
|
||||||
HalDisplayString("\n Screen debugging enabled\n\n");
|
HalDisplayString("\n Screen debugging enabled\n\n");
|
||||||
|
|
|
@ -42,6 +42,13 @@
|
||||||
#define KEY_SCAN_UP 72
|
#define KEY_SCAN_UP 72
|
||||||
#define KEY_SCAN_DOWN 80
|
#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) \
|
#define KDB_ENTER_CONDITION_TO_STRING(cond) \
|
||||||
((cond) == KdbDoNotEnter ? "never" : \
|
((cond) == KdbDoNotEnter ? "never" : \
|
||||||
((cond) == KdbEnterAlways ? "always" : \
|
((cond) == KdbEnterAlways ? "always" : \
|
||||||
|
@ -81,6 +88,7 @@ static BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]);
|
||||||
static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]);
|
static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]);
|
||||||
static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]);
|
static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]);
|
||||||
static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);
|
static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);
|
||||||
|
static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]);
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
@ -101,6 +109,17 @@ static LONG KdbNumberOfColsTerminal = -1;
|
||||||
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
|
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
|
||||||
BOOLEAN KdbpBugCheckRequested = FALSE;
|
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
|
static const struct
|
||||||
{
|
{
|
||||||
PCHAR Name;
|
PCHAR Name;
|
||||||
|
@ -150,6 +169,8 @@ static const struct
|
||||||
{ "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck },
|
{ "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck },
|
||||||
{ "filter", "filter [error|warning|trace|info|level]+|-[componentname|default]", "Enable/disable debug channels", KdbpCmdFilter },
|
{ "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 },
|
{ "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 }
|
{ "help", "help", "Display help screen.", KdbpCmdHelp }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1895,6 +1916,58 @@ KdbpCmdBugCheck(
|
||||||
return FALSE;
|
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.
|
/*!\brief Sets or displays a config variables value.
|
||||||
*/
|
*/
|
||||||
static BOOLEAN
|
static BOOLEAN
|
||||||
|
@ -2110,6 +2183,7 @@ KdbpCmdHelp(
|
||||||
*
|
*
|
||||||
* \note Doesn't correctly handle \\t and terminal escape sequences when calculating the
|
* \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.
|
* 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
|
VOID
|
||||||
KdbpPrint(
|
KdbpPrint(
|
||||||
|
@ -2215,12 +2289,12 @@ KdbpPrint(
|
||||||
if (KdbNumberOfRowsTerminal <= 0)
|
if (KdbNumberOfRowsTerminal <= 0)
|
||||||
{
|
{
|
||||||
/* Set number of rows to the default. */
|
/* Set number of rows to the default. */
|
||||||
KdbNumberOfRowsTerminal = 24;
|
KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport
|
||||||
}
|
}
|
||||||
else if (KdbNumberOfColsTerminal <= 0)
|
else if (KdbNumberOfColsTerminal <= 0)
|
||||||
{
|
{
|
||||||
/* Set number of cols to the default. */
|
/* 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("\n");
|
||||||
|
|
||||||
DbgPrint("--- Press q to abort, any other key to continue ---");
|
DbgPrint("--- Press q to abort, any other key to continue ---");
|
||||||
|
RowsPrintedByTerminal++; /* added by Mna. */
|
||||||
|
|
||||||
if (KdbDebugState & KD_DEBUG_KDSERIAL)
|
if (KdbDebugState & KD_DEBUG_KDSERIAL)
|
||||||
c = KdbpGetCharSerial();
|
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
|
/*!\brief Appends a command to the command history
|
||||||
*
|
*
|
||||||
* \param Command Pointer to the command to append to the history.
|
* \param Command Pointer to the command to append to the history.
|
||||||
|
|
Loading…
Reference in a new issue