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