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