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