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
*/
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 (KdbNumberOfRowsTerminal > 0 &&
(LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
{
+ KdbRepeatLastCommand = FALSE;
+
if (KdbNumberOfColsPrinted > 0)
DbgPrint("\n");
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++)
{
KdPortPutByteEx(&SerialPortInfo, Response);
}
+ if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
+ KbdEnableMouse();
+
/* Print a new line */
KdPortPutByteEx(&SerialPortInfo, '\r');
KdPortPutByteEx(&SerialPortInfo, '\n');