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