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