Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkdb_cli.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS kernel 00003 * Copyright (C) 2005 ReactOS Team 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 /* 00020 * PROJECT: ReactOS kernel 00021 * FILE: ntoskrnl/dbg/kdb_cli.c 00022 * PURPOSE: Kernel debugger command line interface 00023 * PROGRAMMER: Gregor Anich (blight@blight.eu.org) 00024 * Hervé Poussineau 00025 * UPDATE HISTORY: 00026 * Created 16/01/2005 00027 */ 00028 00029 /* INCLUDES ******************************************************************/ 00030 00031 #include <ntoskrnl.h> 00032 00033 #define NDEBUG 00034 #include <debug.h> 00035 00036 /* DEFINES *******************************************************************/ 00037 00038 #define KEY_BS 8 00039 #define KEY_ESC 27 00040 #define KEY_DEL 127 00041 00042 #define KEY_SCAN_UP 72 00043 #define KEY_SCAN_DOWN 80 00044 00045 /* Scan codes of keyboard keys: */ 00046 #define KEYSC_END 0x004f 00047 #define KEYSC_PAGEUP 0x0049 00048 #define KEYSC_PAGEDOWN 0x0051 00049 #define KEYSC_HOME 0x0047 00050 #define KEYSC_ARROWUP 0x0048 00051 00052 #define KDB_ENTER_CONDITION_TO_STRING(cond) \ 00053 ((cond) == KdbDoNotEnter ? "never" : \ 00054 ((cond) == KdbEnterAlways ? "always" : \ 00055 ((cond) == KdbEnterFromKmode ? "kmode" : "umode"))) 00056 00057 #define KDB_ACCESS_TYPE_TO_STRING(type) \ 00058 ((type) == KdbAccessRead ? "read" : \ 00059 ((type) == KdbAccessWrite ? "write" : \ 00060 ((type) == KdbAccessReadWrite ? "rdwr" : "exec"))) 00061 00062 #define NPX_STATE_TO_STRING(state) \ 00063 ((state) == NPX_STATE_LOADED ? "Loaded" : \ 00064 ((state) == NPX_STATE_NOT_LOADED ? "Not loaded" : "Unknown")) 00065 00066 /* PROTOTYPES ****************************************************************/ 00067 00068 static BOOLEAN KdbpCmdEvalExpression(ULONG Argc, PCHAR Argv[]); 00069 static BOOLEAN KdbpCmdDisassembleX(ULONG Argc, PCHAR Argv[]); 00070 static BOOLEAN KdbpCmdRegs(ULONG Argc, PCHAR Argv[]); 00071 static BOOLEAN KdbpCmdBackTrace(ULONG Argc, PCHAR Argv[]); 00072 00073 static BOOLEAN KdbpCmdContinue(ULONG Argc, PCHAR Argv[]); 00074 static BOOLEAN KdbpCmdStep(ULONG Argc, PCHAR Argv[]); 00075 static BOOLEAN KdbpCmdBreakPointList(ULONG Argc, PCHAR Argv[]); 00076 static BOOLEAN KdbpCmdEnableDisableClearBreakPoint(ULONG Argc, PCHAR Argv[]); 00077 static BOOLEAN KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]); 00078 00079 static BOOLEAN KdbpCmdThread(ULONG Argc, PCHAR Argv[]); 00080 static BOOLEAN KdbpCmdProc(ULONG Argc, PCHAR Argv[]); 00081 00082 static BOOLEAN KdbpCmdMod(ULONG Argc, PCHAR Argv[]); 00083 static BOOLEAN KdbpCmdGdtLdtIdt(ULONG Argc, PCHAR Argv[]); 00084 static BOOLEAN KdbpCmdPcr(ULONG Argc, PCHAR Argv[]); 00085 static BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]); 00086 00087 static BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]); 00088 static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]); 00089 static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]); 00090 static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]); 00091 static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]); 00092 00093 #ifdef __ROS_DWARF__ 00094 static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]); 00095 #endif 00096 00097 /* GLOBALS *******************************************************************/ 00098 00099 static BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */ 00100 static BOOLEAN KdbBreakOnModuleLoad = FALSE; /* Set to TRUE to break into KDB when a module is loaded */ 00101 00102 static CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */ 00103 static PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */ 00104 static LONG KdbCommandHistoryBufferIndex = 0; 00105 static LONG KdbCommandHistoryIndex = 0; 00106 00107 static ULONG KdbNumberOfRowsPrinted = 0; 00108 static ULONG KdbNumberOfColsPrinted = 0; 00109 static BOOLEAN KdbOutputAborted = FALSE; 00110 static BOOLEAN KdbRepeatLastCommand = FALSE; 00111 static LONG KdbNumberOfRowsTerminal = -1; 00112 static LONG KdbNumberOfColsTerminal = -1; 00113 00114 PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */ 00115 BOOLEAN KdbpBugCheckRequested = FALSE; 00116 00117 /* Vars for dmesg */ 00118 /* defined in ../kd/kdio.c, declare here: */ 00119 extern volatile BOOLEAN KdbpIsInDmesgMode; 00120 extern const ULONG KdpDmesgBufferSize; 00121 extern PCHAR KdpDmesgBuffer; 00122 extern volatile ULONG KdpDmesgCurrentPosition; 00123 extern volatile ULONG KdpDmesgFreeBytes; 00124 extern volatile ULONG KdbDmesgTotalWritten; 00125 00126 static const struct 00127 { 00128 PCHAR Name; 00129 PCHAR Syntax; 00130 PCHAR Help; 00131 BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]); 00132 } KdbDebuggerCommands[] = { 00133 /* Data */ 00134 { NULL, NULL, "Data", NULL }, 00135 { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression }, 00136 { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX }, 00137 { "x", "x [address] [L count]", "Display count dwords, starting at addr.", KdbpCmdDisassembleX }, 00138 { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs }, 00139 { "cregs", "cregs", "Display control registers.", KdbpCmdRegs }, 00140 { "sregs", "sregs", "Display status registers.", KdbpCmdRegs }, 00141 { "dregs", "dregs", "Display debug registers.", KdbpCmdRegs }, 00142 { "bt", "bt [*frameaddr|thread id]", "Prints current backtrace or from given frame addr", KdbpCmdBackTrace }, 00143 #ifdef __ROS_DWARF__ 00144 { "dt", "dt [mod] [type] [addr]", "Print a struct. Addr is optional.", KdbpCmdPrintStruct }, 00145 #endif 00146 00147 /* Flow control */ 00148 { NULL, NULL, "Flow control", NULL }, 00149 { "cont", "cont", "Continue execution (leave debugger)", KdbpCmdContinue }, 00150 { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep }, 00151 { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep }, 00152 { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList }, 00153 { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 00154 { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 00155 { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint }, 00156 { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint }, 00157 { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint }, 00158 00159 /* Process/Thread */ 00160 { NULL, NULL, "Process/Thread", NULL }, 00161 { "thread", "thread [list[ pid]|[attach ]tid]", "List threads in current or specified process, display thread with given id or attach to thread.", KdbpCmdThread }, 00162 { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc }, 00163 00164 /* System information */ 00165 { NULL, NULL, "System info", NULL }, 00166 { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod }, 00167 { "gdt", "gdt", "Display global descriptor table.", KdbpCmdGdtLdtIdt }, 00168 { "ldt", "ldt", "Display local descriptor table.", KdbpCmdGdtLdtIdt }, 00169 { "idt", "idt", "Display interrupt descriptor table.", KdbpCmdGdtLdtIdt }, 00170 { "pcr", "pcr", "Display processor control region.", KdbpCmdPcr }, 00171 { "tss", "tss", "Display task state segment.", KdbpCmdTss }, 00172 00173 /* Others */ 00174 { NULL, NULL, "Others", NULL }, 00175 { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck }, 00176 { "filter", "filter [error|warning|trace|info|level]+|-[componentname|default]", "Enable/disable debug channels", KdbpCmdFilter }, 00177 { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet }, 00178 { "dmesg", "dmesg", "Display debug messages on screen, with navigation on pages.", KdbpCmdDmesg }, 00179 { "kmsg", "kmsg", "Kernel dmesg. Alias for dmesg.", KdbpCmdDmesg }, 00180 { "help", "help", "Display help screen.", KdbpCmdHelp } 00181 }; 00182 00183 /* FUNCTIONS *****************************************************************/ 00184 00193 static BOOLEAN 00194 KdbpGetComponentId( 00195 IN PCCH ComponentName, 00196 OUT PULONG ComponentId) 00197 { 00198 ULONG i; 00199 00200 static struct 00201 { 00202 PCCH Name; 00203 ULONG Id; 00204 } 00205 ComponentTable[] = 00206 { 00207 { "DEFAULT", DPFLTR_DEFAULT_ID }, 00208 { "SYSTEM", DPFLTR_SYSTEM_ID }, 00209 { "SMSS", DPFLTR_SMSS_ID }, 00210 { "SETUP", DPFLTR_SETUP_ID }, 00211 { "NTFS", DPFLTR_NTFS_ID }, 00212 { "FSTUB", DPFLTR_FSTUB_ID }, 00213 { "CRASHDUMP", DPFLTR_CRASHDUMP_ID }, 00214 { "CDAUDIO", DPFLTR_CDAUDIO_ID }, 00215 { "CDROM", DPFLTR_CDROM_ID }, 00216 { "CLASSPNP", DPFLTR_CLASSPNP_ID }, 00217 { "DISK", DPFLTR_DISK_ID }, 00218 { "REDBOOK", DPFLTR_REDBOOK_ID }, 00219 { "STORPROP", DPFLTR_STORPROP_ID }, 00220 { "SCSIPORT", DPFLTR_SCSIPORT_ID }, 00221 { "SCSIMINIPORT", DPFLTR_SCSIMINIPORT_ID }, 00222 { "CONFIG", DPFLTR_CONFIG_ID }, 00223 { "I8042PRT", DPFLTR_I8042PRT_ID }, 00224 { "SERMOUSE", DPFLTR_SERMOUSE_ID }, 00225 { "LSERMOUS", DPFLTR_LSERMOUS_ID }, 00226 { "KBDHID", DPFLTR_KBDHID_ID }, 00227 { "MOUHID", DPFLTR_MOUHID_ID }, 00228 { "KBDCLASS", DPFLTR_KBDCLASS_ID }, 00229 { "MOUCLASS", DPFLTR_MOUCLASS_ID }, 00230 { "TWOTRACK", DPFLTR_TWOTRACK_ID }, 00231 { "WMILIB", DPFLTR_WMILIB_ID }, 00232 { "ACPI", DPFLTR_ACPI_ID }, 00233 { "AMLI", DPFLTR_AMLI_ID }, 00234 { "HALIA64", DPFLTR_HALIA64_ID }, 00235 { "VIDEO", DPFLTR_VIDEO_ID }, 00236 { "SVCHOST", DPFLTR_SVCHOST_ID }, 00237 { "VIDEOPRT", DPFLTR_VIDEOPRT_ID }, 00238 { "TCPIP", DPFLTR_TCPIP_ID }, 00239 { "DMSYNTH", DPFLTR_DMSYNTH_ID }, 00240 { "NTOSPNP", DPFLTR_NTOSPNP_ID }, 00241 { "FASTFAT", DPFLTR_FASTFAT_ID }, 00242 { "SAMSS", DPFLTR_SAMSS_ID }, 00243 { "PNPMGR", DPFLTR_PNPMGR_ID }, 00244 { "NETAPI", DPFLTR_NETAPI_ID }, 00245 { "SCSERVER", DPFLTR_SCSERVER_ID }, 00246 { "SCCLIENT", DPFLTR_SCCLIENT_ID }, 00247 { "SERIAL", DPFLTR_SERIAL_ID }, 00248 { "SERENUM", DPFLTR_SERENUM_ID }, 00249 { "UHCD", DPFLTR_UHCD_ID }, 00250 { "RPCPROXY", DPFLTR_RPCPROXY_ID }, 00251 { "AUTOCHK", DPFLTR_AUTOCHK_ID }, 00252 { "DCOMSS", DPFLTR_DCOMSS_ID }, 00253 { "UNIMODEM", DPFLTR_UNIMODEM_ID }, 00254 { "SIS", DPFLTR_SIS_ID }, 00255 { "FLTMGR", DPFLTR_FLTMGR_ID }, 00256 { "WMICORE", DPFLTR_WMICORE_ID }, 00257 { "BURNENG", DPFLTR_BURNENG_ID }, 00258 { "IMAPI", DPFLTR_IMAPI_ID }, 00259 { "SXS", DPFLTR_SXS_ID }, 00260 { "FUSION", DPFLTR_FUSION_ID }, 00261 { "IDLETASK", DPFLTR_IDLETASK_ID }, 00262 { "SOFTPCI", DPFLTR_SOFTPCI_ID }, 00263 { "TAPE", DPFLTR_TAPE_ID }, 00264 { "MCHGR", DPFLTR_MCHGR_ID }, 00265 { "IDEP", DPFLTR_IDEP_ID }, 00266 { "PCIIDE", DPFLTR_PCIIDE_ID }, 00267 { "FLOPPY", DPFLTR_FLOPPY_ID }, 00268 { "FDC", DPFLTR_FDC_ID }, 00269 { "TERMSRV", DPFLTR_TERMSRV_ID }, 00270 { "W32TIME", DPFLTR_W32TIME_ID }, 00271 { "PREFETCHER", DPFLTR_PREFETCHER_ID }, 00272 { "RSFILTER", DPFLTR_RSFILTER_ID }, 00273 { "FCPORT", DPFLTR_FCPORT_ID }, 00274 { "PCI", DPFLTR_PCI_ID }, 00275 { "DMIO", DPFLTR_DMIO_ID }, 00276 { "DMCONFIG", DPFLTR_DMCONFIG_ID }, 00277 { "DMADMIN", DPFLTR_DMADMIN_ID }, 00278 { "WSOCKTRANSPORT", DPFLTR_WSOCKTRANSPORT_ID }, 00279 { "VSS", DPFLTR_VSS_ID }, 00280 { "PNPMEM", DPFLTR_PNPMEM_ID }, 00281 { "PROCESSOR", DPFLTR_PROCESSOR_ID }, 00282 { "DMSERVER", DPFLTR_DMSERVER_ID }, 00283 { "SR", DPFLTR_SR_ID }, 00284 { "INFINIBAND", DPFLTR_INFINIBAND_ID }, 00285 { "IHVDRIVER", DPFLTR_IHVDRIVER_ID }, 00286 { "IHVVIDEO", DPFLTR_IHVVIDEO_ID }, 00287 { "IHVAUDIO", DPFLTR_IHVAUDIO_ID }, 00288 { "IHVNETWORK", DPFLTR_IHVNETWORK_ID }, 00289 { "IHVSTREAMING", DPFLTR_IHVSTREAMING_ID }, 00290 { "IHVBUS", DPFLTR_IHVBUS_ID }, 00291 { "HPS", DPFLTR_HPS_ID }, 00292 { "RTLTHREADPOOL", DPFLTR_RTLTHREADPOOL_ID }, 00293 { "LDR", DPFLTR_LDR_ID }, 00294 { "TCPIP6", DPFLTR_TCPIP6_ID }, 00295 { "ISAPNP", DPFLTR_ISAPNP_ID }, 00296 { "SHPC", DPFLTR_SHPC_ID }, 00297 { "STORPORT", DPFLTR_STORPORT_ID }, 00298 { "STORMINIPORT", DPFLTR_STORMINIPORT_ID }, 00299 { "PRINTSPOOLER", DPFLTR_PRINTSPOOLER_ID }, 00300 { "VSSDYNDISK", DPFLTR_VSSDYNDISK_ID }, 00301 { "VERIFIER", DPFLTR_VERIFIER_ID }, 00302 { "VDS", DPFLTR_VDS_ID }, 00303 { "VDSBAS", DPFLTR_VDSBAS_ID }, 00304 { "VDSDYN", DPFLTR_VDSDYN_ID }, 00305 { "VDSDYNDR", DPFLTR_VDSDYNDR_ID }, 00306 { "VDSLDR", DPFLTR_VDSLDR_ID }, 00307 { "VDSUTIL", DPFLTR_VDSUTIL_ID }, 00308 { "DFRGIFC", DPFLTR_DFRGIFC_ID }, 00309 { "MM", DPFLTR_MM_ID }, 00310 { "DFSC", DPFLTR_DFSC_ID }, 00311 { "WOW64", DPFLTR_WOW64_ID }, 00312 { "ALPC", DPFLTR_ALPC_ID }, 00313 { "WDI", DPFLTR_WDI_ID }, 00314 { "PERFLIB", DPFLTR_PERFLIB_ID }, 00315 { "KTM", DPFLTR_KTM_ID }, 00316 { "IOSTRESS", DPFLTR_IOSTRESS_ID }, 00317 { "HEAP", DPFLTR_HEAP_ID }, 00318 { "WHEA", DPFLTR_WHEA_ID }, 00319 { "USERGDI", DPFLTR_USERGDI_ID }, 00320 { "MMCSS", DPFLTR_MMCSS_ID }, 00321 { "TPM", DPFLTR_TPM_ID }, 00322 { "THREADORDER", DPFLTR_THREADORDER_ID }, 00323 { "ENVIRON", DPFLTR_ENVIRON_ID }, 00324 { "EMS", DPFLTR_EMS_ID }, 00325 { "WDT", DPFLTR_WDT_ID }, 00326 { "FVEVOL", DPFLTR_FVEVOL_ID }, 00327 { "NDIS", DPFLTR_NDIS_ID }, 00328 { "NVCTRACE", DPFLTR_NVCTRACE_ID }, 00329 { "LUAFV", DPFLTR_LUAFV_ID }, 00330 { "APPCOMPAT", DPFLTR_APPCOMPAT_ID }, 00331 { "USBSTOR", DPFLTR_USBSTOR_ID }, 00332 { "SBP2PORT", DPFLTR_SBP2PORT_ID }, 00333 { "COVERAGE", DPFLTR_COVERAGE_ID }, 00334 { "CACHEMGR", DPFLTR_CACHEMGR_ID }, 00335 { "MOUNTMGR", DPFLTR_MOUNTMGR_ID }, 00336 { "CFR", DPFLTR_CFR_ID }, 00337 { "TXF", DPFLTR_TXF_ID }, 00338 { "KSECDD", DPFLTR_KSECDD_ID }, 00339 { "FLTREGRESS", DPFLTR_FLTREGRESS_ID }, 00340 { "MPIO", DPFLTR_MPIO_ID }, 00341 { "MSDSM", DPFLTR_MSDSM_ID }, 00342 { "UDFS", DPFLTR_UDFS_ID }, 00343 { "PSHED", DPFLTR_PSHED_ID }, 00344 { "STORVSP", DPFLTR_STORVSP_ID }, 00345 { "LSASS", DPFLTR_LSASS_ID }, 00346 { "SSPICLI", DPFLTR_SSPICLI_ID }, 00347 { "CNG", DPFLTR_CNG_ID }, 00348 { "EXFAT", DPFLTR_EXFAT_ID }, 00349 { "FILETRACE", DPFLTR_FILETRACE_ID }, 00350 { "XSAVE", DPFLTR_XSAVE_ID }, 00351 { "SE", DPFLTR_SE_ID }, 00352 { "DRIVEEXTENDER", DPFLTR_DRIVEEXTENDER_ID }, 00353 }; 00354 00355 for (i = 0; i < sizeof(ComponentTable) / sizeof(ComponentTable[0]); i++) 00356 { 00357 if (_stricmp(ComponentName, ComponentTable[i].Name) == 0) 00358 { 00359 *ComponentId = ComponentTable[i].Id; 00360 return TRUE; 00361 } 00362 } 00363 00364 return FALSE; 00365 } 00366 00379 static BOOLEAN 00380 KdbpEvaluateExpression( 00381 IN PCHAR Expression, 00382 IN LONG ErrOffset, 00383 OUT PULONGLONG Result) 00384 { 00385 static CHAR ErrMsgBuffer[130] = "^ "; 00386 LONG ExpressionErrOffset = -1; 00387 PCHAR ErrMsg = ErrMsgBuffer; 00388 BOOLEAN Ok; 00389 00390 Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result, 00391 &ExpressionErrOffset, ErrMsgBuffer + 2); 00392 if (!Ok) 00393 { 00394 if (ExpressionErrOffset >= 0) 00395 ExpressionErrOffset += ErrOffset; 00396 else 00397 ErrMsg += 2; 00398 00399 KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg); 00400 } 00401 00402 return Ok; 00403 } 00404 00407 static BOOLEAN 00408 KdbpCmdEvalExpression( 00409 ULONG Argc, 00410 PCHAR Argv[]) 00411 { 00412 ULONG i, len; 00413 ULONGLONG Result = 0; 00414 ULONG ul; 00415 LONG l = 0; 00416 BOOLEAN Ok; 00417 00418 if (Argc < 2) 00419 { 00420 KdbpPrint("?: Argument required\n"); 00421 return TRUE; 00422 } 00423 00424 /* Put the arguments back together */ 00425 Argc--; 00426 for (i = 1; i < Argc; i++) 00427 { 00428 len = strlen(Argv[i]); 00429 Argv[i][len] = ' '; 00430 } 00431 00432 /* Evaluate the expression */ 00433 Ok = KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result); 00434 if (Ok) 00435 { 00436 if (Result > 0x00000000ffffffffLL) 00437 { 00438 if (Result & 0x8000000000000000LL) 00439 KdbpPrint("0x%016I64x %20I64u %20I64d\n", Result, Result, Result); 00440 else 00441 KdbpPrint("0x%016I64x %20I64u\n", Result, Result); 00442 } 00443 else 00444 { 00445 ul = (ULONG)Result; 00446 00447 if (ul <= 0xff && ul >= 0x80) 00448 l = (LONG)((CHAR)ul); 00449 else if (ul <= 0xffff && ul >= 0x8000) 00450 l = (LONG)((SHORT)ul); 00451 else 00452 l = (LONG)ul; 00453 00454 if (l < 0) 00455 KdbpPrint("0x%08lx %10lu %10ld\n", ul, ul, l); 00456 else 00457 KdbpPrint("0x%08lx %10lu\n", ul, ul); 00458 } 00459 } 00460 00461 return TRUE; 00462 } 00463 00464 #ifdef __ROS_DWARF__ 00465 00468 static VOID 00469 KdbpPrintStructInternal 00470 (PROSSYM_INFO Info, 00471 PCHAR Indent, 00472 BOOLEAN DoRead, 00473 PVOID BaseAddress, 00474 PROSSYM_AGGREGATE Aggregate) 00475 { 00476 ULONG i; 00477 ULONGLONG Result; 00478 PROSSYM_AGGREGATE_MEMBER Member; 00479 ULONG IndentLen = strlen(Indent); 00480 ROSSYM_AGGREGATE MemberAggregate = {0 }; 00481 00482 for (i = 0; i < Aggregate->NumElements; i++) { 00483 Member = &Aggregate->Elements[i]; 00484 KdbpPrint("%s%p+%x: %s", Indent, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size, Member->Name ? Member->Name : "<anoymous>"); 00485 if (DoRead) { 00486 if (!strcmp(Member->Type, "_UNICODE_STRING")) { 00487 KdbpPrint("\"%wZ\"\n", ((PCHAR)BaseAddress) + Member->BaseOffset); 00488 continue; 00489 } else if (!strcmp(Member->Type, "PUNICODE_STRING")) { 00490 KdbpPrint("\"%wZ\"\n", *(((PUNICODE_STRING*)((PCHAR)BaseAddress) + Member->BaseOffset))); 00491 continue; 00492 } 00493 switch (Member->Size) { 00494 case 1: 00495 case 2: 00496 case 4: 00497 case 8: { 00498 Result = 0; 00499 if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) { 00500 if (Member->Bits) { 00501 Result >>= Member->FirstBit; 00502 Result &= ((1 << Member->Bits) - 1); 00503 } 00504 KdbpPrint(" %lx\n", Result); 00505 } 00506 else goto readfail; 00507 break; 00508 } 00509 default: { 00510 if (Member->Size < 8) { 00511 if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) { 00512 ULONG j; 00513 for (j = 0; j < Member->Size; j++) { 00514 KdbpPrint(" %02x", (int)(Result & 0xff)); 00515 Result >>= 8; 00516 } 00517 } else goto readfail; 00518 } else { 00519 KdbpPrint(" %s @ %p {\n", Member->Type, ((PCHAR)BaseAddress) + Member->BaseOffset); 00520 Indent[IndentLen] = ' '; 00521 if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) { 00522 KdbpPrintStructInternal(Info, Indent, DoRead, ((PCHAR)BaseAddress) + Member->BaseOffset, &MemberAggregate); 00523 RosSymFreeAggregate(&MemberAggregate); 00524 } 00525 Indent[IndentLen] = 0; 00526 KdbpPrint("%s}\n", Indent); 00527 } break; 00528 } 00529 } 00530 } else { 00531 readfail: 00532 if (Member->Size <= 8) { 00533 KdbpPrint(" ??\n"); 00534 } else { 00535 KdbpPrint(" %s @ %x {\n", Member->Type, Member->BaseOffset); 00536 Indent[IndentLen] = ' '; 00537 if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) { 00538 KdbpPrintStructInternal(Info, Indent, DoRead, BaseAddress, &MemberAggregate); 00539 RosSymFreeAggregate(&MemberAggregate); 00540 } 00541 Indent[IndentLen] = 0; 00542 KdbpPrint("%s}\n", Indent); 00543 } 00544 } 00545 } 00546 } 00547 00548 PROSSYM_INFO KdbpSymFindCachedFile(PUNICODE_STRING ModName); 00549 00550 static BOOLEAN 00551 KdbpCmdPrintStruct( 00552 ULONG Argc, 00553 PCHAR Argv[]) 00554 { 00555 ULONG i; 00556 ULONGLONG Result = 0; 00557 PVOID BaseAddress = 0; 00558 ROSSYM_AGGREGATE Aggregate = {0}; 00559 UNICODE_STRING ModName = {0}; 00560 ANSI_STRING AnsiName = {0}; 00561 CHAR Indent[100] = {0}; 00562 PROSSYM_INFO Info; 00563 00564 if (Argc < 3) goto end; 00565 AnsiName.Length = AnsiName.MaximumLength = strlen(Argv[1]); 00566 AnsiName.Buffer = Argv[1]; 00567 RtlAnsiStringToUnicodeString(&ModName, &AnsiName, TRUE); 00568 Info = KdbpSymFindCachedFile(&ModName); 00569 00570 if (!Info || !RosSymAggregate(Info, Argv[2], &Aggregate)) { 00571 DPRINT1("Could not get aggregate\n"); 00572 goto end; 00573 } 00574 00575 // Get an argument for location if it was given 00576 if (Argc > 3) { 00577 ULONG len; 00578 PCHAR ArgStart = Argv[3]; 00579 DPRINT1("Trying to get expression\n"); 00580 for (i = 3; i < Argc - 1; i++) 00581 { 00582 len = strlen(Argv[i]); 00583 Argv[i][len] = ' '; 00584 } 00585 00586 /* Evaluate the expression */ 00587 DPRINT1("Arg: %s\n", ArgStart); 00588 if (KdbpEvaluateExpression(ArgStart, strlen(ArgStart), &Result)) { 00589 BaseAddress = (PVOID)(ULONG_PTR)Result; 00590 DPRINT1("BaseAddress: %p\n", BaseAddress); 00591 } 00592 } 00593 DPRINT1("BaseAddress %p\n", BaseAddress); 00594 KdbpPrintStructInternal(Info, Indent, !!BaseAddress, BaseAddress, &Aggregate); 00595 end: 00596 RosSymFreeAggregate(&Aggregate); 00597 RtlFreeUnicodeString(&ModName); 00598 return TRUE; 00599 } 00600 #endif 00601 00604 static BOOLEAN 00605 KdbpCmdFilter( 00606 ULONG Argc, 00607 PCHAR Argv[]) 00608 { 00609 ULONG i, j, ComponentId, Level; 00610 ULONG set = DPFLTR_MASK, clear = DPFLTR_MASK; 00611 PCHAR pend; 00612 LPCSTR opt, p; 00613 00614 static struct 00615 { 00616 LPCSTR Name; 00617 ULONG Level; 00618 } 00619 debug_classes[] = 00620 { 00621 { "error", 1 << DPFLTR_ERROR_LEVEL }, 00622 { "warning", 1 << DPFLTR_WARNING_LEVEL }, 00623 { "trace", 1 << DPFLTR_TRACE_LEVEL }, 00624 { "info", 1 << DPFLTR_INFO_LEVEL }, 00625 }; 00626 00627 for (i = 1; i < Argc; i++) 00628 { 00629 opt = Argv[i]; 00630 p = opt + strcspn(opt, "+-"); 00631 if (!p[0]) p = opt; /* assume it's a debug channel name */ 00632 00633 if (p > opt) 00634 { 00635 for (j = 0; j < sizeof(debug_classes) / sizeof(debug_classes[0]); j++) 00636 { 00637 SIZE_T len = strlen(debug_classes[j].Name); 00638 if (len != (p - opt)) 00639 continue; 00640 if (_strnicmp(opt, debug_classes[j].Name, len) == 0) /* found it */ 00641 { 00642 if (*p == '+') 00643 set |= debug_classes[j].Level; 00644 else 00645 clear |= debug_classes[j].Level; 00646 break; 00647 } 00648 } 00649 if (j == sizeof(debug_classes) / sizeof(debug_classes[0])) 00650 { 00651 Level = strtoul(opt, &pend, 0); 00652 if (pend != p) 00653 { 00654 KdbpPrint("filter: bad class name '%.*s'\n", p - opt, opt); 00655 continue; 00656 } 00657 if (*p == '+') 00658 set |= Level; 00659 else 00660 clear |= Level; 00661 } 00662 } 00663 else 00664 { 00665 if (*p == '-') 00666 clear = MAXULONG; 00667 else 00668 set = MAXULONG; 00669 } 00670 if (*p == '+' || *p == '-') 00671 p++; 00672 00673 if (!KdbpGetComponentId(p, &ComponentId)) 00674 { 00675 KdbpPrint("filter: '%s' is not a valid component name!\n", p); 00676 return TRUE; 00677 } 00678 00679 /* Get current mask value */ 00680 NtSetDebugFilterState(ComponentId, set, TRUE); 00681 NtSetDebugFilterState(ComponentId, clear, FALSE); 00682 } 00683 00684 return TRUE; 00685 } 00686 00690 static BOOLEAN 00691 KdbpCmdDisassembleX( 00692 ULONG Argc, 00693 PCHAR Argv[]) 00694 { 00695 ULONG Count; 00696 ULONG ul; 00697 INT i; 00698 ULONGLONG Result = 0; 00699 ULONG_PTR Address = KdbCurrentTrapFrame->Tf.Eip; 00700 LONG InstLen; 00701 00702 if (Argv[0][0] == 'x') /* display memory */ 00703 Count = 16; 00704 else /* disassemble */ 00705 Count = 10; 00706 00707 if (Argc >= 2) 00708 { 00709 /* Check for [L count] part */ 00710 ul = 0; 00711 if (strcmp(Argv[Argc-2], "L") == 0) 00712 { 00713 ul = strtoul(Argv[Argc-1], NULL, 0); 00714 if (ul > 0) 00715 { 00716 Count = ul; 00717 Argc -= 2; 00718 } 00719 } 00720 else if (Argv[Argc-1][0] == 'L') 00721 { 00722 ul = strtoul(Argv[Argc-1] + 1, NULL, 0); 00723 if (ul > 0) 00724 { 00725 Count = ul; 00726 Argc--; 00727 } 00728 } 00729 00730 /* Put the remaining arguments back together */ 00731 Argc--; 00732 for (ul = 1; ul < Argc; ul++) 00733 { 00734 Argv[ul][strlen(Argv[ul])] = ' '; 00735 } 00736 Argc++; 00737 } 00738 00739 /* Evaluate the expression */ 00740 if (Argc > 1) 00741 { 00742 if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) 00743 return TRUE; 00744 00745 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 00746 KdbpPrint("Warning: Address %I64x is beeing truncated\n",Result); 00747 00748 Address = (ULONG_PTR)Result; 00749 } 00750 else if (Argv[0][0] == 'x') 00751 { 00752 KdbpPrint("x: Address argument required.\n"); 00753 return TRUE; 00754 } 00755 00756 if (Argv[0][0] == 'x') 00757 { 00758 /* Display dwords */ 00759 ul = 0; 00760 00761 while (Count > 0) 00762 { 00763 if (!KdbSymPrintAddress((PVOID)Address, NULL)) 00764 KdbpPrint("<%x>:", Address); 00765 else 00766 KdbpPrint(":"); 00767 00768 i = min(4, Count); 00769 Count -= i; 00770 00771 while (--i >= 0) 00772 { 00773 if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul)))) 00774 KdbpPrint(" ????????"); 00775 else 00776 KdbpPrint(" %08x", ul); 00777 00778 Address += sizeof(ul); 00779 } 00780 00781 KdbpPrint("\n"); 00782 } 00783 } 00784 else 00785 { 00786 /* Disassemble */ 00787 while (Count-- > 0) 00788 { 00789 if (!KdbSymPrintAddress((PVOID)Address, NULL)) 00790 KdbpPrint("<%08x>: ", Address); 00791 else 00792 KdbpPrint(": "); 00793 00794 InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax); 00795 if (InstLen < 0) 00796 { 00797 KdbpPrint("<INVALID>\n"); 00798 return TRUE; 00799 } 00800 00801 KdbpPrint("\n"); 00802 Address += InstLen; 00803 } 00804 } 00805 00806 return TRUE; 00807 } 00808 00811 static BOOLEAN 00812 KdbpCmdRegs( 00813 ULONG Argc, 00814 PCHAR Argv[]) 00815 { 00816 PKTRAP_FRAME Tf = &KdbCurrentTrapFrame->Tf; 00817 INT i; 00818 static const PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5", 00819 " ZF", " SF", " TF", " IF", " DF", " OF", 00820 NULL, NULL, " NT", " BIT15", " RF", " VF", 00821 " AC", " VIF", " VIP", " ID", " BIT22", 00822 " BIT23", " BIT24", " BIT25", " BIT26", 00823 " BIT27", " BIT28", " BIT29", " BIT30", 00824 " BIT31" }; 00825 00826 if (Argv[0][0] == 'r') /* regs */ 00827 { 00828 KdbpPrint("CS:EIP 0x%04x:0x%08x\n" 00829 "SS:ESP 0x%04x:0x%08x\n" 00830 " EAX 0x%08x EBX 0x%08x\n" 00831 " ECX 0x%08x EDX 0x%08x\n" 00832 " ESI 0x%08x EDI 0x%08x\n" 00833 " EBP 0x%08x\n", 00834 Tf->SegCs & 0xFFFF, Tf->Eip, 00835 Tf->HardwareSegSs, Tf->HardwareEsp, 00836 Tf->Eax, Tf->Ebx, 00837 Tf->Ecx, Tf->Edx, 00838 Tf->Esi, Tf->Edi, 00839 Tf->Ebp); 00840 KdbpPrint("EFLAGS 0x%08x ", Tf->EFlags); 00841 00842 for (i = 0; i < 32; i++) 00843 { 00844 if (i == 1) 00845 { 00846 if ((Tf->EFlags & (1 << 1)) == 0) 00847 KdbpPrint(" !BIT1"); 00848 } 00849 else if (i == 12) 00850 { 00851 KdbpPrint(" IOPL%d", (Tf->EFlags >> 12) & 3); 00852 } 00853 else if (i == 13) 00854 { 00855 } 00856 else if ((Tf->EFlags & (1 << i)) != 0) 00857 { 00858 KdbpPrint(EflagsBits[i]); 00859 } 00860 } 00861 00862 KdbpPrint("\n"); 00863 } 00864 else if (Argv[0][0] == 'c') /* cregs */ 00865 { 00866 ULONG Cr0, Cr2, Cr3, Cr4; 00867 KDESCRIPTOR Gdtr, Idtr; 00868 USHORT Ldtr; 00869 static const PCHAR Cr0Bits[32] = { " PE", " MP", " EM", " TS", " ET", " NE", NULL, NULL, 00870 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 00871 " WP", NULL, " AM", NULL, NULL, NULL, NULL, NULL, 00872 NULL, NULL, NULL, NULL, NULL, " NW", " CD", " PG" }; 00873 static const PCHAR Cr4Bits[32] = { " VME", " PVI", " TSD", " DE", " PSE", " PAE", " MCE", " PGE", 00874 " PCE", " OSFXSR", " OSXMMEXCPT", NULL, NULL, NULL, NULL, NULL, 00875 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 00876 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 00877 00878 Cr0 = KdbCurrentTrapFrame->Cr0; 00879 Cr2 = KdbCurrentTrapFrame->Cr2; 00880 Cr3 = KdbCurrentTrapFrame->Cr3; 00881 Cr4 = KdbCurrentTrapFrame->Cr4; 00882 00883 /* Get descriptor table regs */ 00884 Ke386GetGlobalDescriptorTable(&Gdtr.Limit); 00885 Ldtr = Ke386GetLocalDescriptorTable(); 00886 __sidt(&Idtr.Limit); 00887 00888 /* Display the control registers */ 00889 KdbpPrint("CR0 0x%08x ", Cr0); 00890 00891 for (i = 0; i < 32; i++) 00892 { 00893 if (!Cr0Bits[i]) 00894 continue; 00895 00896 if ((Cr0 & (1 << i)) != 0) 00897 KdbpPrint(Cr0Bits[i]); 00898 } 00899 00900 KdbpPrint("\nCR2 0x%08x\n", Cr2); 00901 KdbpPrint("CR3 0x%08x Pagedir-Base 0x%08x %s%s\n", Cr3, (Cr3 & 0xfffff000), 00902 (Cr3 & (1 << 3)) ? " PWT" : "", (Cr3 & (1 << 4)) ? " PCD" : "" ); 00903 KdbpPrint("CR4 0x%08x ", Cr4); 00904 00905 for (i = 0; i < 32; i++) 00906 { 00907 if (!Cr4Bits[i]) 00908 continue; 00909 00910 if ((Cr4 & (1 << i)) != 0) 00911 KdbpPrint(Cr4Bits[i]); 00912 } 00913 00914 /* Display the descriptor table regs */ 00915 KdbpPrint("\nGDTR Base 0x%08x Size 0x%04x\n", Gdtr.Base, Gdtr.Limit); 00916 KdbpPrint("LDTR 0x%04x\n", Ldtr); 00917 KdbpPrint("IDTR Base 0x%08x Size 0x%04x\n", Idtr.Base, Idtr.Limit); 00918 } 00919 else if (Argv[0][0] == 's') /* sregs */ 00920 { 00921 KdbpPrint("CS 0x%04x Index 0x%04x %cDT RPL%d\n", 00922 Tf->SegCs & 0xffff, (Tf->SegCs & 0xffff) >> 3, 00923 (Tf->SegCs & (1 << 2)) ? 'L' : 'G', Tf->SegCs & 3); 00924 KdbpPrint("DS 0x%04x Index 0x%04x %cDT RPL%d\n", 00925 Tf->SegDs, Tf->SegDs >> 3, (Tf->SegDs & (1 << 2)) ? 'L' : 'G', Tf->SegDs & 3); 00926 KdbpPrint("ES 0x%04x Index 0x%04x %cDT RPL%d\n", 00927 Tf->SegEs, Tf->SegEs >> 3, (Tf->SegEs & (1 << 2)) ? 'L' : 'G', Tf->SegEs & 3); 00928 KdbpPrint("FS 0x%04x Index 0x%04x %cDT RPL%d\n", 00929 Tf->SegFs, Tf->SegFs >> 3, (Tf->SegFs & (1 << 2)) ? 'L' : 'G', Tf->SegFs & 3); 00930 KdbpPrint("GS 0x%04x Index 0x%04x %cDT RPL%d\n", 00931 Tf->SegGs, Tf->SegGs >> 3, (Tf->SegGs & (1 << 2)) ? 'L' : 'G', Tf->SegGs & 3); 00932 KdbpPrint("SS 0x%04x Index 0x%04x %cDT RPL%d\n", 00933 Tf->HardwareSegSs, Tf->HardwareSegSs >> 3, (Tf->HardwareSegSs & (1 << 2)) ? 'L' : 'G', Tf->HardwareSegSs & 3); 00934 } 00935 else /* dregs */ 00936 { 00937 ASSERT(Argv[0][0] == 'd'); 00938 KdbpPrint("DR0 0x%08x\n" 00939 "DR1 0x%08x\n" 00940 "DR2 0x%08x\n" 00941 "DR3 0x%08x\n" 00942 "DR6 0x%08x\n" 00943 "DR7 0x%08x\n", 00944 Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, 00945 Tf->Dr6, Tf->Dr7); 00946 } 00947 00948 return TRUE; 00949 } 00950 00951 static BOOLEAN 00952 KdbpTrapFrameFromPrevTss( 00953 PKTRAP_FRAME TrapFrame) 00954 { 00955 ULONG_PTR Eip, Ebp; 00956 KDESCRIPTOR Gdtr; 00957 KGDTENTRY Desc; 00958 USHORT Sel; 00959 PKTSS Tss; 00960 00961 Ke386GetGlobalDescriptorTable(&Gdtr.Limit); 00962 Sel = Ke386GetTr(); 00963 00964 if ((Sel & (sizeof(KGDTENTRY) - 1)) || 00965 (Sel < sizeof(KGDTENTRY)) || 00966 (Sel + sizeof(KGDTENTRY) - 1 > Gdtr.Limit)) 00967 return FALSE; 00968 00969 if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc, 00970 (PVOID)(Gdtr.Base + Sel), 00971 sizeof(KGDTENTRY)))) 00972 return FALSE; 00973 00974 if (Desc.HighWord.Bits.Type != 0xB) 00975 return FALSE; 00976 00977 Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow | 00978 Desc.HighWord.Bytes.BaseMid << 16 | 00979 Desc.HighWord.Bytes.BaseHi << 24); 00980 00981 if (!NT_SUCCESS(KdbpSafeReadMemory(&Sel, 00982 (PVOID)&Tss->Backlink, 00983 sizeof(USHORT)))) 00984 return FALSE; 00985 00986 if ((Sel & (sizeof(KGDTENTRY) - 1)) || 00987 (Sel < sizeof(KGDTENTRY)) || 00988 (Sel + sizeof(KGDTENTRY) - 1 > Gdtr.Limit)) 00989 return FALSE; 00990 00991 if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc, 00992 (PVOID)(Gdtr.Base + Sel), 00993 sizeof(KGDTENTRY)))) 00994 return FALSE; 00995 00996 if (Desc.HighWord.Bits.Type != 0xB) 00997 return FALSE; 00998 00999 Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow | 01000 Desc.HighWord.Bytes.BaseMid << 16 | 01001 Desc.HighWord.Bytes.BaseHi << 24); 01002 01003 if (!NT_SUCCESS(KdbpSafeReadMemory(&Eip, 01004 (PVOID)&Tss->Eip, 01005 sizeof(ULONG_PTR)))) 01006 return FALSE; 01007 01008 if (!NT_SUCCESS(KdbpSafeReadMemory(&Ebp, 01009 (PVOID)&Tss->Ebp, 01010 sizeof(ULONG_PTR)))) 01011 return FALSE; 01012 01013 TrapFrame->Eip = Eip; 01014 TrapFrame->Ebp = Ebp; 01015 return TRUE; 01016 } 01017 01018 VOID __cdecl KiTrap02(VOID); 01019 VOID FASTCALL KiTrap03Handler(IN PKTRAP_FRAME); 01020 VOID __cdecl KiTrap08(VOID); 01021 VOID __cdecl KiTrap09(VOID); 01022 01023 static BOOLEAN 01024 KdbpInNmiOrDoubleFaultHandler( 01025 ULONG_PTR Address) 01026 { 01027 return (Address > (ULONG_PTR)KiTrap02 && Address < (ULONG_PTR)KiTrap03Handler) || 01028 (Address > (ULONG_PTR)KiTrap08 && Address < (ULONG_PTR)KiTrap09); 01029 } 01030 01033 static BOOLEAN 01034 KdbpCmdBackTrace( 01035 ULONG Argc, 01036 PCHAR Argv[]) 01037 { 01038 ULONG ul; 01039 ULONGLONG Result = 0; 01040 ULONG_PTR Frame = KdbCurrentTrapFrame->Tf.Ebp; 01041 ULONG_PTR Address; 01042 KTRAP_FRAME TrapFrame; 01043 01044 if (Argc >= 2) 01045 { 01046 /* Check for [L count] part */ 01047 ul = 0; 01048 01049 if (strcmp(Argv[Argc-2], "L") == 0) 01050 { 01051 ul = strtoul(Argv[Argc-1], NULL, 0); 01052 if (ul > 0) 01053 { 01054 Argc -= 2; 01055 } 01056 } 01057 else if (Argv[Argc-1][0] == 'L') 01058 { 01059 ul = strtoul(Argv[Argc-1] + 1, NULL, 0); 01060 if (ul > 0) 01061 { 01062 Argc--; 01063 } 01064 } 01065 01066 /* Put the remaining arguments back together */ 01067 Argc--; 01068 for (ul = 1; ul < Argc; ul++) 01069 { 01070 Argv[ul][strlen(Argv[ul])] = ' '; 01071 } 01072 Argc++; 01073 } 01074 01075 /* Check if frame addr or thread id is given. */ 01076 if (Argc > 1) 01077 { 01078 if (Argv[1][0] == '*') 01079 { 01080 Argv[1]++; 01081 01082 /* Evaluate the expression */ 01083 if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) 01084 return TRUE; 01085 01086 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 01087 KdbpPrint("Warning: Address %I64x is beeing truncated\n",Result); 01088 01089 Frame = (ULONG_PTR)Result; 01090 } 01091 else 01092 { 01093 KdbpPrint("Thread backtrace not supported yet!\n"); 01094 return TRUE; 01095 } 01096 } 01097 else 01098 { 01099 KdbpPrint("Eip:\n"); 01100 01101 /* Try printing the function at EIP */ 01102 if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip, &KdbCurrentTrapFrame->Tf)) 01103 KdbpPrint("<%08x>\n", KdbCurrentTrapFrame->Tf.Eip); 01104 else 01105 KdbpPrint("\n"); 01106 } 01107 01108 TrapFrame = KdbCurrentTrapFrame->Tf; 01109 KdbpPrint("Frames:\n"); 01110 01111 for (;;) 01112 { 01113 BOOLEAN GotNextFrame; 01114 01115 if (Frame == 0) 01116 break; 01117 01118 if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof (ULONG_PTR)))) 01119 { 01120 KdbpPrint("Couldn't access memory at 0x%p!\n", Frame + sizeof(ULONG_PTR)); 01121 break; 01122 } 01123 01124 if ((GotNextFrame = NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof (ULONG_PTR))))) 01125 TrapFrame.Ebp = Frame; 01126 01127 /* Print the location of the call instruction */ 01128 if (!KdbSymPrintAddress((PVOID)(Address - 5), &TrapFrame)) 01129 KdbpPrint("<%08x>\n", Address); 01130 else 01131 KdbpPrint("\n"); 01132 01133 if (KdbOutputAborted) break; 01134 01135 if (Address == 0) 01136 break; 01137 01138 if (KdbpInNmiOrDoubleFaultHandler(Address)) 01139 { 01140 if ((GotNextFrame = KdbpTrapFrameFromPrevTss(&TrapFrame))) 01141 { 01142 Address = TrapFrame.Eip; 01143 Frame = TrapFrame.Ebp; 01144 01145 if (!KdbSymPrintAddress((PVOID)Address, &TrapFrame)) 01146 KdbpPrint("<%08x>\n", Address); 01147 else 01148 KdbpPrint("\n"); 01149 } 01150 } 01151 01152 if (!GotNextFrame) 01153 { 01154 KdbpPrint("Couldn't access memory at 0x%p!\n", Frame); 01155 break; 01156 } 01157 } 01158 01159 return TRUE; 01160 } 01161 01164 static BOOLEAN 01165 KdbpCmdContinue( 01166 ULONG Argc, 01167 PCHAR Argv[]) 01168 { 01169 /* Exit the main loop */ 01170 return FALSE; 01171 } 01172 01175 static BOOLEAN 01176 KdbpCmdStep( 01177 ULONG Argc, 01178 PCHAR Argv[]) 01179 { 01180 ULONG Count = 1; 01181 01182 if (Argc > 1) 01183 { 01184 Count = strtoul(Argv[1], NULL, 0); 01185 if (Count == 0) 01186 { 01187 KdbpPrint("%s: Integer argument required\n", Argv[0]); 01188 return TRUE; 01189 } 01190 } 01191 01192 if (Argv[0][0] == 'n') 01193 KdbSingleStepOver = TRUE; 01194 else 01195 KdbSingleStepOver = FALSE; 01196 01197 /* Set the number of single steps and return to the interrupted code. */ 01198 KdbNumSingleSteps = Count; 01199 01200 return FALSE; 01201 } 01202 01205 static BOOLEAN 01206 KdbpCmdBreakPointList( 01207 ULONG Argc, 01208 PCHAR Argv[]) 01209 { 01210 LONG l; 01211 ULONG_PTR Address = 0; 01212 KDB_BREAKPOINT_TYPE Type = 0; 01213 KDB_ACCESS_TYPE AccessType = 0; 01214 UCHAR Size = 0; 01215 UCHAR DebugReg = 0; 01216 BOOLEAN Enabled = FALSE; 01217 BOOLEAN Global = FALSE; 01218 PEPROCESS Process = NULL; 01219 PCHAR str1, str2, ConditionExpr, GlobalOrLocal; 01220 CHAR Buffer[20]; 01221 01222 l = KdbpGetNextBreakPointNr(0); 01223 if (l < 0) 01224 { 01225 KdbpPrint("No breakpoints.\n"); 01226 return TRUE; 01227 } 01228 01229 KdbpPrint("Breakpoints:\n"); 01230 do 01231 { 01232 if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg, 01233 &Enabled, &Global, &Process, &ConditionExpr)) 01234 { 01235 continue; 01236 } 01237 01238 if (l == KdbLastBreakPointNr) 01239 { 01240 str1 = "\x1b[1m*"; 01241 str2 = "\x1b[0m"; 01242 } 01243 else 01244 { 01245 str1 = " "; 01246 str2 = ""; 01247 } 01248 01249 if (Global) 01250 { 01251 GlobalOrLocal = " global"; 01252 } 01253 else 01254 { 01255 GlobalOrLocal = Buffer; 01256 sprintf(Buffer, " PID 0x%08lx", 01257 (ULONG)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE)); 01258 } 01259 01260 if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary) 01261 { 01262 KdbpPrint(" %s%03d BPX 0x%08x%s%s%s%s%s\n", 01263 str1, l, Address, 01264 Enabled ? "" : " disabled", 01265 GlobalOrLocal, 01266 ConditionExpr ? " IF " : "", 01267 ConditionExpr ? ConditionExpr : "", 01268 str2); 01269 } 01270 else if (Type == KdbBreakPointHardware) 01271 { 01272 if (!Enabled) 01273 { 01274 KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s disabled%s%s%s%s\n", str1, l, Address, 01275 KDB_ACCESS_TYPE_TO_STRING(AccessType), 01276 Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), 01277 GlobalOrLocal, 01278 ConditionExpr ? " IF " : "", 01279 ConditionExpr ? ConditionExpr : "", 01280 str2); 01281 } 01282 else 01283 { 01284 KdbpPrint(" %s%03d BPM 0x%08x %-5s %-5s DR%d%s%s%s%s\n", str1, l, Address, 01285 KDB_ACCESS_TYPE_TO_STRING(AccessType), 01286 Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"), 01287 DebugReg, 01288 GlobalOrLocal, 01289 ConditionExpr ? " IF " : "", 01290 ConditionExpr ? ConditionExpr : "", 01291 str2); 01292 } 01293 } 01294 } 01295 while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0); 01296 01297 return TRUE; 01298 } 01299 01302 static BOOLEAN 01303 KdbpCmdEnableDisableClearBreakPoint( 01304 ULONG Argc, 01305 PCHAR Argv[]) 01306 { 01307 PCHAR pend; 01308 ULONG BreakPointNr; 01309 01310 if (Argc < 2) 01311 { 01312 KdbpPrint("%s: argument required\n", Argv[0]); 01313 return TRUE; 01314 } 01315 01316 pend = Argv[1]; 01317 BreakPointNr = strtoul(Argv[1], &pend, 0); 01318 if (pend == Argv[1] || *pend != '\0') 01319 { 01320 KdbpPrint("%s: integer argument required\n", Argv[0]); 01321 return TRUE; 01322 } 01323 01324 if (Argv[0][1] == 'e') /* enable */ 01325 { 01326 KdbpEnableBreakPoint(BreakPointNr, NULL); 01327 } 01328 else if (Argv [0][1] == 'd') /* disable */ 01329 { 01330 KdbpDisableBreakPoint(BreakPointNr, NULL); 01331 } 01332 else /* clear */ 01333 { 01334 ASSERT(Argv[0][1] == 'c'); 01335 KdbpDeleteBreakPoint(BreakPointNr, NULL); 01336 } 01337 01338 return TRUE; 01339 } 01340 01343 static BOOLEAN 01344 KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[]) 01345 { 01346 ULONGLONG Result = 0; 01347 ULONG_PTR Address; 01348 KDB_BREAKPOINT_TYPE Type; 01349 UCHAR Size = 0; 01350 KDB_ACCESS_TYPE AccessType = 0; 01351 ULONG AddressArgIndex, i; 01352 LONG ConditionArgIndex; 01353 BOOLEAN Global = TRUE; 01354 01355 if (Argv[0][2] == 'x') /* software breakpoint */ 01356 { 01357 if (Argc < 2) 01358 { 01359 KdbpPrint("bpx: Address argument required.\n"); 01360 return TRUE; 01361 } 01362 01363 AddressArgIndex = 1; 01364 Type = KdbBreakPointSoftware; 01365 } 01366 else /* memory breakpoint */ 01367 { 01368 ASSERT(Argv[0][2] == 'm'); 01369 01370 if (Argc < 2) 01371 { 01372 KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n"); 01373 return TRUE; 01374 } 01375 01376 if (_stricmp(Argv[1], "x") == 0) 01377 AccessType = KdbAccessExec; 01378 else if (_stricmp(Argv[1], "r") == 0) 01379 AccessType = KdbAccessRead; 01380 else if (_stricmp(Argv[1], "w") == 0) 01381 AccessType = KdbAccessWrite; 01382 else if (_stricmp(Argv[1], "rw") == 0) 01383 AccessType = KdbAccessReadWrite; 01384 else 01385 { 01386 KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]); 01387 return TRUE; 01388 } 01389 01390 if (Argc < 3) 01391 { 01392 KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size"); 01393 return TRUE; 01394 } 01395 01396 AddressArgIndex = 3; 01397 if (_stricmp(Argv[2], "byte") == 0) 01398 Size = 1; 01399 else if (_stricmp(Argv[2], "word") == 0) 01400 Size = 2; 01401 else if (_stricmp(Argv[2], "dword") == 0) 01402 Size = 4; 01403 else if (AccessType == KdbAccessExec) 01404 { 01405 Size = 1; 01406 AddressArgIndex--; 01407 } 01408 else 01409 { 01410 KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]); 01411 return TRUE; 01412 } 01413 01414 if (Argc <= AddressArgIndex) 01415 { 01416 KdbpPrint("bpm: Address argument required.\n"); 01417 return TRUE; 01418 } 01419 01420 Type = KdbBreakPointHardware; 01421 } 01422 01423 /* Put the arguments back together */ 01424 ConditionArgIndex = -1; 01425 for (i = AddressArgIndex; i < (Argc-1); i++) 01426 { 01427 if (strcmp(Argv[i+1], "IF") == 0) /* IF found */ 01428 { 01429 ConditionArgIndex = i + 2; 01430 if ((ULONG)ConditionArgIndex >= Argc) 01431 { 01432 KdbpPrint("%s: IF requires condition expression.\n", Argv[0]); 01433 return TRUE; 01434 } 01435 01436 for (i = ConditionArgIndex; i < (Argc-1); i++) 01437 Argv[i][strlen(Argv[i])] = ' '; 01438 01439 break; 01440 } 01441 01442 Argv[i][strlen(Argv[i])] = ' '; 01443 } 01444 01445 /* Evaluate the address expression */ 01446 if (!KdbpEvaluateExpression(Argv[AddressArgIndex], 01447 sizeof("kdb:> ")-1 + (Argv[AddressArgIndex]-Argv[0]), 01448 &Result)) 01449 { 01450 return TRUE; 01451 } 01452 01453 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 01454 KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result); 01455 01456 Address = (ULONG_PTR)Result; 01457 01458 KdbpInsertBreakPoint(Address, Type, Size, AccessType, 01459 (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex], 01460 Global, NULL); 01461 01462 return TRUE; 01463 } 01464 01467 static BOOLEAN 01468 KdbpCmdThread( 01469 ULONG Argc, 01470 PCHAR Argv[]) 01471 { 01472 PLIST_ENTRY Entry; 01473 PETHREAD Thread = NULL; 01474 PEPROCESS Process = NULL; 01475 BOOLEAN ReferencedThread = FALSE, ReferencedProcess = FALSE; 01476 PULONG Esp; 01477 PULONG Ebp; 01478 ULONG Eip; 01479 ULONG ul = 0; 01480 PCHAR State, pend, str1, str2; 01481 static const PCHAR ThreadStateToString[DeferredReady+1] = 01482 { 01483 "Initialized", "Ready", "Running", 01484 "Standby", "Terminated", "Waiting", 01485 "Transition", "DeferredReady" 01486 }; 01487 01488 ASSERT(KdbCurrentProcess); 01489 01490 if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) 01491 { 01492 Process = KdbCurrentProcess; 01493 01494 if (Argc >= 3) 01495 { 01496 ul = strtoul(Argv[2], &pend, 0); 01497 if (Argv[2] == pend) 01498 { 01499 KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]); 01500 return TRUE; 01501 } 01502 01503 if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) 01504 { 01505 KdbpPrint("thread: Invalid process id!\n"); 01506 return TRUE; 01507 } 01508 01509 /* Remember our reference */ 01510 ReferencedProcess = TRUE; 01511 } 01512 01513 Entry = Process->ThreadListHead.Flink; 01514 if (Entry == &Process->ThreadListHead) 01515 { 01516 if (Argc >= 3) 01517 KdbpPrint("No threads in process 0x%08x!\n", ul); 01518 else 01519 KdbpPrint("No threads in current process!\n"); 01520 01521 if (ReferencedProcess) 01522 ObDereferenceObject(Process); 01523 01524 return TRUE; 01525 } 01526 01527 KdbpPrint(" TID State Prior. Affinity EBP EIP\n"); 01528 do 01529 { 01530 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); 01531 01532 if (Thread == KdbCurrentThread) 01533 { 01534 str1 = "\x1b[1m*"; 01535 str2 = "\x1b[0m"; 01536 } 01537 else 01538 { 01539 str1 = " "; 01540 str2 = ""; 01541 } 01542 01543 if (!Thread->Tcb.InitialStack) 01544 { 01545 /* Thread has no kernel stack (probably terminated) */ 01546 Esp = Ebp = NULL; 01547 Eip = 0; 01548 } 01549 else if (Thread->Tcb.TrapFrame) 01550 { 01551 if (Thread->Tcb.TrapFrame->PreviousPreviousMode == KernelMode) 01552 Esp = (PULONG)Thread->Tcb.TrapFrame->TempEsp; 01553 else 01554 Esp = (PULONG)Thread->Tcb.TrapFrame->HardwareEsp; 01555 01556 Ebp = (PULONG)Thread->Tcb.TrapFrame->Ebp; 01557 Eip = Thread->Tcb.TrapFrame->Eip; 01558 } 01559 else 01560 { 01561 Esp = (PULONG)Thread->Tcb.KernelStack; 01562 Ebp = (PULONG)Esp[4]; 01563 Eip = 0; 01564 01565 if (Ebp) /* FIXME: Should we attach to the process to read Ebp[1]? */ 01566 KdbpSafeReadMemory(&Eip, Ebp + 1, sizeof (Eip)); 01567 } 01568 01569 if (Thread->Tcb.State < (DeferredReady + 1)) 01570 State = ThreadStateToString[Thread->Tcb.State]; 01571 else 01572 State = "Unknown"; 01573 01574 KdbpPrint(" %s0x%08x %-11s %3d 0x%08x 0x%08x 0x%08x%s\n", 01575 str1, 01576 Thread->Cid.UniqueThread, 01577 State, 01578 Thread->Tcb.Priority, 01579 Thread->Tcb.Affinity, 01580 Ebp, 01581 Eip, 01582 str2); 01583 01584 Entry = Entry->Flink; 01585 } 01586 while (Entry != &Process->ThreadListHead); 01587 01588 /* Release our reference, if any */ 01589 if (ReferencedProcess) 01590 ObDereferenceObject(Process); 01591 } 01592 else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) 01593 { 01594 if (Argc < 3) 01595 { 01596 KdbpPrint("thread attach: thread id argument required!\n"); 01597 return TRUE; 01598 } 01599 01600 ul = strtoul(Argv[2], &pend, 0); 01601 if (Argv[2] == pend) 01602 { 01603 KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]); 01604 return TRUE; 01605 } 01606 01607 if (!KdbpAttachToThread((PVOID)ul)) 01608 { 01609 return TRUE; 01610 } 01611 01612 KdbpPrint("Attached to thread 0x%08x.\n", ul); 01613 } 01614 else 01615 { 01616 Thread = KdbCurrentThread; 01617 01618 if (Argc >= 2) 01619 { 01620 ul = strtoul(Argv[1], &pend, 0); 01621 if (Argv[1] == pend) 01622 { 01623 KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]); 01624 return TRUE; 01625 } 01626 01627 if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread))) 01628 { 01629 KdbpPrint("thread: Invalid thread id!\n"); 01630 return TRUE; 01631 } 01632 01633 /* Remember our reference */ 01634 ReferencedThread = TRUE; 01635 } 01636 01637 if (Thread->Tcb.State < (DeferredReady + 1)) 01638 State = ThreadStateToString[Thread->Tcb.State]; 01639 else 01640 State = "Unknown"; 01641 01642 KdbpPrint("%s" 01643 " TID: 0x%08x\n" 01644 " State: %s (0x%x)\n" 01645 " Priority: %d\n" 01646 " Affinity: 0x%08x\n" 01647 " Initial Stack: 0x%08x\n" 01648 " Stack Limit: 0x%08x\n" 01649 " Stack Base: 0x%08x\n" 01650 " Kernel Stack: 0x%08x\n" 01651 " Trap Frame: 0x%08x\n" 01652 " NPX State: %s (0x%x)\n", 01653 (Argc < 2) ? "Current Thread:\n" : "", 01654 Thread->Cid.UniqueThread, 01655 State, Thread->Tcb.State, 01656 Thread->Tcb.Priority, 01657 Thread->Tcb.Affinity, 01658 Thread->Tcb.InitialStack, 01659 Thread->Tcb.StackLimit, 01660 Thread->Tcb.StackBase, 01661 Thread->Tcb.KernelStack, 01662 Thread->Tcb.TrapFrame, 01663 NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState); 01664 01665 /* Release our reference if we had one */ 01666 if (ReferencedThread) 01667 ObDereferenceObject(Thread); 01668 } 01669 01670 return TRUE; 01671 } 01672 01675 static BOOLEAN 01676 KdbpCmdProc( 01677 ULONG Argc, 01678 PCHAR Argv[]) 01679 { 01680 PLIST_ENTRY Entry; 01681 PEPROCESS Process; 01682 BOOLEAN ReferencedProcess = FALSE; 01683 PCHAR State, pend, str1, str2; 01684 ULONG ul; 01685 extern LIST_ENTRY PsActiveProcessHead; 01686 01687 if (Argc >= 2 && _stricmp(Argv[1], "list") == 0) 01688 { 01689 Entry = PsActiveProcessHead.Flink; 01690 if (!Entry || Entry == &PsActiveProcessHead) 01691 { 01692 KdbpPrint("No processes in the system!\n"); 01693 return TRUE; 01694 } 01695 01696 KdbpPrint(" PID State Filename\n"); 01697 do 01698 { 01699 Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks); 01700 01701 if (Process == KdbCurrentProcess) 01702 { 01703 str1 = "\x1b[1m*"; 01704 str2 = "\x1b[0m"; 01705 } 01706 else 01707 { 01708 str1 = " "; 01709 str2 = ""; 01710 } 01711 01712 State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" : 01713 ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition")); 01714 01715 KdbpPrint(" %s0x%08x %-10s %s%s\n", 01716 str1, 01717 Process->UniqueProcessId, 01718 State, 01719 Process->ImageFileName, 01720 str2); 01721 01722 Entry = Entry->Flink; 01723 } 01724 while(Entry != &PsActiveProcessHead); 01725 } 01726 else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0) 01727 { 01728 if (Argc < 3) 01729 { 01730 KdbpPrint("process attach: process id argument required!\n"); 01731 return TRUE; 01732 } 01733 01734 ul = strtoul(Argv[2], &pend, 0); 01735 if (Argv[2] == pend) 01736 { 01737 KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]); 01738 return TRUE; 01739 } 01740 01741 if (!KdbpAttachToProcess((PVOID)ul)) 01742 { 01743 return TRUE; 01744 } 01745 01746 KdbpPrint("Attached to process 0x%08x, thread 0x%08x.\n", (ULONG)ul, 01747 (ULONG)KdbCurrentThread->Cid.UniqueThread); 01748 } 01749 else 01750 { 01751 Process = KdbCurrentProcess; 01752 01753 if (Argc >= 2) 01754 { 01755 ul = strtoul(Argv[1], &pend, 0); 01756 if (Argv[1] == pend) 01757 { 01758 KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]); 01759 return TRUE; 01760 } 01761 01762 if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process))) 01763 { 01764 KdbpPrint("proc: Invalid process id!\n"); 01765 return TRUE; 01766 } 01767 01768 /* Remember our reference */ 01769 ReferencedProcess = TRUE; 01770 } 01771 01772 State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" : 01773 ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition")); 01774 KdbpPrint("%s" 01775 " PID: 0x%08x\n" 01776 " State: %s (0x%x)\n" 01777 " Image Filename: %s\n", 01778 (Argc < 2) ? "Current process:\n" : "", 01779 Process->UniqueProcessId, 01780 State, Process->Pcb.State, 01781 Process->ImageFileName); 01782 01783 /* Release our reference, if any */ 01784 if (ReferencedProcess) 01785 ObDereferenceObject(Process); 01786 } 01787 01788 return TRUE; 01789 } 01790 01793 static BOOLEAN 01794 KdbpCmdMod( 01795 ULONG Argc, 01796 PCHAR Argv[]) 01797 { 01798 ULONGLONG Result = 0; 01799 ULONG_PTR Address; 01800 PLDR_DATA_TABLE_ENTRY LdrEntry; 01801 BOOLEAN DisplayOnlyOneModule = FALSE; 01802 INT i = 0; 01803 01804 if (Argc >= 2) 01805 { 01806 /* Put the arguments back together */ 01807 Argc--; 01808 while (--Argc >= 1) 01809 Argv[Argc][strlen(Argv[Argc])] = ' '; 01810 01811 /* Evaluate the expression */ 01812 if (!KdbpEvaluateExpression(Argv[1], sizeof("kdb:> ")-1 + (Argv[1]-Argv[0]), &Result)) 01813 { 01814 return TRUE; 01815 } 01816 01817 if (Result > (ULONGLONG)(~((ULONG_PTR)0))) 01818 KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result); 01819 01820 Address = (ULONG_PTR)Result; 01821 01822 if (!KdbpSymFindModule((PVOID)Address, NULL, -1, &LdrEntry)) 01823 { 01824 KdbpPrint("No module containing address 0x%p found!\n", Address); 01825 return TRUE; 01826 } 01827 01828 DisplayOnlyOneModule = TRUE; 01829 } 01830 else 01831 { 01832 if (!KdbpSymFindModule(NULL, NULL, 0, &LdrEntry)) 01833 { 01834 ULONG_PTR ntoskrnlBase = ((ULONG_PTR)KdbpCmdMod) & 0xfff00000; 01835 KdbpPrint(" Base Size Name\n"); 01836 KdbpPrint(" %08x %08x %s\n", ntoskrnlBase, 0, "ntoskrnl.exe"); 01837 return TRUE; 01838 } 01839 01840 i = 1; 01841 } 01842 01843 KdbpPrint(" Base Size Name\n"); 01844 for (;;) 01845 { 01846 KdbpPrint(" %08x %08x %wZ\n", LdrEntry->DllBase, LdrEntry->SizeOfImage, &LdrEntry->BaseDllName); 01847 01848 if(DisplayOnlyOneModule || !KdbpSymFindModule(NULL, NULL, i++, &LdrEntry)) 01849 break; 01850 } 01851 01852 return TRUE; 01853 } 01854 01857 static BOOLEAN 01858 KdbpCmdGdtLdtIdt( 01859 ULONG Argc, 01860 PCHAR Argv[]) 01861 { 01862 KDESCRIPTOR Reg; 01863 ULONG SegDesc[2]; 01864 ULONG SegBase; 01865 ULONG SegLimit; 01866 PCHAR SegType; 01867 USHORT SegSel; 01868 UCHAR Type, Dpl; 01869 INT i; 01870 ULONG ul; 01871 01872 if (Argv[0][0] == 'i') 01873 { 01874 /* Read IDTR */ 01875 __sidt(&Reg.Limit); 01876 01877 if (Reg.Limit < 7) 01878 { 01879 KdbpPrint("Interrupt descriptor table is empty.\n"); 01880 return TRUE; 01881 } 01882 01883 KdbpPrint("IDT Base: 0x%08x Limit: 0x%04x\n", Reg.Base, Reg.Limit); 01884 KdbpPrint(" Idx Type Seg. Sel. Offset DPL\n"); 01885 01886 for (i = 0; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) 01887 { 01888 if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) 01889 { 01890 KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); 01891 return TRUE; 01892 } 01893 01894 Dpl = ((SegDesc[1] >> 13) & 3); 01895 if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 01896 SegType = "TASKGATE"; 01897 else if ((SegDesc[1] & 0x1fe0) == 0x0e00) /* 32 bit Interrupt gate */ 01898 SegType = "INTGATE32"; 01899 else if ((SegDesc[1] & 0x1fe0) == 0x0600) /* 16 bit Interrupt gate */ 01900 SegType = "INTGATE16"; 01901 else if ((SegDesc[1] & 0x1fe0) == 0x0f00) /* 32 bit Trap gate */ 01902 SegType = "TRAPGATE32"; 01903 else if ((SegDesc[1] & 0x1fe0) == 0x0700) /* 16 bit Trap gate */ 01904 SegType = "TRAPGATE16"; 01905 else 01906 SegType = "UNKNOWN"; 01907 01908 if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ 01909 { 01910 KdbpPrint(" %03d %-10s [NP] [NP] %02d\n", 01911 i / 8, SegType, Dpl); 01912 } 01913 else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 01914 { 01915 SegSel = SegDesc[0] >> 16; 01916 KdbpPrint(" %03d %-10s 0x%04x %02d\n", 01917 i / 8, SegType, SegSel, Dpl); 01918 } 01919 else 01920 { 01921 SegSel = SegDesc[0] >> 16; 01922 SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff); 01923 KdbpPrint(" %03d %-10s 0x%04x 0x%08x %02d\n", 01924 i / 8, SegType, SegSel, SegBase, Dpl); 01925 } 01926 } 01927 } 01928 else 01929 { 01930 ul = 0; 01931 01932 if (Argv[0][0] == 'g') 01933 { 01934 /* Read GDTR */ 01935 Ke386GetGlobalDescriptorTable(&Reg.Limit); 01936 i = 8; 01937 } 01938 else 01939 { 01940 ASSERT(Argv[0][0] == 'l'); 01941 01942 /* Read LDTR */ 01943 Reg.Limit = Ke386GetLocalDescriptorTable(); 01944 Reg.Base = 0; 01945 i = 0; 01946 ul = 1 << 2; 01947 } 01948 01949 if (Reg.Limit < 7) 01950 { 01951 KdbpPrint("%s descriptor table is empty.\n", 01952 Argv[0][0] == 'g' ? "Global" : "Local"); 01953 return TRUE; 01954 } 01955 01956 KdbpPrint("%cDT Base: 0x%08x Limit: 0x%04x\n", 01957 Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit); 01958 KdbpPrint(" Idx Sel. Type Base Limit DPL Attribs\n"); 01959 01960 for (; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8) 01961 { 01962 if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)(Reg.Base + i), sizeof(SegDesc)))) 01963 { 01964 KdbpPrint("Couldn't access memory at 0x%08x!\n", Reg.Base + i); 01965 return TRUE; 01966 } 01967 01968 Dpl = ((SegDesc[1] >> 13) & 3); 01969 Type = ((SegDesc[1] >> 8) & 0xf); 01970 01971 SegBase = SegDesc[0] >> 16; 01972 SegBase |= (SegDesc[1] & 0xff) << 16; 01973 SegBase |= SegDesc[1] & 0xff000000; 01974 SegLimit = SegDesc[0] & 0x0000ffff; 01975 SegLimit |= (SegDesc[1] >> 16) & 0xf; 01976 01977 if ((SegDesc[1] & (1 << 23)) != 0) 01978 { 01979 SegLimit *= 4096; 01980 SegLimit += 4095; 01981 } 01982 else 01983 { 01984 SegLimit++; 01985 } 01986 01987 if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ 01988 { 01989 switch (Type) 01990 { 01991 case 1: SegType = "TSS16(Avl)"; break; 01992 case 2: SegType = "LDT"; break; 01993 case 3: SegType = "TSS16(Busy)"; break; 01994 case 4: SegType = "CALLGATE16"; break; 01995 case 5: SegType = "TASKGATE"; break; 01996 case 6: SegType = "INTGATE16"; break; 01997 case 7: SegType = "TRAPGATE16"; break; 01998 case 9: SegType = "TSS32(Avl)"; break; 01999 case 11: SegType = "TSS32(Busy)"; break; 02000 case 12: SegType = "CALLGATE32"; break; 02001 case 14: SegType = "INTGATE32"; break; 02002 case 15: SegType = "INTGATE32"; break; 02003 default: SegType = "UNKNOWN"; break; 02004 } 02005 02006 if (!(Type >= 1 && Type <= 3) && 02007 Type != 9 && Type != 11) 02008 { 02009 SegBase = 0; 02010 SegLimit = 0; 02011 } 02012 } 02013 else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ 02014 { 02015 if ((SegDesc[1] & (1 << 22)) != 0) 02016 SegType = "DATA32"; 02017 else 02018 SegType = "DATA16"; 02019 } 02020 else /* Code segment */ 02021 { 02022 if ((SegDesc[1] & (1 << 22)) != 0) 02023 SegType = "CODE32"; 02024 else 02025 SegType = "CODE16"; 02026 } 02027 02028 if ((SegDesc[1] & (1 << 15)) == 0) /* not present */ 02029 { 02030 KdbpPrint(" %03d 0x%04x %-11s [NP] [NP] %02d NP\n", 02031 i / 8, i | Dpl | ul, SegType, Dpl); 02032 } 02033 else 02034 { 02035 KdbpPrint(" %03d 0x%04x %-11s 0x%08x 0x%08x %02d ", 02036 i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl); 02037 02038 if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */ 02039 { 02040 /* FIXME: Display system segment */ 02041 } 02042 else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */ 02043 { 02044 if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */ 02045 KdbpPrint(" E"); 02046 02047 KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R"); 02048 02049 if ((SegDesc[1] & (1 << 8)) != 0) 02050 KdbpPrint(" A"); 02051 } 02052 else /* Code segment */ 02053 { 02054 if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */ 02055 KdbpPrint(" C"); 02056 02057 KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X"); 02058 02059 if ((SegDesc[1] & (1 << 8)) != 0) 02060 KdbpPrint(" A"); 02061 } 02062 02063 if ((SegDesc[1] & (1 << 20)) != 0) 02064 KdbpPrint(" AVL"); 02065 02066 KdbpPrint("\n"); 02067 } 02068 } 02069 } 02070 02071 return TRUE; 02072 } 02073 02076 static BOOLEAN 02077 KdbpCmdPcr( 02078 ULONG Argc, 02079 PCHAR Argv[]) 02080 { 02081 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 02082 02083 KdbpPrint("Current PCR is at 0x%08x.\n", (INT)Pcr); 02084 KdbpPrint(" Tib.ExceptionList: 0x%08x\n" 02085 " Tib.StackBase: 0x%08x\n" 02086 " Tib.StackLimit: 0x%08x\n" 02087 " Tib.SubSystemTib: 0x%08x\n" 02088 " Tib.FiberData/Version: 0x%08x\n" 02089 " Tib.ArbitraryUserPointer: 0x%08x\n" 02090 " Tib.Self: 0x%08x\n" 02091 " Self: 0x%08x\n" 02092 " PCRCB: 0x%08x\n" 02093 " Irql: 0x%02x\n" 02094 " IRR: 0x%08x\n" 02095 " IrrActive: 0x%08x\n" 02096 " IDR: 0x%08x\n" 02097 " KdVersionBlock: 0x%08x\n" 02098 " IDT: 0x%08x\n" 02099 " GDT: 0x%08x\n" 02100 " TSS: 0x%08x\n" 02101 " MajorVersion: 0x%04x\n" 02102 " MinorVersion: 0x%04x\n" 02103 " SetMember: 0x%08x\n" 02104 " StallScaleFactor: 0x%08x\n" 02105 " Number: 0x%02x\n" 02106 " L2CacheAssociativity: 0x%02x\n" 02107 " VdmAlert: 0x%08x\n" 02108 " L2CacheSize: 0x%08x\n" 02109 " InterruptMode: 0x%08x\n", 02110 Pcr->NtTib.ExceptionList, Pcr->NtTib.StackBase, Pcr->NtTib.StackLimit, 02111 Pcr->NtTib.SubSystemTib, Pcr->NtTib.FiberData, Pcr->NtTib.ArbitraryUserPointer, 02112 Pcr->NtTib.Self, Pcr->Self, Pcr->Prcb, Pcr->Irql, Pcr->IRR, Pcr->IrrActive, 02113 Pcr->IDR, Pcr->KdVersionBlock, Pcr->IDT, Pcr->GDT, Pcr->TSS, 02114 Pcr->MajorVersion, Pcr->MinorVersion, Pcr->SetMember, Pcr->StallScaleFactor, 02115 Pcr->Number, Pcr->SecondLevelCacheAssociativity, 02116 Pcr->VdmAlert, Pcr->SecondLevelCacheSize, Pcr->InterruptMode); 02117 02118 return TRUE; 02119 } 02120 02123 static BOOLEAN 02124 KdbpCmdTss( 02125 ULONG Argc, 02126 PCHAR Argv[]) 02127 { 02128 KTSS *Tss = KeGetPcr()->TSS; 02129 02130 KdbpPrint("Current TSS is at 0x%08x.\n", (INT)Tss); 02131 KdbpPrint(" Eip: 0x%08x\n" 02132 " Es: 0x%04x\n" 02133 " Cs: 0x%04x\n" 02134 " Ss: 0x%04x\n" 02135 " Ds: 0x%04x\n" 02136 " Fs: 0x%04x\n" 02137 " Gs: 0x%04x\n" 02138 " IoMapBase: 0x%04x\n", 02139 Tss->Eip, Tss->Es, Tss->Cs, Tss->Ds, Tss->Fs, Tss->Gs, Tss->IoMapBase); 02140 02141 return TRUE; 02142 } 02143 02146 static BOOLEAN 02147 KdbpCmdBugCheck( 02148 ULONG Argc, 02149 PCHAR Argv[]) 02150 { 02151 /* Set the flag and quit looping */ 02152 KdbpBugCheckRequested = TRUE; 02153 02154 return FALSE; 02155 } 02156 02157 VOID 02158 KdbpPager( 02159 IN PCHAR Buffer, 02160 IN ULONG BufLength); 02161 02167 static BOOLEAN 02168 KdbpCmdDmesg( 02169 ULONG Argc, 02170 PCHAR Argv[]) 02171 { 02172 ULONG beg, end; 02173 02174 KdbpIsInDmesgMode = TRUE; /* Toggle logging flag */ 02175 if (!KdpDmesgBuffer) 02176 { 02177 KdbpPrint("Dmesg: error, buffer is not allocated! /DEBUGPORT=SCREEN kernel param required for dmesg.\n"); 02178 return TRUE; 02179 } 02180 02181 KdbpPrint("*** Dmesg *** TotalWritten=%lu, BufferSize=%lu, CurrentPosition=%lu\n", 02182 KdbDmesgTotalWritten, KdpDmesgBufferSize, KdpDmesgCurrentPosition); 02183 02184 // Pass data to the pager: 02185 end = KdpDmesgCurrentPosition; 02186 beg = (end + KdpDmesgFreeBytes) % KdpDmesgBufferSize; 02187 02188 // no roll-overs, and overwritten=lost bytes 02189 if (KdbDmesgTotalWritten <= KdpDmesgBufferSize) 02190 { 02191 // show buffer (KdpDmesgBuffer + beg, num) 02192 KdbpPager(KdpDmesgBuffer, KdpDmesgCurrentPosition); 02193 } 02194 else 02195 { 02196 // show 2 buffers: (KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg) 02197 // and: (KdpDmesgBuffer, end) 02198 KdbpPager(KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg); 02199 KdbpPrint("*** Dmesg: buffer rollup ***\n"); 02200 KdbpPager(KdpDmesgBuffer, end); 02201 } 02202 KdbpPrint("*** Dmesg: end of output ***\n"); 02203 02204 KdbpIsInDmesgMode = FALSE; /* Toggle logging flag */ 02205 02206 return TRUE; 02207 } 02208 02211 static BOOLEAN 02212 KdbpCmdSet( 02213 ULONG Argc, 02214 PCHAR Argv[]) 02215 { 02216 LONG l; 02217 BOOLEAN First; 02218 PCHAR pend = 0; 02219 KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter; 02220 KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter; 02221 02222 static const PCHAR ExceptionNames[21] = 02223 { 02224 "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP", 02225 "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT", 02226 "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK", 02227 "MACHINECHECK", "SIMDFAULT", "OTHERS" 02228 }; 02229 02230 if (Argc == 1) 02231 { 02232 KdbpPrint("Available settings:\n"); 02233 KdbpPrint(" syntax [intel|at&t]\n"); 02234 KdbpPrint(" condition [exception|*] [first|last] [never|always|kmode|umode]\n"); 02235 KdbpPrint(" break_on_module_load [true|false]\n"); 02236 } 02237 else if (strcmp(Argv[1], "syntax") == 0) 02238 { 02239 if (Argc == 2) 02240 { 02241 KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t"); 02242 } 02243 else if (Argc >= 3) 02244 { 02245 if (_stricmp(Argv[2], "intel") == 0) 02246 KdbUseIntelSyntax = TRUE; 02247 else if (_stricmp(Argv[2], "at&t") == 0) 02248 KdbUseIntelSyntax = FALSE; 02249 else 02250 KdbpPrint("Unknown syntax '%s'.\n", Argv[2]); 02251 } 02252 } 02253 else if (strcmp(Argv[1], "condition") == 0) 02254 { 02255 if (Argc == 2) 02256 { 02257 KdbpPrint("Conditions: (First) (Last)\n"); 02258 for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++) 02259 { 02260 if (!ExceptionNames[l]) 02261 continue; 02262 02263 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) 02264 ASSERT(0); 02265 02266 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) 02267 ASSERT(0); 02268 02269 KdbpPrint(" #%02d %-20s %-8s %-8s\n", l, ExceptionNames[l], 02270 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 02271 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 02272 } 02273 02274 ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1)); 02275 KdbpPrint(" %-20s %-8s %-8s\n", ExceptionNames[l], 02276 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 02277 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 02278 } 02279 else 02280 { 02281 if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */ 02282 { 02283 l = -1; 02284 } 02285 else 02286 { 02287 l = strtoul(Argv[2], &pend, 0); 02288 02289 if (Argv[2] == pend) 02290 { 02291 for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++) 02292 { 02293 if (!ExceptionNames[l]) 02294 continue; 02295 02296 if (_stricmp(ExceptionNames[l], Argv[2]) == 0) 02297 break; 02298 } 02299 } 02300 02301 if (l >= RTL_NUMBER_OF(ExceptionNames)) 02302 { 02303 KdbpPrint("Unknown exception '%s'.\n", Argv[2]); 02304 return TRUE; 02305 } 02306 } 02307 02308 if (Argc > 4) 02309 { 02310 if (_stricmp(Argv[3], "first") == 0) 02311 First = TRUE; 02312 else if (_stricmp(Argv[3], "last") == 0) 02313 First = FALSE; 02314 else 02315 { 02316 KdbpPrint("set condition: second argument must be 'first' or 'last'\n"); 02317 return TRUE; 02318 } 02319 02320 if (_stricmp(Argv[4], "never") == 0) 02321 ConditionFirst = KdbDoNotEnter; 02322 else if (_stricmp(Argv[4], "always") == 0) 02323 ConditionFirst = KdbEnterAlways; 02324 else if (_stricmp(Argv[4], "umode") == 0) 02325 ConditionFirst = KdbEnterFromUmode; 02326 else if (_stricmp(Argv[4], "kmode") == 0) 02327 ConditionFirst = KdbEnterFromKmode; 02328 else 02329 { 02330 KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n"); 02331 return TRUE; 02332 } 02333 02334 if (!KdbpSetEnterCondition(l, First, ConditionFirst)) 02335 { 02336 if (l >= 0) 02337 KdbpPrint("Couldn't change condition for exception #%02d\n", l); 02338 else 02339 KdbpPrint("Couldn't change condition for all exceptions\n", l); 02340 } 02341 } 02342 else /* Argc >= 3 */ 02343 { 02344 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst)) 02345 ASSERT(0); 02346 02347 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast)) 02348 ASSERT(0); 02349 02350 if (l < (RTL_NUMBER_OF(ExceptionNames) - 1)) 02351 { 02352 KdbpPrint("Condition for exception #%02d (%s): FirstChance %s LastChance %s\n", 02353 l, ExceptionNames[l], 02354 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 02355 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 02356 } 02357 else 02358 { 02359 KdbpPrint("Condition for all other exceptions: FirstChance %s LastChance %s\n", 02360 KDB_ENTER_CONDITION_TO_STRING(ConditionFirst), 02361 KDB_ENTER_CONDITION_TO_STRING(ConditionLast)); 02362 } 02363 } 02364 } 02365 } 02366 else if (strcmp(Argv[1], "break_on_module_load") == 0) 02367 { 02368 if (Argc == 2) 02369 KdbpPrint("break_on_module_load = %s\n", KdbBreakOnModuleLoad ? "enabled" : "disabled"); 02370 else if (Argc >= 3) 02371 { 02372 if (_stricmp(Argv[2], "enable") == 0 || _stricmp(Argv[2], "enabled") == 0 || _stricmp(Argv[2], "true") == 0) 02373 KdbBreakOnModuleLoad = TRUE; 02374 else if (_stricmp(Argv[2], "disable") == 0 || _stricmp(Argv[2], "disabled") == 0 || _stricmp(Argv[2], "false") == 0) 02375 KdbBreakOnModuleLoad = FALSE; 02376 else 02377 KdbpPrint("Unknown setting '%s'.\n", Argv[2]); 02378 } 02379 } 02380 else 02381 { 02382 KdbpPrint("Unknown setting '%s'.\n", Argv[1]); 02383 } 02384 02385 return TRUE; 02386 } 02387 02390 static BOOLEAN 02391 KdbpCmdHelp( 02392 ULONG Argc, 02393 PCHAR Argv[]) 02394 { 02395 ULONG i; 02396 02397 KdbpPrint("Kernel debugger commands:\n"); 02398 for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) 02399 { 02400 if (!KdbDebuggerCommands[i].Syntax) /* Command group */ 02401 { 02402 if (i > 0) 02403 KdbpPrint("\n"); 02404 02405 KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help); 02406 continue; 02407 } 02408 02409 KdbpPrint(" %-20s - %s\n", 02410 KdbDebuggerCommands[i].Syntax, 02411 KdbDebuggerCommands[i].Help); 02412 } 02413 02414 return TRUE; 02415 } 02416 02426 VOID 02427 KdbpPrint( 02428 IN PCHAR Format, 02429 IN ... OPTIONAL) 02430 { 02431 static CHAR Buffer[4096]; 02432 static BOOLEAN TerminalInitialized = FALSE; 02433 static BOOLEAN TerminalConnected = FALSE; 02434 static BOOLEAN TerminalReportsSize = TRUE; 02435 CHAR c = '\0'; 02436 PCHAR p, p2; 02437 ULONG Length; 02438 ULONG i, j; 02439 LONG RowsPrintedByTerminal; 02440 ULONG ScanCode; 02441 va_list ap; 02442 02443 /* Check if the user has aborted output of the current command */ 02444 if (KdbOutputAborted) 02445 return; 02446 02447 /* Initialize the terminal */ 02448 if (!TerminalInitialized) 02449 { 02450 DbgPrint("\x1b[7h"); /* Enable linewrap */ 02451 02452 /* Query terminal type */ 02453 /*DbgPrint("\x1b[Z");*/ 02454 DbgPrint("\x05"); 02455 02456 TerminalInitialized = TRUE; 02457 Length = 0; 02458 KeStallExecutionProcessor(100000); 02459 02460 for (;;) 02461 { 02462 c = KdbpTryGetCharSerial(5000); 02463 if (c == -1) 02464 break; 02465 02466 Buffer[Length++] = c; 02467 if (Length >= (sizeof (Buffer) - 1)) 02468 break; 02469 } 02470 02471 Buffer[Length] = '\0'; 02472 if (Length > 0) 02473 TerminalConnected = TRUE; 02474 } 02475 02476 /* Get number of rows and columns in terminal */ 02477 if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) || 02478 (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */ 02479 { 02480 if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize) 02481 { 02482 /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ 02483 TerminalReportsSize = FALSE; 02484 KeStallExecutionProcessor(100000); 02485 DbgPrint("\x1b[18t"); 02486 c = KdbpTryGetCharSerial(5000); 02487 02488 if (c == KEY_ESC) 02489 { 02490 c = KdbpTryGetCharSerial(5000); 02491 if (c == '[') 02492 { 02493 Length = 0; 02494 02495 for (;;) 02496 { 02497 c = KdbpTryGetCharSerial(5000); 02498 if (c == -1) 02499 break; 02500 02501 Buffer[Length++] = c; 02502 if (isalpha(c) || Length >= (sizeof (Buffer) - 1)) 02503 break; 02504 } 02505 02506 Buffer[Length] = '\0'; 02507 if (Buffer[0] == '8' && Buffer[1] == ';') 02508 { 02509 for (i = 2; (i < Length) && (Buffer[i] != ';'); i++); 02510 02511 if (Buffer[i] == ';') 02512 { 02513 Buffer[i++] = '\0'; 02514 02515 /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */ 02516 KdbNumberOfRowsTerminal = strtoul(Buffer + 2, NULL, 0); 02517 KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0); 02518 TerminalReportsSize = TRUE; 02519 } 02520 } 02521 } 02522 /* Clear further characters */ 02523 while ((c = KdbpTryGetCharSerial(5000)) != -1); 02524 } 02525 } 02526 02527 if (KdbNumberOfRowsTerminal <= 0) 02528 { 02529 /* Set number of rows to the default. */ 02530 KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport 02531 } 02532 else if (KdbNumberOfColsTerminal <= 0) 02533 { 02534 /* Set number of cols to the default. */ 02535 KdbNumberOfColsTerminal = 75; //80; //Mna.: 75 for SCREEN debugport 02536 } 02537 } 02538 02539 /* Get the string */ 02540 va_start(ap, Format); 02541 Length = _vsnprintf(Buffer, sizeof (Buffer) - 1, Format, ap); 02542 Buffer[Length] = '\0'; 02543 va_end(ap); 02544 02545 p = Buffer; 02546 while (p[0] != '\0') 02547 { 02548 i = strcspn(p, "\n"); 02549 02550 /* Calculate the number of lines which will be printed in the terminal 02551 * when outputting the current line 02552 */ 02553 if (i > 0) 02554 RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal; 02555 else 02556 RowsPrintedByTerminal = 0; 02557 02558 if (p[i] == '\n') 02559 RowsPrintedByTerminal++; 02560 02561 /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/ 02562 02563 /* Display a prompt if we printed one screen full of text */ 02564 if (KdbNumberOfRowsTerminal > 0 && 02565 (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) 02566 { 02567 KdbRepeatLastCommand = FALSE; 02568 02569 if (KdbNumberOfColsPrinted > 0) 02570 DbgPrint("\n"); 02571 02572 DbgPrint("--- Press q to abort, any other key to continue ---"); 02573 RowsPrintedByTerminal++; /* added by Mna. */ 02574 02575 if (KdbDebugState & KD_DEBUG_KDSERIAL) 02576 c = KdbpGetCharSerial(); 02577 else 02578 c = KdbpGetCharKeyboard(&ScanCode); 02579 02580 if (c == '\r') 02581 { 02582 /* Try to read '\n' which might follow '\r' - if \n is not received here 02583 * it will be interpreted as "return" when the next command should be read. 02584 */ 02585 if (KdbDebugState & KD_DEBUG_KDSERIAL) 02586 c = KdbpTryGetCharSerial(5); 02587 else 02588 c = KdbpTryGetCharKeyboard(&ScanCode, 5); 02589 } 02590 02591 DbgPrint("\n"); 02592 if (c == 'q') 02593 { 02594 KdbOutputAborted = TRUE; 02595 return; 02596 } 02597 02598 KdbNumberOfRowsPrinted = 0; 02599 KdbNumberOfColsPrinted = 0; 02600 } 02601 02602 /* Insert a NUL after the line and print only the current line. */ 02603 if (p[i] == '\n' && p[i + 1] != '\0') 02604 { 02605 c = p[i + 1]; 02606 p[i + 1] = '\0'; 02607 } 02608 else 02609 { 02610 c = '\0'; 02611 } 02612 02613 /* Remove escape sequences from the line if there's no terminal connected */ 02614 if (!TerminalConnected) 02615 { 02616 while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */ 02617 { 02618 if (p2[1] == '[') 02619 { 02620 j = 2; 02621 while (!isalpha(p2[j++])); 02622 strcpy(p2, p2 + j); 02623 } 02624 else 02625 { 02626 strcpy(p2, p2 + 1); 02627 } 02628 } 02629 } 02630 02631 DbgPrint("%s", p); 02632 02633 if (c != '\0') 02634 p[i + 1] = c; 02635 02636 /* Set p to the start of the next line and 02637 * remember the number of rows/cols printed 02638 */ 02639 p += i; 02640 if (p[0] == '\n') 02641 { 02642 p++; 02643 KdbNumberOfColsPrinted = 0; 02644 } 02645 else 02646 { 02647 ASSERT(p[0] == '\0'); 02648 KdbNumberOfColsPrinted += i; 02649 } 02650 02651 KdbNumberOfRowsPrinted += RowsPrintedByTerminal; 02652 } 02653 } 02654 02656 /* 02657 * Reverse memchr() 02658 * Find the last occurrence of 'c' in the buffer 's' of size 'n'. 02659 */ 02660 void * 02661 memrchr(const void *s, int c, size_t n) 02662 { 02663 const unsigned char *cp; 02664 02665 if (n != 0) 02666 { 02667 cp = (unsigned char *)s + n; 02668 do 02669 { 02670 if (*(--cp) == (unsigned char)c) 02671 return (void *)cp; 02672 } while (--n != 0); 02673 } 02674 return NULL; 02675 } 02676 02688 PCHAR 02689 CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos) 02690 { 02691 PCHAR p; 02692 // p0 is initial guess of Page Start 02693 ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal; 02694 PCHAR p0 = pCurPos - p0len; 02695 PCHAR prev_p = p0, p1; 02696 ULONG j; 02697 02698 if (pCurPos < Buffer) 02699 pCurPos = Buffer; 02700 ASSERT(pCurPos <= Buffer + BufLength); 02701 02702 p = memrchr(p0, '\n', p0len); 02703 if (NULL == p) 02704 p = p0; 02705 for (j = KdbNumberOfRowsTerminal; j--; ) 02706 { 02707 int linesCnt; 02708 p1 = memrchr(p0, '\n', p-p0); 02709 prev_p = p; 02710 p = p1; 02711 if (NULL == p) 02712 { 02713 p = prev_p; 02714 if (NULL == p) 02715 p = p0; 02716 break; 02717 } 02718 linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal; 02719 if (linesCnt > 1) 02720 j -= linesCnt-1; 02721 } 02722 02723 ASSERT(p != 0); 02724 ++p; 02725 return p; 02726 } 02727 02740 VOID 02741 KdbpPager( 02742 IN PCHAR Buffer, 02743 IN ULONG BufLength) 02744 { 02745 static CHAR InBuffer[4096]; 02746 static BOOLEAN TerminalInitialized = FALSE; 02747 static BOOLEAN TerminalConnected = FALSE; 02748 static BOOLEAN TerminalReportsSize = TRUE; 02749 CHAR c = '\0'; 02750 PCHAR p, p2; 02751 ULONG Length; 02752 ULONG i, j; 02753 LONG RowsPrintedByTerminal; 02754 ULONG ScanCode; 02755 02756 if( BufLength == 0) 02757 return; 02758 02759 /* Check if the user has aborted output of the current command */ 02760 if (KdbOutputAborted) 02761 return; 02762 02763 /* Initialize the terminal */ 02764 if (!TerminalInitialized) 02765 { 02766 DbgPrint("\x1b[7h"); /* Enable linewrap */ 02767 02768 /* Query terminal type */ 02769 /*DbgPrint("\x1b[Z");*/ 02770 DbgPrint("\x05"); 02771 02772 TerminalInitialized = TRUE; 02773 Length = 0; 02774 KeStallExecutionProcessor(100000); 02775 02776 for (;;) 02777 { 02778 c = KdbpTryGetCharSerial(5000); 02779 if (c == -1) 02780 break; 02781 02782 InBuffer[Length++] = c; 02783 if (Length >= (sizeof (InBuffer) - 1)) 02784 break; 02785 } 02786 02787 InBuffer[Length] = '\0'; 02788 if (Length > 0) 02789 TerminalConnected = TRUE; 02790 } 02791 02792 /* Get number of rows and columns in terminal */ 02793 if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) || 02794 (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */ 02795 { 02796 if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize) 02797 { 02798 /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */ 02799 TerminalReportsSize = FALSE; 02800 KeStallExecutionProcessor(100000); 02801 DbgPrint("\x1b[18t"); 02802 c = KdbpTryGetCharSerial(5000); 02803 02804 if (c == KEY_ESC) 02805 { 02806 c = KdbpTryGetCharSerial(5000); 02807 if (c == '[') 02808 { 02809 Length = 0; 02810 02811 for (;;) 02812 { 02813 c = KdbpTryGetCharSerial(5000); 02814 if (c == -1) 02815 break; 02816 02817 InBuffer[Length++] = c; 02818 if (isalpha(c) || Length >= (sizeof (InBuffer) - 1)) 02819 break; 02820 } 02821 02822 InBuffer[Length] = '\0'; 02823 if (InBuffer[0] == '8' && InBuffer[1] == ';') 02824 { 02825 for (i = 2; (i < Length) && (InBuffer[i] != ';'); i++); 02826 02827 if (Buffer[i] == ';') 02828 { 02829 Buffer[i++] = '\0'; 02830 02831 /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */ 02832 KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0); 02833 KdbNumberOfColsTerminal = strtoul(InBuffer + i, NULL, 0); 02834 TerminalReportsSize = TRUE; 02835 } 02836 } 02837 } 02838 /* Clear further characters */ 02839 while ((c = KdbpTryGetCharSerial(5000)) != -1); 02840 } 02841 } 02842 02843 if (KdbNumberOfRowsTerminal <= 0) 02844 { 02845 /* Set number of rows to the default. */ 02846 KdbNumberOfRowsTerminal = 24; 02847 } 02848 else if (KdbNumberOfColsTerminal <= 0) 02849 { 02850 /* Set number of cols to the default. */ 02851 KdbNumberOfColsTerminal = 80; 02852 } 02853 } 02854 02855 /* Get the string */ 02856 p = Buffer; 02857 02858 while (p[0] != '\0') 02859 { 02860 if ( p > Buffer+BufLength) 02861 { 02862 DbgPrint("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer+BufLength)); 02863 return; 02864 } 02865 i = strcspn(p, "\n"); 02866 02867 // Are we out of buffer? 02868 if (p + i > Buffer + BufLength) 02869 // Leaving pager function: 02870 break; 02871 02872 /* Calculate the number of lines which will be printed in the terminal 02873 * when outputting the current line 02874 */ 02875 if (i > 0) 02876 RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal; 02877 else 02878 RowsPrintedByTerminal = 0; 02879 02880 if (p[i] == '\n') 02881 RowsPrintedByTerminal++; 02882 02883 /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/ 02884 02885 /* Display a prompt if we printed one screen full of text */ 02886 if (KdbNumberOfRowsTerminal > 0 && 02887 (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal) 02888 { 02889 KdbRepeatLastCommand = FALSE; 02890 02891 if (KdbNumberOfColsPrinted > 0) 02892 DbgPrint("\n"); 02893 02894 DbgPrint("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---"); 02895 RowsPrintedByTerminal++; 02896 02897 if (KdbDebugState & KD_DEBUG_KDSERIAL) 02898 c = KdbpGetCharSerial(); 02899 else 02900 c = KdbpGetCharKeyboard(&ScanCode); 02901 02902 if (c == '\r') 02903 { 02904 /* Try to read '\n' which might follow '\r' - if \n is not received here 02905 * it will be interpreted as "return" when the next command should be read. 02906 */ 02907 if (KdbDebugState & KD_DEBUG_KDSERIAL) 02908 c = KdbpTryGetCharSerial(5); 02909 else 02910 c = KdbpTryGetCharKeyboard(&ScanCode, 5); 02911 } 02912 02913 //DbgPrint("\n"); //Consize version: don't show pressed key 02914 DbgPrint(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key 02915 02916 if (c == 'q') 02917 { 02918 KdbOutputAborted = TRUE; 02919 return; 02920 } 02921 if ( ScanCode == KEYSC_END || c=='e') 02922 { 02923 PCHAR pBufEnd = Buffer + BufLength; 02924 p = CountOnePageUp(Buffer, BufLength, pBufEnd); 02925 i = strcspn(p, "\n"); 02926 } 02927 else if (ScanCode == KEYSC_PAGEUP || c=='u') 02928 { 02929 p = CountOnePageUp(Buffer, BufLength, p); 02930 i = strcspn(p, "\n"); 02931 } 02932 else if (ScanCode == KEYSC_HOME || c=='h') 02933 { 02934 p = Buffer; 02935 i = strcspn(p, "\n"); 02936 } 02937 else if (ScanCode == KEYSC_ARROWUP) 02938 { 02939 p = CountOnePageUp(Buffer, BufLength, p); 02940 i = strcspn(p, "\n"); 02941 } 02942 02943 KdbNumberOfRowsPrinted = 0; 02944 KdbNumberOfColsPrinted = 0; 02945 } 02946 02947 /* Insert a NUL after the line and print only the current line. */ 02948 if (p[i] == '\n' && p[i + 1] != '\0') 02949 { 02950 c = p[i + 1]; 02951 p[i + 1] = '\0'; 02952 } 02953 else 02954 { 02955 c = '\0'; 02956 } 02957 02958 /* Remove escape sequences from the line if there's no terminal connected */ 02959 if (!TerminalConnected) 02960 { 02961 while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */ 02962 { 02963 if (p2[1] == '[') 02964 { 02965 j = 2; 02966 while (!isalpha(p2[j++])); 02967 strcpy(p2, p2 + j); 02968 } 02969 else 02970 { 02971 strcpy(p2, p2 + 1); 02972 } 02973 } 02974 } 02975 02976 // The main printing of the current line: 02977 DbgPrint(p); 02978 02979 // restore not null char with saved: 02980 if (c != '\0') 02981 p[i + 1] = c; 02982 02983 /* Set p to the start of the next line and 02984 * remember the number of rows/cols printed 02985 */ 02986 p += i; 02987 if (p[0] == '\n') 02988 { 02989 p++; 02990 KdbNumberOfColsPrinted = 0; 02991 } 02992 else 02993 { 02994 ASSERT(p[0] == '\0'); 02995 KdbNumberOfColsPrinted += i; 02996 } 02997 02998 KdbNumberOfRowsPrinted += RowsPrintedByTerminal; 02999 } 03000 } 03001 03006 static VOID 03007 KdbpCommandHistoryAppend( 03008 IN PCHAR Command) 03009 { 03010 ULONG Length1 = strlen(Command) + 1; 03011 ULONG Length2 = 0; 03012 INT i; 03013 PCHAR Buffer; 03014 03015 ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer)); 03016 03017 if (Length1 <= 1 || 03018 (KdbCommandHistory[KdbCommandHistoryIndex] && 03019 strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0)) 03020 { 03021 return; 03022 } 03023 03024 /* Calculate Length1 and Length2 */ 03025 Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex; 03026 KdbCommandHistoryBufferIndex += Length1; 03027 if (KdbCommandHistoryBufferIndex >= (LONG)RTL_NUMBER_OF(KdbCommandHistoryBuffer)) 03028 { 03029 KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer); 03030 Length2 = KdbCommandHistoryBufferIndex; 03031 Length1 -= Length2; 03032 } 03033 03034 /* Remove previous commands until there is enough space to append the new command */ 03035 for (i = KdbCommandHistoryIndex; KdbCommandHistory[i];) 03036 { 03037 if ((Length2 > 0 && 03038 (KdbCommandHistory[i] >= Buffer || 03039 KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) || 03040 (Length2 <= 0 && 03041 (KdbCommandHistory[i] >= Buffer && 03042 KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex)))) 03043 { 03044 KdbCommandHistory[i] = NULL; 03045 } 03046 03047 i--; 03048 if (i < 0) 03049 i = RTL_NUMBER_OF(KdbCommandHistory) - 1; 03050 03051 if (i == KdbCommandHistoryIndex) 03052 break; 03053 } 03054 03055 /* Make sure the new command history entry is free */ 03056 KdbCommandHistoryIndex++; 03057 KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory); 03058 if (KdbCommandHistory[KdbCommandHistoryIndex]) 03059 { 03060 KdbCommandHistory[KdbCommandHistoryIndex] = NULL; 03061 } 03062 03063 /* Append command */ 03064 KdbCommandHistory[KdbCommandHistoryIndex] = Buffer; 03065 ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer)); 03066 memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1); 03067 if (Length2 > 0) 03068 { 03069 memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2); 03070 } 03071 } 03072 03080 static VOID 03081 KdbpReadCommand( 03082 OUT PCHAR Buffer, 03083 IN ULONG Size) 03084 { 03085 CHAR Key; 03086 PCHAR Orig = Buffer; 03087 ULONG ScanCode = 0; 03088 BOOLEAN EchoOn; 03089 static CHAR LastCommand[1024]; 03090 static CHAR NextKey = '\0'; 03091 INT CmdHistIndex = -1; 03092 INT i; 03093 03094 EchoOn = !((KdbDebugState & KD_DEBUG_KDNOECHO) != 0); 03095 03096 for (;;) 03097 { 03098 if (KdbDebugState & KD_DEBUG_KDSERIAL) 03099 { 03100 Key = (NextKey == '\0') ? KdbpGetCharSerial() : NextKey; 03101 NextKey = '\0'; 03102 ScanCode = 0; 03103 if (Key == KEY_ESC) /* ESC */ 03104 { 03105 Key = KdbpGetCharSerial(); 03106 if (Key == '[') 03107 { 03108 Key = KdbpGetCharSerial(); 03109 03110 switch (Key) 03111 { 03112 case 'A': 03113 ScanCode = KEY_SCAN_UP; 03114 break; 03115 case 'B': 03116 ScanCode = KEY_SCAN_DOWN; 03117 break; 03118 case 'C': 03119 break; 03120 case 'D': 03121 break; 03122 } 03123 } 03124 } 03125 } 03126 else 03127 { 03128 ScanCode = 0; 03129 Key = (NextKey == '\0') ? KdbpGetCharKeyboard(&ScanCode) : NextKey; 03130 NextKey = '\0'; 03131 } 03132 03133 if ((ULONG)(Buffer - Orig) >= (Size - 1)) 03134 { 03135 /* Buffer is full, accept only newlines */ 03136 if (Key != '\n') 03137 continue; 03138 } 03139 03140 if (Key == '\r') 03141 { 03142 /* Read the next char - this is to throw away a \n which most clients should 03143 * send after \r. 03144 */ 03145 KeStallExecutionProcessor(100000); 03146 03147 if (KdbDebugState & KD_DEBUG_KDSERIAL) 03148 NextKey = KdbpTryGetCharSerial(5); 03149 else 03150 NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5); 03151 03152 if (NextKey == '\n' || NextKey == -1) /* \n or no response at all */ 03153 NextKey = '\0'; 03154 03155 KdbpPrint("\n"); 03156 03157 /* 03158 * Repeat the last command if the user presses enter. Reduces the 03159 * risk of RSI when single-stepping. 03160 */ 03161 if (Buffer != Orig) 03162 { 03163 KdbRepeatLastCommand = TRUE; 03164 *Buffer = '\0'; 03165 RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Orig); 03166 } 03167 else if (KdbRepeatLastCommand) 03168 RtlStringCbCopyA(Buffer, Size, LastCommand); 03169 else 03170 *Buffer = '\0'; 03171 03172 return; 03173 } 03174 else if (Key == KEY_BS || Key == KEY_DEL) 03175 { 03176 if (Buffer > Orig) 03177 { 03178 Buffer--; 03179 *Buffer = 0; 03180 03181 if (EchoOn) 03182 KdbpPrint("%c %c", KEY_BS, KEY_BS); 03183 else 03184 KdbpPrint(" %c", KEY_BS); 03185 } 03186 } 03187 else if (ScanCode == KEY_SCAN_UP) 03188 { 03189 BOOLEAN Print = TRUE; 03190 03191 if (CmdHistIndex < 0) 03192 { 03193 CmdHistIndex = KdbCommandHistoryIndex; 03194 } 03195 else 03196 { 03197 i = CmdHistIndex - 1; 03198 03199 if (i < 0) 03200 CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1; 03201 03202 if (KdbCommandHistory[i] && i != KdbCommandHistoryIndex) 03203 CmdHistIndex = i; 03204 else 03205 Print = FALSE; 03206 } 03207 03208 if (Print && KdbCommandHistory[CmdHistIndex]) 03209 { 03210 while (Buffer > Orig) 03211 { 03212 Buffer--; 03213 *Buffer = 0; 03214 03215 if (EchoOn) 03216 KdbpPrint("%c %c", KEY_BS, KEY_BS); 03217 else 03218 KdbpPrint(" %c", KEY_BS); 03219 } 03220 03221 i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); 03222 memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); 03223 Orig[i] = '\0'; 03224 Buffer = Orig + i; 03225 KdbpPrint("%s", Orig); 03226 } 03227 } 03228 else if (ScanCode == KEY_SCAN_DOWN) 03229 { 03230 if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex) 03231 { 03232 i = CmdHistIndex + 1; 03233 if (i >= (INT)RTL_NUMBER_OF(KdbCommandHistory)) 03234 i = 0; 03235 03236 if (KdbCommandHistory[i]) 03237 { 03238 CmdHistIndex = i; 03239 while (Buffer > Orig) 03240 { 03241 Buffer--; 03242 *Buffer = 0; 03243 03244 if (EchoOn) 03245 KdbpPrint("%c %c", KEY_BS, KEY_BS); 03246 else 03247 KdbpPrint(" %c", KEY_BS); 03248 } 03249 03250 i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1); 03251 memcpy(Orig, KdbCommandHistory[CmdHistIndex], i); 03252 Orig[i] = '\0'; 03253 Buffer = Orig + i; 03254 KdbpPrint("%s", Orig); 03255 } 03256 } 03257 } 03258 else 03259 { 03260 if (EchoOn) 03261 KdbpPrint("%c", Key); 03262 03263 *Buffer = Key; 03264 Buffer++; 03265 } 03266 } 03267 } 03268 03276 static BOOLEAN 03277 KdbpDoCommand( 03278 IN PCHAR Command) 03279 { 03280 ULONG i; 03281 PCHAR p; 03282 ULONG Argc; 03283 static PCH Argv[256]; 03284 static CHAR OrigCommand[1024]; 03285 03286 RtlStringCbCopyA(OrigCommand, sizeof(OrigCommand), Command); 03287 03288 Argc = 0; 03289 p = Command; 03290 03291 for (;;) 03292 { 03293 while (*p == '\t' || *p == ' ') 03294 p++; 03295 03296 if (*p == '\0') 03297 break; 03298 03299 i = strcspn(p, "\t "); 03300 Argv[Argc++] = p; 03301 p += i; 03302 if (*p == '\0') 03303 break; 03304 03305 *p = '\0'; 03306 p++; 03307 } 03308 03309 if (Argc < 1) 03310 return TRUE; 03311 03312 for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++) 03313 { 03314 if (!KdbDebuggerCommands[i].Name) 03315 continue; 03316 03317 if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0) 03318 { 03319 return KdbDebuggerCommands[i].Fn(Argc, Argv); 03320 } 03321 } 03322 03323 KdbpPrint("Command '%s' is unknown.\n", OrigCommand); 03324 return TRUE; 03325 } 03326 03331 VOID 03332 KdbpCliMainLoop( 03333 IN BOOLEAN EnteredOnSingleStep) 03334 { 03335 static CHAR Command[1024]; 03336 BOOLEAN Continue; 03337 03338 if (EnteredOnSingleStep) 03339 { 03340 if (!KdbSymPrintAddress((PVOID)KdbCurrentTrapFrame->Tf.Eip, &KdbCurrentTrapFrame->Tf)) 03341 { 03342 KdbpPrint("<%x>", KdbCurrentTrapFrame->Tf.Eip); 03343 } 03344 03345 KdbpPrint(": "); 03346 if (KdbpDisassemble(KdbCurrentTrapFrame->Tf.Eip, KdbUseIntelSyntax) < 0) 03347 { 03348 KdbpPrint("<INVALID>"); 03349 } 03350 KdbpPrint("\n"); 03351 } 03352 03353 /* Flush the input buffer */ 03354 if (KdbDebugState & KD_DEBUG_KDSERIAL) 03355 { 03356 while (KdbpTryGetCharSerial(1) != -1); 03357 } 03358 else 03359 { 03360 ULONG ScanCode; 03361 while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1); 03362 } 03363 03364 /* Main loop */ 03365 do 03366 { 03367 /* Reset the number of rows/cols printed */ 03368 KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; 03369 03370 /* Print the prompt */ 03371 KdbpPrint("kdb:> "); 03372 03373 /* Read a command and remember it */ 03374 KdbpReadCommand(Command, sizeof (Command)); 03375 KdbpCommandHistoryAppend(Command); 03376 03377 /* Reset the number of rows/cols printed and output aborted state */ 03378 KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0; 03379 KdbOutputAborted = FALSE; 03380 03381 /* Call the command */ 03382 Continue = KdbpDoCommand(Command); 03383 KdbOutputAborted = FALSE; 03384 } 03385 while (Continue); 03386 } 03387 03392 VOID 03393 KdbpCliModuleLoaded( 03394 IN PUNICODE_STRING Name) 03395 { 03396 if (!KdbBreakOnModuleLoad) 03397 return; 03398 03399 KdbpPrint("Module %wZ loaded.\n", Name); 03400 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 03401 } 03402 03409 VOID 03410 KdbpCliInterpretInitFile() 03411 { 03412 PCHAR p1, p2; 03413 INT i; 03414 CHAR c; 03415 03416 /* Execute the commands in the init file */ 03417 DPRINT("KDB: Executing KDBinit file...\n"); 03418 p1 = KdbInitFileBuffer; 03419 while (p1[0] != '\0') 03420 { 03421 i = strcspn(p1, "\r\n"); 03422 if (i > 0) 03423 { 03424 c = p1[i]; 03425 p1[i] = '\0'; 03426 03427 /* Look for "break" command and comments */ 03428 p2 = p1; 03429 03430 while (isspace(p2[0])) 03431 p2++; 03432 03433 if (strncmp(p2, "break", sizeof("break")-1) == 0 && 03434 (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1]))) 03435 { 03436 /* break into the debugger */ 03437 KdbpCliMainLoop(FALSE); 03438 } 03439 else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */ 03440 { 03441 KdbpDoCommand(p1); 03442 } 03443 03444 p1[i] = c; 03445 } 03446 03447 p1 += i; 03448 while (p1[0] == '\r' || p1[0] == '\n') 03449 p1++; 03450 } 03451 DPRINT("KDB: KDBinit executed\n"); 03452 } 03453 03458 VOID 03459 KdbpCliInit() 03460 { 03461 NTSTATUS Status; 03462 OBJECT_ATTRIBUTES ObjectAttributes; 03463 UNICODE_STRING FileName; 03464 IO_STATUS_BLOCK Iosb; 03465 FILE_STANDARD_INFORMATION FileStdInfo; 03466 HANDLE hFile = NULL; 03467 INT FileSize; 03468 PCHAR FileBuffer; 03469 ULONG OldEflags; 03470 03471 /* Initialize the object attributes */ 03472 RtlInitUnicodeString(&FileName, L"\\SystemRoot\\system32\\drivers\\etc\\KDBinit"); 03473 InitializeObjectAttributes(&ObjectAttributes, &FileName, 0, NULL, NULL); 03474 03475 /* Open the file */ 03476 Status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0, 03477 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | 03478 FILE_NO_INTERMEDIATE_BUFFERING); 03479 if (!NT_SUCCESS(Status)) 03480 { 03481 DPRINT("Could not open \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); 03482 return; 03483 } 03484 03485 /* Get the size of the file */ 03486 Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof (FileStdInfo), 03487 FileStandardInformation); 03488 if (!NT_SUCCESS(Status)) 03489 { 03490 ZwClose(hFile); 03491 DPRINT("Could not query size of \\SystemRoot\\system32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); 03492 return; 03493 } 03494 FileSize = FileStdInfo.EndOfFile.u.LowPart; 03495 03496 /* Allocate memory for the file */ 03497 FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */ 03498 if (!FileBuffer) 03499 { 03500 ZwClose(hFile); 03501 DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize); 03502 return; 03503 } 03504 03505 /* Load file into memory */ 03506 Status = ZwReadFile(hFile, 0, 0, 0, &Iosb, FileBuffer, FileSize, 0, 0); 03507 ZwClose(hFile); 03508 03509 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) 03510 { 03511 ExFreePool(FileBuffer); 03512 DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status); 03513 return; 03514 } 03515 03516 FileSize = min(FileSize, (INT)Iosb.Information); 03517 FileBuffer[FileSize] = '\0'; 03518 03519 /* Enter critical section */ 03520 OldEflags = __readeflags(); 03521 _disable(); 03522 03523 /* Interpret the init file... */ 03524 KdbInitFileBuffer = FileBuffer; 03525 KdbEnter(); 03526 KdbInitFileBuffer = NULL; 03527 03528 /* Leave critical section */ 03529 __writeeflags(OldEflags); 03530 03531 ExFreePool(FileBuffer); 03532 } 03533 03534 VOID 03535 NTAPI 03536 KdpSerialDebugPrint( 03537 LPSTR Message, 03538 ULONG Length 03539 ); 03540 03541 STRING KdpPromptString = RTL_CONSTANT_STRING("kdb:> "); 03542 extern KSPIN_LOCK KdpSerialSpinLock; 03543 03544 ULONG 03545 NTAPI 03546 KdpPrompt(IN LPSTR InString, 03547 IN USHORT InStringLength, 03548 OUT LPSTR OutString, 03549 IN USHORT OutStringLength) 03550 { 03551 USHORT i; 03552 CHAR Response; 03553 ULONG DummyScanCode; 03554 KIRQL OldIrql; 03555 03556 /* Acquire the printing spinlock without waiting at raised IRQL */ 03557 while (TRUE) 03558 { 03559 /* Wait when the spinlock becomes available */ 03560 while (!KeTestSpinLock(&KdpSerialSpinLock)); 03561 03562 /* Spinlock was free, raise IRQL */ 03563 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 03564 03565 /* Try to get the spinlock */ 03566 if (KeTryToAcquireSpinLockAtDpcLevel(&KdpSerialSpinLock)) 03567 break; 03568 03569 /* Someone else got the spinlock, lower IRQL back */ 03570 KeLowerIrql(OldIrql); 03571 } 03572 03573 /* Loop the string to send */ 03574 for (i = 0; i < InStringLength; i++) 03575 { 03576 /* Print it to serial */ 03577 KdPortPutByteEx(&SerialPortInfo, *(PCHAR)(InString + i)); 03578 } 03579 03580 /* Print a new line for log neatness */ 03581 KdPortPutByteEx(&SerialPortInfo, '\r'); 03582 KdPortPutByteEx(&SerialPortInfo, '\n'); 03583 03584 /* Print the kdb prompt */ 03585 for (i = 0; i < KdpPromptString.Length; i++) 03586 { 03587 /* Print it to serial */ 03588 KdPortPutByteEx(&SerialPortInfo, 03589 *(KdpPromptString.Buffer + i)); 03590 } 03591 03592 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 03593 KbdDisableMouse(); 03594 03595 /* Loop the whole string */ 03596 for (i = 0; i < OutStringLength; i++) 03597 { 03598 /* Check if this is serial debugging mode */ 03599 if (KdbDebugState & KD_DEBUG_KDSERIAL) 03600 { 03601 /* Get the character from serial */ 03602 do 03603 { 03604 Response = KdbpTryGetCharSerial(MAXULONG); 03605 } while (Response == -1); 03606 } 03607 else 03608 { 03609 /* Get the response from the keyboard */ 03610 do 03611 { 03612 Response = KdbpTryGetCharKeyboard(&DummyScanCode, MAXULONG); 03613 } while (Response == -1); 03614 } 03615 03616 /* Check for return */ 03617 if (Response == '\r') 03618 { 03619 /* 03620 * We might need to discard the next '\n'. 03621 * Wait a bit to make sure we receive it. 03622 */ 03623 KeStallExecutionProcessor(100000); 03624 03625 /* Check the mode */ 03626 if (KdbDebugState & KD_DEBUG_KDSERIAL) 03627 { 03628 /* Read and discard the next character, if any */ 03629 KdbpTryGetCharSerial(5); 03630 } 03631 else 03632 { 03633 /* Read and discard the next character, if any */ 03634 KdbpTryGetCharKeyboard(&DummyScanCode, 5); 03635 } 03636 03637 /* 03638 * Null terminate the output string -- documentation states that 03639 * DbgPrompt does not null terminate, but it does 03640 */ 03641 *(PCHAR)(OutString + i) = 0; 03642 03643 /* Print a new line */ 03644 KdPortPutByteEx(&SerialPortInfo, '\r'); 03645 KdPortPutByteEx(&SerialPortInfo, '\n'); 03646 03647 /* Release spinlock */ 03648 KiReleaseSpinLock(&KdpSerialSpinLock); 03649 03650 /* Lower IRQL back */ 03651 KeLowerIrql(OldIrql); 03652 03653 /* Return the length */ 03654 return OutStringLength + 1; 03655 } 03656 03657 /* Write it back and print it to the log */ 03658 *(PCHAR)(OutString + i) = Response; 03659 KdPortPutByteEx(&SerialPortInfo, Response); 03660 } 03661 03662 if (!(KdbDebugState & KD_DEBUG_KDSERIAL)) 03663 KbdEnableMouse(); 03664 03665 /* Print a new line */ 03666 KdPortPutByteEx(&SerialPortInfo, '\r'); 03667 KdPortPutByteEx(&SerialPortInfo, '\n'); 03668 03669 /* Release spinlock */ 03670 KiReleaseSpinLock(&KdpSerialSpinLock); 03671 03672 /* Lower IRQL back */ 03673 KeLowerIrql(OldIrql); 03674 03675 /* Return the length */ 03676 return OutStringLength; 03677 } Generated on Mon May 28 2012 04:37:23 for ReactOS by
1.7.6.1
|