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