diff --git a/reactos/ntoskrnl/dbg/kdb_cli.c b/reactos/ntoskrnl/dbg/kdb_cli.c index ef8fe00475b..5d9eff7d87c 100644 --- a/reactos/ntoskrnl/dbg/kdb_cli.c +++ b/reactos/ntoskrnl/dbg/kdb_cli.c @@ -1,2320 +1,2320 @@ -/* - * ReactOS kernel - * Copyright (C) 2005 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* $Id$ - * - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/dbg/kdb_cli.c - * PURPOSE: Kernel debugger command line interface - * PROGRAMMER: Gregor Anich (blight@blight.eu.org) - * UPDATE HISTORY: - * Created 16/01/2005 - */ - -/* INCLUDES ******************************************************************/ - -#include -#include "kdb.h" -#define NDEBUG -#include - -/* DEFINES *******************************************************************/ - -#define KEY_BS 8 -#define KEY_ESC 27 -#define KEY_DEL 127 - -#define KEY_SCAN_UP 72 -#define KEY_SCAN_DOWN 80 - -#define KDB_ENTER_CONDITION_TO_STRING(cond) \ - ((cond) == KdbDoNotEnter ? "never" : \ - ((cond) == KdbEnterAlways ? "always" : \ - ((cond) == KdbEnterFromKmode ? "kmode" : "umode"))) - -#define KDB_ACCESS_TYPE_TO_STRING(type) \ - ((type) == KdbAccessRead ? "read" : \ - ((type) == KdbAccessWrite ? "write" : \ - ((type) == KdbAccessReadWrite ? "rdwr" : "exec"))) - -#define NPX_STATE_TO_STRING(state) \ - ((state) == NPX_STATE_INVALID ? "Invalid" : \ - ((state) == NPX_STATE_VALID ? "Valid" : \ - ((state) == NPX_STATE_DIRTY ? "Dirty" : "Unknown"))) - -/* PROTOTYPES ****************************************************************/ - -STATIC BOOLEAN KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdRegs(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]); - -STATIC BOOLEAN KdbpCmdContinue(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdStep(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]); - -STATIC BOOLEAN KdbpCmdThread(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdProc(ULONG Argc, PCHAR Argv[]); - -STATIC BOOLEAN KdbpCmdMod(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdPcr(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]); - -STATIC BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]); -STATIC BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]); - -/* GLOBALS *******************************************************************/ - -STATIC BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */ - -STATIC CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */ -STATIC PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */ -STATIC LONG KdbCommandHistoryBufferIndex = 0; -STATIC LONG KdbCommandHistoryIndex = 0; - -STATIC ULONG KdbNumberOfRowsPrinted = 0; -STATIC ULONG KdbNumberOfColsPrinted = 0; -STATIC BOOLEAN KdbOutputAborted = FALSE; -STATIC LONG KdbNumberOfRowsTerminal = -1; -STATIC LONG KdbNumberOfColsTerminal = -1; - -PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */ - -STATIC CONST struct -{ - PCHAR Name; - PCHAR Syntax; - PCHAR Help; - BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]); -} KdbDebuggerCommands[] = { - /* Data */ - { NULL, NULL, "Data", NULL }, - { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression }, - { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX }, - { "x", "x [address] [L count]", "Display count dwords, starting at addr.", KdbpCmdDisassembleX }, - { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs }, - { "cregs", "cregs", "Display control registers.", KdbpCmdRegs }, - { "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 }, - - /* Flow control */ - { NULL, NULL, "Flow control", NULL }, - { "cont", "cont", "Continue execution (leave debugger)", KdbpCmdContinue }, - { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep }, - { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep }, - { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList }, - { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, - { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, - { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, - { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint }, - { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint }, - - /* Process/Thread */ - { NULL, NULL, "Process/Thread", NULL }, - { "thread", "thread [list[ pid]|[attach ]tid]", "List threads in current or specified process, display thread with given id or attach to thread.", KdbpCmdThread }, - { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc }, - - /* System information */ - { NULL, NULL, "System info", NULL }, - { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod }, - { "gdt", "gdt", "Display global descriptor table.", KdbpCmdGdtLdtIdt }, - { "ldt", "ldt", "Display local descriptor table.", KdbpCmdGdtLdtIdt }, - { "idt", "idt", "Display interrupt descriptor table.", KdbpCmdGdtLdtIdt }, - { "pcr", "pcr", "Display processor control region.", KdbpCmdPcr }, - { "tss", "tss", "Display task state segment.", KdbpCmdTss }, - - /* Others */ - { NULL, NULL, "Others", NULL }, - { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck }, - { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet }, - { "help", "help", "Display help screen.", KdbpCmdHelp } -}; - -/* FUNCTIONS *****************************************************************/ - -/*!\brief Evaluates an expression... - * - * Much like KdbpRpnEvaluateExpression, but prints the error message (if any) - * at the given offset. - * - * \param Expression Expression to evaluate. - * \param ErrOffset Offset (in characters) to print the error message at. - * \param Result Receives the result on success. - * - * \retval TRUE Success. - * \retval FALSE Failure. - */ -STATIC BOOLEAN -KdbpEvaluateExpression( - IN PCHAR Expression, - IN LONG ErrOffset, - OUT PULONGLONG Result) -{ - STATIC CHAR ErrMsgBuffer[130] = "^ "; - LONG ExpressionErrOffset = -1; - PCHAR ErrMsg = ErrMsgBuffer; - BOOLEAN Ok; - - Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result, - &ExpressionErrOffset, ErrMsgBuffer + 2); - if (!Ok) - { - if (ExpressionErrOffset >= 0) - ExpressionErrOffset += ErrOffset; - else - ErrMsg += 2; - KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg); - } - - return Ok; -} - -/*!\brief Evaluates an expression and displays the result. - */ -STATIC BOOLEAN -KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]) -{ - INT i, len; - ULONGLONG Result = 0; - ULONG ul; - LONG l = 0; - BOOLEAN Ok; - - if (Argc < 2) - { - KdbpPrint("?: Argument required\n"); - return TRUE; - } - - /* Put the arguments back together */ - Argc--; - for (i = 1; i < Argc; i++) - { - len = strlen(Argv[i]); - Argv[i][len] = ' '; - } - - /* Evaluate the expression */ - Ok = KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result); - if (Ok) - { - if (Result > 0x00000000ffffffffLL) - { - if (Result & 0x8000000000000000LL) - KdbpPrint("0x%016I64x %20I64u %20I64d\n", Result, Result, Result); - else - KdbpPrint("0x%016I64x %20I64u\n", Result, Result); - } - else - { - ul = (ULONG)Result; - if (ul <= 0xff && ul >= 0x80) - l = (LONG)((CHAR)ul); - else if (ul <= 0xffff && ul >= 0x8000) - l = (LONG)((SHORT)ul); - else - l = (LONG)ul; - if (l < 0) - KdbpPrint("0x%08lx %10lu %10ld\n", ul, ul, l); - else - KdbpPrint("0x%08lx %10lu\n", ul, ul); - } - } - - return TRUE; -} - -/*!\brief Disassembles 10 instructions at eip or given address or - * displays 16 dwords from memory at given address. - */ -STATIC BOOLEAN -KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]) -{ - ULONG Count; - ULONG ul; - INT i; - ULONGLONG Result = 0; - ULONG_PTR Address = KdbCurrentTrapFrame->Tf.Eip; - LONG InstLen; - - if (Argv[0][0] == 'x') /* display memory */ - Count = 16; - else /* disassemble */ - Count = 10; - - if (Argc >= 2) - { - /* Check for [L count] part */ - ul = 0; - if (strcmp(Argv[Argc-2], "L") == 0) - { - ul = strtoul(Argv[Argc-1], NULL, 0); - if (ul > 0) - { - Count = ul; - Argc -= 2; - } - } - else if (Argv[Argc-1][0] == 'L') - { - ul = strtoul(Argv[Argc-1] + 1, NULL, 0); - if (ul > 0) - { - Count = ul; - Argc--; - } - } - - /* Put the remaining arguments back together */ - Argc--; - for (ul = 1; ul < Argc; ul++) - { - Argv[ul][strlen(Argv[ul])] = ' '; - } - Argc++; - } - - /* Evaluate the expression */ - if (Argc > 1) - { - if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) - return TRUE; - if (Result > (ULONGLONG)(~((ULONG_PTR)0))) - KdbpPrint("Warning: Address %I64x is beeing truncated\n"); - Address = (ULONG_PTR)Result; - } - else if (Argv[0][0] == 'x') - { - KdbpPrint("x: Address argument required.\n"); - return TRUE; - } - - if (Argv[0][0] == 'x') - { - /* Display dwords */ - ul = 0; - while (Count > 0) - { - if (!KdbSymPrintAddress((PVOID)Address)) - KdbpPrint("<%x>:", Address); - else - KdbpPrint(":"); - i = min(4, Count); - Count -= i; - while (--i >= 0) - { - if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul)))) - KdbpPrint(" ????????"); - else - KdbpPrint(" %08x", ul); - Address += sizeof(ul); - } - KdbpPrint("\n"); - } - } - else - { - /* Disassemble */ - while (Count-- > 0) - { - if (!KdbSymPrintAddress((PVOID)Address)) - KdbpPrint("<%08x>: ", Address); - else - KdbpPrint(": "); - InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax); - if (InstLen < 0) - { - KdbpPrint("\n"); - return TRUE; - } - KdbpPrint("\n"); - Address += InstLen; - } - } - - return TRUE; -} - -/*!\brief Displays CPU registers. - */ -STATIC BOOLEAN -KdbpCmdRegs(ULONG Argc, PCHAR Argv[]) -{ - PKTRAP_FRAME Tf = &KdbCurrentTrapFrame->Tf; - INT i; - STATIC CONST PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5", - " ZF", " SF", " TF", " IF", " DF", " OF", - NULL, NULL, " NT", " BIT15", " RF", " VF", - " AC", " VIF", " VIP", " ID", " BIT22", - " BIT23", " BIT24", " BIT25", " BIT26", - " BIT27", " BIT28", " BIT29", " BIT30", - " BIT31" }; - - if (Argv[0][0] == 'r') /* regs */ - { - KdbpPrint("CS:EIP 0x%04x:0x%08x\n" - "SS:ESP 0x%04x:0x%08x\n" - " EAX 0x%08x EBX 0x%08x\n" - " ECX 0x%08x EDX 0x%08x\n" - " ESI 0x%08x EDI 0x%08x\n" - " EBP 0x%08x\n", - Tf->Cs & 0xFFFF, Tf->Eip, - Tf->Ss, Tf->Esp, - Tf->Eax, Tf->Ebx, - Tf->Ecx, Tf->Edx, - Tf->Esi, Tf->Edi, - Tf->Ebp); - KdbpPrint("EFLAGS 0x%08x ", Tf->Eflags); - for (i = 0; i < 32; i++) - { - if (i == 1) - { - if ((Tf->Eflags & (1 << 1)) == 0) - KdbpPrint(" !BIT1"); - } - else if (i == 12) - { - KdbpPrint(" IOPL%d", (Tf->Eflags >> 12) & 3); - } - else if (i == 13) - { - } - else if ((Tf->Eflags & (1 << i)) != 0) - KdbpPrint(EflagsBits[i]); - } - KdbpPrint("\n"); - } - else if (Argv[0][0] == 'c') /* cregs */ - { - ULONG Cr0, Cr2, Cr3, Cr4; - struct __attribute__((packed)) { - USHORT Limit; - ULONG Base; - } Gdtr, Ldtr, Idtr; - ULONG Tr; - STATIC CONST PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - " WP", NULL, " AM", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, " NW", " CD", " PG" }; - STATIC CONST PCHAR Cr4Bits[32] = { " VME", " PVI", " TSD", " DE", " PSE", " PAE", " MCE", " PGE", - " PCE", " OSFXSR", " OSXMMEXCPT", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - - Cr0 = KdbCurrentTrapFrame->Cr0; - Cr2 = KdbCurrentTrapFrame->Cr2; - Cr3 = KdbCurrentTrapFrame->Cr3; - Cr4 = KdbCurrentTrapFrame->Cr4; - - /* Get descriptor table regs */ - asm volatile("sgdt %0" : : "m"(Gdtr)); - asm volatile("sldt %0" : : "m"(Ldtr)); - asm volatile("sidt %0" : : "m"(Idtr)); - - /* Get the task register */ - asm volatile("str %0" : "=g"(Tr)); - - /* Display the control registers */ - KdbpPrint("CR0 0x%08x ", Cr0); - for (i = 0; i < 32; i++) - { - if (Cr0Bits[i] == NULL) - continue; - if ((Cr0 & (1 << i)) != 0) - KdbpPrint(Cr0Bits[i]); - } - KdbpPrint("\nCR2 0x%08x\n", Cr2); - KdbpPrint("CR3 0x%08x Pagedir-Base 0x%08x %s%s\n", Cr3, (Cr3 & 0xfffff000), - (Cr3 & (1 << 3)) ? " PWT" : "", (Cr3 & (1 << 4)) ? " PCD" : "" ); - KdbpPrint("CR4 0x%08x ", Cr4); - for (i = 0; i < 32; i++) - { - if (Cr4Bits[i] == NULL) - continue; - if ((Cr4 & (1 << i)) != 0) - KdbpPrint(Cr4Bits[i]); - } - - /* Display the descriptor table regs */ - KdbpPrint("\nGDTR Base 0x%08x Size 0x%04x\n", Gdtr.Base, Gdtr.Limit); - KdbpPrint("LDTR Base 0x%08x Size 0x%04x\n", Ldtr.Base, Ldtr.Limit); - KdbpPrint("IDTR Base 0x%08x Size 0x%04x\n", Idtr.Base, Idtr.Limit); - } - else if (Argv[0][0] == 's') /* sregs */ - { - KdbpPrint("CS 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Cs & 0xffff, (Tf->Cs & 0xffff) >> 3, - (Tf->Cs & (1 << 2)) ? 'L' : 'G', Tf->Cs & 3); - KdbpPrint("DS 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Ds, Tf->Ds >> 3, (Tf->Ds & (1 << 2)) ? 'L' : 'G', Tf->Ds & 3); - KdbpPrint("ES 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Es, Tf->Es >> 3, (Tf->Es & (1 << 2)) ? 'L' : 'G', Tf->Es & 3); - KdbpPrint("FS 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Fs, Tf->Fs >> 3, (Tf->Fs & (1 << 2)) ? 'L' : 'G', Tf->Fs & 3); - KdbpPrint("GS 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Gs, Tf->Gs >> 3, (Tf->Gs & (1 << 2)) ? 'L' : 'G', Tf->Gs & 3); - KdbpPrint("SS 0x%04x Index 0x%04x %cDT RPL%d\n", - Tf->Ss, Tf->Ss >> 3, (Tf->Ss & (1 << 2)) ? 'L' : 'G', Tf->Ss & 3); - } - else /* dregs */ - { - ASSERT(Argv[0][0] == 'd'); - KdbpPrint("DR0 0x%08x\n" - "DR1 0x%08x\n" - "DR2 0x%08x\n" - "DR3 0x%08x\n" - "DR6 0x%08x\n" - "DR7 0x%08x\n", - Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, - Tf->Dr6, Tf->Dr7); - } - return TRUE; -} - -/*!\brief Displays a backtrace. - */ -STATIC BOOLEAN -KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]) -{ - ULONG Count; - ULONG ul; - ULONGLONG Result = 0; - ULONG_PTR Frame = KdbCurrentTrapFrame->Tf.Ebp; - ULONG_PTR Address; - - if (Argc >= 2) - { - /* Check for [L count] part */ - ul = 0; - if (strcmp(Argv[Argc-2], "L") == 0) - { - ul = strtoul(Argv[Argc-1], NULL, 0); - if (ul > 0) - { - Count = ul; - Argc -= 2; - } - } - else if (Argv[Argc-1][0] == 'L') - { - ul = strtoul(Argv[Argc-1] + 1, NULL, 0); - if (ul > 0) - { - Count = ul; - Argc--; - } - } - - /* Put the remaining arguments back together */ - Argc--; - for (ul = 1; ul < Argc; ul++) - { - Argv[ul][strlen(Argv[ul])] = ' '; - } - Argc++; - } - - /* Check if frame addr or thread id is given. */ - if (Argc > 1) - { - if (Argv[1][0] == '*') - { - Argv[1]++; - /* Evaluate the expression */ - if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) - return TRUE; - if (Result > (ULONGLONG)(~((ULONG_PTR)0))) - KdbpPrint("Warning: Address %I64x is beeing truncated\n"); - Frame = (ULONG_PTR)Result; - } - else - { - - KdbpPrint("Thread backtrace not supported yet!\n"); - return TRUE; - } - } - - KdbpPrint("Frames:\n"); - while (Frame != 0) - { - if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof (ULONG_PTR)))) - { - KdbpPrint("Couldn't access memory at 0x%x!\n", Frame + sizeof(ULONG_PTR)); - break; - } - if (!KdbSymPrintAddress((PVOID)Address)) - KdbpPrint("<%08x>\n", Address); - else - KdbpPrint("\n"); - if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof (ULONG_PTR)))) - { - KdbpPrint("Couldn't access memory at 0x%x!\n", Frame); - break; - } - } - - return TRUE; -} - -/*!\brief Continues execution of the system/leaves KDB. - */ -STATIC BOOLEAN -KdbpCmdContinue(ULONG Argc, PCHAR Argv[]) -{ - /* Exit the main loop */ - return FALSE; -} - -/*!\brief Continues execution of the system/leaves KDB. - */ -STATIC BOOLEAN -KdbpCmdStep(ULONG Argc, PCHAR Argv[]) -{ - ULONG Count = 1; - - if (Argc > 1) - { - Count = strtoul(Argv[1], NULL, 0); - if (Count == 0) - { - KdbpPrint("%s: Integer argument required\n", Argv[0]); - return TRUE; - } - } - - if (Argv[0][0] == 'n') - KdbSingleStepOver = TRUE; - else - KdbSingleStepOver = FALSE; - - /* Set the number of single steps and return to the interrupted code. */ - KdbNumSingleSteps = Count; - - return FALSE; -} - -/*!\brief Lists breakpoints. - */ -STATIC BOOLEAN -KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]) -{ - LONG l; - ULONG_PTR Address = 0; - KDB_BREAKPOINT_TYPE Type = 0; - KDB_ACCESS_TYPE AccessType = 0; - UCHAR Size = 0; - UCHAR DebugReg = 0; - BOOLEAN Enabled = FALSE; - BOOLEAN Global = FALSE; - PEPROCESS Process = NULL; - PCHAR str1, str2, ConditionExpr, GlobalOrLocal; - CHAR Buffer[20]; - - l = KdbpGetNextBreakPointNr(0); - if (l < 0) - { - KdbpPrint("No breakpoints.\n"); - return TRUE; - } - - KdbpPrint("Breakpoints:\n"); - do - { - if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg, - &Enabled, &Global, &Process, &ConditionExpr)) - { - continue; - } - - if (l == KdbLastBreakPointNr) - { - str1 = "\x1b[1m*"; - str2 = "\x1b[0m"; - } - else - { - str1 = " "; - str2 = ""; - } - - if (Global) - GlobalOrLocal = " global"; - else - { - GlobalOrLocal = Buffer; - sprintf(Buffer, " PID 0x%08lx", - (ULONG)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE)); - } - - if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary) - { - KdbpPrint(" %s%03d BPX 0x%08x%s%s%s%s%s\n", - str1, l, Address, - Enabled ? "" : " disabled", - GlobalOrLocal, - ConditionExpr ? " IF " : "", - ConditionExpr ? ConditionExpr : "", - str2); - } - else if (Type == KdbBreakPointHardware) - { - if (!Enabled) - { - KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s disabled%s%s%s%s\n", str1, l, Address, - KDB_ACCESS_TYPE_TO_STRING(AccessType), - Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), - GlobalOrLocal, - ConditionExpr ? " IF " : "", - ConditionExpr ? ConditionExpr : "", - str2); - } - else - { - KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s DR%d%s%s%s%s\n", str1, l, Address, - KDB_ACCESS_TYPE_TO_STRING(AccessType), - Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), - DebugReg, - GlobalOrLocal, - ConditionExpr ? " IF " : "", - ConditionExpr ? ConditionExpr : "", - str2); - } - } - } - while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0); - - return TRUE; -} - -/*!\brief Enables, disables or clears a breakpoint. - */ -STATIC BOOLEAN -KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]) -{ - PCHAR pend; - ULONG BreakPointNr; - - if (Argc < 2) - { - KdbpPrint("%s: argument required\n", Argv[0]); - return TRUE; - } - - pend = Argv[1]; - BreakPointNr = strtoul(Argv[1], &pend, 0); - if (pend == Argv[1] || *pend != '\0') - { - KdbpPrint("%s: integer argument required\n", Argv[0]); - return TRUE; - } - - if (Argv[0][1] == 'e') /* enable */ - { - KdbpEnableBreakPoint(BreakPointNr, NULL); - } - else if (Argv [0][1] == 'd') /* disable */ - { - KdbpDisableBreakPoint(BreakPointNr, NULL); - } - else /* clear */ - { - ASSERT(Argv[0][1] == 'c'); - KdbpDeleteBreakPoint(BreakPointNr, NULL); - } - - return TRUE; -} - -/*!\brief Sets a software or hardware (memory) breakpoint at the given address. - */ -STATIC BOOLEAN -KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]) -{ - ULONGLONG Result = 0; - ULONG_PTR Address; - KDB_BREAKPOINT_TYPE Type; - UCHAR Size = 0; - KDB_ACCESS_TYPE AccessType = 0; - INT AddressArgIndex, ConditionArgIndex, i; - BOOLEAN Global = TRUE; - - if (Argv[0][2] == 'x') /* software breakpoint */ - { - if (Argc < 2) - { - KdbpPrint("bpx: Address argument required.\n"); - return TRUE; - } - - AddressArgIndex = 1; - Type = KdbBreakPointSoftware; - } - else /* memory breakpoint */ - { - ASSERT(Argv[0][2] == 'm'); - - if (Argc < 2) - { - KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n"); - return TRUE; - } - - if (_stricmp(Argv[1], "x") == 0) - AccessType = KdbAccessExec; - else if (_stricmp(Argv[1], "r") == 0) - AccessType = KdbAccessRead; - else if (_stricmp(Argv[1], "w") == 0) - AccessType = KdbAccessWrite; - else if (_stricmp(Argv[1], "rw") == 0) - AccessType = KdbAccessReadWrite; - else - { - KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]); - return TRUE; - } - - if (Argc < 3) - { - KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size"); - return TRUE; - } - AddressArgIndex = 3; - if (_stricmp(Argv[2], "byte") == 0) - Size = 1; - else if (_stricmp(Argv[2], "word") == 0) - Size = 2; - else if (_stricmp(Argv[2], "dword") == 0) - Size = 4; - else if (AccessType == KdbAccessExec) - { - Size = 1; - AddressArgIndex--; - } - else - { - KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]); - return TRUE; - } - - if (Argc <= AddressArgIndex) - { - KdbpPrint("bpm: Address argument required.\n"); - return TRUE; - } - - Type = KdbBreakPointHardware; - } - - /* Put the arguments back together */ - ConditionArgIndex = -1; - for (i = AddressArgIndex; i < (Argc-1); i++) - { - if (strcmp(Argv[i+1], "IF") == 0) /* IF found */ - { - ConditionArgIndex = i + 2; - if (ConditionArgIndex >= Argc) - { - KdbpPrint("%s: IF requires condition expression.\n", Argv[0]); - return TRUE; - } - for (i = ConditionArgIndex; i < (Argc-1); i++) - Argv[i][strlen(Argv[i])] = ' '; - break; - } - Argv[i][strlen(Argv[i])] = ' '; - } - - /* Evaluate the address expression */ - if (!KdbpEvaluateExpression(Argv[AddressArgIndex], - sizeof("kdb:> ")-1 + (Argv[AddressArgIndex]-Argv[0]), - &Result)) - { - return TRUE; - } - if (Result > (ULONGLONG)(~((ULONG_PTR)0))) - KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]); - Address = (ULONG_PTR)Result; - - KdbpInsertBreakPoint(Address, Type, Size, AccessType, - (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex], - Global, NULL); - - return TRUE; -} - -/*!\brief Lists threads or switches to another thread context. - */ -STATIC BOOLEAN -KdbpCmdThread(ULONG Argc, PCHAR Argv[]) -{ - PLIST_ENTRY Entry; - PETHREAD Thread = NULL; - PEPROCESS Process = NULL; - PULONG Esp; - PULONG Ebp; - ULONG Eip; - ULONG ul = 0; - PCHAR State, pend, str1, str2; - STATIC CONST PCHAR ThreadStateToString[THREAD_STATE_MAX] = - { "Initialized", "Ready", "Running", - "Suspended", "Frozen", "Terminated1", - "Terminated2", "Blocked" }; - ASSERT(KdbCurrentProcess != NULL); - - if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) - { - Process = KdbCurrentProcess; - - if (Argc >= 3) - { - ul = strtoul(Argv[2], &pend, 0); - if (Argv[2] == pend) - { - KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]); - return TRUE; - } - if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) - { - KdbpPrint("thread: Invalid process id!\n"); - return TRUE; - } - } - - Entry = Process->ThreadListHead.Flink; - if (Entry == &Process->ThreadListHead) - { - if (Argc >= 3) - KdbpPrint("No threads in process 0x%08x!\n", ul); - else - KdbpPrint("No threads in current process!\n"); - return TRUE; - } - - KdbpPrint(" TID State Prior. Affinity EBP EIP\n"); - do - { - Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); - - if (Thread == KdbCurrentThread) - { - str1 = "\x1b[1m*"; - str2 = "\x1b[0m"; - } - else - { - str1 = " "; - str2 = ""; - } - - if (Thread->Tcb.TrapFrame != NULL) - { - Esp = (PULONG)Thread->Tcb.TrapFrame->Esp; - Ebp = (PULONG)Thread->Tcb.TrapFrame->Ebp; - Eip = Thread->Tcb.TrapFrame->Eip; - } - else - { - Esp = (PULONG)Thread->Tcb.KernelStack; - Ebp = (PULONG)Esp[4]; - Eip = 0; - if (Ebp != NULL) /* FIXME: Should we attach to the process to read Ebp[1]? */ - KdbpSafeReadMemory(&Eip, Ebp + 1, sizeof (Eip));; - } - if (Thread->Tcb.State < THREAD_STATE_MAX) - State = ThreadStateToString[Thread->Tcb.State]; - else - State = "Unknown"; - - KdbpPrint(" %s0x%08x %-11s %3d 0x%08x 0x%08x 0x%08x%s\n", - str1, - Thread->Cid.UniqueThread, - State, - Thread->Tcb.Priority, - Thread->Tcb.Affinity, - Ebp, - Eip, - str2); - - Entry = Entry->Flink; - } - while (Entry != &Process->ThreadListHead); - } - else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) - { - if (Argc < 3) - { - KdbpPrint("thread attach: thread id argument required!\n"); - return TRUE; - } - - ul = strtoul(Argv[2], &pend, 0); - if (Argv[2] == pend) - { - KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]); - return TRUE; - } - if (!KdbpAttachToThread((PVOID)ul)) - { - return TRUE; - } - KdbpPrint("Attached to thread 0x%08x.\n", ul); - } - else - { - Thread = KdbCurrentThread; - - if (Argc >= 2) - { - ul = strtoul(Argv[1], &pend, 0); - if (Argv[1] == pend) - { - KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]); - return TRUE; - } - if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread))) - { - KdbpPrint("thread: Invalid thread id!\n"); - return TRUE; - } - } - - if (Thread->Tcb.State < THREAD_STATE_MAX) - State = ThreadStateToString[Thread->Tcb.State]; - else - State = "Unknown"; - KdbpPrint("%s" - " TID: 0x%08x\n" - " State: %s (0x%x)\n" - " Priority: %d\n" - " Affinity: 0x%08x\n" - " Initial Stack: 0x%08x\n" - " Stack Limit: 0x%08x\n" - " Stack Base: 0x%08x\n" - " Kernel Stack: 0x%08x\n" - " Trap Frame: 0x%08x\n" - " NPX State: %s (0x%x)\n", - (Argc < 2) ? "Current Thread:\n" : "", - Thread->Cid.UniqueThread, - State, Thread->Tcb.State, - Thread->Tcb.Priority, - Thread->Tcb.Affinity, - Thread->Tcb.InitialStack, - Thread->Tcb.StackLimit, - Thread->Tcb.StackBase, - Thread->Tcb.KernelStack, - Thread->Tcb.TrapFrame, - NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState); - - } - - return TRUE; -} - -/*!\brief Lists processes or switches to another process context. - */ -STATIC BOOLEAN -KdbpCmdProc(ULONG Argc, PCHAR Argv[]) -{ - PLIST_ENTRY Entry; - PEPROCESS Process; - PCHAR State, pend, str1, str2; - ULONG ul; - extern LIST_ENTRY PsActiveProcessHead; - - if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) - { - Entry = PsActiveProcessHead.Flink; - if (Entry == &PsActiveProcessHead) - { - KdbpPrint("No processes in the system!\n"); - return TRUE; - } - - KdbpPrint(" PID State Filename\n"); - do - { - Process = CONTAINING_RECORD(Entry, EPROCESS, ProcessListEntry); - - if (Process == KdbCurrentProcess) - { - str1 = "\x1b[1m*"; - str2 = "\x1b[0m"; - } - else - { - str1 = " "; - str2 = ""; - } - - State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" : - ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown")); - - KdbpPrint(" %s0x%08x %-10s %s%s\n", - str1, - Process->UniqueProcessId, - State, - Process->ImageFileName, - str2); - - Entry = Entry->Flink; - } - while(Entry != &PsActiveProcessHead); - } - else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) - { - if (Argc < 3) - { - KdbpPrint("process attach: process id argument required!\n"); - return TRUE; - } - - ul = strtoul(Argv[2], &pend, 0); - if (Argv[2] == pend) - { - KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]); - return TRUE; - } - if (!KdbpAttachToProcess((PVOID)ul)) - { - return TRUE; - } - KdbpPrint("Attached to process 0x%08x, thread 0x%08x.\n", (UINT)ul, - (UINT)KdbCurrentThread->Cid.UniqueThread); - } - else - { - Process = KdbCurrentProcess; - - if (Argc >= 2) - { - ul = strtoul(Argv[1], &pend, 0); - if (Argv[1] == pend) - { - KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]); - return TRUE; - } - if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) - { - KdbpPrint("proc: Invalid process id!\n"); - return TRUE; - } - } - - State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" : - ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown")); - KdbpPrint("%s" - " PID: 0x%08x\n" - " State: %s (0x%x)\n" - " Image Filename: %s\n", - (Argc < 2) ? "Current process:\n" : "", - Process->UniqueProcessId, - State, Process->Pcb.State, - Process->ImageFileName); - } - - return TRUE; -} - -/*!\brief Lists loaded modules or the one containing the specified address. - */ -STATIC BOOLEAN -KdbpCmdMod(ULONG Argc, PCHAR Argv[]) -{ - ULONGLONG Result = 0; - ULONG_PTR Address; - KDB_MODULE_INFO Info; - BOOLEAN DisplayOnlyOneModule = FALSE; - INT i = 0; - - if (Argc >= 2) - { - /* Put the arguments back together */ - Argc--; - while (--Argc >= 1) - Argv[Argc][strlen(Argv[Argc])] = ' '; - - /* Evaluate the expression */ - if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) - { - return TRUE; - } - if (Result > (ULONGLONG)(~((ULONG_PTR)0))) - KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]); - Address = (ULONG_PTR)Result; - - if (!KdbpSymFindModuleByAddress((PVOID)Address, &Info)) - { - KdbpPrint("No module containing address 0x%x found!\n", Address); - return TRUE; - } - DisplayOnlyOneModule = TRUE; - } - else - { - if (!KdbpSymFindModuleByIndex(0, &Info)) - { - KdbpPrint("No modules.\n"); - return TRUE; - } - i = 1; - } - - KdbpPrint(" Base Size Name\n"); - for (;;) - { - KdbpPrint(" %08x %08x %ws\n", Info.Base, Info.Size, Info.Name); - - if ((!DisplayOnlyOneModule && !KdbpSymFindModuleByIndex(i++, &Info)) || - DisplayOnlyOneModule) - { - break; - } - } - - return TRUE; -} - -/*!\brief Displays GDT, LDT or IDTd. - */ -STATIC BOOLEAN -KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]) -{ - struct __attribute__((packed)) { - USHORT Limit; - ULONG Base; - } Reg; - ULONG SegDesc[2]; - ULONG SegBase; - ULONG SegLimit; - PCHAR SegType; - USHORT SegSel; - UCHAR Type, Dpl; - INT i; - ULONG ul; - - if (Argv[0][0] == 'i') - { - /* Read IDTR */ - asm volatile("sidt %0" : : "m"(Reg)); - - if (Reg.Limit < 7) - { - KdbpPrint("Interrupt descriptor table is empty.\n"); - return TRUE; - } - KdbpPrint("IDT Base: 0x%08x Limit: 0x%04x\n", Reg.Base, Reg.Limit); - KdbpPrint(" Idx Type Seg. Sel. Offset DPL\n"); - for (i = 0; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) - { - if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) - { - KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); - return TRUE; - } - - Dpl = ((SegDesc[1] >> 13) & 3); - if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ - SegType = "TASKGATE"; - else if ((SegDesc[1] & 0x1fe0) == 0x0e00) /* 32 bit Interrupt gate */ - SegType = "INTGATE32"; - else if ((SegDesc[1] & 0x1fe0) == 0x0600) /* 16 bit Interrupt gate */ - SegType = "INTGATE16"; - else if ((SegDesc[1] & 0x1fe0) == 0x0f00) /* 32 bit Trap gate */ - SegType = "TRAPGATE32"; - else if ((SegDesc[1] & 0x1fe0) == 0x0700) /* 16 bit Trap gate */ - SegType = "TRAPGATE16"; - else - SegType = "UNKNOWN"; - - if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ - { - KdbpPrint(" %03d %-10s [NP] [NP] %02d\n", - i / 8, SegType, Dpl); - } - else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ - { - SegSel = SegDesc[0] >> 16; - KdbpPrint(" %03d %-10s 0x%04x %02d\n", - i / 8, SegType, SegSel, Dpl); - } - else - { - SegSel = SegDesc[0] >> 16; - SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff); - KdbpPrint(" %03d %-10s 0x%04x 0x%08x %02d\n", - i / 8, SegType, SegSel, SegBase, Dpl); - } - } - } - else - { - ul = 0; - if (Argv[0][0] == 'g') - { - /* Read GDTR */ - asm volatile("sgdt %0" : : "m"(Reg)); - i = 8; - } - else - { - ASSERT(Argv[0][0] == 'l'); - /* Read LDTR */ - asm volatile("sldt %0" : : "m"(Reg)); - i = 0; - ul = 1 << 2; - } - - if (Reg.Limit < 7) - { - KdbpPrint("%s descriptor table is empty.\n", - Argv[0][0] == 'g' ? "Global" : "Local"); - return TRUE; - } - KdbpPrint("%cDT Base: 0x%08x Limit: 0x%04x\n", - Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit); - KdbpPrint(" Idx Sel. Type Base Limit DPL Attribs\n"); - for ( ; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) - { - if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) - { - KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); - return TRUE; - } - Dpl = ((SegDesc[1] >> 13) & 3); - Type = ((SegDesc[1] >> 8) & 0xf); - - SegBase = SegDesc[0] >> 16; - SegBase |= (SegDesc[1] & 0xff) << 16; - SegBase |= SegDesc[1] & 0xff000000; - SegLimit = SegDesc[0] & 0x0000ffff; - SegLimit |= (SegDesc[1] >> 16) & 0xf; - if ((SegDesc[1] & (1 << 23)) != 0) - { - SegLimit *= 4096; - SegLimit += 4095; - } - else - { - SegLimit++; - } - - if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ - { - switch (Type) - { - case 1: SegType = "TSS16(Avl)"; break; - case 2: SegType = "LDT"; break; - case 3: SegType = "TSS16(Busy)"; break; - case 4: SegType = "CALLGATE16"; break; - case 5: SegType = "TASKGATE"; break; - case 6: SegType = "INTGATE16"; break; - case 7: SegType = "TRAPGATE16"; break; - case 9: SegType = "TSS32(Avl)"; break; - case 11: SegType = "TSS32(Busy)"; break; - case 12: SegType = "CALLGATE32"; break; - case 14: SegType = "INTGATE32"; break; - case 15: SegType = "INTGATE32"; break; - default: SegType = "UNKNOWN"; break; - } - if (!(Type >= 1 && Type <= 3) && - Type != 9 && Type != 11) - { - SegBase = 0; - SegLimit = 0; - } - } - else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ - { - if ((SegDesc[1] & (1 << 22)) != 0) - SegType = "DATA32"; - else - SegType = "DATA16"; - - } - else /* Code segment */ - { - if ((SegDesc[1] & (1 << 22)) != 0) - SegType = "CODE32"; - else - SegType = "CODE16"; - } - - if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ - { - KdbpPrint(" %03d 0x%04x %-11s [NP] [NP] %02d NP\n", - i / 8, i | Dpl | ul, SegType, Dpl); - } - else - { - KdbpPrint(" %03d 0x%04x %-11s 0x%08x 0x%08x %02d ", - i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl); - if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ - { - /* FIXME: Display system segment */ - } - else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ - { - if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */ - KdbpPrint(" E"); - KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R"); - if ((SegDesc[1] & (1 << 8)) != 0) - KdbpPrint(" A"); - } - else /* Code segment */ - { - if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */ - KdbpPrint(" C"); - KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X"); - if ((SegDesc[1] & (1 << 8)) != 0) - KdbpPrint(" A"); - } - if ((SegDesc[1] & (1 << 20)) != 0) - KdbpPrint(" AVL"); - KdbpPrint("\n"); - } - } - } - - return TRUE; -} - -/*!\brief Displays the KPCR - */ -STATIC BOOLEAN -KdbpCmdPcr(ULONG Argc, PCHAR Argv[]) -{ - PKPCR Pcr = KeGetCurrentKPCR(); - - KdbpPrint("Current PCR is at 0x%08x.\n", (INT)Pcr); - KdbpPrint(" Tib.ExceptionList: 0x%08x\n" - " Tib.StackBase: 0x%08x\n" - " Tib.StackLimit: 0x%08x\n" - " Tib.SubSystemTib: 0x%08x\n" - " Tib.FiberData/Version: 0x%08x\n" - " Tib.ArbitraryUserPointer: 0x%08x\n" - " Tib.Self: 0x%08x\n" - " Self: 0x%08x\n" - " PCRCB: 0x%08x\n" - " Irql: 0x%02x\n" - " IRR: 0x%08x\n" - " IrrActive: 0x%08x\n" - " IDR: 0x%08x\n" - " KdVersionBlock: 0x%08x\n" - " IDT: 0x%08x\n" - " GDT: 0x%08x\n" - " TSS: 0x%08x\n" - " MajorVersion: 0x%04x\n" - " MinorVersion: 0x%04x\n" - " SetMember: 0x%08x\n" - " StallScaleFactor: 0x%08x\n" - " DebugActive: 0x%02x\n" - " ProcessorNumber: 0x%02x\n" - " L2CacheAssociativity: 0x%02x\n" - " VdmAlert: 0x%08x\n" - " L2CacheSize: 0x%08x\n" - " InterruptMode: 0x%08x\n", - Pcr->Tib.ExceptionList, Pcr->Tib.StackBase, Pcr->Tib.StackLimit, - Pcr->Tib.SubSystemTib, Pcr->Tib.FiberData, Pcr->Tib.ArbitraryUserPointer, - Pcr->Tib.Self, Pcr->Self, Pcr->PCRCB, Pcr->Irql, Pcr->IRR, Pcr->IrrActive, - Pcr->IDR, Pcr->KdVersionBlock, Pcr->IDT, Pcr->GDT, Pcr->TSS, - Pcr->MajorVersion, Pcr->MinorVersion, Pcr->SetMember, Pcr->StallScaleFactor, - Pcr->DebugActive, Pcr->ProcessorNumber, Pcr->L2CacheAssociativity, - Pcr->VdmAlert, Pcr->L2CacheSize, Pcr->InterruptMode); - - return TRUE; -} - -/*!\brief Displays the TSS - */ -STATIC BOOLEAN -KdbpCmdTss(ULONG Argc, PCHAR Argv[]) -{ - KTSS *Tss = KeGetCurrentKPCR()->TSS; - - KdbpPrint("Current TSS is at 0x%08x.\n", (INT)Tss); - KdbpPrint(" PreviousTask: 0x%08x\n" - " Ss0:Esp0: 0x%04x:0x%08x\n" - " Ss1:Esp1: 0x%04x:0x%08x\n" - " Ss2:Esp2: 0x%04x:0x%08x\n" - " Cr3: 0x%08x\n" - " Eip: 0x%08x\n" - " Eflags: 0x%08x\n" - " Eax: 0x%08x\n" - " Ecx: 0x%08x\n" - " Edx: 0x%08x\n" - " Ebx: 0x%08x\n" - " Esp: 0x%08x\n" - " Ebp: 0x%08x\n" - " Esi: 0x%08x\n" - " Edi: 0x%08x\n" - " Es: 0x%04x\n" - " Cs: 0x%04x\n" - " Ss: 0x%04x\n" - " Ds: 0x%04x\n" - " Fs: 0x%04x\n" - " Gs: 0x%04x\n" - " Ldt: 0x%04x\n" - " Trap: 0x%04x\n" - " IoMapBase: 0x%04x\n", - Tss->PreviousTask, Tss->Ss0, Tss->Esp0, Tss->Ss1, Tss->Esp1, - Tss->Ss2, Tss->Esp2, Tss->Cr3, Tss->Eip, Tss->Eflags, Tss->Eax, - Tss->Ecx, Tss->Edx, Tss->Ebx, Tss->Esp, Tss->Ebp, Tss->Esi, - Tss->Edi, Tss->Es, Tss->Cs, Tss->Ss, Tss->Ds, Tss->Fs, Tss->Gs, - Tss->Ldt, Tss->Trap, Tss->IoMapBase); - return TRUE; -} - -/*!\brief Bugchecks the system. - */ -STATIC BOOLEAN -KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]) -{ - KEBUGCHECK(0xDEADDEAD); - return TRUE; -} - -/*!\brief Sets or displays a config variables value. - */ -STATIC BOOLEAN -KdbpCmdSet(ULONG Argc, PCHAR Argv[]) -{ - LONG l; - BOOLEAN First; - PCHAR pend = 0; - KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter; - KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter; - STATIC CONST PCHAR ExceptionNames[21] = - { "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP", - "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT", - "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK", - "MACHINECHECK", "SIMDFAULT", "OTHERS" }; - - if (Argc == 1) - { - KdbpPrint("Available settings:\n"); - KdbpPrint(" syntax [intel|at&t]\n"); - KdbpPrint(" condition [exception|*] [first|last] [never|always|kmode|umode]\n"); - } - else if (strcmp(Argv[1], "syntax") == 0) - { - if (Argc == 2) - KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t"); - else if (Argc >= 3) - { - if (_stricmp(Argv[2], "intel") == 0) - KdbUseIntelSyntax = TRUE; - else if (_stricmp(Argv[2], "at&t") == 0) - KdbUseIntelSyntax = FALSE; - else - KdbpPrint("Unknown syntax '%s'.\n", Argv[2]); - } - } - else if (strcmp(Argv[1], "condition") == 0) - { - if (Argc == 2) - { - KdbpPrint("Conditions: (First) (Last)\n"); - for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++) - { - if (ExceptionNames[l] == NULL) - continue; - if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) - ASSERT(0); - if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) - ASSERT(0); - KdbpPrint(" #%02d %-20s %-8s %-8s\n", l, ExceptionNames[l], - KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), - KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); - } - ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1)); - KdbpPrint(" %-20s %-8s %-8s\n", ExceptionNames[l], - KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), - KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); - } - else - { - if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */ - l = -1; - else - { - l = (LONG)strtoul(Argv[2], &pend, 0); - if (Argv[2] == pend) - { - for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++) - { - if (ExceptionNames[l] == NULL) - continue; - if (_stricmp(ExceptionNames[l], Argv[2]) == 0) - break; - } - } - if (l >= RTL_NUMBER_OF(ExceptionNames)) - { - KdbpPrint("Unknown exception '%s'.\n", Argv[2]); - return TRUE; - } - } - if (Argc > 4) - { - if (_stricmp(Argv[3], "first") == 0) - First = TRUE; - else if (_stricmp(Argv[3], "last") == 0) - First = FALSE; - else - { - KdbpPrint("set condition: second argument must be 'first' or 'last'\n"); - return TRUE; - } - if (_stricmp(Argv[4], "never") == 0) - ConditionFirst = KdbDoNotEnter; - else if (_stricmp(Argv[4], "always") == 0) - ConditionFirst = KdbEnterAlways; - else if (_stricmp(Argv[4], "umode") == 0) - ConditionFirst = KdbEnterFromUmode; - else if (_stricmp(Argv[4], "kmode") == 0) - ConditionFirst = KdbEnterFromKmode; - else - { - KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n"); - return TRUE; - } - if (!KdbpSetEnterCondition(l, First, ConditionFirst)) - { - if (l >= 0) - KdbpPrint("Couldn't change condition for exception #%02d\n", l); - else - KdbpPrint("Couldn't change condition for all exceptions\n", l); - } - } - else /* Argc >= 3 */ - { - if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) - ASSERT(0); - if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) - ASSERT(0); - if (l < (RTL_NUMBER_OF(ExceptionNames) - 1)) - { - KdbpPrint("Condition for exception #%02d (%s): FirstChance %s LastChance %s\n", - l, ExceptionNames[l], - KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), - KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); - } - else - { - KdbpPrint("Condition for all other exceptions: FirstChance %s LastChance %s\n", - KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), - KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); - } - } - } - } - else - KdbpPrint("Unknown setting '%s'.\n", Argv[1]); - - return TRUE; -} - -/*!\brief Displays help screen. - */ -STATIC BOOLEAN -KdbpCmdHelp(ULONG Argc, PCHAR Argv[]) -{ - ULONG i; - - KdbpPrint("Kernel debugger commands:\n"); - for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) - { - if (KdbDebuggerCommands[i].Syntax == NULL) /* Command group */ - { - if (i > 0) - KdbpPrint("\n"); - KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help); - continue; - } - - KdbpPrint(" %-20s - %s\n", - KdbDebuggerCommands[i].Syntax, - KdbDebuggerCommands[i].Help); - } - - return TRUE; -} - -/*!\brief Prints the given string with printf-like formatting. - * - * \param Format Format of the string/arguments. - * \param ... Variable number of arguments matching the format specified in \a Format. - * - * \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. - */ -VOID -KdbpPrint( - IN PCHAR Format, - IN ... OPTIONAL) -{ - STATIC CHAR Buffer[4096]; - STATIC BOOLEAN TerminalInitialized = FALSE; - STATIC BOOLEAN TerminalReportsSize = TRUE; - CHAR c = '\0'; - PCHAR p; - INT Length; - INT i; - INT RowsPrintedByTerminal; - ULONG ScanCode; - va_list ap; - - /* Check if the user has aborted output of the current command */ - if (KdbOutputAborted) - return; - - /* Initialize the terminal */ - if (!TerminalInitialized) - { - DbgPrint("\x1b[7h"); /* Enable linewrap */ - TerminalInitialized = 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 ((KdDebugState & KD_DEBUG_KDSERIAL) && TerminalReportsSize) - { - /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ - TerminalReportsSize = FALSE; - //DbgPrint("\x1b[18t"); - c = KdbpTryGetCharSerial(10); - if (c == KEY_ESC) - { - c = KdbpTryGetCharSerial(5); - if (c == '[') - { - Length = 0; - for (;;) - { - c = KdbpTryGetCharSerial(5); - if (c == -1) - break; - Buffer[Length++] = c; - if (isalpha(c) || Length >= (sizeof (Buffer) - 1)) - break; - } - Buffer[Length] = '\0'; - if (Buffer[0] == '8' && Buffer[1] == ';') - { - for (i = 2; (i < Length) && (Buffer[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(Buffer + 2, NULL, 0); - KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0); - TerminalReportsSize = TRUE; - } - } - } - } - } - - 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 */ - va_start(ap, Format); - Length = _vsnprintf(Buffer, sizeof (Buffer) - 1, Format, ap); - Buffer[Length] = '\0'; - va_end(ap); - - p = Buffer; - while (p[0] != '\0') - { - i = strcspn(p, "\n"); - - /* 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 ((KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) - { - if (KdbNumberOfColsPrinted > 0) - DbgPrint("\n"); - DbgPrint("--- Press q to abort, any other key to continue ---"); - if (KdDebugState & 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 (KdDebugState & KD_DEBUG_KDSERIAL) - c = KdbpTryGetCharSerial(5); - else - c = KdbpTryGetCharKeyboard(&ScanCode, 5); - } - DbgPrint("\n"); - if (c == 'q') - { - KdbOutputAborted = TRUE; - return; - } - 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'; - } - - DbgPrint("%s", p); - - 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. - */ -STATIC VOID -KdbpCommandHistoryAppend( - IN PCHAR Command) -{ - LONG Length1 = strlen(Command) + 1; - LONG Length2 = 0; - INT i; - PCHAR Buffer; - - ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer)); - - if (Length1 <= 1 || - (KdbCommandHistory[KdbCommandHistoryIndex] != NULL && - strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0)) - { - return; - } - - /* Calculate Length1 and Length2 */ - Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex; - KdbCommandHistoryBufferIndex += Length1; - if (KdbCommandHistoryBufferIndex >= RTL_NUMBER_OF(KdbCommandHistoryBuffer)) - { - KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer); - Length2 = KdbCommandHistoryBufferIndex; - Length1 -= Length2; - } - - /* Remove previous commands until there is enough space to append the new command */ - for (i = KdbCommandHistoryIndex; KdbCommandHistory[i] != NULL;) - { - if ((Length2 > 0 && - (KdbCommandHistory[i] >= Buffer || - KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) || - (Length2 <= 0 && - (KdbCommandHistory[i] >= Buffer && - KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex)))) - { - KdbCommandHistory[i] = NULL; - } - i--; - if (i < 0) - i = RTL_NUMBER_OF(KdbCommandHistory) - 1; - if (i == KdbCommandHistoryIndex) - break; - } - - /* Make sure the new command history entry is free */ - KdbCommandHistoryIndex++; - KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory); - if (KdbCommandHistory[KdbCommandHistoryIndex] != NULL) - { - KdbCommandHistory[KdbCommandHistoryIndex] = NULL; - } - - /* Append command */ - KdbCommandHistory[KdbCommandHistoryIndex] = Buffer; - ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer)); - memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1); - if (Length2 > 0) - { - memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2); - } -} - -/*!\brief Reads a line of user-input. - * - * \param Buffer Buffer to store the input into. Trailing newlines are removed. - * \param Size Size of \a Buffer. - * - * \note Accepts only \n newlines, \r is ignored. - */ -STATIC VOID -KdbpReadCommand( - OUT PCHAR Buffer, - IN ULONG Size) -{ - CHAR Key, NextKey; - PCHAR Orig = Buffer; - ULONG ScanCode = 0; - BOOLEAN EchoOn; - STATIC CHAR LastCommand[1024] = ""; - STATIC CHAR LastKey = '\0'; - INT CmdHistIndex = -1; - INT i; - - EchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0); - - for (;;) - { - if (KdDebugState & KD_DEBUG_KDSERIAL) - { - Key = KdbpGetCharSerial(); - ScanCode = 0; - 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 = KdbpGetCharKeyboard(&ScanCode); - } - - if ((Buffer - Orig) >= (Size - 1)) - { - /* Buffer is full, accept only newlines */ - if (Key != '\n') - continue; - } - - if (Key == '\r') - { - /* Read the next char - this is to throw away a \n which most clients should - * send after \r. - */ - if (KdDebugState & KD_DEBUG_KDSERIAL) - NextKey = KdbpTryGetCharSerial(5); - else - NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5); - DbgPrint("\n"); - /* - * Repeat the last command if the user presses enter. Reduces the - * risk of RSI when single-stepping. - */ - if (Buffer == Orig) - { - strncpy(Buffer, LastCommand, Size); - Buffer[Size - 1] = '\0'; - } - else - { - *Buffer = '\0'; - strncpy(LastCommand, Orig, sizeof (LastCommand)); - LastCommand[sizeof (LastCommand) - 1] = '\0'; - } - LastKey = Key; - return; - } - else if (Key == KEY_BS || Key == KEY_DEL) - { - if (Buffer > Orig) - { - Buffer--; - *Buffer = 0; - if (EchoOn) - DbgPrint("%c %c", KEY_BS, KEY_BS); - else - DbgPrint(" %c", KEY_BS); - } - } - else if (ScanCode == KEY_SCAN_UP) - { - BOOLEAN Print = TRUE; - if (CmdHistIndex < 0) - CmdHistIndex = KdbCommandHistoryIndex; - else - { - i = CmdHistIndex - 1; - if (i < 0) - CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1; - if (KdbCommandHistory[i] != NULL && i != KdbCommandHistoryIndex) - CmdHistIndex = i; - else - Print = FALSE; - } - if (Print && KdbCommandHistory[CmdHistIndex] != NULL) - { - while (Buffer > Orig) - { - Buffer--; - *Buffer = 0; - if (EchoOn) - DbgPrint("%c %c", KEY_BS, KEY_BS); - else - DbgPrint(" %c", KEY_BS); - } - i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); - memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); - Orig[i] = '\0'; - Buffer = Orig + i; - DbgPrint("%s", Orig); - } - } - else if (ScanCode == KEY_SCAN_DOWN) - { - if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex) - { - i = CmdHistIndex + 1; - if (i >= RTL_NUMBER_OF(KdbCommandHistory)) - i = 0; - if (KdbCommandHistory[i] != NULL) - { - CmdHistIndex = i; - while (Buffer > Orig) - { - Buffer--; - *Buffer = 0; - if (EchoOn) - DbgPrint("%c %c", KEY_BS, KEY_BS); - else - DbgPrint(" %c", KEY_BS); - } - i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); - memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); - Orig[i] = '\0'; - Buffer = Orig + i; - DbgPrint("%s", Orig); - } - } - } - else - { - if (EchoOn) - DbgPrint("%c", Key); - - *Buffer = Key; - Buffer++; - } - LastKey = Key; - } -} - -/*!\brief Parses command line and executes command if found - * - * \param Command Command line to parse and execute if possible. - * - * \retval TRUE Don't continue execution. - * \retval FALSE Continue execution (leave KDB) - */ -STATIC BOOL -KdbpDoCommand( - IN PCHAR Command) -{ - ULONG i; - PCHAR p; - ULONG Argc; - STATIC PCH Argv[256]; - STATIC CHAR OrigCommand[1024]; - - strncpy(OrigCommand, Command, sizeof(OrigCommand) - 1); - OrigCommand[sizeof(OrigCommand) - 1] = '\0'; - - Argc = 0; - p = Command; - for (;;) - { - while (*p == '\t' || *p == ' ') - p++; - if (*p == '\0') - break; - - i = strcspn(p, "\t "); - Argv[Argc++] = p; - p += i; - if (*p == '\0') - break; - *p = '\0'; - p++; - } - if (Argc < 1) - return TRUE; - - for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) - { - if (KdbDebuggerCommands[i].Name == NULL) - continue; - - if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0) - { - return KdbDebuggerCommands[i].Fn(Argc, Argv); - } - } - - KdbpPrint("Command '%s' is unknown.\n", OrigCommand); - return TRUE; -} - -/*!\brief KDB Main Loop. - * - * \param EnteredOnSingleStep TRUE if KDB was entered on single step. - */ -VOID -KdbpCliMainLoop( - IN BOOLEAN EnteredOnSingleStep) -{ - STATIC CHAR Command[1024]; - BOOLEAN Continue; - - if (EnteredOnSingleStep) - { - if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip)) - { - DbgPrint("<%x>", KdbCurrentTrapFrame->Tf.Eip); - } - DbgPrint(": "); - if (KdbpDisassemble(KdbCurrentTrapFrame->Tf.Eip, KdbUseIntelSyntax) < 0) - { - DbgPrint(""); - } - DbgPrint("\n"); - } - - do - { - /* Print the prompt */ - DbgPrint("kdb:> "); - - /* Read a command and remember it */ - KdbpReadCommand(Command, sizeof (Command)); - KdbpCommandHistoryAppend(Command); - - /* Reset the number of rows/cols printed and output aborted state */ - KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; - KdbOutputAborted = FALSE; - - /* Call the command */ - Continue = KdbpDoCommand(Command); - } while (Continue); -} - -/*!\brief Called when a module is loaded. - * - * \param Name Filename of the module which was loaded. - */ -VOID -KdbpCliModuleLoaded(IN PUNICODE_STRING Name) -{ - return; - - DbgPrint("Module %wZ loaded.\n", Name); - DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); -} - -/*!\brief This function is called by KdbEnterDebuggerException... - * - * Used to interpret the init file in a context with a trapframe setup - * (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will - * call this function if KdbInitFileBuffer is not NULL. - */ -VOID -KdbpCliInterpretInitFile() -{ - PCHAR p1, p2; - INT i; - CHAR c; - - /* Execute the commands in the init file */ - DbgPrint("KDB: Executing KDBinit file...\n"); - p1 = KdbInitFileBuffer; - while (p1[0] != '\0') - { - i = strcspn(p1, "\r\n"); - if (i > 0) - { - c = p1[i]; - p1[i] = '\0'; - - /* Look for "break" command and comments */ - p2 = p1; - while (isspace(p2[0])) - p2++; - if (strncmp(p2, "break", sizeof("break")-1) == 0 && - (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1]))) - { - /* break into the debugger */ - KdbpCliMainLoop(FALSE); - } - else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */ - { - KdbpDoCommand(p1); - } - - p1[i] = c; - } - p1 += i; - while (p1[0] == '\r' || p1[0] == '\n') - p1++; - } - DbgPrint("KDB: KDBinit executed\n"); -} - -/*!\brief Called when KDB is initialized - * - * Reads the KDBinit file from the SystemRoot\system32\drivers\etc directory and executes it. - */ -VOID -KdbpCliInit() -{ - NTSTATUS Status; - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING FileName; - IO_STATUS_BLOCK Iosb; - FILE_STANDARD_INFORMATION FileStdInfo; - HANDLE hFile = NULL; - INT FileSize; - PCHAR FileBuffer; - ULONG OldEflags; - - /* Initialize the object attributes */ - RtlInitUnicodeString(&FileName, L"\\SystemRoot\\system32\\drivers\\etc\\KDBinit"); - InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL); - - /* Open the file */ - Status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0, - FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | - FILE_NO_INTERMEDIATE_BUFFERING); - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not open \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); - return; - } - - /* Get the size of the file */ - Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof (FileStdInfo), - FileStandardInformation); - if (!NT_SUCCESS(Status)) - { - ZwClose(hFile); - DPRINT("Could not query size of \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); - return; - } - FileSize = FileStdInfo.EndOfFile.u.LowPart; - - /* Allocate memory for the file */ - FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */ - if (FileBuffer == NULL) - { - ZwClose(hFile); - DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize); - return; - } - - /* Load file into memory */ - Status = ZwReadFile(hFile, 0, 0, 0, &Iosb, FileBuffer, FileSize, 0, 0); - ZwClose(hFile); - if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) - { - ExFreePool(FileBuffer); - DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status); - return; - } - FileSize = min(FileSize, Iosb.Information); - FileBuffer[FileSize] = '\0'; - - /* Enter critical section */ - Ke386SaveFlags(OldEflags); - Ke386DisableInterrupts(); - - /* Interpret the init file... */ - KdbInitFileBuffer = FileBuffer; - KdbEnter(); - KdbInitFileBuffer = NULL; - - /* Leave critical section */ - Ke386RestoreFlags(OldEflags); - - ExFreePool(FileBuffer); -} - +/* + * ReactOS kernel + * Copyright (C) 2005 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id$ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/dbg/kdb_cli.c + * PURPOSE: Kernel debugger command line interface + * PROGRAMMER: Gregor Anich (blight@blight.eu.org) + * UPDATE HISTORY: + * Created 16/01/2005 + */ + +/* INCLUDES ******************************************************************/ + +#include +#include "kdb.h" +#define NDEBUG +#include + +/* DEFINES *******************************************************************/ + +#define KEY_BS 8 +#define KEY_ESC 27 +#define KEY_DEL 127 + +#define KEY_SCAN_UP 72 +#define KEY_SCAN_DOWN 80 + +#define KDB_ENTER_CONDITION_TO_STRING(cond) \ + ((cond) == KdbDoNotEnter ? "never" : \ + ((cond) == KdbEnterAlways ? "always" : \ + ((cond) == KdbEnterFromKmode ? "kmode" : "umode"))) + +#define KDB_ACCESS_TYPE_TO_STRING(type) \ + ((type) == KdbAccessRead ? "read" : \ + ((type) == KdbAccessWrite ? "write" : \ + ((type) == KdbAccessReadWrite ? "rdwr" : "exec"))) + +#define NPX_STATE_TO_STRING(state) \ + ((state) == NPX_STATE_INVALID ? "Invalid" : \ + ((state) == NPX_STATE_VALID ? "Valid" : \ + ((state) == NPX_STATE_DIRTY ? "Dirty" : "Unknown"))) + +/* PROTOTYPES ****************************************************************/ + +STATIC BOOLEAN KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdRegs(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]); + +STATIC BOOLEAN KdbpCmdContinue(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdStep(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]); + +STATIC BOOLEAN KdbpCmdThread(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdProc(ULONG Argc, PCHAR Argv[]); + +STATIC BOOLEAN KdbpCmdMod(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdPcr(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]); + +STATIC BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]); +STATIC BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]); + +/* GLOBALS *******************************************************************/ + +STATIC BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */ + +STATIC CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */ +STATIC PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */ +STATIC LONG KdbCommandHistoryBufferIndex = 0; +STATIC LONG KdbCommandHistoryIndex = 0; + +STATIC ULONG KdbNumberOfRowsPrinted = 0; +STATIC ULONG KdbNumberOfColsPrinted = 0; +STATIC BOOLEAN KdbOutputAborted = FALSE; +STATIC LONG KdbNumberOfRowsTerminal = -1; +STATIC LONG KdbNumberOfColsTerminal = -1; + +PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */ + +STATIC CONST struct +{ + PCHAR Name; + PCHAR Syntax; + PCHAR Help; + BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]); +} KdbDebuggerCommands[] = { + /* Data */ + { NULL, NULL, "Data", NULL }, + { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression }, + { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX }, + { "x", "x [address] [L count]", "Display count dwords, starting at addr.", KdbpCmdDisassembleX }, + { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs }, + { "cregs", "cregs", "Display control registers.", KdbpCmdRegs }, + { "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 }, + + /* Flow control */ + { NULL, NULL, "Flow control", NULL }, + { "cont", "cont", "Continue execution (leave debugger)", KdbpCmdContinue }, + { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep }, + { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep }, + { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList }, + { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, + { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, + { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, + { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint }, + { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint }, + + /* Process/Thread */ + { NULL, NULL, "Process/Thread", NULL }, + { "thread", "thread [list[ pid]|[attach ]tid]", "List threads in current or specified process, display thread with given id or attach to thread.", KdbpCmdThread }, + { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc }, + + /* System information */ + { NULL, NULL, "System info", NULL }, + { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod }, + { "gdt", "gdt", "Display global descriptor table.", KdbpCmdGdtLdtIdt }, + { "ldt", "ldt", "Display local descriptor table.", KdbpCmdGdtLdtIdt }, + { "idt", "idt", "Display interrupt descriptor table.", KdbpCmdGdtLdtIdt }, + { "pcr", "pcr", "Display processor control region.", KdbpCmdPcr }, + { "tss", "tss", "Display task state segment.", KdbpCmdTss }, + + /* Others */ + { NULL, NULL, "Others", NULL }, + { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck }, + { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet }, + { "help", "help", "Display help screen.", KdbpCmdHelp } +}; + +/* FUNCTIONS *****************************************************************/ + +/*!\brief Evaluates an expression... + * + * Much like KdbpRpnEvaluateExpression, but prints the error message (if any) + * at the given offset. + * + * \param Expression Expression to evaluate. + * \param ErrOffset Offset (in characters) to print the error message at. + * \param Result Receives the result on success. + * + * \retval TRUE Success. + * \retval FALSE Failure. + */ +STATIC BOOLEAN +KdbpEvaluateExpression( + IN PCHAR Expression, + IN LONG ErrOffset, + OUT PULONGLONG Result) +{ + STATIC CHAR ErrMsgBuffer[130] = "^ "; + LONG ExpressionErrOffset = -1; + PCHAR ErrMsg = ErrMsgBuffer; + BOOLEAN Ok; + + Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result, + &ExpressionErrOffset, ErrMsgBuffer + 2); + if (!Ok) + { + if (ExpressionErrOffset >= 0) + ExpressionErrOffset += ErrOffset; + else + ErrMsg += 2; + KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg); + } + + return Ok; +} + +/*!\brief Evaluates an expression and displays the result. + */ +STATIC BOOLEAN +KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]) +{ + INT i, len; + ULONGLONG Result = 0; + ULONG ul; + LONG l = 0; + BOOLEAN Ok; + + if (Argc < 2) + { + KdbpPrint("?: Argument required\n"); + return TRUE; + } + + /* Put the arguments back together */ + Argc--; + for (i = 1; i < Argc; i++) + { + len = strlen(Argv[i]); + Argv[i][len] = ' '; + } + + /* Evaluate the expression */ + Ok = KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result); + if (Ok) + { + if (Result > 0x00000000ffffffffLL) + { + if (Result & 0x8000000000000000LL) + KdbpPrint("0x%016I64x %20I64u %20I64d\n", Result, Result, Result); + else + KdbpPrint("0x%016I64x %20I64u\n", Result, Result); + } + else + { + ul = (ULONG)Result; + if (ul <= 0xff && ul >= 0x80) + l = (LONG)((CHAR)ul); + else if (ul <= 0xffff && ul >= 0x8000) + l = (LONG)((SHORT)ul); + else + l = (LONG)ul; + if (l < 0) + KdbpPrint("0x%08lx %10lu %10ld\n", ul, ul, l); + else + KdbpPrint("0x%08lx %10lu\n", ul, ul); + } + } + + return TRUE; +} + +/*!\brief Disassembles 10 instructions at eip or given address or + * displays 16 dwords from memory at given address. + */ +STATIC BOOLEAN +KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]) +{ + ULONG Count; + ULONG ul; + INT i; + ULONGLONG Result = 0; + ULONG_PTR Address = KdbCurrentTrapFrame->Tf.Eip; + LONG InstLen; + + if (Argv[0][0] == 'x') /* display memory */ + Count = 16; + else /* disassemble */ + Count = 10; + + if (Argc >= 2) + { + /* Check for [L count] part */ + ul = 0; + if (strcmp(Argv[Argc-2], "L") == 0) + { + ul = strtoul(Argv[Argc-1], NULL, 0); + if (ul > 0) + { + Count = ul; + Argc -= 2; + } + } + else if (Argv[Argc-1][0] == 'L') + { + ul = strtoul(Argv[Argc-1] + 1, NULL, 0); + if (ul > 0) + { + Count = ul; + Argc--; + } + } + + /* Put the remaining arguments back together */ + Argc--; + for (ul = 1; ul < Argc; ul++) + { + Argv[ul][strlen(Argv[ul])] = ' '; + } + Argc++; + } + + /* Evaluate the expression */ + if (Argc > 1) + { + if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) + return TRUE; + if (Result > (ULONGLONG)(~((ULONG_PTR)0))) + KdbpPrint("Warning: Address %I64x is beeing truncated\n"); + Address = (ULONG_PTR)Result; + } + else if (Argv[0][0] == 'x') + { + KdbpPrint("x: Address argument required.\n"); + return TRUE; + } + + if (Argv[0][0] == 'x') + { + /* Display dwords */ + ul = 0; + while (Count > 0) + { + if (!KdbSymPrintAddress((PVOID)Address)) + KdbpPrint("<%x>:", Address); + else + KdbpPrint(":"); + i = min(4, Count); + Count -= i; + while (--i >= 0) + { + if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul)))) + KdbpPrint(" ????????"); + else + KdbpPrint(" %08x", ul); + Address += sizeof(ul); + } + KdbpPrint("\n"); + } + } + else + { + /* Disassemble */ + while (Count-- > 0) + { + if (!KdbSymPrintAddress((PVOID)Address)) + KdbpPrint("<%08x>: ", Address); + else + KdbpPrint(": "); + InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax); + if (InstLen < 0) + { + KdbpPrint("\n"); + return TRUE; + } + KdbpPrint("\n"); + Address += InstLen; + } + } + + return TRUE; +} + +/*!\brief Displays CPU registers. + */ +STATIC BOOLEAN +KdbpCmdRegs(ULONG Argc, PCHAR Argv[]) +{ + PKTRAP_FRAME Tf = &KdbCurrentTrapFrame->Tf; + INT i; + STATIC CONST PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5", + " ZF", " SF", " TF", " IF", " DF", " OF", + NULL, NULL, " NT", " BIT15", " RF", " VF", + " AC", " VIF", " VIP", " ID", " BIT22", + " BIT23", " BIT24", " BIT25", " BIT26", + " BIT27", " BIT28", " BIT29", " BIT30", + " BIT31" }; + + if (Argv[0][0] == 'r') /* regs */ + { + KdbpPrint("CS:EIP 0x%04x:0x%08x\n" + "SS:ESP 0x%04x:0x%08x\n" + " EAX 0x%08x EBX 0x%08x\n" + " ECX 0x%08x EDX 0x%08x\n" + " ESI 0x%08x EDI 0x%08x\n" + " EBP 0x%08x\n", + Tf->Cs & 0xFFFF, Tf->Eip, + Tf->Ss, Tf->Esp, + Tf->Eax, Tf->Ebx, + Tf->Ecx, Tf->Edx, + Tf->Esi, Tf->Edi, + Tf->Ebp); + KdbpPrint("EFLAGS 0x%08x ", Tf->Eflags); + for (i = 0; i < 32; i++) + { + if (i == 1) + { + if ((Tf->Eflags & (1 << 1)) == 0) + KdbpPrint(" !BIT1"); + } + else if (i == 12) + { + KdbpPrint(" IOPL%d", (Tf->Eflags >> 12) & 3); + } + else if (i == 13) + { + } + else if ((Tf->Eflags & (1 << i)) != 0) + KdbpPrint(EflagsBits[i]); + } + KdbpPrint("\n"); + } + else if (Argv[0][0] == 'c') /* cregs */ + { + ULONG Cr0, Cr2, Cr3, Cr4; + struct __attribute__((packed)) { + USHORT Limit; + ULONG Base; + } Gdtr, Ldtr, Idtr; + ULONG Tr; + STATIC CONST PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + " WP", NULL, " AM", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, " NW", " CD", " PG" }; + STATIC CONST PCHAR Cr4Bits[32] = { " VME", " PVI", " TSD", " DE", " PSE", " PAE", " MCE", " PGE", + " PCE", " OSFXSR", " OSXMMEXCPT", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + Cr0 = KdbCurrentTrapFrame->Cr0; + Cr2 = KdbCurrentTrapFrame->Cr2; + Cr3 = KdbCurrentTrapFrame->Cr3; + Cr4 = KdbCurrentTrapFrame->Cr4; + + /* Get descriptor table regs */ + asm volatile("sgdt %0" : : "m"(Gdtr)); + asm volatile("sldt %0" : : "m"(Ldtr)); + asm volatile("sidt %0" : : "m"(Idtr)); + + /* Get the task register */ + asm volatile("str %0" : "=g"(Tr)); + + /* Display the control registers */ + KdbpPrint("CR0 0x%08x ", Cr0); + for (i = 0; i < 32; i++) + { + if (Cr0Bits[i] == NULL) + continue; + if ((Cr0 & (1 << i)) != 0) + KdbpPrint(Cr0Bits[i]); + } + KdbpPrint("\nCR2 0x%08x\n", Cr2); + KdbpPrint("CR3 0x%08x Pagedir-Base 0x%08x %s%s\n", Cr3, (Cr3 & 0xfffff000), + (Cr3 & (1 << 3)) ? " PWT" : "", (Cr3 & (1 << 4)) ? " PCD" : "" ); + KdbpPrint("CR4 0x%08x ", Cr4); + for (i = 0; i < 32; i++) + { + if (Cr4Bits[i] == NULL) + continue; + if ((Cr4 & (1 << i)) != 0) + KdbpPrint(Cr4Bits[i]); + } + + /* Display the descriptor table regs */ + KdbpPrint("\nGDTR Base 0x%08x Size 0x%04x\n", Gdtr.Base, Gdtr.Limit); + KdbpPrint("LDTR Base 0x%08x Size 0x%04x\n", Ldtr.Base, Ldtr.Limit); + KdbpPrint("IDTR Base 0x%08x Size 0x%04x\n", Idtr.Base, Idtr.Limit); + } + else if (Argv[0][0] == 's') /* sregs */ + { + KdbpPrint("CS 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Cs & 0xffff, (Tf->Cs & 0xffff) >> 3, + (Tf->Cs & (1 << 2)) ? 'L' : 'G', Tf->Cs & 3); + KdbpPrint("DS 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Ds, Tf->Ds >> 3, (Tf->Ds & (1 << 2)) ? 'L' : 'G', Tf->Ds & 3); + KdbpPrint("ES 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Es, Tf->Es >> 3, (Tf->Es & (1 << 2)) ? 'L' : 'G', Tf->Es & 3); + KdbpPrint("FS 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Fs, Tf->Fs >> 3, (Tf->Fs & (1 << 2)) ? 'L' : 'G', Tf->Fs & 3); + KdbpPrint("GS 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Gs, Tf->Gs >> 3, (Tf->Gs & (1 << 2)) ? 'L' : 'G', Tf->Gs & 3); + KdbpPrint("SS 0x%04x Index 0x%04x %cDT RPL%d\n", + Tf->Ss, Tf->Ss >> 3, (Tf->Ss & (1 << 2)) ? 'L' : 'G', Tf->Ss & 3); + } + else /* dregs */ + { + ASSERT(Argv[0][0] == 'd'); + KdbpPrint("DR0 0x%08x\n" + "DR1 0x%08x\n" + "DR2 0x%08x\n" + "DR3 0x%08x\n" + "DR6 0x%08x\n" + "DR7 0x%08x\n", + Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, + Tf->Dr6, Tf->Dr7); + } + return TRUE; +} + +/*!\brief Displays a backtrace. + */ +STATIC BOOLEAN +KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]) +{ + ULONG Count; + ULONG ul; + ULONGLONG Result = 0; + ULONG_PTR Frame = KdbCurrentTrapFrame->Tf.Ebp; + ULONG_PTR Address; + + if (Argc >= 2) + { + /* Check for [L count] part */ + ul = 0; + if (strcmp(Argv[Argc-2], "L") == 0) + { + ul = strtoul(Argv[Argc-1], NULL, 0); + if (ul > 0) + { + Count = ul; + Argc -= 2; + } + } + else if (Argv[Argc-1][0] == 'L') + { + ul = strtoul(Argv[Argc-1] + 1, NULL, 0); + if (ul > 0) + { + Count = ul; + Argc--; + } + } + + /* Put the remaining arguments back together */ + Argc--; + for (ul = 1; ul < Argc; ul++) + { + Argv[ul][strlen(Argv[ul])] = ' '; + } + Argc++; + } + + /* Check if frame addr or thread id is given. */ + if (Argc > 1) + { + if (Argv[1][0] == '*') + { + Argv[1]++; + /* Evaluate the expression */ + if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) + return TRUE; + if (Result > (ULONGLONG)(~((ULONG_PTR)0))) + KdbpPrint("Warning: Address %I64x is beeing truncated\n"); + Frame = (ULONG_PTR)Result; + } + else + { + + KdbpPrint("Thread backtrace not supported yet!\n"); + return TRUE; + } + } + + KdbpPrint("Frames:\n"); + while (Frame != 0) + { + if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof (ULONG_PTR)))) + { + KdbpPrint("Couldn't access memory at 0x%x!\n", Frame + sizeof(ULONG_PTR)); + break; + } + if (!KdbSymPrintAddress((PVOID)Address)) + KdbpPrint("<%08x>\n", Address); + else + KdbpPrint("\n"); + if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof (ULONG_PTR)))) + { + KdbpPrint("Couldn't access memory at 0x%x!\n", Frame); + break; + } + } + + return TRUE; +} + +/*!\brief Continues execution of the system/leaves KDB. + */ +STATIC BOOLEAN +KdbpCmdContinue(ULONG Argc, PCHAR Argv[]) +{ + /* Exit the main loop */ + return FALSE; +} + +/*!\brief Continues execution of the system/leaves KDB. + */ +STATIC BOOLEAN +KdbpCmdStep(ULONG Argc, PCHAR Argv[]) +{ + ULONG Count = 1; + + if (Argc > 1) + { + Count = strtoul(Argv[1], NULL, 0); + if (Count == 0) + { + KdbpPrint("%s: Integer argument required\n", Argv[0]); + return TRUE; + } + } + + if (Argv[0][0] == 'n') + KdbSingleStepOver = TRUE; + else + KdbSingleStepOver = FALSE; + + /* Set the number of single steps and return to the interrupted code. */ + KdbNumSingleSteps = Count; + + return FALSE; +} + +/*!\brief Lists breakpoints. + */ +STATIC BOOLEAN +KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]) +{ + LONG l; + ULONG_PTR Address = 0; + KDB_BREAKPOINT_TYPE Type = 0; + KDB_ACCESS_TYPE AccessType = 0; + UCHAR Size = 0; + UCHAR DebugReg = 0; + BOOLEAN Enabled = FALSE; + BOOLEAN Global = FALSE; + PEPROCESS Process = NULL; + PCHAR str1, str2, ConditionExpr, GlobalOrLocal; + CHAR Buffer[20]; + + l = KdbpGetNextBreakPointNr(0); + if (l < 0) + { + KdbpPrint("No breakpoints.\n"); + return TRUE; + } + + KdbpPrint("Breakpoints:\n"); + do + { + if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg, + &Enabled, &Global, &Process, &ConditionExpr)) + { + continue; + } + + if (l == KdbLastBreakPointNr) + { + str1 = "\x1b[1m*"; + str2 = "\x1b[0m"; + } + else + { + str1 = " "; + str2 = ""; + } + + if (Global) + GlobalOrLocal = " global"; + else + { + GlobalOrLocal = Buffer; + sprintf(Buffer, " PID 0x%08lx", + (ULONG)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE)); + } + + if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary) + { + KdbpPrint(" %s%03d BPX 0x%08x%s%s%s%s%s\n", + str1, l, Address, + Enabled ? "" : " disabled", + GlobalOrLocal, + ConditionExpr ? " IF " : "", + ConditionExpr ? ConditionExpr : "", + str2); + } + else if (Type == KdbBreakPointHardware) + { + if (!Enabled) + { + KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s disabled%s%s%s%s\n", str1, l, Address, + KDB_ACCESS_TYPE_TO_STRING(AccessType), + Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), + GlobalOrLocal, + ConditionExpr ? " IF " : "", + ConditionExpr ? ConditionExpr : "", + str2); + } + else + { + KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s DR%d%s%s%s%s\n", str1, l, Address, + KDB_ACCESS_TYPE_TO_STRING(AccessType), + Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), + DebugReg, + GlobalOrLocal, + ConditionExpr ? " IF " : "", + ConditionExpr ? ConditionExpr : "", + str2); + } + } + } + while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0); + + return TRUE; +} + +/*!\brief Enables, disables or clears a breakpoint. + */ +STATIC BOOLEAN +KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]) +{ + PCHAR pend; + ULONG BreakPointNr; + + if (Argc < 2) + { + KdbpPrint("%s: argument required\n", Argv[0]); + return TRUE; + } + + pend = Argv[1]; + BreakPointNr = strtoul(Argv[1], &pend, 0); + if (pend == Argv[1] || *pend != '\0') + { + KdbpPrint("%s: integer argument required\n", Argv[0]); + return TRUE; + } + + if (Argv[0][1] == 'e') /* enable */ + { + KdbpEnableBreakPoint(BreakPointNr, NULL); + } + else if (Argv [0][1] == 'd') /* disable */ + { + KdbpDisableBreakPoint(BreakPointNr, NULL); + } + else /* clear */ + { + ASSERT(Argv[0][1] == 'c'); + KdbpDeleteBreakPoint(BreakPointNr, NULL); + } + + return TRUE; +} + +/*!\brief Sets a software or hardware (memory) breakpoint at the given address. + */ +STATIC BOOLEAN +KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]) +{ + ULONGLONG Result = 0; + ULONG_PTR Address; + KDB_BREAKPOINT_TYPE Type; + UCHAR Size = 0; + KDB_ACCESS_TYPE AccessType = 0; + INT AddressArgIndex, ConditionArgIndex, i; + BOOLEAN Global = TRUE; + + if (Argv[0][2] == 'x') /* software breakpoint */ + { + if (Argc < 2) + { + KdbpPrint("bpx: Address argument required.\n"); + return TRUE; + } + + AddressArgIndex = 1; + Type = KdbBreakPointSoftware; + } + else /* memory breakpoint */ + { + ASSERT(Argv[0][2] == 'm'); + + if (Argc < 2) + { + KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n"); + return TRUE; + } + + if (_stricmp(Argv[1], "x") == 0) + AccessType = KdbAccessExec; + else if (_stricmp(Argv[1], "r") == 0) + AccessType = KdbAccessRead; + else if (_stricmp(Argv[1], "w") == 0) + AccessType = KdbAccessWrite; + else if (_stricmp(Argv[1], "rw") == 0) + AccessType = KdbAccessReadWrite; + else + { + KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]); + return TRUE; + } + + if (Argc < 3) + { + KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size"); + return TRUE; + } + AddressArgIndex = 3; + if (_stricmp(Argv[2], "byte") == 0) + Size = 1; + else if (_stricmp(Argv[2], "word") == 0) + Size = 2; + else if (_stricmp(Argv[2], "dword") == 0) + Size = 4; + else if (AccessType == KdbAccessExec) + { + Size = 1; + AddressArgIndex--; + } + else + { + KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]); + return TRUE; + } + + if (Argc <= AddressArgIndex) + { + KdbpPrint("bpm: Address argument required.\n"); + return TRUE; + } + + Type = KdbBreakPointHardware; + } + + /* Put the arguments back together */ + ConditionArgIndex = -1; + for (i = AddressArgIndex; i < (Argc-1); i++) + { + if (strcmp(Argv[i+1], "IF") == 0) /* IF found */ + { + ConditionArgIndex = i + 2; + if (ConditionArgIndex >= Argc) + { + KdbpPrint("%s: IF requires condition expression.\n", Argv[0]); + return TRUE; + } + for (i = ConditionArgIndex; i < (Argc-1); i++) + Argv[i][strlen(Argv[i])] = ' '; + break; + } + Argv[i][strlen(Argv[i])] = ' '; + } + + /* Evaluate the address expression */ + if (!KdbpEvaluateExpression(Argv[AddressArgIndex], + sizeof("kdb:> ")-1 + (Argv[AddressArgIndex]-Argv[0]), + &Result)) + { + return TRUE; + } + if (Result > (ULONGLONG)(~((ULONG_PTR)0))) + KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]); + Address = (ULONG_PTR)Result; + + KdbpInsertBreakPoint(Address, Type, Size, AccessType, + (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex], + Global, NULL); + + return TRUE; +} + +/*!\brief Lists threads or switches to another thread context. + */ +STATIC BOOLEAN +KdbpCmdThread(ULONG Argc, PCHAR Argv[]) +{ + PLIST_ENTRY Entry; + PETHREAD Thread = NULL; + PEPROCESS Process = NULL; + PULONG Esp; + PULONG Ebp; + ULONG Eip; + ULONG ul = 0; + PCHAR State, pend, str1, str2; + STATIC CONST PCHAR ThreadStateToString[THREAD_STATE_MAX] = + { "Initialized", "Ready", "Running", + "Suspended", "Frozen", "Terminated1", + "Terminated2", "Blocked" }; + ASSERT(KdbCurrentProcess != NULL); + + if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) + { + Process = KdbCurrentProcess; + + if (Argc >= 3) + { + ul = strtoul(Argv[2], &pend, 0); + if (Argv[2] == pend) + { + KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]); + return TRUE; + } + if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) + { + KdbpPrint("thread: Invalid process id!\n"); + return TRUE; + } + } + + Entry = Process->ThreadListHead.Flink; + if (Entry == &Process->ThreadListHead) + { + if (Argc >= 3) + KdbpPrint("No threads in process 0x%08x!\n", ul); + else + KdbpPrint("No threads in current process!\n"); + return TRUE; + } + + KdbpPrint(" TID State Prior. Affinity EBP EIP\n"); + do + { + Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); + + if (Thread == KdbCurrentThread) + { + str1 = "\x1b[1m*"; + str2 = "\x1b[0m"; + } + else + { + str1 = " "; + str2 = ""; + } + + if (Thread->Tcb.TrapFrame != NULL) + { + Esp = (PULONG)Thread->Tcb.TrapFrame->Esp; + Ebp = (PULONG)Thread->Tcb.TrapFrame->Ebp; + Eip = Thread->Tcb.TrapFrame->Eip; + } + else + { + Esp = (PULONG)Thread->Tcb.KernelStack; + Ebp = (PULONG)Esp[4]; + Eip = 0; + if (Ebp != NULL) /* FIXME: Should we attach to the process to read Ebp[1]? */ + KdbpSafeReadMemory(&Eip, Ebp + 1, sizeof (Eip));; + } + if (Thread->Tcb.State < THREAD_STATE_MAX) + State = ThreadStateToString[Thread->Tcb.State]; + else + State = "Unknown"; + + KdbpPrint(" %s0x%08x %-11s %3d 0x%08x 0x%08x 0x%08x%s\n", + str1, + Thread->Cid.UniqueThread, + State, + Thread->Tcb.Priority, + Thread->Tcb.Affinity, + Ebp, + Eip, + str2); + + Entry = Entry->Flink; + } + while (Entry != &Process->ThreadListHead); + } + else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) + { + if (Argc < 3) + { + KdbpPrint("thread attach: thread id argument required!\n"); + return TRUE; + } + + ul = strtoul(Argv[2], &pend, 0); + if (Argv[2] == pend) + { + KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]); + return TRUE; + } + if (!KdbpAttachToThread((PVOID)ul)) + { + return TRUE; + } + KdbpPrint("Attached to thread 0x%08x.\n", ul); + } + else + { + Thread = KdbCurrentThread; + + if (Argc >= 2) + { + ul = strtoul(Argv[1], &pend, 0); + if (Argv[1] == pend) + { + KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]); + return TRUE; + } + if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread))) + { + KdbpPrint("thread: Invalid thread id!\n"); + return TRUE; + } + } + + if (Thread->Tcb.State < THREAD_STATE_MAX) + State = ThreadStateToString[Thread->Tcb.State]; + else + State = "Unknown"; + KdbpPrint("%s" + " TID: 0x%08x\n" + " State: %s (0x%x)\n" + " Priority: %d\n" + " Affinity: 0x%08x\n" + " Initial Stack: 0x%08x\n" + " Stack Limit: 0x%08x\n" + " Stack Base: 0x%08x\n" + " Kernel Stack: 0x%08x\n" + " Trap Frame: 0x%08x\n" + " NPX State: %s (0x%x)\n", + (Argc < 2) ? "Current Thread:\n" : "", + Thread->Cid.UniqueThread, + State, Thread->Tcb.State, + Thread->Tcb.Priority, + Thread->Tcb.Affinity, + Thread->Tcb.InitialStack, + Thread->Tcb.StackLimit, + Thread->Tcb.StackBase, + Thread->Tcb.KernelStack, + Thread->Tcb.TrapFrame, + NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState); + + } + + return TRUE; +} + +/*!\brief Lists processes or switches to another process context. + */ +STATIC BOOLEAN +KdbpCmdProc(ULONG Argc, PCHAR Argv[]) +{ + PLIST_ENTRY Entry; + PEPROCESS Process; + PCHAR State, pend, str1, str2; + ULONG ul; + extern LIST_ENTRY PsActiveProcessHead; + + if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) + { + Entry = PsActiveProcessHead.Flink; + if (Entry == &PsActiveProcessHead) + { + KdbpPrint("No processes in the system!\n"); + return TRUE; + } + + KdbpPrint(" PID State Filename\n"); + do + { + Process = CONTAINING_RECORD(Entry, EPROCESS, ProcessListEntry); + + if (Process == KdbCurrentProcess) + { + str1 = "\x1b[1m*"; + str2 = "\x1b[0m"; + } + else + { + str1 = " "; + str2 = ""; + } + + State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" : + ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown")); + + KdbpPrint(" %s0x%08x %-10s %s%s\n", + str1, + Process->UniqueProcessId, + State, + Process->ImageFileName, + str2); + + Entry = Entry->Flink; + } + while(Entry != &PsActiveProcessHead); + } + else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) + { + if (Argc < 3) + { + KdbpPrint("process attach: process id argument required!\n"); + return TRUE; + } + + ul = strtoul(Argv[2], &pend, 0); + if (Argv[2] == pend) + { + KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]); + return TRUE; + } + if (!KdbpAttachToProcess((PVOID)ul)) + { + return TRUE; + } + KdbpPrint("Attached to process 0x%08x, thread 0x%08x.\n", (UINT)ul, + (UINT)KdbCurrentThread->Cid.UniqueThread); + } + else + { + Process = KdbCurrentProcess; + + if (Argc >= 2) + { + ul = strtoul(Argv[1], &pend, 0); + if (Argv[1] == pend) + { + KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]); + return TRUE; + } + if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) + { + KdbpPrint("proc: Invalid process id!\n"); + return TRUE; + } + } + + State = ((Process->Pcb.State == PROCESS_STATE_TERMINATED) ? "Terminated" : + ((Process->Pcb.State == PROCESS_STATE_ACTIVE) ? "Active" : "Unknown")); + KdbpPrint("%s" + " PID: 0x%08x\n" + " State: %s (0x%x)\n" + " Image Filename: %s\n", + (Argc < 2) ? "Current process:\n" : "", + Process->UniqueProcessId, + State, Process->Pcb.State, + Process->ImageFileName); + } + + return TRUE; +} + +/*!\brief Lists loaded modules or the one containing the specified address. + */ +STATIC BOOLEAN +KdbpCmdMod(ULONG Argc, PCHAR Argv[]) +{ + ULONGLONG Result = 0; + ULONG_PTR Address; + KDB_MODULE_INFO Info; + BOOLEAN DisplayOnlyOneModule = FALSE; + INT i = 0; + + if (Argc >= 2) + { + /* Put the arguments back together */ + Argc--; + while (--Argc >= 1) + Argv[Argc][strlen(Argv[Argc])] = ' '; + + /* Evaluate the expression */ + if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) + { + return TRUE; + } + if (Result > (ULONGLONG)(~((ULONG_PTR)0))) + KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0]); + Address = (ULONG_PTR)Result; + + if (!KdbpSymFindModuleByAddress((PVOID)Address, &Info)) + { + KdbpPrint("No module containing address 0x%x found!\n", Address); + return TRUE; + } + DisplayOnlyOneModule = TRUE; + } + else + { + if (!KdbpSymFindModuleByIndex(0, &Info)) + { + KdbpPrint("No modules.\n"); + return TRUE; + } + i = 1; + } + + KdbpPrint(" Base Size Name\n"); + for (;;) + { + KdbpPrint(" %08x %08x %ws\n", Info.Base, Info.Size, Info.Name); + + if ((!DisplayOnlyOneModule && !KdbpSymFindModuleByIndex(i++, &Info)) || + DisplayOnlyOneModule) + { + break; + } + } + + return TRUE; +} + +/*!\brief Displays GDT, LDT or IDTd. + */ +STATIC BOOLEAN +KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]) +{ + struct __attribute__((packed)) { + USHORT Limit; + ULONG Base; + } Reg; + ULONG SegDesc[2]; + ULONG SegBase; + ULONG SegLimit; + PCHAR SegType; + USHORT SegSel; + UCHAR Type, Dpl; + INT i; + ULONG ul; + + if (Argv[0][0] == 'i') + { + /* Read IDTR */ + asm volatile("sidt %0" : : "m"(Reg)); + + if (Reg.Limit < 7) + { + KdbpPrint("Interrupt descriptor table is empty.\n"); + return TRUE; + } + KdbpPrint("IDT Base: 0x%08x Limit: 0x%04x\n", Reg.Base, Reg.Limit); + KdbpPrint(" Idx Type Seg. Sel. Offset DPL\n"); + for (i = 0; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) + { + if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) + { + KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); + return TRUE; + } + + Dpl = ((SegDesc[1] >> 13) & 3); + if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ + SegType = "TASKGATE"; + else if ((SegDesc[1] & 0x1fe0) == 0x0e00) /* 32 bit Interrupt gate */ + SegType = "INTGATE32"; + else if ((SegDesc[1] & 0x1fe0) == 0x0600) /* 16 bit Interrupt gate */ + SegType = "INTGATE16"; + else if ((SegDesc[1] & 0x1fe0) == 0x0f00) /* 32 bit Trap gate */ + SegType = "TRAPGATE32"; + else if ((SegDesc[1] & 0x1fe0) == 0x0700) /* 16 bit Trap gate */ + SegType = "TRAPGATE16"; + else + SegType = "UNKNOWN"; + + if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ + { + KdbpPrint(" %03d %-10s [NP] [NP] %02d\n", + i / 8, SegType, Dpl); + } + else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ + { + SegSel = SegDesc[0] >> 16; + KdbpPrint(" %03d %-10s 0x%04x %02d\n", + i / 8, SegType, SegSel, Dpl); + } + else + { + SegSel = SegDesc[0] >> 16; + SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff); + KdbpPrint(" %03d %-10s 0x%04x 0x%08x %02d\n", + i / 8, SegType, SegSel, SegBase, Dpl); + } + } + } + else + { + ul = 0; + if (Argv[0][0] == 'g') + { + /* Read GDTR */ + asm volatile("sgdt %0" : : "m"(Reg)); + i = 8; + } + else + { + ASSERT(Argv[0][0] == 'l'); + /* Read LDTR */ + asm volatile("sldt %0" : : "m"(Reg)); + i = 0; + ul = 1 << 2; + } + + if (Reg.Limit < 7) + { + KdbpPrint("%s descriptor table is empty.\n", + Argv[0][0] == 'g' ? "Global" : "Local"); + return TRUE; + } + KdbpPrint("%cDT Base: 0x%08x Limit: 0x%04x\n", + Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit); + KdbpPrint(" Idx Sel. Type Base Limit DPL Attribs\n"); + for ( ; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) + { + if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) + { + KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); + return TRUE; + } + Dpl = ((SegDesc[1] >> 13) & 3); + Type = ((SegDesc[1] >> 8) & 0xf); + + SegBase = SegDesc[0] >> 16; + SegBase |= (SegDesc[1] & 0xff) << 16; + SegBase |= SegDesc[1] & 0xff000000; + SegLimit = SegDesc[0] & 0x0000ffff; + SegLimit |= (SegDesc[1] >> 16) & 0xf; + if ((SegDesc[1] & (1 << 23)) != 0) + { + SegLimit *= 4096; + SegLimit += 4095; + } + else + { + SegLimit++; + } + + if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ + { + switch (Type) + { + case 1: SegType = "TSS16(Avl)"; break; + case 2: SegType = "LDT"; break; + case 3: SegType = "TSS16(Busy)"; break; + case 4: SegType = "CALLGATE16"; break; + case 5: SegType = "TASKGATE"; break; + case 6: SegType = "INTGATE16"; break; + case 7: SegType = "TRAPGATE16"; break; + case 9: SegType = "TSS32(Avl)"; break; + case 11: SegType = "TSS32(Busy)"; break; + case 12: SegType = "CALLGATE32"; break; + case 14: SegType = "INTGATE32"; break; + case 15: SegType = "INTGATE32"; break; + default: SegType = "UNKNOWN"; break; + } + if (!(Type >= 1 && Type <= 3) && + Type != 9 && Type != 11) + { + SegBase = 0; + SegLimit = 0; + } + } + else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ + { + if ((SegDesc[1] & (1 << 22)) != 0) + SegType = "DATA32"; + else + SegType = "DATA16"; + + } + else /* Code segment */ + { + if ((SegDesc[1] & (1 << 22)) != 0) + SegType = "CODE32"; + else + SegType = "CODE16"; + } + + if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ + { + KdbpPrint(" %03d 0x%04x %-11s [NP] [NP] %02d NP\n", + i / 8, i | Dpl | ul, SegType, Dpl); + } + else + { + KdbpPrint(" %03d 0x%04x %-11s 0x%08x 0x%08x %02d ", + i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl); + if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ + { + /* FIXME: Display system segment */ + } + else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ + { + if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */ + KdbpPrint(" E"); + KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R"); + if ((SegDesc[1] & (1 << 8)) != 0) + KdbpPrint(" A"); + } + else /* Code segment */ + { + if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */ + KdbpPrint(" C"); + KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X"); + if ((SegDesc[1] & (1 << 8)) != 0) + KdbpPrint(" A"); + } + if ((SegDesc[1] & (1 << 20)) != 0) + KdbpPrint(" AVL"); + KdbpPrint("\n"); + } + } + } + + return TRUE; +} + +/*!\brief Displays the KPCR + */ +STATIC BOOLEAN +KdbpCmdPcr(ULONG Argc, PCHAR Argv[]) +{ + PKPCR Pcr = KeGetCurrentKPCR(); + + KdbpPrint("Current PCR is at 0x%08x.\n", (INT)Pcr); + KdbpPrint(" Tib.ExceptionList: 0x%08x\n" + " Tib.StackBase: 0x%08x\n" + " Tib.StackLimit: 0x%08x\n" + " Tib.SubSystemTib: 0x%08x\n" + " Tib.FiberData/Version: 0x%08x\n" + " Tib.ArbitraryUserPointer: 0x%08x\n" + " Tib.Self: 0x%08x\n" + " Self: 0x%08x\n" + " PCRCB: 0x%08x\n" + " Irql: 0x%02x\n" + " IRR: 0x%08x\n" + " IrrActive: 0x%08x\n" + " IDR: 0x%08x\n" + " KdVersionBlock: 0x%08x\n" + " IDT: 0x%08x\n" + " GDT: 0x%08x\n" + " TSS: 0x%08x\n" + " MajorVersion: 0x%04x\n" + " MinorVersion: 0x%04x\n" + " SetMember: 0x%08x\n" + " StallScaleFactor: 0x%08x\n" + " DebugActive: 0x%02x\n" + " ProcessorNumber: 0x%02x\n" + " L2CacheAssociativity: 0x%02x\n" + " VdmAlert: 0x%08x\n" + " L2CacheSize: 0x%08x\n" + " InterruptMode: 0x%08x\n", + Pcr->Tib.ExceptionList, Pcr->Tib.StackBase, Pcr->Tib.StackLimit, + Pcr->Tib.SubSystemTib, Pcr->Tib.FiberData, Pcr->Tib.ArbitraryUserPointer, + Pcr->Tib.Self, Pcr->Self, Pcr->Prcb, Pcr->Irql, Pcr->IRR, Pcr->IrrActive, + Pcr->IDR, Pcr->KdVersionBlock, Pcr->IDT, Pcr->GDT, Pcr->TSS, + Pcr->MajorVersion, Pcr->MinorVersion, Pcr->SetMember, Pcr->StallScaleFactor, + Pcr->DebugActive, Pcr->ProcessorNumber, Pcr->L2CacheAssociativity, + Pcr->VdmAlert, Pcr->L2CacheSize, Pcr->InterruptMode); + + return TRUE; +} + +/*!\brief Displays the TSS + */ +STATIC BOOLEAN +KdbpCmdTss(ULONG Argc, PCHAR Argv[]) +{ + KTSS *Tss = KeGetCurrentKPCR()->TSS; + + KdbpPrint("Current TSS is at 0x%08x.\n", (INT)Tss); + KdbpPrint(" PreviousTask: 0x%08x\n" + " Ss0:Esp0: 0x%04x:0x%08x\n" + " Ss1:Esp1: 0x%04x:0x%08x\n" + " Ss2:Esp2: 0x%04x:0x%08x\n" + " Cr3: 0x%08x\n" + " Eip: 0x%08x\n" + " Eflags: 0x%08x\n" + " Eax: 0x%08x\n" + " Ecx: 0x%08x\n" + " Edx: 0x%08x\n" + " Ebx: 0x%08x\n" + " Esp: 0x%08x\n" + " Ebp: 0x%08x\n" + " Esi: 0x%08x\n" + " Edi: 0x%08x\n" + " Es: 0x%04x\n" + " Cs: 0x%04x\n" + " Ss: 0x%04x\n" + " Ds: 0x%04x\n" + " Fs: 0x%04x\n" + " Gs: 0x%04x\n" + " Ldt: 0x%04x\n" + " Trap: 0x%04x\n" + " IoMapBase: 0x%04x\n", + Tss->PreviousTask, Tss->Ss0, Tss->Esp0, Tss->Ss1, Tss->Esp1, + Tss->Ss2, Tss->Esp2, Tss->Cr3, Tss->Eip, Tss->Eflags, Tss->Eax, + Tss->Ecx, Tss->Edx, Tss->Ebx, Tss->Esp, Tss->Ebp, Tss->Esi, + Tss->Edi, Tss->Es, Tss->Cs, Tss->Ss, Tss->Ds, Tss->Fs, Tss->Gs, + Tss->Ldt, Tss->Trap, Tss->IoMapBase); + return TRUE; +} + +/*!\brief Bugchecks the system. + */ +STATIC BOOLEAN +KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]) +{ + KEBUGCHECK(0xDEADDEAD); + return TRUE; +} + +/*!\brief Sets or displays a config variables value. + */ +STATIC BOOLEAN +KdbpCmdSet(ULONG Argc, PCHAR Argv[]) +{ + LONG l; + BOOLEAN First; + PCHAR pend = 0; + KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter; + KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter; + STATIC CONST PCHAR ExceptionNames[21] = + { "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP", + "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT", + "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK", + "MACHINECHECK", "SIMDFAULT", "OTHERS" }; + + if (Argc == 1) + { + KdbpPrint("Available settings:\n"); + KdbpPrint(" syntax [intel|at&t]\n"); + KdbpPrint(" condition [exception|*] [first|last] [never|always|kmode|umode]\n"); + } + else if (strcmp(Argv[1], "syntax") == 0) + { + if (Argc == 2) + KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t"); + else if (Argc >= 3) + { + if (_stricmp(Argv[2], "intel") == 0) + KdbUseIntelSyntax = TRUE; + else if (_stricmp(Argv[2], "at&t") == 0) + KdbUseIntelSyntax = FALSE; + else + KdbpPrint("Unknown syntax '%s'.\n", Argv[2]); + } + } + else if (strcmp(Argv[1], "condition") == 0) + { + if (Argc == 2) + { + KdbpPrint("Conditions: (First) (Last)\n"); + for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++) + { + if (ExceptionNames[l] == NULL) + continue; + if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) + ASSERT(0); + if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) + ASSERT(0); + KdbpPrint(" #%02d %-20s %-8s %-8s\n", l, ExceptionNames[l], + KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), + KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); + } + ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1)); + KdbpPrint(" %-20s %-8s %-8s\n", ExceptionNames[l], + KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), + KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); + } + else + { + if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */ + l = -1; + else + { + l = (LONG)strtoul(Argv[2], &pend, 0); + if (Argv[2] == pend) + { + for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++) + { + if (ExceptionNames[l] == NULL) + continue; + if (_stricmp(ExceptionNames[l], Argv[2]) == 0) + break; + } + } + if (l >= RTL_NUMBER_OF(ExceptionNames)) + { + KdbpPrint("Unknown exception '%s'.\n", Argv[2]); + return TRUE; + } + } + if (Argc > 4) + { + if (_stricmp(Argv[3], "first") == 0) + First = TRUE; + else if (_stricmp(Argv[3], "last") == 0) + First = FALSE; + else + { + KdbpPrint("set condition: second argument must be 'first' or 'last'\n"); + return TRUE; + } + if (_stricmp(Argv[4], "never") == 0) + ConditionFirst = KdbDoNotEnter; + else if (_stricmp(Argv[4], "always") == 0) + ConditionFirst = KdbEnterAlways; + else if (_stricmp(Argv[4], "umode") == 0) + ConditionFirst = KdbEnterFromUmode; + else if (_stricmp(Argv[4], "kmode") == 0) + ConditionFirst = KdbEnterFromKmode; + else + { + KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n"); + return TRUE; + } + if (!KdbpSetEnterCondition(l, First, ConditionFirst)) + { + if (l >= 0) + KdbpPrint("Couldn't change condition for exception #%02d\n", l); + else + KdbpPrint("Couldn't change condition for all exceptions\n", l); + } + } + else /* Argc >= 3 */ + { + if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) + ASSERT(0); + if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) + ASSERT(0); + if (l < (RTL_NUMBER_OF(ExceptionNames) - 1)) + { + KdbpPrint("Condition for exception #%02d (%s): FirstChance %s LastChance %s\n", + l, ExceptionNames[l], + KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), + KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); + } + else + { + KdbpPrint("Condition for all other exceptions: FirstChance %s LastChance %s\n", + KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), + KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); + } + } + } + } + else + KdbpPrint("Unknown setting '%s'.\n", Argv[1]); + + return TRUE; +} + +/*!\brief Displays help screen. + */ +STATIC BOOLEAN +KdbpCmdHelp(ULONG Argc, PCHAR Argv[]) +{ + ULONG i; + + KdbpPrint("Kernel debugger commands:\n"); + for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) + { + if (KdbDebuggerCommands[i].Syntax == NULL) /* Command group */ + { + if (i > 0) + KdbpPrint("\n"); + KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help); + continue; + } + + KdbpPrint(" %-20s - %s\n", + KdbDebuggerCommands[i].Syntax, + KdbDebuggerCommands[i].Help); + } + + return TRUE; +} + +/*!\brief Prints the given string with printf-like formatting. + * + * \param Format Format of the string/arguments. + * \param ... Variable number of arguments matching the format specified in \a Format. + * + * \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. + */ +VOID +KdbpPrint( + IN PCHAR Format, + IN ... OPTIONAL) +{ + STATIC CHAR Buffer[4096]; + STATIC BOOLEAN TerminalInitialized = FALSE; + STATIC BOOLEAN TerminalReportsSize = TRUE; + CHAR c = '\0'; + PCHAR p; + INT Length; + INT i; + INT RowsPrintedByTerminal; + ULONG ScanCode; + va_list ap; + + /* Check if the user has aborted output of the current command */ + if (KdbOutputAborted) + return; + + /* Initialize the terminal */ + if (!TerminalInitialized) + { + DbgPrint("\x1b[7h"); /* Enable linewrap */ + TerminalInitialized = 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 ((KdDebugState & KD_DEBUG_KDSERIAL) && TerminalReportsSize) + { + /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ + TerminalReportsSize = FALSE; + //DbgPrint("\x1b[18t"); + c = KdbpTryGetCharSerial(10); + if (c == KEY_ESC) + { + c = KdbpTryGetCharSerial(5); + if (c == '[') + { + Length = 0; + for (;;) + { + c = KdbpTryGetCharSerial(5); + if (c == -1) + break; + Buffer[Length++] = c; + if (isalpha(c) || Length >= (sizeof (Buffer) - 1)) + break; + } + Buffer[Length] = '\0'; + if (Buffer[0] == '8' && Buffer[1] == ';') + { + for (i = 2; (i < Length) && (Buffer[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(Buffer + 2, NULL, 0); + KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0); + TerminalReportsSize = TRUE; + } + } + } + } + } + + 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 */ + va_start(ap, Format); + Length = _vsnprintf(Buffer, sizeof (Buffer) - 1, Format, ap); + Buffer[Length] = '\0'; + va_end(ap); + + p = Buffer; + while (p[0] != '\0') + { + i = strcspn(p, "\n"); + + /* 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 ((KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) + { + if (KdbNumberOfColsPrinted > 0) + DbgPrint("\n"); + DbgPrint("--- Press q to abort, any other key to continue ---"); + if (KdDebugState & 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 (KdDebugState & KD_DEBUG_KDSERIAL) + c = KdbpTryGetCharSerial(5); + else + c = KdbpTryGetCharKeyboard(&ScanCode, 5); + } + DbgPrint("\n"); + if (c == 'q') + { + KdbOutputAborted = TRUE; + return; + } + 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'; + } + + DbgPrint("%s", p); + + 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. + */ +STATIC VOID +KdbpCommandHistoryAppend( + IN PCHAR Command) +{ + LONG Length1 = strlen(Command) + 1; + LONG Length2 = 0; + INT i; + PCHAR Buffer; + + ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer)); + + if (Length1 <= 1 || + (KdbCommandHistory[KdbCommandHistoryIndex] != NULL && + strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0)) + { + return; + } + + /* Calculate Length1 and Length2 */ + Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex; + KdbCommandHistoryBufferIndex += Length1; + if (KdbCommandHistoryBufferIndex >= RTL_NUMBER_OF(KdbCommandHistoryBuffer)) + { + KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer); + Length2 = KdbCommandHistoryBufferIndex; + Length1 -= Length2; + } + + /* Remove previous commands until there is enough space to append the new command */ + for (i = KdbCommandHistoryIndex; KdbCommandHistory[i] != NULL;) + { + if ((Length2 > 0 && + (KdbCommandHistory[i] >= Buffer || + KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) || + (Length2 <= 0 && + (KdbCommandHistory[i] >= Buffer && + KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex)))) + { + KdbCommandHistory[i] = NULL; + } + i--; + if (i < 0) + i = RTL_NUMBER_OF(KdbCommandHistory) - 1; + if (i == KdbCommandHistoryIndex) + break; + } + + /* Make sure the new command history entry is free */ + KdbCommandHistoryIndex++; + KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory); + if (KdbCommandHistory[KdbCommandHistoryIndex] != NULL) + { + KdbCommandHistory[KdbCommandHistoryIndex] = NULL; + } + + /* Append command */ + KdbCommandHistory[KdbCommandHistoryIndex] = Buffer; + ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer)); + memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1); + if (Length2 > 0) + { + memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2); + } +} + +/*!\brief Reads a line of user-input. + * + * \param Buffer Buffer to store the input into. Trailing newlines are removed. + * \param Size Size of \a Buffer. + * + * \note Accepts only \n newlines, \r is ignored. + */ +STATIC VOID +KdbpReadCommand( + OUT PCHAR Buffer, + IN ULONG Size) +{ + CHAR Key, NextKey; + PCHAR Orig = Buffer; + ULONG ScanCode = 0; + BOOLEAN EchoOn; + STATIC CHAR LastCommand[1024] = ""; + STATIC CHAR LastKey = '\0'; + INT CmdHistIndex = -1; + INT i; + + EchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0); + + for (;;) + { + if (KdDebugState & KD_DEBUG_KDSERIAL) + { + Key = KdbpGetCharSerial(); + ScanCode = 0; + 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 = KdbpGetCharKeyboard(&ScanCode); + } + + if ((Buffer - Orig) >= (Size - 1)) + { + /* Buffer is full, accept only newlines */ + if (Key != '\n') + continue; + } + + if (Key == '\r') + { + /* Read the next char - this is to throw away a \n which most clients should + * send after \r. + */ + if (KdDebugState & KD_DEBUG_KDSERIAL) + NextKey = KdbpTryGetCharSerial(5); + else + NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5); + DbgPrint("\n"); + /* + * Repeat the last command if the user presses enter. Reduces the + * risk of RSI when single-stepping. + */ + if (Buffer == Orig) + { + strncpy(Buffer, LastCommand, Size); + Buffer[Size - 1] = '\0'; + } + else + { + *Buffer = '\0'; + strncpy(LastCommand, Orig, sizeof (LastCommand)); + LastCommand[sizeof (LastCommand) - 1] = '\0'; + } + LastKey = Key; + return; + } + else if (Key == KEY_BS || Key == KEY_DEL) + { + if (Buffer > Orig) + { + Buffer--; + *Buffer = 0; + if (EchoOn) + DbgPrint("%c %c", KEY_BS, KEY_BS); + else + DbgPrint(" %c", KEY_BS); + } + } + else if (ScanCode == KEY_SCAN_UP) + { + BOOLEAN Print = TRUE; + if (CmdHistIndex < 0) + CmdHistIndex = KdbCommandHistoryIndex; + else + { + i = CmdHistIndex - 1; + if (i < 0) + CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1; + if (KdbCommandHistory[i] != NULL && i != KdbCommandHistoryIndex) + CmdHistIndex = i; + else + Print = FALSE; + } + if (Print && KdbCommandHistory[CmdHistIndex] != NULL) + { + while (Buffer > Orig) + { + Buffer--; + *Buffer = 0; + if (EchoOn) + DbgPrint("%c %c", KEY_BS, KEY_BS); + else + DbgPrint(" %c", KEY_BS); + } + i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); + memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); + Orig[i] = '\0'; + Buffer = Orig + i; + DbgPrint("%s", Orig); + } + } + else if (ScanCode == KEY_SCAN_DOWN) + { + if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex) + { + i = CmdHistIndex + 1; + if (i >= RTL_NUMBER_OF(KdbCommandHistory)) + i = 0; + if (KdbCommandHistory[i] != NULL) + { + CmdHistIndex = i; + while (Buffer > Orig) + { + Buffer--; + *Buffer = 0; + if (EchoOn) + DbgPrint("%c %c", KEY_BS, KEY_BS); + else + DbgPrint(" %c", KEY_BS); + } + i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); + memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); + Orig[i] = '\0'; + Buffer = Orig + i; + DbgPrint("%s", Orig); + } + } + } + else + { + if (EchoOn) + DbgPrint("%c", Key); + + *Buffer = Key; + Buffer++; + } + LastKey = Key; + } +} + +/*!\brief Parses command line and executes command if found + * + * \param Command Command line to parse and execute if possible. + * + * \retval TRUE Don't continue execution. + * \retval FALSE Continue execution (leave KDB) + */ +STATIC BOOL +KdbpDoCommand( + IN PCHAR Command) +{ + ULONG i; + PCHAR p; + ULONG Argc; + STATIC PCH Argv[256]; + STATIC CHAR OrigCommand[1024]; + + strncpy(OrigCommand, Command, sizeof(OrigCommand) - 1); + OrigCommand[sizeof(OrigCommand) - 1] = '\0'; + + Argc = 0; + p = Command; + for (;;) + { + while (*p == '\t' || *p == ' ') + p++; + if (*p == '\0') + break; + + i = strcspn(p, "\t "); + Argv[Argc++] = p; + p += i; + if (*p == '\0') + break; + *p = '\0'; + p++; + } + if (Argc < 1) + return TRUE; + + for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) + { + if (KdbDebuggerCommands[i].Name == NULL) + continue; + + if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0) + { + return KdbDebuggerCommands[i].Fn(Argc, Argv); + } + } + + KdbpPrint("Command '%s' is unknown.\n", OrigCommand); + return TRUE; +} + +/*!\brief KDB Main Loop. + * + * \param EnteredOnSingleStep TRUE if KDB was entered on single step. + */ +VOID +KdbpCliMainLoop( + IN BOOLEAN EnteredOnSingleStep) +{ + STATIC CHAR Command[1024]; + BOOLEAN Continue; + + if (EnteredOnSingleStep) + { + if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip)) + { + DbgPrint("<%x>", KdbCurrentTrapFrame->Tf.Eip); + } + DbgPrint(": "); + if (KdbpDisassemble(KdbCurrentTrapFrame->Tf.Eip, KdbUseIntelSyntax) < 0) + { + DbgPrint(""); + } + DbgPrint("\n"); + } + + do + { + /* Print the prompt */ + DbgPrint("kdb:> "); + + /* Read a command and remember it */ + KdbpReadCommand(Command, sizeof (Command)); + KdbpCommandHistoryAppend(Command); + + /* Reset the number of rows/cols printed and output aborted state */ + KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; + KdbOutputAborted = FALSE; + + /* Call the command */ + Continue = KdbpDoCommand(Command); + } while (Continue); +} + +/*!\brief Called when a module is loaded. + * + * \param Name Filename of the module which was loaded. + */ +VOID +KdbpCliModuleLoaded(IN PUNICODE_STRING Name) +{ + return; + + DbgPrint("Module %wZ loaded.\n", Name); + DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); +} + +/*!\brief This function is called by KdbEnterDebuggerException... + * + * Used to interpret the init file in a context with a trapframe setup + * (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will + * call this function if KdbInitFileBuffer is not NULL. + */ +VOID +KdbpCliInterpretInitFile() +{ + PCHAR p1, p2; + INT i; + CHAR c; + + /* Execute the commands in the init file */ + DbgPrint("KDB: Executing KDBinit file...\n"); + p1 = KdbInitFileBuffer; + while (p1[0] != '\0') + { + i = strcspn(p1, "\r\n"); + if (i > 0) + { + c = p1[i]; + p1[i] = '\0'; + + /* Look for "break" command and comments */ + p2 = p1; + while (isspace(p2[0])) + p2++; + if (strncmp(p2, "break", sizeof("break")-1) == 0 && + (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1]))) + { + /* break into the debugger */ + KdbpCliMainLoop(FALSE); + } + else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */ + { + KdbpDoCommand(p1); + } + + p1[i] = c; + } + p1 += i; + while (p1[0] == '\r' || p1[0] == '\n') + p1++; + } + DbgPrint("KDB: KDBinit executed\n"); +} + +/*!\brief Called when KDB is initialized + * + * Reads the KDBinit file from the SystemRoot\system32\drivers\etc directory and executes it. + */ +VOID +KdbpCliInit() +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING FileName; + IO_STATUS_BLOCK Iosb; + FILE_STANDARD_INFORMATION FileStdInfo; + HANDLE hFile = NULL; + INT FileSize; + PCHAR FileBuffer; + ULONG OldEflags; + + /* Initialize the object attributes */ + RtlInitUnicodeString(&FileName, L"\\SystemRoot\\system32\\drivers\\etc\\KDBinit"); + InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL); + + /* Open the file */ + Status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | + FILE_NO_INTERMEDIATE_BUFFERING); + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not open \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); + return; + } + + /* Get the size of the file */ + Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof (FileStdInfo), + FileStandardInformation); + if (!NT_SUCCESS(Status)) + { + ZwClose(hFile); + DPRINT("Could not query size of \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); + return; + } + FileSize = FileStdInfo.EndOfFile.u.LowPart; + + /* Allocate memory for the file */ + FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */ + if (FileBuffer == NULL) + { + ZwClose(hFile); + DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize); + return; + } + + /* Load file into memory */ + Status = ZwReadFile(hFile, 0, 0, 0, &Iosb, FileBuffer, FileSize, 0, 0); + ZwClose(hFile); + if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) + { + ExFreePool(FileBuffer); + DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status); + return; + } + FileSize = min(FileSize, Iosb.Information); + FileBuffer[FileSize] = '\0'; + + /* Enter critical section */ + Ke386SaveFlags(OldEflags); + Ke386DisableInterrupts(); + + /* Interpret the init file... */ + KdbInitFileBuffer = FileBuffer; + KdbEnter(); + KdbInitFileBuffer = NULL; + + /* Leave critical section */ + Ke386RestoreFlags(OldEflags); + + ExFreePool(FileBuffer); +} + diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 03951a885d7..fe66586543b 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -38,19 +38,6 @@ ExInit3 (VOID) } -/* - * @implemented - */ -BOOLEAN STDCALL -ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature) -{ - if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) - return(FALSE); - - return(SharedUserData->ProcessorFeatures[ProcessorFeature]); -} - - VOID STDCALL ExPostSystemEvent (ULONG Unknown1, ULONG Unknown2, diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index bf4c528484f..f76e9695ae2 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -46,17 +46,18 @@ ExGetCurrentProcessorCpuUsage ( PULONG CpuUsage ) { - PKPCR Pcr; + PKPRCB Prcb; ULONG TotalTime; - ULONG PercentTime = 0; ULONGLONG ScaledIdle; - Pcr = KeGetCurrentKPCR(); + Prcb = KeGetCurrentPrcb(); - ScaledIdle = Pcr->PrcbData.IdleThread->KernelTime * 100; - TotalTime = Pcr->PrcbData.KernelTime + Pcr->PrcbData.UserTime; - if (TotalTime) PercentTime = 100 - (ScaledIdle / TotalTime); - CpuUsage = &PercentTime; + ScaledIdle = Prcb->IdleThread->KernelTime * 100; + TotalTime = Prcb->KernelTime + Prcb->UserTime; + if (TotalTime != 0) + *CpuUsage = 100 - (ScaledIdle / TotalTime); + else + *CpuUsage = 0; } /* @@ -70,20 +71,27 @@ ExGetCurrentProcessorCounts ( PULONG ProcessorNumber ) { - PKPCR Pcr; - ULONG TotalTime; - ULONG ThreadTime; - ULONG ProcNumber; + PKPRCB Prcb; - Pcr = KeGetCurrentKPCR(); + Prcb = KeGetCurrentPrcb(); - TotalTime = Pcr->PrcbData.KernelTime + Pcr->PrcbData.UserTime; - ThreadTime = Pcr->PrcbData.CurrentThread->KernelTime; - ProcNumber = Pcr->ProcessorNumber; + *ThreadKernelTime = Prcb->KernelTime + Prcb->UserTime; + *TotalCpuTime = Prcb->CurrentThread->KernelTime; + *ProcessorNumber = KeGetCurrentKPCR()->ProcessorNumber; +} - ThreadKernelTime = &ThreadTime; - TotalCpuTime = &TotalTime; - ProcessorNumber = &ProcNumber; +/* + * @implemented + */ +BOOLEAN +STDCALL +ExIsProcessorFeaturePresent(IN ULONG ProcessorFeature) +{ + /* Quick check to see if it exists at all */ + if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return(FALSE); + + /* Return our support for it */ + return(SharedUserData->ProcessorFeatures[ProcessorFeature]); } NTSTATUS STDCALL @@ -363,7 +371,7 @@ QSI_DEF(SystemProcessorInformation) { PSYSTEM_PROCESSOR_INFORMATION Spi = (PSYSTEM_PROCESSOR_INFORMATION) Buffer; - PKPCR Pcr; + PKPRCB Prcb; *ReqSize = sizeof (SYSTEM_PROCESSOR_INFORMATION); /* * Check user buffer's size @@ -372,12 +380,12 @@ QSI_DEF(SystemProcessorInformation) { return (STATUS_INFO_LENGTH_MISMATCH); } - Pcr = KeGetCurrentKPCR(); + Prcb = KeGetCurrentPrcb(); Spi->ProcessorArchitecture = 0; /* Intel Processor */ - Spi->ProcessorLevel = Pcr->PrcbData.CpuType; - Spi->ProcessorRevision = Pcr->PrcbData.CpuStep; + Spi->ProcessorLevel = Prcb->CpuType; + Spi->ProcessorRevision = Prcb->CpuStep; Spi->Unknown = 0; - Spi->FeatureBits = Pcr->PrcbData.FeatureBits; + Spi->FeatureBits = Prcb->FeatureBits; DPRINT("Arch %d Level %d Rev 0x%x\n", Spi->ProcessorArchitecture, Spi->ProcessorLevel, Spi->ProcessorRevision); @@ -713,7 +721,7 @@ QSI_DEF(SystemProcessorPerformanceInformation) ULONG i; LARGE_INTEGER CurrentTime; - PKPCR Pcr; + PKPRCB Prcb; *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSORTIME_INFO); /* @@ -725,19 +733,17 @@ QSI_DEF(SystemProcessorPerformanceInformation) } CurrentTime.QuadPart = KeQueryInterruptTime(); - Pcr = (PKPCR)KPCR_BASE; + Prcb = ((PKPCR)KPCR_BASE)->Prcb; for (i = 0; i < KeNumberProcessors; i++) { - - Spi->TotalProcessorRunTime.QuadPart = (Pcr->PrcbData.IdleThread->KernelTime + Pcr->PrcbData.IdleThread->UserTime) * 100000LL; // IdleTime - Spi->TotalProcessorTime.QuadPart = Pcr->PrcbData.KernelTime * 100000LL; // KernelTime - Spi->TotalProcessorUserTime.QuadPart = Pcr->PrcbData.UserTime * 100000LL; - Spi->TotalDPCTime.QuadPart = Pcr->PrcbData.DpcTime * 100000LL; - Spi->TotalInterruptTime.QuadPart = Pcr->PrcbData.InterruptTime * 100000LL; - Spi->TotalInterrupts = Pcr->PrcbData.InterruptCount; // Interrupt Count + Spi->TotalProcessorRunTime.QuadPart = (Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime) * 100000LL; // IdleTime + Spi->TotalProcessorTime.QuadPart = Prcb->KernelTime * 100000LL; // KernelTime + Spi->TotalProcessorUserTime.QuadPart = Prcb->UserTime * 100000LL; + Spi->TotalDPCTime.QuadPart = Prcb->DpcTime * 100000LL; + Spi->TotalInterruptTime.QuadPart = Prcb->InterruptTime * 100000LL; + Spi->TotalInterrupts = Prcb->InterruptCount; // Interrupt Count Spi++; -// Pcr++; - Pcr = (PKPCR)((ULONG_PTR)Pcr + PAGE_SIZE); + Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE); } return (STATUS_SUCCESS); diff --git a/reactos/ntoskrnl/include/internal/i386/ps.h b/reactos/ntoskrnl/include/internal/i386/ps.h index f6cf2dc6bc7..cf9e505b9f2 100644 --- a/reactos/ntoskrnl/include/internal/i386/ps.h +++ b/reactos/ntoskrnl/include/internal/i386/ps.h @@ -217,7 +217,7 @@ typedef struct _KPCR_TIB { typedef struct _KPCR { KPCR_TIB Tib; /* 00 */ struct _KPCR *Self; /* 1C */ - struct _KPRCB *PCRCB; /* 20 */ + struct _KPRCB *Prcb; /* 20 */ KIRQL Irql; /* 24 */ ULONG IRR; /* 28 */ ULONG IrrActive; /* 2C */ @@ -269,9 +269,28 @@ static inline PKPCR KeGetCurrentKPCR(VOID) return((PKPCR)value); } +static inline PKPRCB KeGetCurrentPrcb(VOID) +{ + ULONG value; + +#if defined(__GNUC__) + __asm__ __volatile__ ("movl %%fs:0x20, %0\n\t" + : "=r" (value) + : /* no inputs */ + ); +#elif defined(_MSC_VER) + __asm mov eax, fs:0x20; + __asm mov value, eax; +#else +#error Unknown compiler for inline assembler +#endif + return((PKPRCB)value); +} + #else #define KeGetCurrentKPCR(X) ((PKPCR)KPCR_BASE) +#define KeGetCurrentPrcb() (((PKPCR)KPCR_BASE)->Prcb) #endif diff --git a/reactos/ntoskrnl/ke/clock.c b/reactos/ntoskrnl/ke/clock.c index e9424cbed4f..4a03c0ed363 100644 --- a/reactos/ntoskrnl/ke/clock.c +++ b/reactos/ntoskrnl/ke/clock.c @@ -242,22 +242,22 @@ KeUpdateRunTime( IN KIRQL Irql ) { - PKPCR Pcr; + PKPRCB Prcb; PKTHREAD CurrentThread; PKPROCESS CurrentProcess; #if 0 ULONG DpcLastCount; #endif - Pcr = KeGetCurrentKPCR(); + Prcb = KeGetCurrentPrcb(); /* Make sure we don't go further if we're in early boot phase. */ - if (Pcr == NULL || Pcr->PrcbData.CurrentThread == NULL) + if (Prcb == NULL || Prcb->CurrentThread == NULL) return; - DPRINT("KernelTime %u, UserTime %u \n", Pcr->PrcbData.KernelTime, Pcr->PrcbData.UserTime); + DPRINT("KernelTime %u, UserTime %u \n", Prcb->KernelTime, Prcb->UserTime); - CurrentThread = Pcr->PrcbData.CurrentThread; + CurrentThread = Prcb->CurrentThread; CurrentProcess = CurrentThread->ApcState.Process; /* @@ -269,36 +269,36 @@ KeUpdateRunTime( { InterlockedIncrementUL(&CurrentThread->UserTime); InterlockedIncrementUL(&CurrentProcess->UserTime); - Pcr->PrcbData.UserTime++; + Prcb->UserTime++; } else { if (Irql > DISPATCH_LEVEL) { - Pcr->PrcbData.InterruptTime++; + Prcb->InterruptTime++; } else if (Irql == DISPATCH_LEVEL) { - Pcr->PrcbData.DpcTime++; + Prcb->DpcTime++; } else { InterlockedIncrementUL(&CurrentThread->KernelTime); InterlockedIncrementUL(&CurrentProcess->KernelTime); - Pcr->PrcbData.KernelTime++; + Prcb->KernelTime++; } } #if 0 - DpcLastCount = Pcr->PrcbData.DpcLastCount; - Pcr->PrcbData.DpcLastCount = Pcr->PrcbData.DpcCount; - Pcr->PrcbData.DpcRequestRate = ((Pcr->PrcbData.DpcCount - DpcLastCount) + - Pcr->PrcbData.DpcRequestRate) / 2; + DpcLastCount = Prcb->DpcLastCount; + Prcb->DpcLastCount = Prcb->DpcCount; + Prcb->DpcRequestRate = ((Prcb->DpcCount - DpcLastCount) + + Prcb->DpcRequestRate) / 2; #endif - if (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0 && - Pcr->PrcbData.DpcRoutineActive == FALSE && - Pcr->PrcbData.DpcInterruptRequested == FALSE) + if (Prcb->DpcData[0].DpcQueueDepth > 0 && + Prcb->DpcRoutineActive == FALSE && + Prcb->DpcInterruptRequested == FALSE) { HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } @@ -311,7 +311,7 @@ KeUpdateRunTime( */ if ((CurrentThread->Quantum -= 3) <= 0) { - Pcr->PrcbData.QuantumEnd = TRUE; + Prcb->QuantumEnd = TRUE; HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } } diff --git a/reactos/ntoskrnl/ke/i386/fpu.c b/reactos/ntoskrnl/ke/i386/fpu.c index fd5d5dcee17..59195b40c72 100644 --- a/reactos/ntoskrnl/ke/i386/fpu.c +++ b/reactos/ntoskrnl/ke/i386/fpu.c @@ -1,4 +1,4 @@ -/* $Id:$ +/* $Id$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -228,7 +228,7 @@ KiCheckFPU(VOID) unsigned short int status; int cr0; ULONG Flags; - PKPCR Pcr = KeGetCurrentKPCR(); + PKPRCB Prcb = KeGetCurrentPrcb(); Ke386SaveFlags(Flags); Ke386DisableInterrupts(); @@ -275,7 +275,7 @@ KiCheckFPU(VOID) HardwareMathSupport = 1; /* check for and enable MMX/SSE support if possible */ - if ((Pcr->PrcbData.FeatureBits & X86_FEATURE_FXSR) != 0) + if ((Prcb->FeatureBits & X86_FEATURE_FXSR) != 0) { BYTE DummyArea[sizeof(FX_SAVE_AREA) + 15]; PFX_SAVE_AREA FxSaveArea; @@ -300,7 +300,7 @@ KiCheckFPU(VOID) } } /* FIXME: Check for SSE3 in Ke386CpuidFlags2! */ - if (Pcr->PrcbData.FeatureBits & (X86_FEATURE_SSE | X86_FEATURE_SSE2)) + if (Prcb->FeatureBits & (X86_FEATURE_SSE | X86_FEATURE_SSE2)) { Ke386SetCr4(Ke386GetCr4() | X86_CR4_OSXMMEXCPT); @@ -401,7 +401,7 @@ KiHandleFpuFault(PKTRAP_FRAME Tf, ULONG ExceptionNr) CurrentThread = KeGetCurrentThread(); #ifndef CONFIG_SMP - NpxThread = KeGetCurrentKPCR()->PrcbData.NpxThread; + NpxThread = KeGetCurrentPrcb()->NpxThread; #endif ASSERT(CurrentThread != NULL); @@ -414,7 +414,7 @@ KiHandleFpuFault(PKTRAP_FRAME Tf, ULONG ExceptionNr) /* save the FPU state into the owner's save area */ if (NpxThread != NULL) { - KeGetCurrentKPCR()->PrcbData.NpxThread = NULL; + KeGetCurrentPrcb()->NpxThread = NULL; FxSaveArea = (PFX_SAVE_AREA)((char *)NpxThread->InitialStack - sizeof (FX_SAVE_AREA)); /* the fnsave might raise a delayed #MF exception */ if (FxsrSupport) @@ -463,7 +463,7 @@ KiHandleFpuFault(PKTRAP_FRAME Tf, ULONG ExceptionNr) asm volatile("finit"); } } - KeGetCurrentKPCR()->PrcbData.NpxThread = CurrentThread; + KeGetCurrentPrcb()->NpxThread = CurrentThread; #ifndef CONFIG_SMP } #endif @@ -487,7 +487,7 @@ KiHandleFpuFault(PKTRAP_FRAME Tf, ULONG ExceptionNr) KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); - NpxThread = KeGetCurrentKPCR()->PrcbData.NpxThread; + NpxThread = KeGetCurrentPrcb()->NpxThread; CurrentThread = KeGetCurrentThread(); if (NpxThread == NULL) { diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index cf90d44695f..865dd302fcb 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -315,7 +315,7 @@ KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe) * the PIC. */ - KeGetCurrentKPCR()->PrcbData.InterruptCount++; + KeGetCurrentPrcb()->InterruptCount++; /* * Notify the rest of the kernel of the raised irq level. For the diff --git a/reactos/ntoskrnl/ke/i386/kernel.c b/reactos/ntoskrnl/ke/i386/kernel.c index bd901a32679..98915f77210 100644 --- a/reactos/ntoskrnl/ke/i386/kernel.c +++ b/reactos/ntoskrnl/ke/i386/kernel.c @@ -146,6 +146,7 @@ KePrepareForApplicationProcessorInit(ULONG Id) Pcr->ProcessorNumber = Id; Pcr->Tib.Self = &Pcr->Tib; Pcr->Self = Pcr; + Pcr->Prcb = &Pcr->PrcbData; Pcr->Irql = SYNCH_LEVEL; Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz; @@ -238,6 +239,7 @@ KeInit1(PCHAR CommandLine, PULONG LastKernelAddress) KPCR = (PKPCR)KPCR_BASE; memset(KPCR, 0, PAGE_SIZE); KPCR->Self = KPCR; + KPCR->Prcb = &KPCR->PrcbData; KPCR->Irql = SYNCH_LEVEL; KPCR->Tib.Self = &KPCR->Tib; KPCR->GDT = KiBootGdt; diff --git a/reactos/ntoskrnl/ke/ipi.c b/reactos/ntoskrnl/ke/ipi.c index 3798d44acdf..25843863125 100644 --- a/reactos/ntoskrnl/ke/ipi.c +++ b/reactos/ntoskrnl/ke/ipi.c @@ -32,7 +32,7 @@ KiIpiSendRequest(ULONG TargetSet, ULONG IpiRequest) if (TargetSet & (1 << i)) { Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); - Ke386TestAndSetBit(IpiRequest, &Pcr->PrcbData.IpiFrozen); + Ke386TestAndSetBit(IpiRequest, &Pcr->Prcb->IpiFrozen); HalRequestIpi(i); } } @@ -50,34 +50,34 @@ KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame, LARGE_INTEGER StartTime, CurrentTime, Frequency; ULONG Count = 5; #endif - PKPCR Pcr; + PKPRCB Prcb; ASSERT(KeGetCurrentIrql() == IPI_LEVEL); DPRINT("KiIpiServiceRoutine\n"); - Pcr = KeGetCurrentKPCR(); + Prcb = KeGetCurrentPrcb(); - if (Ke386TestAndClearBit(IPI_REQUEST_APC, &Pcr->PrcbData.IpiFrozen)) + if (Ke386TestAndClearBit(IPI_REQUEST_APC, &Prcb->IpiFrozen)) { HalRequestSoftwareInterrupt(APC_LEVEL); } - if (Ke386TestAndClearBit(IPI_REQUEST_DPC, &Pcr->PrcbData.IpiFrozen)) + if (Ke386TestAndClearBit(IPI_REQUEST_DPC, &Prcb->IpiFrozen)) { - Pcr->PrcbData.DpcInterruptRequested = TRUE; + Prcb->DpcInterruptRequested = TRUE; HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } - if (Ke386TestAndClearBit(IPI_REQUEST_FUNCTIONCALL, &Pcr->PrcbData.IpiFrozen)) + if (Ke386TestAndClearBit(IPI_REQUEST_FUNCTIONCALL, &Prcb->IpiFrozen)) { - InterlockedDecrementUL(&Pcr->PrcbData.SignalDone->CurrentPacket[1]); - if (InterlockedCompareExchangeUL(&Pcr->PrcbData.SignalDone->CurrentPacket[2], 0, 0)) + InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]); + if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0)) { #ifdef DBG StartTime = KeQueryPerformanceCounter(&Frequency); #endif - while (0 != InterlockedCompareExchangeUL(&Pcr->PrcbData.SignalDone->CurrentPacket[1], 0, 0)) + while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0)) { #ifdef DBG CurrentTime = KeQueryPerformanceCounter(NULL); @@ -89,14 +89,14 @@ KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame, #endif } } - ((VOID STDCALL(*)(PVOID))(Pcr->PrcbData.SignalDone->WorkerRoutine))(Pcr->PrcbData.SignalDone->CurrentPacket[0]); - Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Pcr->PrcbData.SignalDone->TargetSet); - if (InterlockedCompareExchangeUL(&Pcr->PrcbData.SignalDone->CurrentPacket[2], 0, 0)) + ((VOID STDCALL(*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]); + Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Prcb->SignalDone->TargetSet); + if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0)) { #ifdef DBG StartTime = KeQueryPerformanceCounter(&Frequency); #endif - while (0 != InterlockedCompareExchangeUL(&Pcr->PrcbData.SignalDone->TargetSet, 0, 0)) + while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0)) { #ifdef DBG CurrentTime = KeQueryPerformanceCounter(NULL); @@ -108,7 +108,7 @@ KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame, #endif } } - InterlockedExchangePointer(&Pcr->PrcbData.SignalDone, NULL); + InterlockedExchangePointer(&Prcb->SignalDone, NULL); } DPRINT("KiIpiServiceRoutine done\n"); return TRUE; @@ -119,18 +119,18 @@ STDCALL KiIpiSendPacket(ULONG TargetSet, VOID STDCALL (*WorkerRoutine)(PVOID), PVOID Argument, ULONG Count, BOOLEAN Synchronize) { ULONG i, Processor, CurrentProcessor; - PKPCR Pcr, CurrentPcr; + PKPRCB Prcb, CurrentPrcb; KIRQL oldIrql; ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL); - CurrentPcr = KeGetCurrentKPCR(); - InterlockedExchangeUL(&CurrentPcr->PrcbData.TargetSet, TargetSet); - InterlockedExchangeUL(&CurrentPcr->PrcbData.WorkerRoutine, (ULONG_PTR)WorkerRoutine); - InterlockedExchangePointer(&CurrentPcr->PrcbData.CurrentPacket[0], Argument); - InterlockedExchangeUL(&CurrentPcr->PrcbData.CurrentPacket[1], Count); - InterlockedExchangeUL(&CurrentPcr->PrcbData.CurrentPacket[2], Synchronize ? 1 : 0); + CurrentPrcb = KeGetCurrentPrcb(); + InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet); + InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine); + InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument); + InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count); + InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0); CurrentProcessor = 1 << KeGetCurrentProcessorNumber(); @@ -138,9 +138,9 @@ KiIpiSendPacket(ULONG TargetSet, VOID STDCALL (*WorkerRoutine)(PVOID), PVOID Arg { if (TargetSet & Processor) { - Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); - while(0 != InterlockedCompareExchangeUL(&Pcr->PrcbData.SignalDone, (LONG)&CurrentPcr->PrcbData, 0)); - Ke386TestAndSetBit(IPI_REQUEST_FUNCTIONCALL, &Pcr->PrcbData.IpiFrozen); + Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb; + while(0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0)); + Ke386TestAndSetBit(IPI_REQUEST_FUNCTIONCALL, &Prcb->IpiFrozen); if (Processor != CurrentProcessor) { HalRequestIpi(i); diff --git a/reactos/ntoskrnl/ps/i386/continue.c b/reactos/ntoskrnl/ps/i386/continue.c index 10d2c60650b..39064fd139a 100644 --- a/reactos/ntoskrnl/ps/i386/continue.c +++ b/reactos/ntoskrnl/ps/i386/continue.c @@ -67,9 +67,9 @@ NtContinue ( { Thread->NpxState = NPX_STATE_VALID; KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); - if (KeGetCurrentKPCR()->PrcbData.NpxThread == Thread) + if (KeGetCurrentPrcb()->NpxThread == Thread) { - KeGetCurrentKPCR()->PrcbData.NpxThread = NULL; + KeGetCurrentPrcb()->NpxThread = NULL; Ke386SetCr0(Ke386GetCr0() | X86_CR0_TS); } else diff --git a/reactos/ntoskrnl/ps/idle.c b/reactos/ntoskrnl/ps/idle.c index d338cc56c12..21bcd16b964 100644 --- a/reactos/ntoskrnl/ps/idle.c +++ b/reactos/ntoskrnl/ps/idle.c @@ -1,4 +1,4 @@ -/* $Id:$ +/* $Id$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -26,11 +26,11 @@ PsIdleThreadMain(PVOID Context) { KIRQL oldlvl; - PKPCR Pcr = KeGetCurrentKPCR(); + PKPRCB Prcb = KeGetCurrentPrcb(); for(;;) { - if (Pcr->PrcbData.DpcData[0].DpcQueueDepth > 0) + if (Prcb->DpcData[0].DpcQueueDepth > 0) { KeRaiseIrql(DISPATCH_LEVEL,&oldlvl); KiDispatchInterrupt(); @@ -80,7 +80,7 @@ PsInitIdleThread(VOID) return; } NtClose(IdleThreadHandle); - KeGetCurrentKPCR()->PrcbData.IdleThread = &IdleThread->Tcb; + KeGetCurrentPrcb()->IdleThread = &IdleThread->Tcb; KeSetPriorityThread(&IdleThread->Tcb, LOW_PRIORITY); KeSetAffinityThread(&IdleThread->Tcb, 1 << 0); diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index acd9271c3e5..7a3cde75b57 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -151,7 +151,7 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus) /* If the ProcessoR Control Block's NpxThread points to the current thread * unset it. */ - InterlockedCompareExchangePointer(&KeGetCurrentKPCR()->PrcbData.NpxThread, + InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, NULL, ETHREAD_TO_KTHREAD(CurrentThread)); KeReleaseDispatcherDatabaseLock(oldIrql); diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index 2c485c9d285..6dd3f89890b 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -1769,7 +1769,7 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle, KeQuerySystemTime(&SystemTime); - Prcb = &KeGetCurrentKPCR()->PrcbData; + Prcb = KeGetCurrentPrcb(); NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ SystemTime.u.LowPart ^ SystemTime.u.HighPart; diff --git a/reactos/ntoskrnl/ps/w32call.c b/reactos/ntoskrnl/ps/w32call.c index d6ee975793c..c009883f381 100644 --- a/reactos/ntoskrnl/ps/w32call.c +++ b/reactos/ntoskrnl/ps/w32call.c @@ -129,7 +129,7 @@ NtCallbackReturn (PVOID Result, */ KeRaiseIrql(HIGH_LEVEL, &oldIrql); if ((Thread->Tcb.NpxState & NPX_STATE_VALID) && - ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentKPCR()->PrcbData.NpxThread) + ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread) { RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA), (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA), @@ -317,7 +317,7 @@ NtW32Call (IN ULONG RoutineIndex, SavedState.SavedCallbackStack = Thread->Tcb.CallbackStack; SavedState.SavedExceptionStack = (PVOID)KeGetCurrentKPCR()->TSS->Esp0; if ((Thread->Tcb.NpxState & NPX_STATE_VALID) && - ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentKPCR()->PrcbData.NpxThread) + ETHREAD_TO_KTHREAD(Thread) != KeGetCurrentPrcb()->NpxThread) { RtlCopyMemory((char*)NewStack + StackSize - sizeof(FX_SAVE_AREA), (char*)SavedState.SavedInitialStack - sizeof(FX_SAVE_AREA),