static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);
static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]);
-#ifdef __ROS_CMAKE__
+BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[]);
+
+#ifdef __ROS_DWARF__
static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]);
#endif
/* GLOBALS *******************************************************************/
+static PKDBG_CLI_ROUTINE KdbCliCallbacks[10];
static BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */
static BOOLEAN KdbBreakOnModuleLoad = FALSE; /* Set to TRUE to break into KDB when a module is loaded */
static ULONG KdbNumberOfRowsPrinted = 0;
static ULONG KdbNumberOfColsPrinted = 0;
static BOOLEAN KdbOutputAborted = FALSE;
+static BOOLEAN KdbRepeatLastCommand = FALSE;
static LONG KdbNumberOfRowsTerminal = -1;
static LONG KdbNumberOfColsTerminal = -1;
{ "sregs", "sregs", "Display status registers.", KdbpCmdRegs },
{ "dregs", "dregs", "Display debug registers.", KdbpCmdRegs },
{ "bt", "bt [*frameaddr|thread id]", "Prints current backtrace or from given frame addr", KdbpCmdBackTrace },
-#ifdef __ROS_CMAKE__
+#ifdef __ROS_DWARF__
{ "dt", "dt [mod] [type] [addr]", "Print a struct. Addr is optional.", KdbpCmdPrintStruct },
#endif
{ "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 },
+ { "!pool", "!pool [Address [Flags]]", "Display information about pool allocations.", ExpKdbgExtPool }
};
/* FUNCTIONS *****************************************************************/
return Ok;
}
+BOOLEAN
+NTAPI
+KdbpGetHexNumber(
+ IN PCHAR pszNum,
+ OUT ULONG_PTR *pulValue)
+{
+ char *endptr;
+
+ /* Skip optional '0x' prefix */
+ if ((pszNum[0] == '0') && ((pszNum[1] == 'x') || (pszNum[1] == 'X')))
+ pszNum += 2;
+
+ /* Make a number from the string (hex) */
+ *pulValue = strtoul(pszNum, &endptr, 16);
+
+ return (*endptr == '\0');
+}
+
/*!\brief Evaluates an expression and displays the result.
*/
static BOOLEAN
return TRUE;
}
-#ifdef __ROS_CMAKE__
+#ifdef __ROS_DWARF__
/*!\brief Print a struct
*/
static VOID
KdbpPrintStructInternal
-(PROSSYM_INFO Info,
- PCHAR Indent,
- BOOLEAN DoRead,
- PVOID BaseAddress,
+(PROSSYM_INFO Info,
+ PCHAR Indent,
+ BOOLEAN DoRead,
+ PVOID BaseAddress,
PROSSYM_AGGREGATE Aggregate)
{
ULONG i;
ULONGLONG Result;
PROSSYM_AGGREGATE_MEMBER Member;
ULONG IndentLen = strlen(Indent);
- ROSSYM_AGGREGATE MemberAggregate = { };
+ ROSSYM_AGGREGATE MemberAggregate = {0 };
for (i = 0; i < Aggregate->NumElements; i++) {
Member = &Aggregate->Elements[i];
default: {
if (Member->Size < 8) {
if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) {
- int j;
+ ULONG j;
for (j = 0; j < Member->Size; j++) {
KdbpPrint(" %02x", (int)(Result & 0xff));
Result >>= 8;
ULONG Argc,
PCHAR Argv[])
{
- int i;
+ ULONG i;
ULONGLONG Result = 0;
PVOID BaseAddress = 0;
- ROSSYM_AGGREGATE Aggregate = { };
- UNICODE_STRING ModName = { };
- ANSI_STRING AnsiName = { };
- CHAR Indent[100] = { };
+ ROSSYM_AGGREGATE Aggregate = {0};
+ UNICODE_STRING ModName = {0};
+ ANSI_STRING AnsiName = {0};
+ CHAR Indent[100] = {0};
+ PROSSYM_INFO Info;
+
if (Argc < 3) goto end;
AnsiName.Length = AnsiName.MaximumLength = strlen(Argv[1]);
AnsiName.Buffer = Argv[1];
RtlAnsiStringToUnicodeString(&ModName, &AnsiName, TRUE);
- PROSSYM_INFO Info = KdbpSymFindCachedFile(&ModName);
+ Info = KdbpSymFindCachedFile(&ModName);
if (!Info || !RosSymAggregate(Info, Argv[2], &Aggregate)) {
DPRINT1("Could not get aggregate\n");
goto end;
}
-
+
// Get an argument for location if it was given
if (Argc > 3) {
ULONG len;
len = strlen(Argv[i]);
Argv[i][len] = ' ';
}
-
+
/* Evaluate the expression */
DPRINT1("Arg: %s\n", ArgStart);
if (KdbpEvaluateExpression(ArgStart, strlen(ArgStart), &Result)) {
else if (Argv[0][0] == 'c') /* cregs */
{
ULONG Cr0, Cr2, Cr3, Cr4;
- KDESCRIPTOR Gdtr, Idtr;
+ KDESCRIPTOR Gdtr = {0, 0, 0}, Idtr = {0, 0, 0};
USHORT Ldtr;
static const PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
return TRUE;
}
+static BOOLEAN
+KdbpTrapFrameFromPrevTss(
+ PKTRAP_FRAME TrapFrame)
+{
+ ULONG_PTR Eip, Ebp;
+ KDESCRIPTOR Gdtr;
+ KGDTENTRY Desc;
+ USHORT Sel;
+ PKTSS Tss;
+
+ Ke386GetGlobalDescriptorTable(&Gdtr.Limit);
+ Sel = Ke386GetTr();
+
+ if ((Sel & (sizeof(KGDTENTRY) - 1)) ||
+ (Sel < sizeof(KGDTENTRY)) ||
+ (Sel + sizeof(KGDTENTRY) - 1 > Gdtr.Limit))
+ return FALSE;
+
+ if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc,
+ (PVOID)(Gdtr.Base + Sel),
+ sizeof(KGDTENTRY))))
+ return FALSE;
+
+ if (Desc.HighWord.Bits.Type != 0xB)
+ return FALSE;
+
+ Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow |
+ Desc.HighWord.Bytes.BaseMid << 16 |
+ Desc.HighWord.Bytes.BaseHi << 24);
+
+ if (!NT_SUCCESS(KdbpSafeReadMemory(&Sel,
+ (PVOID)&Tss->Backlink,
+ sizeof(USHORT))))
+ return FALSE;
+
+ if ((Sel & (sizeof(KGDTENTRY) - 1)) ||
+ (Sel < sizeof(KGDTENTRY)) ||
+ (Sel + sizeof(KGDTENTRY) - 1 > Gdtr.Limit))
+ return FALSE;
+
+ if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc,
+ (PVOID)(Gdtr.Base + Sel),
+ sizeof(KGDTENTRY))))
+ return FALSE;
+
+ if (Desc.HighWord.Bits.Type != 0xB)
+ return FALSE;
+
+ Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow |
+ Desc.HighWord.Bytes.BaseMid << 16 |
+ Desc.HighWord.Bytes.BaseHi << 24);
+
+ if (!NT_SUCCESS(KdbpSafeReadMemory(&Eip,
+ (PVOID)&Tss->Eip,
+ sizeof(ULONG_PTR))))
+ return FALSE;
+
+ if (!NT_SUCCESS(KdbpSafeReadMemory(&Ebp,
+ (PVOID)&Tss->Ebp,
+ sizeof(ULONG_PTR))))
+ return FALSE;
+
+ TrapFrame->Eip = Eip;
+ TrapFrame->Ebp = Ebp;
+ return TRUE;
+}
+
+VOID __cdecl KiTrap02(VOID);
+VOID FASTCALL KiTrap03Handler(IN PKTRAP_FRAME);
+VOID __cdecl KiTrap08(VOID);
+VOID __cdecl KiTrap09(VOID);
+
+static BOOLEAN
+KdbpInNmiOrDoubleFaultHandler(
+ ULONG_PTR Address)
+{
+ return (Address > (ULONG_PTR)KiTrap02 && Address < (ULONG_PTR)KiTrap03Handler) ||
+ (Address > (ULONG_PTR)KiTrap08 && Address < (ULONG_PTR)KiTrap09);
+}
+
/*!\brief Displays a backtrace.
*/
static BOOLEAN
if (Address == 0)
break;
+ if (KdbpInNmiOrDoubleFaultHandler(Address))
+ {
+ if ((GotNextFrame = KdbpTrapFrameFromPrevTss(&TrapFrame)))
+ {
+ Address = TrapFrame.Eip;
+ Frame = TrapFrame.Ebp;
+
+ if (!KdbSymPrintAddress((PVOID)Address, &TrapFrame))
+ KdbpPrint("<%08x>\n", Address);
+ else
+ KdbpPrint("\n");
+ }
+ }
+
if (!GotNextFrame)
{
KdbpPrint("Couldn't access memory at 0x%p!\n", Frame);
if (strcmp(Argv[i+1], "IF") == 0) /* IF found */
{
ConditionArgIndex = i + 2;
- if (ConditionArgIndex >= Argc)
+ if ((ULONG)ConditionArgIndex >= Argc)
{
KdbpPrint("%s: IF requires condition expression.\n", Argv[0]);
return TRUE;
if (KdbNumberOfRowsTerminal > 0 &&
(LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
{
+ KdbRepeatLastCommand = FALSE;
+
if (KdbNumberOfColsPrinted > 0)
DbgPrint("\n");
p = p0;
for (j = KdbNumberOfRowsTerminal; j--; )
{
+ int linesCnt;
p1 = memrchr(p0, '\n', p-p0);
prev_p = p;
p = p1;
p = p0;
break;
}
- int linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
+ linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
if (linesCnt > 1)
j -= linesCnt-1;
}
if (KdbNumberOfRowsTerminal > 0 &&
(LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
{
+ KdbRepeatLastCommand = FALSE;
+
if (KdbNumberOfColsPrinted > 0)
DbgPrint("\n");
PCHAR Orig = Buffer;
ULONG ScanCode = 0;
BOOLEAN EchoOn;
- static CHAR LastCommand[1024] = "";
+ static CHAR LastCommand[1024];
static CHAR NextKey = '\0';
INT CmdHistIndex = -1;
INT i;
* Repeat the last command if the user presses enter. Reduces the
* risk of RSI when single-stepping.
*/
- if (Buffer == Orig)
- {
- RtlStringCbCopyA(Buffer, Size, LastCommand);
- }
- else
+ if (Buffer != Orig)
{
+ KdbRepeatLastCommand = TRUE;
*Buffer = '\0';
RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Orig);
}
+ else if (KdbRepeatLastCommand)
+ RtlStringCbCopyA(Buffer, Size, LastCommand);
+ else
+ *Buffer = '\0';
return;
}
}
}
+
+BOOLEAN
+NTAPI
+KdbRegisterCliCallback(
+ PVOID Callback,
+ BOOLEAN Deregister)
+{
+ ULONG i;
+
+ /* Loop all entries */
+ for (i = 0; i < _countof(KdbCliCallbacks); i++)
+ {
+ /* Check if deregistering was requested */
+ if (Deregister)
+ {
+ /* Check if this entry is the one that was registered */
+ if (KdbCliCallbacks[i] == Callback)
+ {
+ /* Delete it and report success */
+ KdbCliCallbacks[i] = NULL;
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* Check if this entry is free */
+ if (KdbCliCallbacks[i] == NULL)
+ {
+ /* Set it and and report success */
+ KdbCliCallbacks[i] = Callback;
+ return TRUE;
+ }
+ }
+ }
+
+ /* Unsuccessful */
+ return FALSE;
+}
+
+/*! \brief Invokes registered CLI callbacks until one of them handled the
+ * Command.
+ *
+ * \param Command - Command line to parse and execute if possible.
+ * \param Argc - Number of arguments in Argv
+ * \param Argv - Array of strings, each of them containing one argument.
+ *
+ * \return TRUE, if the command was handled, FALSE if it was not handled.
+ */
+static
+BOOLEAN
+KdbpInvokeCliCallbacks(
+ IN PCHAR Command,
+ IN ULONG Argc,
+ IN PCH Argv[])
+{
+ ULONG i;
+
+ /* Loop all entries */
+ for (i = 0; i < _countof(KdbCliCallbacks); i++)
+ {
+ /* Check if this entry is registered */
+ if (KdbCliCallbacks[i])
+ {
+ /* Invoke the callback and check if it handled the command */
+ if (KdbCliCallbacks[i](Command, Argc, Argv))
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ /* None of the callbacks handled the command */
+ return FALSE;
+}
+
+
/*!\brief Parses command line and executes command if found
*
* \param Command Command line to parse and execute if possible.
ULONG i;
PCHAR p;
ULONG Argc;
+ // FIXME: for what do we need a 1024 characters command line and 256 tokens?
static PCH Argv[256];
static CHAR OrigCommand[1024];
}
}
+ /* Now invoke the registered callbacks */
+ if (KdbpInvokeCliCallbacks(Command, Argc, Argv))
+ {
+ return TRUE;
+ }
+
KdbpPrint("Command '%s' is unknown.\n", OrigCommand);
return TRUE;
}
InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL);
/* Open the file */
- Status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0,
+ Status = ZwOpenFile(&hFile, FILE_READ_DATA | SYNCHRONIZE,
+ &ObjectAttributes, &Iosb, 0,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_NO_INTERMEDIATE_BUFFERING);
if (!NT_SUCCESS(Status))
*(KdpPromptString.Buffer + i));
}
+ if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
+ KbdDisableMouse();
+
/* Loop the whole string */
for (i = 0; i < OutStringLength; i++)
{
KdbpTryGetCharKeyboard(&DummyScanCode, 5);
}
- /*
+ /*
* Null terminate the output string -- documentation states that
* DbgPrompt does not null terminate, but it does
*/
/* Print a new line */
KdPortPutByteEx(&SerialPortInfo, '\r');
- KdPortPutByteEx(&SerialPortInfo, '\n');
+ KdPortPutByteEx(&SerialPortInfo, '\n');
/* Release spinlock */
KiReleaseSpinLock(&KdpSerialSpinLock);
KdPortPutByteEx(&SerialPortInfo, Response);
}
+ if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
+ KbdEnableMouse();
+
/* Print a new line */
KdPortPutByteEx(&SerialPortInfo, '\r');
KdPortPutByteEx(&SerialPortInfo, '\n');