1 /* 2 * ReactOS kernel 3 * Copyright (C) 2005 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * PROJECT: ReactOS kernel 21 * FILE: ntoskrnl/kdbg/kdb_cli.c 22 * PURPOSE: Kernel debugger command line interface 23 * PROGRAMMER: Gregor Anich (blight@blight.eu.org) 24 * Herv� Poussineau 25 * UPDATE HISTORY: 26 * Created 16/01/2005 27 */ 28 29 /* INCLUDES ******************************************************************/ 30 31 #include <ntoskrnl.h> 32 33 #define NDEBUG 34 #include <debug.h> 35 36 /* DEFINES *******************************************************************/ 37 38 #define KEY_BS 8 39 #define KEY_ESC 27 40 #define KEY_DEL 127 41 42 #define KEY_SCAN_UP 72 43 #define KEY_SCAN_DOWN 80 44 45 /* Scan codes of keyboard keys: */ 46 #define KEYSC_END 0x004f 47 #define KEYSC_PAGEUP 0x0049 48 #define KEYSC_PAGEDOWN 0x0051 49 #define KEYSC_HOME 0x0047 50 #define KEYSC_ARROWUP 0x0048 51 52 #define KDB_ENTER_CONDITION_TO_STRING(cond) \ 53 ((cond) == KdbDoNotEnter ? "never" : \ 54 ((cond) == KdbEnterAlways ? "always" : \ 55 ((cond) == KdbEnterFromKmode ? "kmode" : "umode"))) 56 57 #define KDB_ACCESS_TYPE_TO_STRING(type) \ 58 ((type) == KdbAccessRead ? "read" : \ 59 ((type) == KdbAccessWrite ? "write" : \ 60 ((type) == KdbAccessReadWrite ? "rdwr" : "exec"))) 61 62 #define NPX_STATE_TO_STRING(state) \ 63 ((state) == NPX_STATE_LOADED ? "Loaded" : \ 64 ((state) == NPX_STATE_NOT_LOADED ? "Not loaded" : "Unknown")) 65 66 /* PROTOTYPES ****************************************************************/ 67 68 static BOOLEAN KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]); 69 static BOOLEAN KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]); 70 static BOOLEAN KdbpCmdRegs(ULONG Argc, PCHAR Argv[]); 71 static BOOLEAN KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]); 72 73 static BOOLEAN KdbpCmdContinue(ULONG Argc, PCHAR Argv[]); 74 static BOOLEAN KdbpCmdStep(ULONG Argc, PCHAR Argv[]); 75 static BOOLEAN KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]); 76 static BOOLEAN KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]); 77 static BOOLEAN KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]); 78 79 static BOOLEAN KdbpCmdThread(ULONG Argc, PCHAR Argv[]); 80 static BOOLEAN KdbpCmdProc(ULONG Argc, PCHAR Argv[]); 81 82 static BOOLEAN KdbpCmdMod(ULONG Argc, PCHAR Argv[]); 83 static BOOLEAN KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]); 84 static BOOLEAN KdbpCmdPcr(ULONG Argc, PCHAR Argv[]); 85 static BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]); 86 87 static BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]); 88 static BOOLEAN KdbpCmdReboot(ULONG Argc, PCHAR Argv[]); 89 static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]); 90 static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]); 91 static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]); 92 static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]); 93 94 BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[]); 95 BOOLEAN ExpKdbgExtPoolUsed(ULONG Argc, PCHAR Argv[]); 96 BOOLEAN ExpKdbgExtPoolFind(ULONG Argc, PCHAR Argv[]); 97 BOOLEAN ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]); 98 BOOLEAN ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]); 99 BOOLEAN ExpKdbgExtIrpFind(ULONG Argc, PCHAR Argv[]); 100 BOOLEAN ExpKdbgExtHandle(ULONG Argc, PCHAR Argv[]); 101 102 #ifdef __ROS_DWARF__ 103 static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]); 104 #endif 105 106 /* GLOBALS *******************************************************************/ 107 108 static PKDBG_CLI_ROUTINE KdbCliCallbacks[10]; 109 static BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */ 110 static BOOLEAN KdbBreakOnModuleLoad = FALSE; /* Set to TRUE to break into KDB when a module is loaded */ 111 112 static CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */ 113 static PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */ 114 static LONG KdbCommandHistoryBufferIndex = 0; 115 static LONG KdbCommandHistoryIndex = 0; 116 117 static ULONG KdbNumberOfRowsPrinted = 0; 118 static ULONG KdbNumberOfColsPrinted = 0; 119 static BOOLEAN KdbOutputAborted = FALSE; 120 static BOOLEAN KdbRepeatLastCommand = FALSE; 121 static LONG KdbNumberOfRowsTerminal = -1; 122 static LONG KdbNumberOfColsTerminal = -1; 123 124 PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */ 125 BOOLEAN KdbpBugCheckRequested = FALSE; 126 127 /* Vars for dmesg */ 128 /* defined in ../kd/kdio.c, declare here: */ 129 extern volatile BOOLEAN KdbpIsInDmesgMode; 130 extern const ULONG KdpDmesgBufferSize; 131 extern PCHAR KdpDmesgBuffer; 132 extern volatile ULONG KdpDmesgCurrentPosition; 133 extern volatile ULONG KdpDmesgFreeBytes; 134 extern volatile ULONG KdbDmesgTotalWritten; 135 136 STRING KdbPromptString = RTL_CONSTANT_STRING("kdb:> "); 137 138 // 139 // Debug Filter Component Table 140 // 141 static struct 142 { 143 PCSTR Name; 144 ULONG Id; 145 } 146 ComponentTable[] = 147 { 148 // 149 // Default components 150 // 151 { "WIN2000", MAXULONG }, 152 { "DEFAULT", DPFLTR_DEFAULT_ID }, 153 // 154 // Standard components 155 // 156 { "SYSTEM", DPFLTR_SYSTEM_ID }, 157 { "SMSS", DPFLTR_SMSS_ID }, 158 { "SETUP", DPFLTR_SETUP_ID }, 159 { "NTFS", DPFLTR_NTFS_ID }, 160 { "FSTUB", DPFLTR_FSTUB_ID }, 161 { "CRASHDUMP", DPFLTR_CRASHDUMP_ID }, 162 { "CDAUDIO", DPFLTR_CDAUDIO_ID }, 163 { "CDROM", DPFLTR_CDROM_ID }, 164 { "CLASSPNP", DPFLTR_CLASSPNP_ID }, 165 { "DISK", DPFLTR_DISK_ID }, 166 { "REDBOOK", DPFLTR_REDBOOK_ID }, 167 { "STORPROP", DPFLTR_STORPROP_ID }, 168 { "SCSIPORT", DPFLTR_SCSIPORT_ID }, 169 { "SCSIMINIPORT", DPFLTR_SCSIMINIPORT_ID }, 170 { "CONFIG", DPFLTR_CONFIG_ID }, 171 { "I8042PRT", DPFLTR_I8042PRT_ID }, 172 { "SERMOUSE", DPFLTR_SERMOUSE_ID }, 173 { "LSERMOUS", DPFLTR_LSERMOUS_ID }, 174 { "KBDHID", DPFLTR_KBDHID_ID }, 175 { "MOUHID", DPFLTR_MOUHID_ID }, 176 { "KBDCLASS", DPFLTR_KBDCLASS_ID }, 177 { "MOUCLASS", DPFLTR_MOUCLASS_ID }, 178 { "TWOTRACK", DPFLTR_TWOTRACK_ID }, 179 { "WMILIB", DPFLTR_WMILIB_ID }, 180 { "ACPI", DPFLTR_ACPI_ID }, 181 { "AMLI", DPFLTR_AMLI_ID }, 182 { "HALIA64", DPFLTR_HALIA64_ID }, 183 { "VIDEO", DPFLTR_VIDEO_ID }, 184 { "SVCHOST", DPFLTR_SVCHOST_ID }, 185 { "VIDEOPRT", DPFLTR_VIDEOPRT_ID }, 186 { "TCPIP", DPFLTR_TCPIP_ID }, 187 { "DMSYNTH", DPFLTR_DMSYNTH_ID }, 188 { "NTOSPNP", DPFLTR_NTOSPNP_ID }, 189 { "FASTFAT", DPFLTR_FASTFAT_ID }, 190 { "SAMSS", DPFLTR_SAMSS_ID }, 191 { "PNPMGR", DPFLTR_PNPMGR_ID }, 192 { "NETAPI", DPFLTR_NETAPI_ID }, 193 { "SCSERVER", DPFLTR_SCSERVER_ID }, 194 { "SCCLIENT", DPFLTR_SCCLIENT_ID }, 195 { "SERIAL", DPFLTR_SERIAL_ID }, 196 { "SERENUM", DPFLTR_SERENUM_ID }, 197 { "UHCD", DPFLTR_UHCD_ID }, 198 { "RPCPROXY", DPFLTR_RPCPROXY_ID }, 199 { "AUTOCHK", DPFLTR_AUTOCHK_ID }, 200 { "DCOMSS", DPFLTR_DCOMSS_ID }, 201 { "UNIMODEM", DPFLTR_UNIMODEM_ID }, 202 { "SIS", DPFLTR_SIS_ID }, 203 { "FLTMGR", DPFLTR_FLTMGR_ID }, 204 { "WMICORE", DPFLTR_WMICORE_ID }, 205 { "BURNENG", DPFLTR_BURNENG_ID }, 206 { "IMAPI", DPFLTR_IMAPI_ID }, 207 { "SXS", DPFLTR_SXS_ID }, 208 { "FUSION", DPFLTR_FUSION_ID }, 209 { "IDLETASK", DPFLTR_IDLETASK_ID }, 210 { "SOFTPCI", DPFLTR_SOFTPCI_ID }, 211 { "TAPE", DPFLTR_TAPE_ID }, 212 { "MCHGR", DPFLTR_MCHGR_ID }, 213 { "IDEP", DPFLTR_IDEP_ID }, 214 { "PCIIDE", DPFLTR_PCIIDE_ID }, 215 { "FLOPPY", DPFLTR_FLOPPY_ID }, 216 { "FDC", DPFLTR_FDC_ID }, 217 { "TERMSRV", DPFLTR_TERMSRV_ID }, 218 { "W32TIME", DPFLTR_W32TIME_ID }, 219 { "PREFETCHER", DPFLTR_PREFETCHER_ID }, 220 { "RSFILTER", DPFLTR_RSFILTER_ID }, 221 { "FCPORT", DPFLTR_FCPORT_ID }, 222 { "PCI", DPFLTR_PCI_ID }, 223 { "DMIO", DPFLTR_DMIO_ID }, 224 { "DMCONFIG", DPFLTR_DMCONFIG_ID }, 225 { "DMADMIN", DPFLTR_DMADMIN_ID }, 226 { "WSOCKTRANSPORT", DPFLTR_WSOCKTRANSPORT_ID }, 227 { "VSS", DPFLTR_VSS_ID }, 228 { "PNPMEM", DPFLTR_PNPMEM_ID }, 229 { "PROCESSOR", DPFLTR_PROCESSOR_ID }, 230 { "DMSERVER", DPFLTR_DMSERVER_ID }, 231 { "SR", DPFLTR_SR_ID }, 232 { "INFINIBAND", DPFLTR_INFINIBAND_ID }, 233 { "IHVDRIVER", DPFLTR_IHVDRIVER_ID }, 234 { "IHVVIDEO", DPFLTR_IHVVIDEO_ID }, 235 { "IHVAUDIO", DPFLTR_IHVAUDIO_ID }, 236 { "IHVNETWORK", DPFLTR_IHVNETWORK_ID }, 237 { "IHVSTREAMING", DPFLTR_IHVSTREAMING_ID }, 238 { "IHVBUS", DPFLTR_IHVBUS_ID }, 239 { "HPS", DPFLTR_HPS_ID }, 240 { "RTLTHREADPOOL", DPFLTR_RTLTHREADPOOL_ID }, 241 { "LDR", DPFLTR_LDR_ID }, 242 { "TCPIP6", DPFLTR_TCPIP6_ID }, 243 { "ISAPNP", DPFLTR_ISAPNP_ID }, 244 { "SHPC", DPFLTR_SHPC_ID }, 245 { "STORPORT", DPFLTR_STORPORT_ID }, 246 { "STORMINIPORT", DPFLTR_STORMINIPORT_ID }, 247 { "PRINTSPOOLER", DPFLTR_PRINTSPOOLER_ID }, 248 { "VSSDYNDISK", DPFLTR_VSSDYNDISK_ID }, 249 { "VERIFIER", DPFLTR_VERIFIER_ID }, 250 { "VDS", DPFLTR_VDS_ID }, 251 { "VDSBAS", DPFLTR_VDSBAS_ID }, 252 { "VDSDYN", DPFLTR_VDSDYN_ID }, // Specified in Vista+ 253 { "VDSDYNDR", DPFLTR_VDSDYNDR_ID }, 254 { "VDSLDR", DPFLTR_VDSLDR_ID }, // Specified in Vista+ 255 { "VDSUTIL", DPFLTR_VDSUTIL_ID }, 256 { "DFRGIFC", DPFLTR_DFRGIFC_ID }, 257 { "MM", DPFLTR_MM_ID }, 258 { "DFSC", DPFLTR_DFSC_ID }, 259 { "WOW64", DPFLTR_WOW64_ID }, 260 // 261 // Components specified in Vista+, some of which we also use in ReactOS 262 // 263 { "ALPC", DPFLTR_ALPC_ID }, 264 { "WDI", DPFLTR_WDI_ID }, 265 { "PERFLIB", DPFLTR_PERFLIB_ID }, 266 { "KTM", DPFLTR_KTM_ID }, 267 { "IOSTRESS", DPFLTR_IOSTRESS_ID }, 268 { "HEAP", DPFLTR_HEAP_ID }, 269 { "WHEA", DPFLTR_WHEA_ID }, 270 { "USERGDI", DPFLTR_USERGDI_ID }, 271 { "MMCSS", DPFLTR_MMCSS_ID }, 272 { "TPM", DPFLTR_TPM_ID }, 273 { "THREADORDER", DPFLTR_THREADORDER_ID }, 274 { "ENVIRON", DPFLTR_ENVIRON_ID }, 275 { "EMS", DPFLTR_EMS_ID }, 276 { "WDT", DPFLTR_WDT_ID }, 277 { "FVEVOL", DPFLTR_FVEVOL_ID }, 278 { "NDIS", DPFLTR_NDIS_ID }, 279 { "NVCTRACE", DPFLTR_NVCTRACE_ID }, 280 { "LUAFV", DPFLTR_LUAFV_ID }, 281 { "APPCOMPAT", DPFLTR_APPCOMPAT_ID }, 282 { "USBSTOR", DPFLTR_USBSTOR_ID }, 283 { "SBP2PORT", DPFLTR_SBP2PORT_ID }, 284 { "COVERAGE", DPFLTR_COVERAGE_ID }, 285 { "CACHEMGR", DPFLTR_CACHEMGR_ID }, 286 { "MOUNTMGR", DPFLTR_MOUNTMGR_ID }, 287 { "CFR", DPFLTR_CFR_ID }, 288 { "TXF", DPFLTR_TXF_ID }, 289 { "KSECDD", DPFLTR_KSECDD_ID }, 290 { "FLTREGRESS", DPFLTR_FLTREGRESS_ID }, 291 { "MPIO", DPFLTR_MPIO_ID }, 292 { "MSDSM", DPFLTR_MSDSM_ID }, 293 { "UDFS", DPFLTR_UDFS_ID }, 294 { "PSHED", DPFLTR_PSHED_ID }, 295 { "STORVSP", DPFLTR_STORVSP_ID }, 296 { "LSASS", DPFLTR_LSASS_ID }, 297 { "SSPICLI", DPFLTR_SSPICLI_ID }, 298 { "CNG", DPFLTR_CNG_ID }, 299 { "EXFAT", DPFLTR_EXFAT_ID }, 300 { "FILETRACE", DPFLTR_FILETRACE_ID }, 301 { "XSAVE", DPFLTR_XSAVE_ID }, 302 { "SE", DPFLTR_SE_ID }, 303 { "DRIVEEXTENDER", DPFLTR_DRIVEEXTENDER_ID }, 304 }; 305 306 // 307 // Command Table 308 // 309 static const struct 310 { 311 PCHAR Name; 312 PCHAR Syntax; 313 PCHAR Help; 314 BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]); 315 } KdbDebuggerCommands[] = { 316 /* Data */ 317 { NULL, NULL, "Data", NULL }, 318 { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression }, 319 { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX }, 320 { "x", "x [address] [L count]", "Display count dwords, starting at address.", KdbpCmdDisassembleX }, 321 { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs }, 322 { "cregs", "cregs", "Display control, descriptor table and task segment registers.", KdbpCmdRegs }, 323 { "sregs", "sregs", "Display status registers.", KdbpCmdRegs }, 324 { "dregs", "dregs", "Display debug registers.", KdbpCmdRegs }, 325 { "bt", "bt [*frameaddr|thread id]", "Prints current backtrace or from given frame address.", KdbpCmdBackTrace }, 326 #ifdef __ROS_DWARF__ 327 { "dt", "dt [mod] [type] [addr]", "Print a struct. The address is optional.", KdbpCmdPrintStruct }, 328 #endif 329 330 /* Flow control */ 331 { NULL, NULL, "Flow control", NULL }, 332 { "cont", "cont", "Continue execution (leave debugger).", KdbpCmdContinue }, 333 { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep }, 334 { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep }, 335 { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList }, 336 { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 337 { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 338 { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 339 { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint }, 340 { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint }, 341 342 /* Process/Thread */ 343 { NULL, NULL, "Process/Thread", NULL }, 344 { "thread", "thread [list[ pid]|[attach ]tid]", "List threads in current or specified process, display thread with given id or attach to thread.", KdbpCmdThread }, 345 { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc }, 346 347 /* System information */ 348 { NULL, NULL, "System info", NULL }, 349 { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod }, 350 { "gdt", "gdt", "Display the global descriptor table.", KdbpCmdGdtLdtIdt }, 351 { "ldt", "ldt", "Display the local descriptor table.", KdbpCmdGdtLdtIdt }, 352 { "idt", "idt", "Display the interrupt descriptor table.", KdbpCmdGdtLdtIdt }, 353 { "pcr", "pcr", "Display the processor control region.", KdbpCmdPcr }, 354 { "tss", "tss [selector|*descaddr]", "Display the current task state segment, or the one specified by its selector number or descriptor address.", KdbpCmdTss }, 355 356 /* Others */ 357 { NULL, NULL, "Others", NULL }, 358 { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck }, 359 { "reboot", "reboot", "Reboots the system.", KdbpCmdReboot}, 360 { "filter", "filter [error|warning|trace|info|level]+|-[componentname|default]", "Enable/disable debug channels.", KdbpCmdFilter }, 361 { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet }, 362 { "dmesg", "dmesg", "Display debug messages on screen, with navigation on pages.", KdbpCmdDmesg }, 363 { "kmsg", "kmsg", "Kernel dmesg. Alias for dmesg.", KdbpCmdDmesg }, 364 { "help", "help", "Display help screen.", KdbpCmdHelp }, 365 { "!pool", "!pool [Address [Flags]]", "Display information about pool allocations.", ExpKdbgExtPool }, 366 { "!poolused", "!poolused [Flags [Tag]]", "Display pool usage.", ExpKdbgExtPoolUsed }, 367 { "!poolfind", "!poolfind Tag [Pool]", "Search for pool tag allocations.", ExpKdbgExtPoolFind }, 368 { "!filecache", "!filecache", "Display cache usage.", ExpKdbgExtFileCache }, 369 { "!defwrites", "!defwrites", "Display cache write values.", ExpKdbgExtDefWrites }, 370 { "!irpfind", "!irpfind [Pool [startaddress [criteria data]]]", "Lists IRPs potentially matching criteria.", ExpKdbgExtIrpFind }, 371 { "!handle", "!handle [Handle]", "Displays info about handles.", ExpKdbgExtHandle }, 372 }; 373 374 /* FUNCTIONS *****************************************************************/ 375 376 /*!\brief Evaluates an expression... 377 * 378 * Much like KdbpRpnEvaluateExpression, but prints the error message (if any) 379 * at the given offset. 380 * 381 * \param Expression Expression to evaluate. 382 * \param ErrOffset Offset (in characters) to print the error message at. 383 * \param Result Receives the result on success. 384 * 385 * \retval TRUE Success. 386 * \retval FALSE Failure. 387 */ 388 static BOOLEAN 389 KdbpEvaluateExpression( 390 IN PCHAR Expression, 391 IN LONG ErrOffset, 392 OUT PULONGLONG Result) 393 { 394 static CHAR ErrMsgBuffer[130] = "^ "; 395 LONG ExpressionErrOffset = -1; 396 PCHAR ErrMsg = ErrMsgBuffer; 397 BOOLEAN Ok; 398 399 Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result, 400 &ExpressionErrOffset, ErrMsgBuffer + 2); 401 if (!Ok) 402 { 403 if (ExpressionErrOffset >= 0) 404 ExpressionErrOffset += ErrOffset; 405 else 406 ErrMsg += 2; 407 408 KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg); 409 } 410 411 return Ok; 412 } 413 414 BOOLEAN 415 NTAPI 416 KdbpGetHexNumber( 417 IN PCHAR pszNum, 418 OUT ULONG_PTR *pulValue) 419 { 420 char *endptr; 421 422 /* Skip optional '0x' prefix */ 423 if ((pszNum[0] == '0') && ((pszNum[1] == 'x') || (pszNum[1] == 'X'))) 424 pszNum += 2; 425 426 /* Make a number from the string (hex) */ 427 *pulValue = strtoul(pszNum, &endptr, 16); 428 429 return (*endptr == '\0'); 430 } 431 432 /*!\brief Evaluates an expression and displays the result. 433 */ 434 static BOOLEAN 435 KdbpCmdEvalExpression( 436 ULONG Argc, 437 PCHAR Argv[]) 438 { 439 ULONG i, len; 440 ULONGLONG Result = 0; 441 ULONG ul; 442 LONG l = 0; 443 BOOLEAN Ok; 444 445 if (Argc < 2) 446 { 447 KdbpPrint("?: Argument required\n"); 448 return TRUE; 449 } 450 451 /* Put the arguments back together */ 452 Argc--; 453 for (i = 1; i < Argc; i++) 454 { 455 len = strlen(Argv[i]); 456 Argv[i][len] = ' '; 457 } 458 459 /* Evaluate the expression */ 460 Ok = KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result); 461 if (Ok) 462 { 463 if (Result > 0x00000000ffffffffLL) 464 { 465 if (Result & 0x8000000000000000LL) 466 KdbpPrint("0x%016I64x %20I64u %20I64d\n", Result, Result, Result); 467 else 468 KdbpPrint("0x%016I64x %20I64u\n", Result, Result); 469 } 470 else 471 { 472 ul = (ULONG)Result; 473 474 if (ul <= 0xff && ul >= 0x80) 475 l = (LONG)((CHAR)ul); 476 else if (ul <= 0xffff && ul >= 0x8000) 477 l = (LONG)((SHORT)ul); 478 else 479 l = (LONG)ul; 480 481 if (l < 0) 482 KdbpPrint("0x%08lx %10lu %10ld\n", ul, ul, l); 483 else 484 KdbpPrint("0x%08lx %10lu\n", ul, ul); 485 } 486 } 487 488 return TRUE; 489 } 490 491 #ifdef __ROS_DWARF__ 492 493 /*!\brief Print a struct 494 */ 495 static VOID 496 KdbpPrintStructInternal 497 (PROSSYM_INFO Info, 498 PCHAR Indent, 499 BOOLEAN DoRead, 500 PVOID BaseAddress, 501 PROSSYM_AGGREGATE Aggregate) 502 { 503 ULONG i; 504 ULONGLONG Result; 505 PROSSYM_AGGREGATE_MEMBER Member; 506 ULONG IndentLen = strlen(Indent); 507 ROSSYM_AGGREGATE MemberAggregate = {0 }; 508 509 for (i = 0; i < Aggregate->NumElements; i++) { 510 Member = &Aggregate->Elements[i]; 511 KdbpPrint("%s%p+%x: %s", Indent, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size, Member->Name ? Member->Name : "<anoymous>"); 512 if (DoRead) { 513 if (!strcmp(Member->Type, "_UNICODE_STRING")) { 514 KdbpPrint("\"%wZ\"\n", ((PCHAR)BaseAddress) + Member->BaseOffset); 515 continue; 516 } else if (!strcmp(Member->Type, "PUNICODE_STRING")) { 517 KdbpPrint("\"%wZ\"\n", *(((PUNICODE_STRING*)((PCHAR)BaseAddress) + Member->BaseOffset))); 518 continue; 519 } 520 switch (Member->Size) { 521 case 1: 522 case 2: 523 case 4: 524 case 8: { 525 Result = 0; 526 if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) { 527 if (Member->Bits) { 528 Result >>= Member->FirstBit; 529 Result &= ((1 << Member->Bits) - 1); 530 } 531 KdbpPrint(" %lx\n", Result); 532 } 533 else goto readfail; 534 break; 535 } 536 default: { 537 if (Member->Size < 8) { 538 if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) { 539 ULONG j; 540 for (j = 0; j < Member->Size; j++) { 541 KdbpPrint(" %02x", (int)(Result & 0xff)); 542 Result >>= 8; 543 } 544 } else goto readfail; 545 } else { 546 KdbpPrint(" %s @ %p {\n", Member->Type, ((PCHAR)BaseAddress) + Member->BaseOffset); 547 Indent[IndentLen] = ' '; 548 if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) { 549 KdbpPrintStructInternal(Info, Indent, DoRead, ((PCHAR)BaseAddress) + Member->BaseOffset, &MemberAggregate); 550 RosSymFreeAggregate(&MemberAggregate); 551 } 552 Indent[IndentLen] = 0; 553 KdbpPrint("%s}\n", Indent); 554 } break; 555 } 556 } 557 } else { 558 readfail: 559 if (Member->Size <= 8) { 560 KdbpPrint(" ??\n"); 561 } else { 562 KdbpPrint(" %s @ %x {\n", Member->Type, Member->BaseOffset); 563 Indent[IndentLen] = ' '; 564 if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) { 565 KdbpPrintStructInternal(Info, Indent, DoRead, BaseAddress, &MemberAggregate); 566 RosSymFreeAggregate(&MemberAggregate); 567 } 568 Indent[IndentLen] = 0; 569 KdbpPrint("%s}\n", Indent); 570 } 571 } 572 } 573 } 574 575 PROSSYM_INFO KdbpSymFindCachedFile(PUNICODE_STRING ModName); 576 577 static BOOLEAN 578 KdbpCmdPrintStruct( 579 ULONG Argc, 580 PCHAR Argv[]) 581 { 582 ULONG i; 583 ULONGLONG Result = 0; 584 PVOID BaseAddress = 0; 585 ROSSYM_AGGREGATE Aggregate = {0}; 586 UNICODE_STRING ModName = {0}; 587 ANSI_STRING AnsiName = {0}; 588 CHAR Indent[100] = {0}; 589 PROSSYM_INFO Info; 590 591 if (Argc < 3) goto end; 592 AnsiName.Length = AnsiName.MaximumLength = strlen(Argv[1]); 593 AnsiName.Buffer = Argv[1]; 594 RtlAnsiStringToUnicodeString(&ModName, &AnsiName, TRUE); 595 Info = KdbpSymFindCachedFile(&ModName); 596 597 if (!Info || !RosSymAggregate(Info, Argv[2], &Aggregate)) { 598 DPRINT1("Could not get aggregate\n"); 599 goto end; 600 } 601 602 // Get an argument for location if it was given 603 if (Argc > 3) { 604 ULONG len; 605 PCHAR ArgStart = Argv[3]; 606 DPRINT1("Trying to get expression\n"); 607 for (i = 3; i < Argc - 1; i++) 608 { 609 len = strlen(Argv[i]); 610 Argv[i][len] = ' '; 611 } 612 613 /* Evaluate the expression */ 614 DPRINT1("Arg: %s\n", ArgStart); 615 if (KdbpEvaluateExpression(ArgStart, strlen(ArgStart), &Result)) { 616 BaseAddress = (PVOID)(ULONG_PTR)Result; 617 DPRINT1("BaseAddress: %p\n", BaseAddress); 618 } 619 } 620 DPRINT1("BaseAddress %p\n", BaseAddress); 621 KdbpPrintStructInternal(Info, Indent, !!BaseAddress, BaseAddress, &Aggregate); 622 end: 623 RosSymFreeAggregate(&Aggregate); 624 RtlFreeUnicodeString(&ModName); 625 return TRUE; 626 } 627 #endif 628 629 /*!\brief Retrieves the component ID corresponding to a given component name. 630 * 631 * \param ComponentName The name of the component. 632 * \param ComponentId Receives the component id on success. 633 * 634 * \retval TRUE Success. 635 * \retval FALSE Failure. 636 */ 637 static BOOLEAN 638 KdbpGetComponentId( 639 IN PCSTR ComponentName, 640 OUT PULONG ComponentId) 641 { 642 ULONG i; 643 644 for (i = 0; i < sizeof(ComponentTable) / sizeof(ComponentTable[0]); i++) 645 { 646 if (_stricmp(ComponentName, ComponentTable[i].Name) == 0) 647 { 648 *ComponentId = ComponentTable[i].Id; 649 return TRUE; 650 } 651 } 652 653 return FALSE; 654 } 655 656 /*!\brief Displays the list of active debug channels, or enable/disable debug channels. 657 */ 658 static BOOLEAN 659 KdbpCmdFilter( 660 ULONG Argc, 661 PCHAR Argv[]) 662 { 663 ULONG i, j, ComponentId, Level; 664 ULONG set = DPFLTR_MASK, clear = DPFLTR_MASK; 665 PCHAR pend; 666 PCSTR opt, p; 667 668 static struct 669 { 670 PCSTR Name; 671 ULONG Level; 672 } 673 debug_classes[] = 674 { 675 { "error", 1 << DPFLTR_ERROR_LEVEL }, 676 { "warning", 1 << DPFLTR_WARNING_LEVEL }, 677 { "trace", 1 << DPFLTR_TRACE_LEVEL }, 678 { "info", 1 << DPFLTR_INFO_LEVEL }, 679 }; 680 681 if (Argc <= 1) 682 { 683 /* Display the list of available debug filter components */ 684 KdbpPrint("REMARKS:\n" 685 "- The 'WIN2000' system-wide debug filter component is used for DbgPrint()\n" 686 " messages without Component ID and Level.\n" 687 "- The 'DEFAULT' debug filter component is used for DbgPrint() messages with\n" 688 " an unknown Component ID.\n\n"); 689 KdbpPrint("The list of debug filter components currently available on your system is:\n\n"); 690 KdbpPrint(" Component Name Component ID\n" 691 "================ ==============\n"); 692 for (i = 0; i < sizeof(ComponentTable) / sizeof(ComponentTable[0]); i++) 693 { 694 KdbpPrint("%16s 0x%08lx\n", ComponentTable[i].Name, ComponentTable[i].Id); 695 } 696 return TRUE; 697 } 698 699 for (i = 1; i < Argc; i++) 700 { 701 opt = Argv[i]; 702 p = opt + strcspn(opt, "+-"); 703 if (!p[0]) p = opt; /* Assume it's a debug channel name */ 704 705 if (p > opt) 706 { 707 for (j = 0; j < sizeof(debug_classes) / sizeof(debug_classes[0]); j++) 708 { 709 SIZE_T len = strlen(debug_classes[j].Name); 710 if (len != (p - opt)) 711 continue; 712 if (_strnicmp(opt, debug_classes[j].Name, len) == 0) /* Found it */ 713 { 714 if (*p == '+') 715 set |= debug_classes[j].Level; 716 else 717 clear |= debug_classes[j].Level; 718 break; 719 } 720 } 721 if (j == sizeof(debug_classes) / sizeof(debug_classes[0])) 722 { 723 Level = strtoul(opt, &pend, 0); 724 if (pend != p) 725 { 726 KdbpPrint("filter: bad class name '%.*s'\n", p - opt, opt); 727 continue; 728 } 729 if (*p == '+') 730 set |= Level; 731 else 732 clear |= Level; 733 } 734 } 735 else 736 { 737 if (*p == '-') 738 clear = MAXULONG; 739 else 740 set = MAXULONG; 741 } 742 if (*p == '+' || *p == '-') 743 p++; 744 745 if (!KdbpGetComponentId(p, &ComponentId)) 746 { 747 KdbpPrint("filter: '%s' is not a valid component name!\n", p); 748 return TRUE; 749 } 750 751 /* Get current mask value */ 752 NtSetDebugFilterState(ComponentId, set, TRUE); 753 NtSetDebugFilterState(ComponentId, clear, FALSE); 754 } 755 756 return TRUE; 757 } 758 759 /*!\brief Disassembles 10 instructions at eip or given address or 760 * displays 16 dwords from memory at given address. 761 */ 762 static BOOLEAN 763 KdbpCmdDisassembleX( 764 ULONG Argc, 765 PCHAR Argv[]) 766 { 767 ULONG Count; 768 ULONG ul; 769 INT i; 770 ULONGLONG Result = 0; 771 ULONG_PTR Address = KdbCurrentTrapFrame->Tf.Eip; 772 LONG InstLen; 773 774 if (Argv[0][0] == 'x') /* display memory */ 775 Count = 16; 776 else /* disassemble */ 777 Count = 10; 778 779 if (Argc >= 2) 780 { 781 /* Check for [L count] part */ 782 ul = 0; 783 if (strcmp(Argv[Argc-2], "L") == 0) 784 { 785 ul = strtoul(Argv[Argc-1], NULL, 0); 786 if (ul > 0) 787 { 788 Count = ul; 789 Argc -= 2; 790 } 791 } 792 else if (Argv[Argc-1][0] == 'L') 793 { 794 ul = strtoul(Argv[Argc-1] + 1, NULL, 0); 795 if (ul > 0) 796 { 797 Count = ul; 798 Argc--; 799 } 800 } 801 802 /* Put the remaining arguments back together */ 803 Argc--; 804 for (ul = 1; ul < Argc; ul++) 805 { 806 Argv[ul][strlen(Argv[ul])] = ' '; 807 } 808 Argc++; 809 } 810 811 /* Evaluate the expression */ 812 if (Argc > 1) 813 { 814 if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result)) 815 return TRUE; 816 817 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 818 KdbpPrint("Warning: Address %I64x is beeing truncated\n",Result); 819 820 Address = (ULONG_PTR)Result; 821 } 822 else if (Argv[0][0] == 'x') 823 { 824 KdbpPrint("x: Address argument required.\n"); 825 return TRUE; 826 } 827 828 if (Argv[0][0] == 'x') 829 { 830 /* Display dwords */ 831 ul = 0; 832 833 while (Count > 0) 834 { 835 if (!KdbSymPrintAddress((PVOID)Address, NULL)) 836 KdbpPrint("<%08x>:", Address); 837 else 838 KdbpPrint(":"); 839 840 i = min(4, Count); 841 Count -= i; 842 843 while (--i >= 0) 844 { 845 if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul)))) 846 KdbpPrint(" ????????"); 847 else 848 KdbpPrint(" %08x", ul); 849 850 Address += sizeof(ul); 851 } 852 853 KdbpPrint("\n"); 854 } 855 } 856 else 857 { 858 /* Disassemble */ 859 while (Count-- > 0) 860 { 861 if (!KdbSymPrintAddress((PVOID)Address, NULL)) 862 KdbpPrint("<%08x>: ", Address); 863 else 864 KdbpPrint(": "); 865 866 InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax); 867 if (InstLen < 0) 868 { 869 KdbpPrint("<INVALID>\n"); 870 return TRUE; 871 } 872 873 KdbpPrint("\n"); 874 Address += InstLen; 875 } 876 } 877 878 return TRUE; 879 } 880 881 /*!\brief Displays CPU registers. 882 */ 883 static BOOLEAN 884 KdbpCmdRegs( 885 ULONG Argc, 886 PCHAR Argv[]) 887 { 888 PKTRAP_FRAME Tf = &KdbCurrentTrapFrame->Tf; 889 INT i; 890 static const PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5", 891 " ZF", " SF", " TF", " IF", " DF", " OF", 892 NULL, NULL, " NT", " BIT15", " RF", " VF", 893 " AC", " VIF", " VIP", " ID", " BIT22", 894 " BIT23", " BIT24", " BIT25", " BIT26", 895 " BIT27", " BIT28", " BIT29", " BIT30", 896 " BIT31" }; 897 898 if (Argv[0][0] == 'r') /* regs */ 899 { 900 KdbpPrint("CS:EIP 0x%04x:0x%08x\n" 901 "SS:ESP 0x%04x:0x%08x\n" 902 " EAX 0x%08x EBX 0x%08x\n" 903 " ECX 0x%08x EDX 0x%08x\n" 904 " ESI 0x%08x EDI 0x%08x\n" 905 " EBP 0x%08x\n", 906 Tf->SegCs & 0xFFFF, Tf->Eip, 907 Tf->HardwareSegSs, Tf->HardwareEsp, 908 Tf->Eax, Tf->Ebx, 909 Tf->Ecx, Tf->Edx, 910 Tf->Esi, Tf->Edi, 911 Tf->Ebp); 912 913 /* Display the EFlags */ 914 KdbpPrint("EFLAGS 0x%08x ", Tf->EFlags); 915 for (i = 0; i < 32; i++) 916 { 917 if (i == 1) 918 { 919 if ((Tf->EFlags & (1 << 1)) == 0) 920 KdbpPrint(" !BIT1"); 921 } 922 else if (i == 12) 923 { 924 KdbpPrint(" IOPL%d", (Tf->EFlags >> 12) & 3); 925 } 926 else if (i == 13) 927 { 928 } 929 else if ((Tf->EFlags & (1 << i)) != 0) 930 { 931 KdbpPrint(EflagsBits[i]); 932 } 933 } 934 KdbpPrint("\n"); 935 } 936 else if (Argv[0][0] == 'c') /* cregs */ 937 { 938 ULONG Cr0, Cr2, Cr3, Cr4; 939 KDESCRIPTOR Gdtr = {0, 0, 0}, Idtr = {0, 0, 0}; 940 USHORT Ldtr, Tr; 941 static const PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL, 942 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 943 " WP", NULL, " AM", NULL, NULL, NULL, NULL, NULL, 944 NULL, NULL, NULL, NULL, NULL, " NW", " CD", " PG" }; 945 static const PCHAR Cr4Bits[32] = { " VME", " PVI", " TSD", " DE", " PSE", " PAE", " MCE", " PGE", 946 " PCE", " OSFXSR", " OSXMMEXCPT", NULL, NULL, NULL, NULL, NULL, 947 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 948 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 949 950 /* Retrieve the control registers */ 951 Cr0 = KdbCurrentTrapFrame->Cr0; 952 Cr2 = KdbCurrentTrapFrame->Cr2; 953 Cr3 = KdbCurrentTrapFrame->Cr3; 954 Cr4 = KdbCurrentTrapFrame->Cr4; 955 956 /* Retrieve the descriptor table and task segment registers */ 957 Ke386GetGlobalDescriptorTable(&Gdtr.Limit); 958 Ldtr = Ke386GetLocalDescriptorTable(); 959 __sidt(&Idtr.Limit); 960 Tr = Ke386GetTr(); 961 962 /* Display the control registers */ 963 KdbpPrint("CR0 0x%08x ", Cr0); 964 for (i = 0; i < 32; i++) 965 { 966 if (!Cr0Bits[i]) 967 continue; 968 969 if ((Cr0 & (1 << i)) != 0) 970 KdbpPrint(Cr0Bits[i]); 971 } 972 KdbpPrint("\n"); 973 974 KdbpPrint("CR2 0x%08x\n", Cr2); 975 KdbpPrint("CR3 0x%08x Pagedir-Base 0x%08x %s%s\n", Cr3, (Cr3 & 0xfffff000), 976 (Cr3 & (1 << 3)) ? " PWT" : "", (Cr3 & (1 << 4)) ? " PCD" : "" ); 977 KdbpPrint("CR4 0x%08x ", Cr4); 978 for (i = 0; i < 32; i++) 979 { 980 if (!Cr4Bits[i]) 981 continue; 982 983 if ((Cr4 & (1 << i)) != 0) 984 KdbpPrint(Cr4Bits[i]); 985 } 986 KdbpPrint("\n"); 987 988 /* Display the descriptor table and task segment registers */ 989 KdbpPrint("GDTR Base 0x%08x Size 0x%04x\n", Gdtr.Base, Gdtr.Limit); 990 KdbpPrint("LDTR 0x%04x\n", Ldtr); 991 KdbpPrint("IDTR Base 0x%08x Size 0x%04x\n", Idtr.Base, Idtr.Limit); 992 KdbpPrint("TR 0x%04x\n", Tr); 993 } 994 else if (Argv[0][0] == 's') /* sregs */ 995 { 996 KdbpPrint("CS 0x%04x Index 0x%04x %cDT RPL%d\n", 997 Tf->SegCs & 0xffff, (Tf->SegCs & 0xffff) >> 3, 998 (Tf->SegCs & (1 << 2)) ? 'L' : 'G', Tf->SegCs & 3); 999 KdbpPrint("DS 0x%04x Index 0x%04x %cDT RPL%d\n", 1000 Tf->SegDs, Tf->SegDs >> 3, (Tf->SegDs & (1 << 2)) ? 'L' : 'G', Tf->SegDs & 3); 1001 KdbpPrint("ES 0x%04x Index 0x%04x %cDT RPL%d\n", 1002 Tf->SegEs, Tf->SegEs >> 3, (Tf->SegEs & (1 << 2)) ? 'L' : 'G', Tf->SegEs & 3); 1003 KdbpPrint("FS 0x%04x Index 0x%04x %cDT RPL%d\n", 1004 Tf->SegFs, Tf->SegFs >> 3, (Tf->SegFs & (1 << 2)) ? 'L' : 'G', Tf->SegFs & 3); 1005 KdbpPrint("GS 0x%04x Index 0x%04x %cDT RPL%d\n", 1006 Tf->SegGs, Tf->SegGs >> 3, (Tf->SegGs & (1 << 2)) ? 'L' : 'G', Tf->SegGs & 3); 1007 KdbpPrint("SS 0x%04x Index 0x%04x %cDT RPL%d\n", 1008 Tf->HardwareSegSs, Tf->HardwareSegSs >> 3, (Tf->HardwareSegSs & (1 << 2)) ? 'L' : 'G', Tf->HardwareSegSs & 3); 1009 } 1010 else /* dregs */ 1011 { 1012 ASSERT(Argv[0][0] == 'd'); 1013 KdbpPrint("DR0 0x%08x\n" 1014 "DR1 0x%08x\n" 1015 "DR2 0x%08x\n" 1016 "DR3 0x%08x\n" 1017 "DR6 0x%08x\n" 1018 "DR7 0x%08x\n", 1019 Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, 1020 Tf->Dr6, Tf->Dr7); 1021 } 1022 1023 return TRUE; 1024 } 1025 1026 static PKTSS 1027 KdbpRetrieveTss( 1028 IN USHORT TssSelector, 1029 OUT PULONG pType OPTIONAL, 1030 IN PKDESCRIPTOR pGdtr OPTIONAL) 1031 { 1032 KDESCRIPTOR Gdtr; 1033 KGDTENTRY Desc; 1034 PKTSS Tss; 1035 1036 /* Retrieve the Global Descriptor Table (user-provided or system) */ 1037 if (pGdtr) 1038 Gdtr = *pGdtr; 1039 else 1040 Ke386GetGlobalDescriptorTable(&Gdtr.Limit); 1041 1042 /* Check limits */ 1043 if ((TssSelector & (sizeof(KGDTENTRY) - 1)) || 1044 (TssSelector < sizeof(KGDTENTRY)) || 1045 (TssSelector + sizeof(KGDTENTRY) - 1 > Gdtr.Limit)) 1046 { 1047 return NULL; 1048 } 1049 1050 /* Retrieve the descriptor */ 1051 if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc, 1052 (PVOID)(Gdtr.Base + TssSelector), 1053 sizeof(KGDTENTRY)))) 1054 { 1055 return NULL; 1056 } 1057 1058 /* Check for TSS32(Avl) or TSS32(Busy) */ 1059 if (Desc.HighWord.Bits.Type != 9 && Desc.HighWord.Bits.Type != 11) 1060 { 1061 return NULL; 1062 } 1063 if (pType) *pType = Desc.HighWord.Bits.Type; 1064 1065 Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow | 1066 Desc.HighWord.Bytes.BaseMid << 16 | 1067 Desc.HighWord.Bytes.BaseHi << 24); 1068 1069 return Tss; 1070 } 1071 1072 FORCEINLINE BOOLEAN 1073 KdbpIsNestedTss( 1074 IN USHORT TssSelector, 1075 IN PKTSS Tss) 1076 { 1077 USHORT Backlink; 1078 1079 if (!Tss) 1080 return FALSE; 1081 1082 /* Retrieve the TSS Backlink */ 1083 if (!NT_SUCCESS(KdbpSafeReadMemory(&Backlink, 1084 (PVOID)&Tss->Backlink, 1085 sizeof(USHORT)))) 1086 { 1087 return FALSE; 1088 } 1089 1090 return (Backlink != 0 && Backlink != TssSelector); 1091 } 1092 1093 static BOOLEAN 1094 KdbpTrapFrameFromPrevTss( 1095 IN OUT PKTRAP_FRAME TrapFrame, 1096 OUT PUSHORT TssSelector, 1097 IN OUT PKTSS* pTss, 1098 IN PKDESCRIPTOR pGdtr) 1099 { 1100 ULONG_PTR Eip, Ebp; 1101 USHORT Backlink; 1102 PKTSS Tss = *pTss; 1103 1104 /* Retrieve the TSS Backlink */ 1105 if (!NT_SUCCESS(KdbpSafeReadMemory(&Backlink, 1106 (PVOID)&Tss->Backlink, 1107 sizeof(USHORT)))) 1108 { 1109 return FALSE; 1110 } 1111 1112 /* Retrieve the parent TSS */ 1113 Tss = KdbpRetrieveTss(Backlink, NULL, pGdtr); 1114 if (!Tss) 1115 return FALSE; 1116 1117 if (!NT_SUCCESS(KdbpSafeReadMemory(&Eip, 1118 (PVOID)&Tss->Eip, 1119 sizeof(ULONG_PTR)))) 1120 { 1121 return FALSE; 1122 } 1123 1124 if (!NT_SUCCESS(KdbpSafeReadMemory(&Ebp, 1125 (PVOID)&Tss->Ebp, 1126 sizeof(ULONG_PTR)))) 1127 { 1128 return FALSE; 1129 } 1130 1131 /* Return the parent TSS and its trap frame */ 1132 *TssSelector = Backlink; 1133 *pTss = Tss; 1134 TrapFrame->Eip = Eip; 1135 TrapFrame->Ebp = Ebp; 1136 return TRUE; 1137 } 1138 1139 /*!\brief Displays a backtrace. 1140 */ 1141 static BOOLEAN 1142 KdbpCmdBackTrace( 1143 ULONG Argc, 1144 PCHAR Argv[]) 1145 { 1146 ULONG ul; 1147 ULONGLONG Result = 0; 1148 KTRAP_FRAME TrapFrame = KdbCurrentTrapFrame->Tf; 1149 ULONG_PTR Frame = TrapFrame.Ebp; 1150 ULONG_PTR Address; 1151 KDESCRIPTOR Gdtr; 1152 USHORT TssSelector; 1153 PKTSS Tss; 1154 1155 if (Argc >= 2) 1156 { 1157 /* Check for [L count] part */ 1158 ul = 0; 1159 if (strcmp(Argv[Argc-2], "L") == 0) 1160 { 1161 ul = strtoul(Argv[Argc-1], NULL, 0); 1162 if (ul > 0) 1163 { 1164 Argc -= 2; 1165 } 1166 } 1167 else if (Argv[Argc-1][0] == 'L') 1168 { 1169 ul = strtoul(Argv[Argc-1] + 1, NULL, 0); 1170 if (ul > 0) 1171 { 1172 Argc--; 1173 } 1174 } 1175 1176 /* Put the remaining arguments back together */ 1177 Argc--; 1178 for (ul = 1; ul < Argc; ul++) 1179 { 1180 Argv[ul][strlen(Argv[ul])] = ' '; 1181 } 1182 Argc++; 1183 } 1184 1185 /* Check if a Frame Address or Thread ID is given */ 1186 if (Argc > 1) 1187 { 1188 if (Argv[1][0] == '*') 1189 { 1190 Argv[1]++; 1191 1192 /* Evaluate the expression */ 1193 if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result)) 1194 return TRUE; 1195 1196 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 1197 KdbpPrint("Warning: Address %I64x is beeing truncated\n", Result); 1198 1199 Frame = (ULONG_PTR)Result; 1200 } 1201 else 1202 { 1203 KdbpPrint("Thread backtrace not supported yet!\n"); 1204 return TRUE; 1205 } 1206 } 1207 1208 /* Retrieve the Global Descriptor Table */ 1209 Ke386GetGlobalDescriptorTable(&Gdtr.Limit); 1210 1211 /* Retrieve the current (active) TSS */ 1212 TssSelector = Ke386GetTr(); 1213 Tss = KdbpRetrieveTss(TssSelector, NULL, &Gdtr); 1214 if (KdbpIsNestedTss(TssSelector, Tss)) 1215 { 1216 /* Display the active TSS if it is nested */ 1217 KdbpPrint("[Active TSS 0x%04x @ 0x%p]\n", TssSelector, Tss); 1218 } 1219 1220 /* If no Frame Address or Thread ID was given, try printing the function at EIP */ 1221 if (Argc <= 1) 1222 { 1223 KdbpPrint("Eip:\n"); 1224 if (!KdbSymPrintAddress((PVOID)TrapFrame.Eip, &TrapFrame)) 1225 KdbpPrint("<%08x>\n", TrapFrame.Eip); 1226 else 1227 KdbpPrint("\n"); 1228 } 1229 1230 /* Walk through the frames */ 1231 KdbpPrint("Frames:\n"); 1232 for (;;) 1233 { 1234 BOOLEAN GotNextFrame; 1235 1236 if (Frame == 0) 1237 goto CheckForParentTSS; 1238 1239 Address = 0; 1240 if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof(ULONG_PTR)))) 1241 { 1242 KdbpPrint("Couldn't access memory at 0x%p!\n", Frame + sizeof(ULONG_PTR)); 1243 goto CheckForParentTSS; 1244 } 1245 1246 if (Address == 0) 1247 goto CheckForParentTSS; 1248 1249 GotNextFrame = NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof(ULONG_PTR))); 1250 if (GotNextFrame) 1251 TrapFrame.Ebp = Frame; 1252 // else 1253 // Frame = 0; 1254 1255 /* Print the location of the call instruction (assumed 5 bytes length) */ 1256 if (!KdbSymPrintAddress((PVOID)(Address - 5), &TrapFrame)) 1257 KdbpPrint("<%08x>\n", Address); 1258 else 1259 KdbpPrint("\n"); 1260 1261 if (KdbOutputAborted) 1262 break; 1263 1264 if (!GotNextFrame) 1265 { 1266 KdbpPrint("Couldn't access memory at 0x%p!\n", Frame); 1267 goto CheckForParentTSS; // break; 1268 } 1269 1270 continue; 1271 1272 CheckForParentTSS: 1273 /* 1274 * We have ended the stack walking for the current (active) TSS. 1275 * Check whether this TSS was nested, and if so switch to its parent 1276 * and walk its stack. 1277 */ 1278 if (!KdbpIsNestedTss(TssSelector, Tss)) 1279 break; // The TSS is not nested, we stop there. 1280 1281 GotNextFrame = KdbpTrapFrameFromPrevTss(&TrapFrame, &TssSelector, &Tss, &Gdtr); 1282 if (!GotNextFrame) 1283 { 1284 KdbpPrint("Couldn't access parent TSS 0x%04x\n", Tss->Backlink); 1285 break; // Cannot retrieve the parent TSS, we stop there. 1286 } 1287 Address = TrapFrame.Eip; 1288 Frame = TrapFrame.Ebp; 1289 1290 KdbpPrint("[Parent TSS 0x%04x @ 0x%p]\n", TssSelector, Tss); 1291 1292 if (!KdbSymPrintAddress((PVOID)Address, &TrapFrame)) 1293 KdbpPrint("<%08x>\n", Address); 1294 else 1295 KdbpPrint("\n"); 1296 } 1297 1298 return TRUE; 1299 } 1300 1301 /*!\brief Continues execution of the system/leaves KDB. 1302 */ 1303 static BOOLEAN 1304 KdbpCmdContinue( 1305 ULONG Argc, 1306 PCHAR Argv[]) 1307 { 1308 /* Exit the main loop */ 1309 return FALSE; 1310 } 1311 1312 /*!\brief Continues execution of the system/leaves KDB. 1313 */ 1314 static BOOLEAN 1315 KdbpCmdStep( 1316 ULONG Argc, 1317 PCHAR Argv[]) 1318 { 1319 ULONG Count = 1; 1320 1321 if (Argc > 1) 1322 { 1323 Count = strtoul(Argv[1], NULL, 0); 1324 if (Count == 0) 1325 { 1326 KdbpPrint("%s: Integer argument required\n", Argv[0]); 1327 return TRUE; 1328 } 1329 } 1330 1331 if (Argv[0][0] == 'n') 1332 KdbSingleStepOver = TRUE; 1333 else 1334 KdbSingleStepOver = FALSE; 1335 1336 /* Set the number of single steps and return to the interrupted code. */ 1337 KdbNumSingleSteps = Count; 1338 1339 return FALSE; 1340 } 1341 1342 /*!\brief Lists breakpoints. 1343 */ 1344 static BOOLEAN 1345 KdbpCmdBreakPointList( 1346 ULONG Argc, 1347 PCHAR Argv[]) 1348 { 1349 LONG l; 1350 ULONG_PTR Address = 0; 1351 KDB_BREAKPOINT_TYPE Type = 0; 1352 KDB_ACCESS_TYPE AccessType = 0; 1353 UCHAR Size = 0; 1354 UCHAR DebugReg = 0; 1355 BOOLEAN Enabled = FALSE; 1356 BOOLEAN Global = FALSE; 1357 PEPROCESS Process = NULL; 1358 PCHAR str1, str2, ConditionExpr, GlobalOrLocal; 1359 CHAR Buffer[20]; 1360 1361 l = KdbpGetNextBreakPointNr(0); 1362 if (l < 0) 1363 { 1364 KdbpPrint("No breakpoints.\n"); 1365 return TRUE; 1366 } 1367 1368 KdbpPrint("Breakpoints:\n"); 1369 do 1370 { 1371 if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg, 1372 &Enabled, &Global, &Process, &ConditionExpr)) 1373 { 1374 continue; 1375 } 1376 1377 if (l == KdbLastBreakPointNr) 1378 { 1379 str1 = "\x1b[1m*"; 1380 str2 = "\x1b[0m"; 1381 } 1382 else 1383 { 1384 str1 = " "; 1385 str2 = ""; 1386 } 1387 1388 if (Global) 1389 { 1390 GlobalOrLocal = " global"; 1391 } 1392 else 1393 { 1394 GlobalOrLocal = Buffer; 1395 sprintf(Buffer, " PID 0x%08lx", 1396 (ULONG)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE)); 1397 } 1398 1399 if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary) 1400 { 1401 KdbpPrint(" %s%03d BPX 0x%08x%s%s%s%s%s\n", 1402 str1, l, Address, 1403 Enabled ? "" : " disabled", 1404 GlobalOrLocal, 1405 ConditionExpr ? " IF " : "", 1406 ConditionExpr ? ConditionExpr : "", 1407 str2); 1408 } 1409 else if (Type == KdbBreakPointHardware) 1410 { 1411 if (!Enabled) 1412 { 1413 KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s disabled%s%s%s%s\n", str1, l, Address, 1414 KDB_ACCESS_TYPE_TO_STRING(AccessType), 1415 Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), 1416 GlobalOrLocal, 1417 ConditionExpr ? " IF " : "", 1418 ConditionExpr ? ConditionExpr : "", 1419 str2); 1420 } 1421 else 1422 { 1423 KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s DR%d%s%s%s%s\n", str1, l, Address, 1424 KDB_ACCESS_TYPE_TO_STRING(AccessType), 1425 Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), 1426 DebugReg, 1427 GlobalOrLocal, 1428 ConditionExpr ? " IF " : "", 1429 ConditionExpr ? ConditionExpr : "", 1430 str2); 1431 } 1432 } 1433 } 1434 while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0); 1435 1436 return TRUE; 1437 } 1438 1439 /*!\brief Enables, disables or clears a breakpoint. 1440 */ 1441 static BOOLEAN 1442 KdbpCmdEnableDisableClearBreakPoint( 1443 ULONG Argc, 1444 PCHAR Argv[]) 1445 { 1446 PCHAR pend; 1447 ULONG BreakPointNr; 1448 1449 if (Argc < 2) 1450 { 1451 KdbpPrint("%s: argument required\n", Argv[0]); 1452 return TRUE; 1453 } 1454 1455 pend = Argv[1]; 1456 BreakPointNr = strtoul(Argv[1], &pend, 0); 1457 if (pend == Argv[1] || *pend != '\0') 1458 { 1459 KdbpPrint("%s: integer argument required\n", Argv[0]); 1460 return TRUE; 1461 } 1462 1463 if (Argv[0][1] == 'e') /* enable */ 1464 { 1465 KdbpEnableBreakPoint(BreakPointNr, NULL); 1466 } 1467 else if (Argv [0][1] == 'd') /* disable */ 1468 { 1469 KdbpDisableBreakPoint(BreakPointNr, NULL); 1470 } 1471 else /* clear */ 1472 { 1473 ASSERT(Argv[0][1] == 'c'); 1474 KdbpDeleteBreakPoint(BreakPointNr, NULL); 1475 } 1476 1477 return TRUE; 1478 } 1479 1480 /*!\brief Sets a software or hardware (memory) breakpoint at the given address. 1481 */ 1482 static BOOLEAN 1483 KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]) 1484 { 1485 ULONGLONG Result = 0; 1486 ULONG_PTR Address; 1487 KDB_BREAKPOINT_TYPE Type; 1488 UCHAR Size = 0; 1489 KDB_ACCESS_TYPE AccessType = 0; 1490 ULONG AddressArgIndex, i; 1491 LONG ConditionArgIndex; 1492 BOOLEAN Global = TRUE; 1493 1494 if (Argv[0][2] == 'x') /* software breakpoint */ 1495 { 1496 if (Argc < 2) 1497 { 1498 KdbpPrint("bpx: Address argument required.\n"); 1499 return TRUE; 1500 } 1501 1502 AddressArgIndex = 1; 1503 Type = KdbBreakPointSoftware; 1504 } 1505 else /* memory breakpoint */ 1506 { 1507 ASSERT(Argv[0][2] == 'm'); 1508 1509 if (Argc < 2) 1510 { 1511 KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n"); 1512 return TRUE; 1513 } 1514 1515 if (_stricmp(Argv[1], "x") == 0) 1516 AccessType = KdbAccessExec; 1517 else if (_stricmp(Argv[1], "r") == 0) 1518 AccessType = KdbAccessRead; 1519 else if (_stricmp(Argv[1], "w") == 0) 1520 AccessType = KdbAccessWrite; 1521 else if (_stricmp(Argv[1], "rw") == 0) 1522 AccessType = KdbAccessReadWrite; 1523 else 1524 { 1525 KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]); 1526 return TRUE; 1527 } 1528 1529 if (Argc < 3) 1530 { 1531 KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size"); 1532 return TRUE; 1533 } 1534 1535 AddressArgIndex = 3; 1536 if (_stricmp(Argv[2], "byte") == 0) 1537 Size = 1; 1538 else if (_stricmp(Argv[2], "word") == 0) 1539 Size = 2; 1540 else if (_stricmp(Argv[2], "dword") == 0) 1541 Size = 4; 1542 else if (AccessType == KdbAccessExec) 1543 { 1544 Size = 1; 1545 AddressArgIndex--; 1546 } 1547 else 1548 { 1549 KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]); 1550 return TRUE; 1551 } 1552 1553 if (Argc <= AddressArgIndex) 1554 { 1555 KdbpPrint("bpm: Address argument required.\n"); 1556 return TRUE; 1557 } 1558 1559 Type = KdbBreakPointHardware; 1560 } 1561 1562 /* Put the arguments back together */ 1563 ConditionArgIndex = -1; 1564 for (i = AddressArgIndex; i < (Argc-1); i++) 1565 { 1566 if (strcmp(Argv[i+1], "IF") == 0) /* IF found */ 1567 { 1568 ConditionArgIndex = i + 2; 1569 if ((ULONG)ConditionArgIndex >= Argc) 1570 { 1571 KdbpPrint("%s: IF requires condition expression.\n", Argv[0]); 1572 return TRUE; 1573 } 1574 1575 for (i = ConditionArgIndex; i < (Argc-1); i++) 1576 Argv[i][strlen(Argv[i])] = ' '; 1577 1578 break; 1579 } 1580 1581 Argv[i][strlen(Argv[i])] = ' '; 1582 } 1583 1584 /* Evaluate the address expression */ 1585 if (!KdbpEvaluateExpression(Argv[AddressArgIndex], 1586 KdbPromptString.Length + (Argv[AddressArgIndex]-Argv[0]), 1587 &Result)) 1588 { 1589 return TRUE; 1590 } 1591 1592 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 1593 KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result); 1594 1595 Address = (ULONG_PTR)Result; 1596 1597 KdbpInsertBreakPoint(Address, Type, Size, AccessType, 1598 (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex], 1599 Global, NULL); 1600 1601 return TRUE; 1602 } 1603 1604 /*!\brief Lists threads or switches to another thread context. 1605 */ 1606 static BOOLEAN 1607 KdbpCmdThread( 1608 ULONG Argc, 1609 PCHAR Argv[]) 1610 { 1611 PLIST_ENTRY Entry; 1612 PETHREAD Thread = NULL; 1613 PEPROCESS Process = NULL; 1614 BOOLEAN ReferencedThread = FALSE, ReferencedProcess = FALSE; 1615 PULONG Esp; 1616 PULONG Ebp; 1617 ULONG Eip; 1618 ULONG ul = 0; 1619 PCHAR State, pend, str1, str2; 1620 static const PCHAR ThreadStateToString[DeferredReady+1] = 1621 { 1622 "Initialized", "Ready", "Running", 1623 "Standby", "Terminated", "Waiting", 1624 "Transition", "DeferredReady" 1625 }; 1626 1627 ASSERT(KdbCurrentProcess); 1628 1629 if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) 1630 { 1631 Process = KdbCurrentProcess; 1632 1633 if (Argc >= 3) 1634 { 1635 ul = strtoul(Argv[2], &pend, 0); 1636 if (Argv[2] == pend) 1637 { 1638 KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]); 1639 return TRUE; 1640 } 1641 1642 if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) 1643 { 1644 KdbpPrint("thread: Invalid process id!\n"); 1645 return TRUE; 1646 } 1647 1648 /* Remember our reference */ 1649 ReferencedProcess = TRUE; 1650 } 1651 1652 Entry = Process->ThreadListHead.Flink; 1653 if (Entry == &Process->ThreadListHead) 1654 { 1655 if (Argc >= 3) 1656 KdbpPrint("No threads in process 0x%08x!\n", ul); 1657 else 1658 KdbpPrint("No threads in current process!\n"); 1659 1660 if (ReferencedProcess) 1661 ObDereferenceObject(Process); 1662 1663 return TRUE; 1664 } 1665 1666 KdbpPrint(" TID State Prior. Affinity EBP EIP\n"); 1667 do 1668 { 1669 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); 1670 1671 if (Thread == KdbCurrentThread) 1672 { 1673 str1 = "\x1b[1m*"; 1674 str2 = "\x1b[0m"; 1675 } 1676 else 1677 { 1678 str1 = " "; 1679 str2 = ""; 1680 } 1681 1682 if (!Thread->Tcb.InitialStack) 1683 { 1684 /* Thread has no kernel stack (probably terminated) */ 1685 Esp = Ebp = NULL; 1686 Eip = 0; 1687 } 1688 else if (Thread->Tcb.TrapFrame) 1689 { 1690 if (Thread->Tcb.TrapFrame->PreviousPreviousMode == KernelMode) 1691 Esp = (PULONG)Thread->Tcb.TrapFrame->TempEsp; 1692 else 1693 Esp = (PULONG)Thread->Tcb.TrapFrame->HardwareEsp; 1694 1695 Ebp = (PULONG)Thread->Tcb.TrapFrame->Ebp; 1696 Eip = Thread->Tcb.TrapFrame->Eip; 1697 } 1698 else 1699 { 1700 Esp = (PULONG)Thread->Tcb.KernelStack; 1701 Ebp = (PULONG)Esp[4]; 1702 Eip = 0; 1703 1704 if (Ebp) /* FIXME: Should we attach to the process to read Ebp[1]? */ 1705 KdbpSafeReadMemory(&Eip, Ebp + 1, sizeof (Eip)); 1706 } 1707 1708 if (Thread->Tcb.State < (DeferredReady + 1)) 1709 State = ThreadStateToString[Thread->Tcb.State]; 1710 else 1711 State = "Unknown"; 1712 1713 KdbpPrint(" %s0x%08x %-11s %3d 0x%08x 0x%08x 0x%08x%s\n", 1714 str1, 1715 Thread->Cid.UniqueThread, 1716 State, 1717 Thread->Tcb.Priority, 1718 Thread->Tcb.Affinity, 1719 Ebp, 1720 Eip, 1721 str2); 1722 1723 Entry = Entry->Flink; 1724 } 1725 while (Entry != &Process->ThreadListHead); 1726 1727 /* Release our reference, if any */ 1728 if (ReferencedProcess) 1729 ObDereferenceObject(Process); 1730 } 1731 else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) 1732 { 1733 if (Argc < 3) 1734 { 1735 KdbpPrint("thread attach: thread id argument required!\n"); 1736 return TRUE; 1737 } 1738 1739 ul = strtoul(Argv[2], &pend, 0); 1740 if (Argv[2] == pend) 1741 { 1742 KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]); 1743 return TRUE; 1744 } 1745 1746 if (!KdbpAttachToThread((PVOID)ul)) 1747 { 1748 return TRUE; 1749 } 1750 1751 KdbpPrint("Attached to thread 0x%08x.\n", ul); 1752 } 1753 else 1754 { 1755 Thread = KdbCurrentThread; 1756 1757 if (Argc >= 2) 1758 { 1759 ul = strtoul(Argv[1], &pend, 0); 1760 if (Argv[1] == pend) 1761 { 1762 KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]); 1763 return TRUE; 1764 } 1765 1766 if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread))) 1767 { 1768 KdbpPrint("thread: Invalid thread id!\n"); 1769 return TRUE; 1770 } 1771 1772 /* Remember our reference */ 1773 ReferencedThread = TRUE; 1774 } 1775 1776 if (Thread->Tcb.State < (DeferredReady + 1)) 1777 State = ThreadStateToString[Thread->Tcb.State]; 1778 else 1779 State = "Unknown"; 1780 1781 KdbpPrint("%s" 1782 " TID: 0x%08x\n" 1783 " State: %s (0x%x)\n" 1784 " Priority: %d\n" 1785 " Affinity: 0x%08x\n" 1786 " Initial Stack: 0x%08x\n" 1787 " Stack Limit: 0x%08x\n" 1788 " Stack Base: 0x%08x\n" 1789 " Kernel Stack: 0x%08x\n" 1790 " Trap Frame: 0x%08x\n" 1791 " NPX State: %s (0x%x)\n", 1792 (Argc < 2) ? "Current Thread:\n" : "", 1793 Thread->Cid.UniqueThread, 1794 State, Thread->Tcb.State, 1795 Thread->Tcb.Priority, 1796 Thread->Tcb.Affinity, 1797 Thread->Tcb.InitialStack, 1798 Thread->Tcb.StackLimit, 1799 Thread->Tcb.StackBase, 1800 Thread->Tcb.KernelStack, 1801 Thread->Tcb.TrapFrame, 1802 NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState); 1803 1804 /* Release our reference if we had one */ 1805 if (ReferencedThread) 1806 ObDereferenceObject(Thread); 1807 } 1808 1809 return TRUE; 1810 } 1811 1812 /*!\brief Lists processes or switches to another process context. 1813 */ 1814 static BOOLEAN 1815 KdbpCmdProc( 1816 ULONG Argc, 1817 PCHAR Argv[]) 1818 { 1819 PLIST_ENTRY Entry; 1820 PEPROCESS Process; 1821 BOOLEAN ReferencedProcess = FALSE; 1822 PCHAR State, pend, str1, str2; 1823 ULONG ul; 1824 extern LIST_ENTRY PsActiveProcessHead; 1825 1826 if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) 1827 { 1828 Entry = PsActiveProcessHead.Flink; 1829 if (!Entry || Entry == &PsActiveProcessHead) 1830 { 1831 KdbpPrint("No processes in the system!\n"); 1832 return TRUE; 1833 } 1834 1835 KdbpPrint(" PID State Filename\n"); 1836 do 1837 { 1838 Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks); 1839 1840 if (Process == KdbCurrentProcess) 1841 { 1842 str1 = "\x1b[1m*"; 1843 str2 = "\x1b[0m"; 1844 } 1845 else 1846 { 1847 str1 = " "; 1848 str2 = ""; 1849 } 1850 1851 State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" : 1852 ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition")); 1853 1854 KdbpPrint(" %s0x%08x %-10s %s%s\n", 1855 str1, 1856 Process->UniqueProcessId, 1857 State, 1858 Process->ImageFileName, 1859 str2); 1860 1861 Entry = Entry->Flink; 1862 } 1863 while(Entry != &PsActiveProcessHead); 1864 } 1865 else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) 1866 { 1867 if (Argc < 3) 1868 { 1869 KdbpPrint("process attach: process id argument required!\n"); 1870 return TRUE; 1871 } 1872 1873 ul = strtoul(Argv[2], &pend, 0); 1874 if (Argv[2] == pend) 1875 { 1876 KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]); 1877 return TRUE; 1878 } 1879 1880 if (!KdbpAttachToProcess((PVOID)ul)) 1881 { 1882 return TRUE; 1883 } 1884 1885 KdbpPrint("Attached to process 0x%08x, thread 0x%08x.\n", (ULONG)ul, 1886 (ULONG)KdbCurrentThread->Cid.UniqueThread); 1887 } 1888 else 1889 { 1890 Process = KdbCurrentProcess; 1891 1892 if (Argc >= 2) 1893 { 1894 ul = strtoul(Argv[1], &pend, 0); 1895 if (Argv[1] == pend) 1896 { 1897 KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]); 1898 return TRUE; 1899 } 1900 1901 if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) 1902 { 1903 KdbpPrint("proc: Invalid process id!\n"); 1904 return TRUE; 1905 } 1906 1907 /* Remember our reference */ 1908 ReferencedProcess = TRUE; 1909 } 1910 1911 State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" : 1912 ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition")); 1913 KdbpPrint("%s" 1914 " PID: 0x%08x\n" 1915 " State: %s (0x%x)\n" 1916 " Image Filename: %s\n", 1917 (Argc < 2) ? "Current process:\n" : "", 1918 Process->UniqueProcessId, 1919 State, Process->Pcb.State, 1920 Process->ImageFileName); 1921 1922 /* Release our reference, if any */ 1923 if (ReferencedProcess) 1924 ObDereferenceObject(Process); 1925 } 1926 1927 return TRUE; 1928 } 1929 1930 /*!\brief Lists loaded modules or the one containing the specified address. 1931 */ 1932 static BOOLEAN 1933 KdbpCmdMod( 1934 ULONG Argc, 1935 PCHAR Argv[]) 1936 { 1937 ULONGLONG Result = 0; 1938 ULONG_PTR Address; 1939 PLDR_DATA_TABLE_ENTRY LdrEntry; 1940 BOOLEAN DisplayOnlyOneModule = FALSE; 1941 INT i = 0; 1942 1943 if (Argc >= 2) 1944 { 1945 /* Put the arguments back together */ 1946 Argc--; 1947 while (--Argc >= 1) 1948 Argv[Argc][strlen(Argv[Argc])] = ' '; 1949 1950 /* Evaluate the expression */ 1951 if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result)) 1952 { 1953 return TRUE; 1954 } 1955 1956 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 1957 KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result); 1958 1959 Address = (ULONG_PTR)Result; 1960 1961 if (!KdbpSymFindModule((PVOID)Address, NULL, -1, &LdrEntry)) 1962 { 1963 KdbpPrint("No module containing address 0x%p found!\n", Address); 1964 return TRUE; 1965 } 1966 1967 DisplayOnlyOneModule = TRUE; 1968 } 1969 else 1970 { 1971 if (!KdbpSymFindModule(NULL, NULL, 0, &LdrEntry)) 1972 { 1973 ULONG_PTR ntoskrnlBase = ((ULONG_PTR)KdbpCmdMod) & 0xfff00000; 1974 KdbpPrint(" Base Size Name\n"); 1975 KdbpPrint(" %08x %08x %s\n", ntoskrnlBase, 0, "ntoskrnl.exe"); 1976 return TRUE; 1977 } 1978 1979 i = 1; 1980 } 1981 1982 KdbpPrint(" Base Size Name\n"); 1983 for (;;) 1984 { 1985 KdbpPrint(" %08x %08x %wZ\n", LdrEntry->DllBase, LdrEntry->SizeOfImage, &LdrEntry->BaseDllName); 1986 1987 if(DisplayOnlyOneModule || !KdbpSymFindModule(NULL, NULL, i++, &LdrEntry)) 1988 break; 1989 } 1990 1991 return TRUE; 1992 } 1993 1994 /*!\brief Displays GDT, LDT or IDT. 1995 */ 1996 static BOOLEAN 1997 KdbpCmdGdtLdtIdt( 1998 ULONG Argc, 1999 PCHAR Argv[]) 2000 { 2001 KDESCRIPTOR Reg; 2002 ULONG SegDesc[2]; 2003 ULONG SegBase; 2004 ULONG SegLimit; 2005 PCHAR SegType; 2006 USHORT SegSel; 2007 UCHAR Type, Dpl; 2008 INT i; 2009 ULONG ul; 2010 2011 if (Argv[0][0] == 'i') 2012 { 2013 /* Read IDTR */ 2014 __sidt(&Reg.Limit); 2015 2016 if (Reg.Limit < 7) 2017 { 2018 KdbpPrint("Interrupt descriptor table is empty.\n"); 2019 return TRUE; 2020 } 2021 2022 KdbpPrint("IDT Base: 0x%08x Limit: 0x%04x\n", Reg.Base, Reg.Limit); 2023 KdbpPrint(" Idx Type Seg. Sel. Offset DPL\n"); 2024 2025 for (i = 0; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) 2026 { 2027 if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) 2028 { 2029 KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); 2030 return TRUE; 2031 } 2032 2033 Dpl = ((SegDesc[1] >> 13) & 3); 2034 if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 2035 SegType = "TASKGATE"; 2036 else if ((SegDesc[1] & 0x1fe0) == 0x0e00) /* 32 bit Interrupt gate */ 2037 SegType = "INTGATE32"; 2038 else if ((SegDesc[1] & 0x1fe0) == 0x0600) /* 16 bit Interrupt gate */ 2039 SegType = "INTGATE16"; 2040 else if ((SegDesc[1] & 0x1fe0) == 0x0f00) /* 32 bit Trap gate */ 2041 SegType = "TRAPGATE32"; 2042 else if ((SegDesc[1] & 0x1fe0) == 0x0700) /* 16 bit Trap gate */ 2043 SegType = "TRAPGATE16"; 2044 else 2045 SegType = "UNKNOWN"; 2046 2047 if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ 2048 { 2049 KdbpPrint(" %03d %-10s [NP] [NP] %02d\n", 2050 i / 8, SegType, Dpl); 2051 } 2052 else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 2053 { 2054 SegSel = SegDesc[0] >> 16; 2055 KdbpPrint(" %03d %-10s 0x%04x %02d\n", 2056 i / 8, SegType, SegSel, Dpl); 2057 } 2058 else 2059 { 2060 SegSel = SegDesc[0] >> 16; 2061 SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff); 2062 KdbpPrint(" %03d %-10s 0x%04x 0x%08x %02d\n", 2063 i / 8, SegType, SegSel, SegBase, Dpl); 2064 } 2065 } 2066 } 2067 else 2068 { 2069 ul = 0; 2070 2071 if (Argv[0][0] == 'g') 2072 { 2073 /* Read GDTR */ 2074 Ke386GetGlobalDescriptorTable(&Reg.Limit); 2075 i = 8; 2076 } 2077 else 2078 { 2079 ASSERT(Argv[0][0] == 'l'); 2080 2081 /* Read LDTR */ 2082 Reg.Limit = Ke386GetLocalDescriptorTable(); 2083 Reg.Base = 0; 2084 i = 0; 2085 ul = 1 << 2; 2086 } 2087 2088 if (Reg.Limit < 7) 2089 { 2090 KdbpPrint("%s descriptor table is empty.\n", 2091 Argv[0][0] == 'g' ? "Global" : "Local"); 2092 return TRUE; 2093 } 2094 2095 KdbpPrint("%cDT Base: 0x%08x Limit: 0x%04x\n", 2096 Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit); 2097 KdbpPrint(" Idx Sel. Type Base Limit DPL Attribs\n"); 2098 2099 for (; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) 2100 { 2101 if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) 2102 { 2103 KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); 2104 return TRUE; 2105 } 2106 2107 Dpl = ((SegDesc[1] >> 13) & 3); 2108 Type = ((SegDesc[1] >> 8) & 0xf); 2109 2110 SegBase = SegDesc[0] >> 16; 2111 SegBase |= (SegDesc[1] & 0xff) << 16; 2112 SegBase |= SegDesc[1] & 0xff000000; 2113 SegLimit = SegDesc[0] & 0x0000ffff; 2114 SegLimit |= (SegDesc[1] >> 16) & 0xf; 2115 2116 if ((SegDesc[1] & (1 << 23)) != 0) 2117 { 2118 SegLimit *= 4096; 2119 SegLimit += 4095; 2120 } 2121 else 2122 { 2123 SegLimit++; 2124 } 2125 2126 if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ 2127 { 2128 switch (Type) 2129 { 2130 case 1: SegType = "TSS16(Avl)"; break; 2131 case 2: SegType = "LDT"; break; 2132 case 3: SegType = "TSS16(Busy)"; break; 2133 case 4: SegType = "CALLGATE16"; break; 2134 case 5: SegType = "TASKGATE"; break; 2135 case 6: SegType = "INTGATE16"; break; 2136 case 7: SegType = "TRAPGATE16"; break; 2137 case 9: SegType = "TSS32(Avl)"; break; 2138 case 11: SegType = "TSS32(Busy)"; break; 2139 case 12: SegType = "CALLGATE32"; break; 2140 case 14: SegType = "INTGATE32"; break; 2141 case 15: SegType = "TRAPGATE32"; break; 2142 default: SegType = "UNKNOWN"; break; 2143 } 2144 2145 if (!(Type >= 1 && Type <= 3) && 2146 Type != 9 && Type != 11) 2147 { 2148 SegBase = 0; 2149 SegLimit = 0; 2150 } 2151 } 2152 else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ 2153 { 2154 if ((SegDesc[1] & (1 << 22)) != 0) 2155 SegType = "DATA32"; 2156 else 2157 SegType = "DATA16"; 2158 } 2159 else /* Code segment */ 2160 { 2161 if ((SegDesc[1] & (1 << 22)) != 0) 2162 SegType = "CODE32"; 2163 else 2164 SegType = "CODE16"; 2165 } 2166 2167 if ((SegDesc[1] & (1 << 15)) == 0) /* Not present */ 2168 { 2169 KdbpPrint(" %03d 0x%04x %-11s [NP] [NP] %02d NP\n", 2170 i / 8, i | Dpl | ul, SegType, Dpl); 2171 } 2172 else 2173 { 2174 KdbpPrint(" %03d 0x%04x %-11s 0x%08x 0x%08x %02d ", 2175 i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl); 2176 2177 if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ 2178 { 2179 /* FIXME: Display system segment */ 2180 } 2181 else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ 2182 { 2183 if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */ 2184 KdbpPrint(" E"); 2185 2186 KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R"); 2187 2188 if ((SegDesc[1] & (1 << 8)) != 0) 2189 KdbpPrint(" A"); 2190 } 2191 else /* Code segment */ 2192 { 2193 if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */ 2194 KdbpPrint(" C"); 2195 2196 KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X"); 2197 2198 if ((SegDesc[1] & (1 << 8)) != 0) 2199 KdbpPrint(" A"); 2200 } 2201 2202 if ((SegDesc[1] & (1 << 20)) != 0) 2203 KdbpPrint(" AVL"); 2204 2205 KdbpPrint("\n"); 2206 } 2207 } 2208 } 2209 2210 return TRUE; 2211 } 2212 2213 /*!\brief Displays the KPCR 2214 */ 2215 static BOOLEAN 2216 KdbpCmdPcr( 2217 ULONG Argc, 2218 PCHAR Argv[]) 2219 { 2220 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 2221 2222 KdbpPrint("Current PCR is at 0x%p.\n", Pcr); 2223 KdbpPrint(" Tib.ExceptionList: 0x%08x\n" 2224 " Tib.StackBase: 0x%08x\n" 2225 " Tib.StackLimit: 0x%08x\n" 2226 " Tib.SubSystemTib: 0x%08x\n" 2227 " Tib.FiberData/Version: 0x%08x\n" 2228 " Tib.ArbitraryUserPointer: 0x%08x\n" 2229 " Tib.Self: 0x%08x\n" 2230 " SelfPcr: 0x%08x\n" 2231 " PCRCB: 0x%08x\n" 2232 " Irql: 0x%02x\n" 2233 " IRR: 0x%08x\n" 2234 " IrrActive: 0x%08x\n" 2235 " IDR: 0x%08x\n" 2236 " KdVersionBlock: 0x%08x\n" 2237 " IDT: 0x%08x\n" 2238 " GDT: 0x%08x\n" 2239 " TSS: 0x%08x\n" 2240 " MajorVersion: 0x%04x\n" 2241 " MinorVersion: 0x%04x\n" 2242 " SetMember: 0x%08x\n" 2243 " StallScaleFactor: 0x%08x\n" 2244 " Number: 0x%02x\n" 2245 " L2CacheAssociativity: 0x%02x\n" 2246 " VdmAlert: 0x%08x\n" 2247 " L2CacheSize: 0x%08x\n" 2248 " InterruptMode: 0x%08x\n", 2249 Pcr->NtTib.ExceptionList, Pcr->NtTib.StackBase, Pcr->NtTib.StackLimit, 2250 Pcr->NtTib.SubSystemTib, Pcr->NtTib.FiberData, Pcr->NtTib.ArbitraryUserPointer, 2251 Pcr->NtTib.Self, Pcr->SelfPcr, Pcr->Prcb, Pcr->Irql, Pcr->IRR, Pcr->IrrActive, 2252 Pcr->IDR, Pcr->KdVersionBlock, Pcr->IDT, Pcr->GDT, Pcr->TSS, 2253 Pcr->MajorVersion, Pcr->MinorVersion, Pcr->SetMember, Pcr->StallScaleFactor, 2254 Pcr->Number, Pcr->SecondLevelCacheAssociativity, 2255 Pcr->VdmAlert, Pcr->SecondLevelCacheSize, Pcr->InterruptMode); 2256 2257 return TRUE; 2258 } 2259 2260 /*!\brief Displays the TSS 2261 */ 2262 static BOOLEAN 2263 KdbpCmdTss( 2264 ULONG Argc, 2265 PCHAR Argv[]) 2266 { 2267 USHORT TssSelector; 2268 PKTSS Tss = NULL; 2269 2270 if (Argc >= 2) 2271 { 2272 /* 2273 * Specified TSS via its selector [selector] or descriptor address [*descaddr]. 2274 * Note that we ignore any other argument values. 2275 */ 2276 PCHAR Param, pszNext; 2277 ULONG ulValue; 2278 2279 Param = Argv[1]; 2280 if (Argv[1][0] == '*') 2281 ++Param; 2282 2283 ulValue = strtoul(Param, &pszNext, 0); 2284 if (pszNext && *pszNext) 2285 { 2286 KdbpPrint("Invalid TSS specification.\n"); 2287 return TRUE; 2288 } 2289 2290 if (Argv[1][0] == '*') 2291 { 2292 /* Descriptor specified */ 2293 TssSelector = 0; // Unknown selector! 2294 // TODO: Room for improvement: Find the TSS descriptor 2295 // in the GDT so as to validate it. 2296 Tss = (PKTSS)(ULONG_PTR)ulValue; 2297 if (!Tss) 2298 { 2299 KdbpPrint("Invalid 32-bit TSS descriptor.\n"); 2300 return TRUE; 2301 } 2302 } 2303 else 2304 { 2305 /* Selector specified, retrive the corresponding TSS */ 2306 TssSelector = (USHORT)ulValue; 2307 Tss = KdbpRetrieveTss(TssSelector, NULL, NULL); 2308 if (!Tss) 2309 { 2310 KdbpPrint("Invalid 32-bit TSS selector.\n"); 2311 return TRUE; 2312 } 2313 } 2314 } 2315 2316 if (!Tss) 2317 { 2318 /* If no TSS was specified, use the current TSS descriptor */ 2319 TssSelector = Ke386GetTr(); 2320 Tss = KeGetPcr()->TSS; 2321 // NOTE: If everything works OK, Tss is the current TSS corresponding to the TR selector. 2322 } 2323 2324 KdbpPrint("%s TSS 0x%04x is at 0x%p.\n", 2325 (Tss == KeGetPcr()->TSS) ? "Current" : "Specified", TssSelector, Tss); 2326 KdbpPrint(" Backlink: 0x%04x\n" 2327 " Ss0:Esp0: 0x%04x:0x%08x\n" 2328 // NOTE: Ss1:Esp1 and Ss2:Esp2: are in the NotUsed1 field. 2329 " CR3: 0x%08x\n" 2330 " EFlags: 0x%08x\n" 2331 " Eax: 0x%08x\n" 2332 " Ebx: 0x%08x\n" 2333 " Ecx: 0x%08x\n" 2334 " Edx: 0x%08x\n" 2335 " Esi: 0x%08x\n" 2336 " Edi: 0x%08x\n" 2337 " Eip: 0x%08x\n" 2338 " Esp: 0x%08x\n" 2339 " Ebp: 0x%08x\n" 2340 " Cs: 0x%04x\n" 2341 " Ss: 0x%04x\n" 2342 " Ds: 0x%04x\n" 2343 " Es: 0x%04x\n" 2344 " Fs: 0x%04x\n" 2345 " Gs: 0x%04x\n" 2346 " LDT: 0x%04x\n" 2347 " Flags: 0x%04x\n" 2348 " IoMapBase: 0x%04x\n", 2349 Tss->Backlink, Tss->Ss0, Tss->Esp0, Tss->CR3, Tss->EFlags, 2350 Tss->Eax, Tss->Ebx, Tss->Ecx, Tss->Edx, Tss->Esi, Tss->Edi, 2351 Tss->Eip, Tss->Esp, Tss->Ebp, 2352 Tss->Cs, Tss->Ss, Tss->Ds, Tss->Es, Tss->Fs, Tss->Gs, 2353 Tss->LDT, Tss->Flags, Tss->IoMapBase); 2354 2355 return TRUE; 2356 } 2357 2358 /*!\brief Bugchecks the system. 2359 */ 2360 static BOOLEAN 2361 KdbpCmdBugCheck( 2362 ULONG Argc, 2363 PCHAR Argv[]) 2364 { 2365 /* Set the flag and quit looping */ 2366 KdbpBugCheckRequested = TRUE; 2367 return FALSE; 2368 } 2369 2370 static BOOLEAN 2371 KdbpCmdReboot( 2372 ULONG Argc, 2373 PCHAR Argv[]) 2374 { 2375 /* Reboot immediately (we do not return) */ 2376 HalReturnToFirmware(HalRebootRoutine); 2377 return FALSE; 2378 } 2379 2380 2381 VOID 2382 KdbpPager( 2383 IN PCHAR Buffer, 2384 IN ULONG BufLength); 2385 2386 /*!\brief Display debug messages on screen, with paging. 2387 * 2388 * Keys for per-page view: Home, End, PageUp, Arrow Up, PageDown, 2389 * all others are as PageDown. 2390 */ 2391 static BOOLEAN 2392 KdbpCmdDmesg( 2393 ULONG Argc, 2394 PCHAR Argv[]) 2395 { 2396 ULONG beg, end; 2397 2398 KdbpIsInDmesgMode = TRUE; /* Toggle logging flag */ 2399 if (!KdpDmesgBuffer) 2400 { 2401 KdbpPrint("Dmesg: error, buffer is not allocated! /DEBUGPORT=SCREEN kernel param required for dmesg.\n"); 2402 return TRUE; 2403 } 2404 2405 KdbpPrint("*** Dmesg *** TotalWritten=%lu, BufferSize=%lu, CurrentPosition=%lu\n", 2406 KdbDmesgTotalWritten, KdpDmesgBufferSize, KdpDmesgCurrentPosition); 2407 2408 /* Pass data to the pager */ 2409 end = KdpDmesgCurrentPosition; 2410 beg = (end + KdpDmesgFreeBytes) % KdpDmesgBufferSize; 2411 2412 /* No roll-overs, and overwritten=lost bytes */ 2413 if (KdbDmesgTotalWritten <= KdpDmesgBufferSize) 2414 { 2415 /* Show buffer (KdpDmesgBuffer + beg, num) */ 2416 KdbpPager(KdpDmesgBuffer, KdpDmesgCurrentPosition); 2417 } 2418 else 2419 { 2420 /* Show 2 buffers: (KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg) 2421 * and: (KdpDmesgBuffer, end) */ 2422 KdbpPager(KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg); 2423 KdbpPrint("*** Dmesg: buffer rollup ***\n"); 2424 KdbpPager(KdpDmesgBuffer, end); 2425 } 2426 KdbpPrint("*** Dmesg: end of output ***\n"); 2427 2428 KdbpIsInDmesgMode = FALSE; /* Toggle logging flag */ 2429 2430 return TRUE; 2431 } 2432 2433 /*!\brief Sets or displays a config variables value. 2434 */ 2435 static BOOLEAN 2436 KdbpCmdSet( 2437 ULONG Argc, 2438 PCHAR Argv[]) 2439 { 2440 LONG l; 2441 BOOLEAN First; 2442 PCHAR pend = 0; 2443 KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter; 2444 KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter; 2445 2446 static const PCHAR ExceptionNames[21] = 2447 { 2448 "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP", 2449 "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT", 2450 "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK", 2451 "MACHINECHECK", "SIMDFAULT", "OTHERS" 2452 }; 2453 2454 if (Argc == 1) 2455 { 2456 KdbpPrint("Available settings:\n"); 2457 KdbpPrint(" syntax [intel|at&t]\n"); 2458 KdbpPrint(" condition [exception|*] [first|last] [never|always|kmode|umode]\n"); 2459 KdbpPrint(" break_on_module_load [true|false]\n"); 2460 } 2461 else if (strcmp(Argv[1], "syntax") == 0) 2462 { 2463 if (Argc == 2) 2464 { 2465 KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t"); 2466 } 2467 else if (Argc >= 3) 2468 { 2469 if (_stricmp(Argv[2], "intel") == 0) 2470 KdbUseIntelSyntax = TRUE; 2471 else if (_stricmp(Argv[2], "at&t") == 0) 2472 KdbUseIntelSyntax = FALSE; 2473 else 2474 KdbpPrint("Unknown syntax '%s'.\n", Argv[2]); 2475 } 2476 } 2477 else if (strcmp(Argv[1], "condition") == 0) 2478 { 2479 if (Argc == 2) 2480 { 2481 KdbpPrint("Conditions: (First) (Last)\n"); 2482 for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++) 2483 { 2484 if (!ExceptionNames[l]) 2485 continue; 2486 2487 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) 2488 ASSERT(FALSE); 2489 2490 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) 2491 ASSERT(FALSE); 2492 2493 KdbpPrint(" #%02d %-20s %-8s %-8s\n", l, ExceptionNames[l], 2494 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 2495 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 2496 } 2497 2498 ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1)); 2499 KdbpPrint(" %-20s %-8s %-8s\n", ExceptionNames[l], 2500 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 2501 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 2502 } 2503 else 2504 { 2505 if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */ 2506 { 2507 l = -1; 2508 } 2509 else 2510 { 2511 l = strtoul(Argv[2], &pend, 0); 2512 2513 if (Argv[2] == pend) 2514 { 2515 for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++) 2516 { 2517 if (!ExceptionNames[l]) 2518 continue; 2519 2520 if (_stricmp(ExceptionNames[l], Argv[2]) == 0) 2521 break; 2522 } 2523 } 2524 2525 if (l >= RTL_NUMBER_OF(ExceptionNames)) 2526 { 2527 KdbpPrint("Unknown exception '%s'.\n", Argv[2]); 2528 return TRUE; 2529 } 2530 } 2531 2532 if (Argc > 4) 2533 { 2534 if (_stricmp(Argv[3], "first") == 0) 2535 First = TRUE; 2536 else if (_stricmp(Argv[3], "last") == 0) 2537 First = FALSE; 2538 else 2539 { 2540 KdbpPrint("set condition: second argument must be 'first' or 'last'\n"); 2541 return TRUE; 2542 } 2543 2544 if (_stricmp(Argv[4], "never") == 0) 2545 ConditionFirst = KdbDoNotEnter; 2546 else if (_stricmp(Argv[4], "always") == 0) 2547 ConditionFirst = KdbEnterAlways; 2548 else if (_stricmp(Argv[4], "umode") == 0) 2549 ConditionFirst = KdbEnterFromUmode; 2550 else if (_stricmp(Argv[4], "kmode") == 0) 2551 ConditionFirst = KdbEnterFromKmode; 2552 else 2553 { 2554 KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n"); 2555 return TRUE; 2556 } 2557 2558 if (!KdbpSetEnterCondition(l, First, ConditionFirst)) 2559 { 2560 if (l >= 0) 2561 KdbpPrint("Couldn't change condition for exception #%02d\n", l); 2562 else 2563 KdbpPrint("Couldn't change condition for all exceptions\n", l); 2564 } 2565 } 2566 else /* Argc >= 3 */ 2567 { 2568 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) 2569 ASSERT(FALSE); 2570 2571 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) 2572 ASSERT(FALSE); 2573 2574 if (l < (RTL_NUMBER_OF(ExceptionNames) - 1)) 2575 { 2576 KdbpPrint("Condition for exception #%02d (%s): FirstChance %s LastChance %s\n", 2577 l, ExceptionNames[l], 2578 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 2579 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 2580 } 2581 else 2582 { 2583 KdbpPrint("Condition for all other exceptions: FirstChance %s LastChance %s\n", 2584 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 2585 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 2586 } 2587 } 2588 } 2589 } 2590 else if (strcmp(Argv[1], "break_on_module_load") == 0) 2591 { 2592 if (Argc == 2) 2593 KdbpPrint("break_on_module_load = %s\n", KdbBreakOnModuleLoad ? "enabled" : "disabled"); 2594 else if (Argc >= 3) 2595 { 2596 if (_stricmp(Argv[2], "enable") == 0 || _stricmp(Argv[2], "enabled") == 0 || _stricmp(Argv[2], "true") == 0) 2597 KdbBreakOnModuleLoad = TRUE; 2598 else if (_stricmp(Argv[2], "disable") == 0 || _stricmp(Argv[2], "disabled") == 0 || _stricmp(Argv[2], "false") == 0) 2599 KdbBreakOnModuleLoad = FALSE; 2600 else 2601 KdbpPrint("Unknown setting '%s'.\n", Argv[2]); 2602 } 2603 } 2604 else 2605 { 2606 KdbpPrint("Unknown setting '%s'.\n", Argv[1]); 2607 } 2608 2609 return TRUE; 2610 } 2611 2612 /*!\brief Displays help screen. 2613 */ 2614 static BOOLEAN 2615 KdbpCmdHelp( 2616 ULONG Argc, 2617 PCHAR Argv[]) 2618 { 2619 ULONG i; 2620 2621 KdbpPrint("Kernel debugger commands:\n"); 2622 for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) 2623 { 2624 if (!KdbDebuggerCommands[i].Syntax) /* Command group */ 2625 { 2626 if (i > 0) 2627 KdbpPrint("\n"); 2628 2629 KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help); 2630 continue; 2631 } 2632 2633 KdbpPrint(" %-20s - %s\n", 2634 KdbDebuggerCommands[i].Syntax, 2635 KdbDebuggerCommands[i].Help); 2636 } 2637 2638 return TRUE; 2639 } 2640 2641 /*!\brief Prints the given string with printf-like formatting. 2642 * 2643 * \param Format Format of the string/arguments. 2644 * \param ... Variable number of arguments matching the format specified in \a Format. 2645 * 2646 * \note Doesn't correctly handle \\t and terminal escape sequences when calculating the 2647 * number of lines required to print a single line from the Buffer in the terminal. 2648 * Prints maximum 4096 chars, because of its buffer size. 2649 */ 2650 VOID 2651 KdbpPrint( 2652 IN PCHAR Format, 2653 IN ... OPTIONAL) 2654 { 2655 static CHAR Buffer[4096]; 2656 static BOOLEAN TerminalInitialized = FALSE; 2657 static BOOLEAN TerminalConnected = FALSE; 2658 static BOOLEAN TerminalReportsSize = TRUE; 2659 CHAR c = '\0'; 2660 PCHAR p, p2; 2661 ULONG Length; 2662 ULONG i, j; 2663 LONG RowsPrintedByTerminal; 2664 ULONG ScanCode; 2665 va_list ap; 2666 2667 /* Check if the user has aborted output of the current command */ 2668 if (KdbOutputAborted) 2669 return; 2670 2671 /* Initialize the terminal */ 2672 if (!TerminalInitialized) 2673 { 2674 DbgPrint("\x1b[7h"); /* Enable linewrap */ 2675 2676 /* Query terminal type */ 2677 /*DbgPrint("\x1b[Z");*/ 2678 DbgPrint("\x05"); 2679 2680 TerminalInitialized = TRUE; 2681 Length = 0; 2682 KeStallExecutionProcessor(100000); 2683 2684 for (;;) 2685 { 2686 c = KdbpTryGetCharSerial(5000); 2687 if (c == -1) 2688 break; 2689 2690 Buffer[Length++] = c; 2691 if (Length >= (sizeof (Buffer) - 1)) 2692 break; 2693 } 2694 2695 Buffer[Length] = '\0'; 2696 if (Length > 0) 2697 TerminalConnected = TRUE; 2698 } 2699 2700 /* Get number of rows and columns in terminal */ 2701 if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) || 2702 (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */ 2703 { 2704 if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize) 2705 { 2706 /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ 2707 TerminalReportsSize = FALSE; 2708 KeStallExecutionProcessor(100000); 2709 DbgPrint("\x1b[18t"); 2710 c = KdbpTryGetCharSerial(5000); 2711 2712 if (c == KEY_ESC) 2713 { 2714 c = KdbpTryGetCharSerial(5000); 2715 if (c == '[') 2716 { 2717 Length = 0; 2718 2719 for (;;) 2720 { 2721 c = KdbpTryGetCharSerial(5000); 2722 if (c == -1) 2723 break; 2724 2725 Buffer[Length++] = c; 2726 if (isalpha(c) || Length >= (sizeof (Buffer) - 1)) 2727 break; 2728 } 2729 2730 Buffer[Length] = '\0'; 2731 if (Buffer[0] == '8' && Buffer[1] == ';') 2732 { 2733 for (i = 2; (i < Length) && (Buffer[i] != ';'); i++); 2734 2735 if (Buffer[i] == ';') 2736 { 2737 Buffer[i++] = '\0'; 2738 2739 /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */ 2740 KdbNumberOfRowsTerminal = strtoul(Buffer + 2, NULL, 0); 2741 KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0); 2742 TerminalReportsSize = TRUE; 2743 } 2744 } 2745 } 2746 /* Clear further characters */ 2747 while ((c = KdbpTryGetCharSerial(5000)) != -1); 2748 } 2749 } 2750 2751 if (KdbNumberOfRowsTerminal <= 0) 2752 { 2753 /* Set number of rows to the default. */ 2754 KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport 2755 } 2756 else if (KdbNumberOfColsTerminal <= 0) 2757 { 2758 /* Set number of cols to the default. */ 2759 KdbNumberOfColsTerminal = 75; //80; //Mna.: 75 for SCREEN debugport 2760 } 2761 } 2762 2763 /* Get the string */ 2764 va_start(ap, Format); 2765 Length = _vsnprintf(Buffer, sizeof (Buffer) - 1, Format, ap); 2766 Buffer[Length] = '\0'; 2767 va_end(ap); 2768 2769 p = Buffer; 2770 while (p[0] != '\0') 2771 { 2772 i = strcspn(p, "\n"); 2773 2774 /* Calculate the number of lines which will be printed in the terminal 2775 * when outputting the current line 2776 */ 2777 if (i > 0) 2778 RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal; 2779 else 2780 RowsPrintedByTerminal = 0; 2781 2782 if (p[i] == '\n') 2783 RowsPrintedByTerminal++; 2784 2785 /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/ 2786 2787 /* Display a prompt if we printed one screen full of text */ 2788 if (KdbNumberOfRowsTerminal > 0 && 2789 (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) 2790 { 2791 KdbRepeatLastCommand = FALSE; 2792 2793 if (KdbNumberOfColsPrinted > 0) 2794 DbgPrint("\n"); 2795 2796 DbgPrint("--- Press q to abort, any other key to continue ---"); 2797 RowsPrintedByTerminal++; /* added by Mna. */ 2798 2799 if (KdbDebugState & KD_DEBUG_KDSERIAL) 2800 c = KdbpGetCharSerial(); 2801 else 2802 c = KdbpGetCharKeyboard(&ScanCode); 2803 2804 if (c == '\r') 2805 { 2806 /* Try to read '\n' which might follow '\r' - if \n is not received here 2807 * it will be interpreted as "return" when the next command should be read. 2808 */ 2809 if (KdbDebugState & KD_DEBUG_KDSERIAL) 2810 c = KdbpTryGetCharSerial(5); 2811 else 2812 c = KdbpTryGetCharKeyboard(&ScanCode, 5); 2813 } 2814 2815 DbgPrint("\n"); 2816 if (c == 'q') 2817 { 2818 KdbOutputAborted = TRUE; 2819 return; 2820 } 2821 2822 KdbNumberOfRowsPrinted = 0; 2823 KdbNumberOfColsPrinted = 0; 2824 } 2825 2826 /* Insert a NUL after the line and print only the current line. */ 2827 if (p[i] == '\n' && p[i + 1] != '\0') 2828 { 2829 c = p[i + 1]; 2830 p[i + 1] = '\0'; 2831 } 2832 else 2833 { 2834 c = '\0'; 2835 } 2836 2837 /* Remove escape sequences from the line if there's no terminal connected */ 2838 if (!TerminalConnected) 2839 { 2840 while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */ 2841 { 2842 size_t len = strlen(p2); 2843 if (p2[1] == '[') 2844 { 2845 j = 2; 2846 while (!isalpha(p2[j++])); 2847 memmove(p2, p2 + j, len + 1 - j); 2848 } 2849 else 2850 { 2851 memmove(p2, p2 + 1, len); 2852 } 2853 } 2854 } 2855 2856 DbgPrint("%s", p); 2857 2858 if (c != '\0') 2859 p[i + 1] = c; 2860 2861 /* Set p to the start of the next line and 2862 * remember the number of rows/cols printed 2863 */ 2864 p += i; 2865 if (p[0] == '\n') 2866 { 2867 p++; 2868 KdbNumberOfColsPrinted = 0; 2869 } 2870 else 2871 { 2872 ASSERT(p[0] == '\0'); 2873 KdbNumberOfColsPrinted += i; 2874 } 2875 2876 KdbNumberOfRowsPrinted += RowsPrintedByTerminal; 2877 } 2878 } 2879 2880 /** memrchr(), explicitly defined, since was absent in MinGW of RosBE. */ 2881 /* 2882 * Reverse memchr() 2883 * Find the last occurrence of 'c' in the buffer 's' of size 'n'. 2884 */ 2885 void * 2886 memrchr(const void *s, int c, size_t n) 2887 { 2888 const unsigned char *cp; 2889 2890 if (n != 0) 2891 { 2892 cp = (unsigned char *)s + n; 2893 do 2894 { 2895 if (*(--cp) == (unsigned char)c) 2896 return (void *)cp; 2897 } while (--n != 0); 2898 } 2899 return NULL; 2900 } 2901 2902 /*!\brief Calculate pointer position for N lines upper of current position. 2903 * 2904 * \param Buffer Characters buffer to operate on. 2905 * \param BufLength Buffer size. 2906 * 2907 * \note Calculate pointer position for N lines upper of current displaying 2908 * position within the given buffer. 2909 * 2910 * Used by KdbpPager(). 2911 * Now N lines count is hardcoded to KdbNumberOfRowsTerminal. 2912 */ 2913 PCHAR 2914 CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos) 2915 { 2916 PCHAR p; 2917 // p0 is initial guess of Page Start 2918 ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal; 2919 PCHAR p0 = pCurPos - p0len; 2920 PCHAR prev_p = p0, p1; 2921 ULONG j; 2922 2923 if (pCurPos < Buffer) 2924 pCurPos = Buffer; 2925 ASSERT(pCurPos <= Buffer + BufLength); 2926 2927 p = memrchr(p0, '\n', p0len); 2928 if (NULL == p) 2929 p = p0; 2930 for (j = KdbNumberOfRowsTerminal; j--; ) 2931 { 2932 int linesCnt; 2933 p1 = memrchr(p0, '\n', p-p0); 2934 prev_p = p; 2935 p = p1; 2936 if (NULL == p) 2937 { 2938 p = prev_p; 2939 if (NULL == p) 2940 p = p0; 2941 break; 2942 } 2943 linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal; 2944 if (linesCnt > 1) 2945 j -= linesCnt-1; 2946 } 2947 2948 ASSERT(p != 0); 2949 ++p; 2950 return p; 2951 } 2952 2953 /*!\brief Prints the given string with, page by page. 2954 * 2955 * \param Buffer Characters buffer to print. 2956 * \param BufferLen Buffer size. 2957 * 2958 * \note Doesn't correctly handle \\t and terminal escape sequences when calculating the 2959 * number of lines required to print a single line from the Buffer in the terminal. 2960 * Maximum length of buffer is limited only by memory size. 2961 * 2962 * Note: BufLength should be greater then (KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal). 2963 * 2964 */ 2965 VOID 2966 KdbpPager( 2967 IN PCHAR Buffer, 2968 IN ULONG BufLength) 2969 { 2970 static CHAR InBuffer[4096]; 2971 static BOOLEAN TerminalInitialized = FALSE; 2972 static BOOLEAN TerminalConnected = FALSE; 2973 static BOOLEAN TerminalReportsSize = TRUE; 2974 CHAR c = '\0'; 2975 PCHAR p, p2; 2976 ULONG Length; 2977 ULONG i, j; 2978 LONG RowsPrintedByTerminal; 2979 ULONG ScanCode; 2980 2981 if( BufLength == 0) 2982 return; 2983 2984 /* Check if the user has aborted output of the current command */ 2985 if (KdbOutputAborted) 2986 return; 2987 2988 /* Initialize the terminal */ 2989 if (!TerminalInitialized) 2990 { 2991 DbgPrint("\x1b[7h"); /* Enable linewrap */ 2992 2993 /* Query terminal type */ 2994 /*DbgPrint("\x1b[Z");*/ 2995 DbgPrint("\x05"); 2996 2997 TerminalInitialized = TRUE; 2998 Length = 0; 2999 KeStallExecutionProcessor(100000); 3000 3001 for (;;) 3002 { 3003 c = KdbpTryGetCharSerial(5000); 3004 if (c == -1) 3005 break; 3006 3007 InBuffer[Length++] = c; 3008 if (Length >= (sizeof (InBuffer) - 1)) 3009 break; 3010 } 3011 3012 InBuffer[Length] = '\0'; 3013 if (Length > 0) 3014 TerminalConnected = TRUE; 3015 } 3016 3017 /* Get number of rows and columns in terminal */ 3018 if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) || 3019 (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */ 3020 { 3021 if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize) 3022 { 3023 /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ 3024 TerminalReportsSize = FALSE; 3025 KeStallExecutionProcessor(100000); 3026 DbgPrint("\x1b[18t"); 3027 c = KdbpTryGetCharSerial(5000); 3028 3029 if (c == KEY_ESC) 3030 { 3031 c = KdbpTryGetCharSerial(5000); 3032 if (c == '[') 3033 { 3034 Length = 0; 3035 3036 for (;;) 3037 { 3038 c = KdbpTryGetCharSerial(5000); 3039 if (c == -1) 3040 break; 3041 3042 InBuffer[Length++] = c; 3043 if (isalpha(c) || Length >= (sizeof (InBuffer) - 1)) 3044 break; 3045 } 3046 3047 InBuffer[Length] = '\0'; 3048 if (InBuffer[0] == '8' && InBuffer[1] == ';') 3049 { 3050 for (i = 2; (i < Length) && (InBuffer[i] != ';'); i++); 3051 3052 if (Buffer[i] == ';') 3053 { 3054 Buffer[i++] = '\0'; 3055 3056 /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */ 3057 KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0); 3058 KdbNumberOfColsTerminal = strtoul(InBuffer + i, NULL, 0); 3059 TerminalReportsSize = TRUE; 3060 } 3061 } 3062 } 3063 /* Clear further characters */ 3064 while ((c = KdbpTryGetCharSerial(5000)) != -1); 3065 } 3066 } 3067 3068 if (KdbNumberOfRowsTerminal <= 0) 3069 { 3070 /* Set number of rows to the default. */ 3071 KdbNumberOfRowsTerminal = 24; 3072 } 3073 else if (KdbNumberOfColsTerminal <= 0) 3074 { 3075 /* Set number of cols to the default. */ 3076 KdbNumberOfColsTerminal = 80; 3077 } 3078 } 3079 3080 /* Get the string */ 3081 p = Buffer; 3082 3083 while (p[0] != '\0') 3084 { 3085 if ( p > Buffer+BufLength) 3086 { 3087 DbgPrint("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer+BufLength)); 3088 return; 3089 } 3090 i = strcspn(p, "\n"); 3091 3092 // Are we out of buffer? 3093 if (p + i > Buffer + BufLength) 3094 // Leaving pager function: 3095 break; 3096 3097 /* Calculate the number of lines which will be printed in the terminal 3098 * when outputting the current line. 3099 */ 3100 if (i > 0) 3101 RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal; 3102 else 3103 RowsPrintedByTerminal = 0; 3104 3105 if (p[i] == '\n') 3106 RowsPrintedByTerminal++; 3107 3108 /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/ 3109 3110 /* Display a prompt if we printed one screen full of text */ 3111 if (KdbNumberOfRowsTerminal > 0 && 3112 (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) 3113 { 3114 KdbRepeatLastCommand = FALSE; 3115 3116 if (KdbNumberOfColsPrinted > 0) 3117 DbgPrint("\n"); 3118 3119 DbgPrint("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---"); 3120 RowsPrintedByTerminal++; 3121 3122 if (KdbDebugState & KD_DEBUG_KDSERIAL) 3123 c = KdbpGetCharSerial(); 3124 else 3125 c = KdbpGetCharKeyboard(&ScanCode); 3126 3127 if (c == '\r') 3128 { 3129 /* Try to read '\n' which might follow '\r' - if \n is not received here 3130 * it will be interpreted as "return" when the next command should be read. 3131 */ 3132 if (KdbDebugState & KD_DEBUG_KDSERIAL) 3133 c = KdbpTryGetCharSerial(5); 3134 else 3135 c = KdbpTryGetCharKeyboard(&ScanCode, 5); 3136 } 3137 3138 //DbgPrint("\n"); //Consize version: don't show pressed key 3139 DbgPrint(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key 3140 3141 if (c == 'q') 3142 { 3143 KdbOutputAborted = TRUE; 3144 return; 3145 } 3146 if ( ScanCode == KEYSC_END || c=='e') 3147 { 3148 PCHAR pBufEnd = Buffer + BufLength; 3149 p = CountOnePageUp(Buffer, BufLength, pBufEnd); 3150 i = strcspn(p, "\n"); 3151 } 3152 else if (ScanCode == KEYSC_PAGEUP || c=='u') 3153 { 3154 p = CountOnePageUp(Buffer, BufLength, p); 3155 i = strcspn(p, "\n"); 3156 } 3157 else if (ScanCode == KEYSC_HOME || c=='h') 3158 { 3159 p = Buffer; 3160 i = strcspn(p, "\n"); 3161 } 3162 else if (ScanCode == KEYSC_ARROWUP) 3163 { 3164 p = CountOnePageUp(Buffer, BufLength, p); 3165 i = strcspn(p, "\n"); 3166 } 3167 3168 KdbNumberOfRowsPrinted = 0; 3169 KdbNumberOfColsPrinted = 0; 3170 } 3171 3172 /* Insert a NUL after the line and print only the current line. */ 3173 if (p[i] == '\n' && p[i + 1] != '\0') 3174 { 3175 c = p[i + 1]; 3176 p[i + 1] = '\0'; 3177 } 3178 else 3179 { 3180 c = '\0'; 3181 } 3182 3183 /* Remove escape sequences from the line if there's no terminal connected */ 3184 if (!TerminalConnected) 3185 { 3186 while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */ 3187 { 3188 size_t len = strlen(p2); 3189 if (p2[1] == '[') 3190 { 3191 j = 2; 3192 while (!isalpha(p2[j++])); 3193 memmove(p2, p2 + j, len + 1 - j); 3194 } 3195 else 3196 { 3197 memmove(p2, p2 + 1, len); 3198 } 3199 } 3200 } 3201 3202 // The main printing of the current line: 3203 DbgPrint(p); 3204 3205 // restore not null char with saved: 3206 if (c != '\0') 3207 p[i + 1] = c; 3208 3209 /* Set p to the start of the next line and 3210 * remember the number of rows/cols printed 3211 */ 3212 p += i; 3213 if (p[0] == '\n') 3214 { 3215 p++; 3216 KdbNumberOfColsPrinted = 0; 3217 } 3218 else 3219 { 3220 ASSERT(p[0] == '\0'); 3221 KdbNumberOfColsPrinted += i; 3222 } 3223 3224 KdbNumberOfRowsPrinted += RowsPrintedByTerminal; 3225 } 3226 } 3227 3228 /*!\brief Appends a command to the command history 3229 * 3230 * \param Command Pointer to the command to append to the history. 3231 */ 3232 static VOID 3233 KdbpCommandHistoryAppend( 3234 IN PCHAR Command) 3235 { 3236 ULONG Length1 = strlen(Command) + 1; 3237 ULONG Length2 = 0; 3238 INT i; 3239 PCHAR Buffer; 3240 3241 ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer)); 3242 3243 if (Length1 <= 1 || 3244 (KdbCommandHistory[KdbCommandHistoryIndex] && 3245 strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0)) 3246 { 3247 return; 3248 } 3249 3250 /* Calculate Length1 and Length2 */ 3251 Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex; 3252 KdbCommandHistoryBufferIndex += Length1; 3253 if (KdbCommandHistoryBufferIndex >= (LONG)RTL_NUMBER_OF(KdbCommandHistoryBuffer)) 3254 { 3255 KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer); 3256 Length2 = KdbCommandHistoryBufferIndex; 3257 Length1 -= Length2; 3258 } 3259 3260 /* Remove previous commands until there is enough space to append the new command */ 3261 for (i = KdbCommandHistoryIndex; KdbCommandHistory[i];) 3262 { 3263 if ((Length2 > 0 && 3264 (KdbCommandHistory[i] >= Buffer || 3265 KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) || 3266 (Length2 <= 0 && 3267 (KdbCommandHistory[i] >= Buffer && 3268 KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex)))) 3269 { 3270 KdbCommandHistory[i] = NULL; 3271 } 3272 3273 i--; 3274 if (i < 0) 3275 i = RTL_NUMBER_OF(KdbCommandHistory) - 1; 3276 3277 if (i == KdbCommandHistoryIndex) 3278 break; 3279 } 3280 3281 /* Make sure the new command history entry is free */ 3282 KdbCommandHistoryIndex++; 3283 KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory); 3284 if (KdbCommandHistory[KdbCommandHistoryIndex]) 3285 { 3286 KdbCommandHistory[KdbCommandHistoryIndex] = NULL; 3287 } 3288 3289 /* Append command */ 3290 KdbCommandHistory[KdbCommandHistoryIndex] = Buffer; 3291 ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer)); 3292 memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1); 3293 if (Length2 > 0) 3294 { 3295 memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2); 3296 } 3297 } 3298 3299 /*!\brief Reads a line of user-input. 3300 * 3301 * \param Buffer Buffer to store the input into. Trailing newlines are removed. 3302 * \param Size Size of \a Buffer. 3303 * 3304 * \note Accepts only \n newlines, \r is ignored. 3305 */ 3306 static VOID 3307 KdbpReadCommand( 3308 OUT PCHAR Buffer, 3309 IN ULONG Size) 3310 { 3311 CHAR Key; 3312 PCHAR Orig = Buffer; 3313 ULONG ScanCode = 0; 3314 BOOLEAN EchoOn; 3315 static CHAR LastCommand[1024]; 3316 static CHAR NextKey = '\0'; 3317 INT CmdHistIndex = -1; 3318 INT i; 3319 3320 EchoOn = !((KdbDebugState & KD_DEBUG_KDNOECHO) != 0); 3321 3322 for (;;) 3323 { 3324 if (KdbDebugState & KD_DEBUG_KDSERIAL) 3325 { 3326 Key = (NextKey == '\0') ? KdbpGetCharSerial() : NextKey; 3327 NextKey = '\0'; 3328 ScanCode = 0; 3329 if (Key == KEY_ESC) /* ESC */ 3330 { 3331 Key = KdbpGetCharSerial(); 3332 if (Key == '[') 3333 { 3334 Key = KdbpGetCharSerial(); 3335 3336 switch (Key) 3337 { 3338 case 'A': 3339 ScanCode = KEY_SCAN_UP; 3340 break; 3341 case 'B': 3342 ScanCode = KEY_SCAN_DOWN; 3343 break; 3344 case 'C': 3345 break; 3346 case 'D': 3347 break; 3348 } 3349 } 3350 } 3351 } 3352 else 3353 { 3354 ScanCode = 0; 3355 Key = (NextKey == '\0') ? KdbpGetCharKeyboard(&ScanCode) : NextKey; 3356 NextKey = '\0'; 3357 } 3358 3359 if ((ULONG)(Buffer - Orig) >= (Size - 1)) 3360 { 3361 /* Buffer is full, accept only newlines */ 3362 if (Key != '\n') 3363 continue; 3364 } 3365 3366 if (Key == '\r') 3367 { 3368 /* Read the next char - this is to throw away a \n which most clients should 3369 * send after \r. 3370 */ 3371 KeStallExecutionProcessor(100000); 3372 3373 if (KdbDebugState & KD_DEBUG_KDSERIAL) 3374 NextKey = KdbpTryGetCharSerial(5); 3375 else 3376 NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5); 3377 3378 if (NextKey == '\n' || NextKey == -1) /* \n or no response at all */ 3379 NextKey = '\0'; 3380 3381 KdbpPrint("\n"); 3382 3383 /* 3384 * Repeat the last command if the user presses enter. Reduces the 3385 * risk of RSI when single-stepping. 3386 */ 3387 if (Buffer != Orig) 3388 { 3389 KdbRepeatLastCommand = TRUE; 3390 *Buffer = '\0'; 3391 RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Orig); 3392 } 3393 else if (KdbRepeatLastCommand) 3394 RtlStringCbCopyA(Buffer, Size, LastCommand); 3395 else 3396 *Buffer = '\0'; 3397 3398 return; 3399 } 3400 else if (Key == KEY_BS || Key == KEY_DEL) 3401 { 3402 if (Buffer > Orig) 3403 { 3404 Buffer--; 3405 *Buffer = 0; 3406 3407 if (EchoOn) 3408 KdbpPrint("%c %c", KEY_BS, KEY_BS); 3409 else 3410 KdbpPrint(" %c", KEY_BS); 3411 } 3412 } 3413 else if (ScanCode == KEY_SCAN_UP) 3414 { 3415 BOOLEAN Print = TRUE; 3416 3417 if (CmdHistIndex < 0) 3418 { 3419 CmdHistIndex = KdbCommandHistoryIndex; 3420 } 3421 else 3422 { 3423 i = CmdHistIndex - 1; 3424 3425 if (i < 0) 3426 CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1; 3427 3428 if (KdbCommandHistory[i] && i != KdbCommandHistoryIndex) 3429 CmdHistIndex = i; 3430 else 3431 Print = FALSE; 3432 } 3433 3434 if (Print && KdbCommandHistory[CmdHistIndex]) 3435 { 3436 while (Buffer > Orig) 3437 { 3438 Buffer--; 3439 *Buffer = 0; 3440 3441 if (EchoOn) 3442 KdbpPrint("%c %c", KEY_BS, KEY_BS); 3443 else 3444 KdbpPrint(" %c", KEY_BS); 3445 } 3446 3447 i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); 3448 memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); 3449 Orig[i] = '\0'; 3450 Buffer = Orig + i; 3451 KdbpPrint("%s", Orig); 3452 } 3453 } 3454 else if (ScanCode == KEY_SCAN_DOWN) 3455 { 3456 if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex) 3457 { 3458 i = CmdHistIndex + 1; 3459 if (i >= (INT)RTL_NUMBER_OF(KdbCommandHistory)) 3460 i = 0; 3461 3462 if (KdbCommandHistory[i]) 3463 { 3464 CmdHistIndex = i; 3465 while (Buffer > Orig) 3466 { 3467 Buffer--; 3468 *Buffer = 0; 3469 3470 if (EchoOn) 3471 KdbpPrint("%c %c", KEY_BS, KEY_BS); 3472 else 3473 KdbpPrint(" %c", KEY_BS); 3474 } 3475 3476 i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); 3477 memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); 3478 Orig[i] = '\0'; 3479 Buffer = Orig + i; 3480 KdbpPrint("%s", Orig); 3481 } 3482 } 3483 } 3484 else 3485 { 3486 if (EchoOn) 3487 KdbpPrint("%c", Key); 3488 3489 *Buffer = Key; 3490 Buffer++; 3491 } 3492 } 3493 } 3494 3495 3496 BOOLEAN 3497 NTAPI 3498 KdbRegisterCliCallback( 3499 PVOID Callback, 3500 BOOLEAN Deregister) 3501 { 3502 ULONG i; 3503 3504 /* Loop all entries */ 3505 for (i = 0; i < _countof(KdbCliCallbacks); i++) 3506 { 3507 /* Check if deregistering was requested */ 3508 if (Deregister) 3509 { 3510 /* Check if this entry is the one that was registered */ 3511 if (KdbCliCallbacks[i] == Callback) 3512 { 3513 /* Delete it and report success */ 3514 KdbCliCallbacks[i] = NULL; 3515 return TRUE; 3516 } 3517 } 3518 else 3519 { 3520 /* Check if this entry is free */ 3521 if (KdbCliCallbacks[i] == NULL) 3522 { 3523 /* Set it and and report success */ 3524 KdbCliCallbacks[i] = Callback; 3525 return TRUE; 3526 } 3527 } 3528 } 3529 3530 /* Unsuccessful */ 3531 return FALSE; 3532 } 3533 3534 /*! \brief Invokes registered CLI callbacks until one of them handled the 3535 * Command. 3536 * 3537 * \param Command - Command line to parse and execute if possible. 3538 * \param Argc - Number of arguments in Argv 3539 * \param Argv - Array of strings, each of them containing one argument. 3540 * 3541 * \return TRUE, if the command was handled, FALSE if it was not handled. 3542 */ 3543 static 3544 BOOLEAN 3545 KdbpInvokeCliCallbacks( 3546 IN PCHAR Command, 3547 IN ULONG Argc, 3548 IN PCHAR Argv[]) 3549 { 3550 ULONG i; 3551 3552 /* Loop all entries */ 3553 for (i = 0; i < _countof(KdbCliCallbacks); i++) 3554 { 3555 /* Check if this entry is registered */ 3556 if (KdbCliCallbacks[i]) 3557 { 3558 /* Invoke the callback and check if it handled the command */ 3559 if (KdbCliCallbacks[i](Command, Argc, Argv)) 3560 { 3561 return TRUE; 3562 } 3563 } 3564 } 3565 3566 /* None of the callbacks handled the command */ 3567 return FALSE; 3568 } 3569 3570 3571 /*!\brief Parses command line and executes command if found 3572 * 3573 * \param Command Command line to parse and execute if possible. 3574 * 3575 * \retval TRUE Don't continue execution. 3576 * \retval FALSE Continue execution (leave KDB) 3577 */ 3578 static BOOLEAN 3579 KdbpDoCommand( 3580 IN PCHAR Command) 3581 { 3582 ULONG i; 3583 PCHAR p; 3584 ULONG Argc; 3585 // FIXME: for what do we need a 1024 characters command line and 256 tokens? 3586 static PCHAR Argv[256]; 3587 static CHAR OrigCommand[1024]; 3588 3589 RtlStringCbCopyA(OrigCommand, sizeof(OrigCommand), Command); 3590 3591 Argc = 0; 3592 p = Command; 3593 3594 for (;;) 3595 { 3596 while (*p == '\t' || *p == ' ') 3597 p++; 3598 3599 if (*p == '\0') 3600 break; 3601 3602 i = strcspn(p, "\t "); 3603 Argv[Argc++] = p; 3604 p += i; 3605 if (*p == '\0') 3606 break; 3607 3608 *p = '\0'; 3609 p++; 3610 } 3611 3612 if (Argc < 1) 3613 return TRUE; 3614 3615 for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) 3616 { 3617 if (!KdbDebuggerCommands[i].Name) 3618 continue; 3619 3620 if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0) 3621 { 3622 return KdbDebuggerCommands[i].Fn(Argc, Argv); 3623 } 3624 } 3625 3626 /* Now invoke the registered callbacks */ 3627 if (KdbpInvokeCliCallbacks(Command, Argc, Argv)) 3628 { 3629 return TRUE; 3630 } 3631 3632 KdbpPrint("Command '%s' is unknown.\n", OrigCommand); 3633 return TRUE; 3634 } 3635 3636 /*!\brief KDB Main Loop. 3637 * 3638 * \param EnteredOnSingleStep TRUE if KDB was entered on single step. 3639 */ 3640 VOID 3641 KdbpCliMainLoop( 3642 IN BOOLEAN EnteredOnSingleStep) 3643 { 3644 static CHAR Command[1024]; 3645 BOOLEAN Continue; 3646 3647 if (EnteredOnSingleStep) 3648 { 3649 if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip, &KdbCurrentTrapFrame->Tf)) 3650 { 3651 KdbpPrint("<%08x>", KdbCurrentTrapFrame->Tf.Eip); 3652 } 3653 3654 KdbpPrint(": "); 3655 if (KdbpDisassemble(KdbCurrentTrapFrame->Tf.Eip, KdbUseIntelSyntax) < 0) 3656 { 3657 KdbpPrint("<INVALID>"); 3658 } 3659 KdbpPrint("\n"); 3660 } 3661 3662 /* Flush the input buffer */ 3663 if (KdbDebugState & KD_DEBUG_KDSERIAL) 3664 { 3665 while (KdbpTryGetCharSerial(1) != -1); 3666 } 3667 else 3668 { 3669 ULONG ScanCode; 3670 while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1); 3671 } 3672 3673 /* Main loop */ 3674 do 3675 { 3676 /* Reset the number of rows/cols printed */ 3677 KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; 3678 3679 /* Print the prompt */ 3680 KdbpPrint(KdbPromptString.Buffer); 3681 3682 /* Read a command and remember it */ 3683 KdbpReadCommand(Command, sizeof (Command)); 3684 KdbpCommandHistoryAppend(Command); 3685 3686 /* Reset the number of rows/cols printed and output aborted state */ 3687 KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; 3688 KdbOutputAborted = FALSE; 3689 3690 /* Call the command */ 3691 Continue = KdbpDoCommand(Command); 3692 KdbOutputAborted = FALSE; 3693 } 3694 while (Continue); 3695 } 3696 3697 /*!\brief Called when a module is loaded. 3698 * 3699 * \param Name Filename of the module which was loaded. 3700 */ 3701 VOID 3702 KdbpCliModuleLoaded( 3703 IN PUNICODE_STRING Name) 3704 { 3705 if (!KdbBreakOnModuleLoad) 3706 return; 3707 3708 KdbpPrint("Module %wZ loaded.\n", Name); 3709 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 3710 } 3711 3712 /*!\brief This function is called by KdbEnterDebuggerException... 3713 * 3714 * Used to interpret the init file in a context with a trapframe setup 3715 * (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will 3716 * call this function if KdbInitFileBuffer is not NULL. 3717 */ 3718 VOID 3719 KdbpCliInterpretInitFile(VOID) 3720 { 3721 PCHAR p1, p2; 3722 INT i; 3723 CHAR c; 3724 3725 /* Execute the commands in the init file */ 3726 DPRINT("KDB: Executing KDBinit file...\n"); 3727 p1 = KdbInitFileBuffer; 3728 while (p1[0] != '\0') 3729 { 3730 i = strcspn(p1, "\r\n"); 3731 if (i > 0) 3732 { 3733 c = p1[i]; 3734 p1[i] = '\0'; 3735 3736 /* Look for "break" command and comments */ 3737 p2 = p1; 3738 3739 while (isspace(p2[0])) 3740 p2++; 3741 3742 if (strncmp(p2, "break", sizeof("break")-1) == 0 && 3743 (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1]))) 3744 { 3745 /* break into the debugger */ 3746 KdbpCliMainLoop(FALSE); 3747 } 3748 else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */ 3749 { 3750 KdbpDoCommand(p1); 3751 } 3752 3753 p1[i] = c; 3754 } 3755 3756 p1 += i; 3757 while (p1[0] == '\r' || p1[0] == '\n') 3758 p1++; 3759 } 3760 DPRINT("KDB: KDBinit executed\n"); 3761 } 3762 3763 /*!\brief Called when KDB is initialized 3764 * 3765 * Reads the KDBinit file from the SystemRoot\System32\drivers\etc directory and executes it. 3766 */ 3767 VOID 3768 KdbpCliInit(VOID) 3769 { 3770 NTSTATUS Status; 3771 OBJECT_ATTRIBUTES ObjectAttributes; 3772 UNICODE_STRING FileName; 3773 IO_STATUS_BLOCK Iosb; 3774 FILE_STANDARD_INFORMATION FileStdInfo; 3775 HANDLE hFile = NULL; 3776 INT FileSize; 3777 PCHAR FileBuffer; 3778 ULONG OldEflags; 3779 3780 /* Initialize the object attributes */ 3781 RtlInitUnicodeString(&FileName, L"\\SystemRoot\\System32\\drivers\\etc\\KDBinit"); 3782 InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL); 3783 3784 /* Open the file */ 3785 Status = ZwOpenFile(&hFile, FILE_READ_DATA | SYNCHRONIZE, 3786 &ObjectAttributes, &Iosb, 0, 3787 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 3788 FILE_NO_INTERMEDIATE_BUFFERING); 3789 if (!NT_SUCCESS(Status)) 3790 { 3791 DPRINT("Could not open \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); 3792 return; 3793 } 3794 3795 /* Get the size of the file */ 3796 Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof (FileStdInfo), 3797 FileStandardInformation); 3798 if (!NT_SUCCESS(Status)) 3799 { 3800 ZwClose(hFile); 3801 DPRINT("Could not query size of \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); 3802 return; 3803 } 3804 FileSize = FileStdInfo.EndOfFile.u.LowPart; 3805 3806 /* Allocate memory for the file */ 3807 FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */ 3808 if (!FileBuffer) 3809 { 3810 ZwClose(hFile); 3811 DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize); 3812 return; 3813 } 3814 3815 /* Load file into memory */ 3816 Status = ZwReadFile(hFile, NULL, NULL, NULL, &Iosb, FileBuffer, FileSize, NULL, NULL); 3817 ZwClose(hFile); 3818 3819 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) 3820 { 3821 ExFreePool(FileBuffer); 3822 DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status); 3823 return; 3824 } 3825 3826 FileSize = min(FileSize, (INT)Iosb.Information); 3827 FileBuffer[FileSize] = '\0'; 3828 3829 /* Enter critical section */ 3830 OldEflags = __readeflags(); 3831 _disable(); 3832 3833 /* Interpret the init file... */ 3834 KdbInitFileBuffer = FileBuffer; 3835 KdbEnter(); 3836 KdbInitFileBuffer = NULL; 3837 3838 /* Leave critical section */ 3839 __writeeflags(OldEflags); 3840 3841 ExFreePool(FileBuffer); 3842 } 3843