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