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