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