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