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