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