xref: /reactos/ntoskrnl/kdbg/kdb_cli.c (revision b97d5fd2)
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[]);
853726b992SJérôme Gardou #ifdef _M_IX86
86c2c66affSColin Finck static BOOLEAN KdbpCmdTss(ULONG Argc, PCHAR Argv[]);
873726b992SJérôme Gardou #endif
88c2c66affSColin Finck 
89c2c66affSColin Finck static BOOLEAN KdbpCmdBugCheck(ULONG Argc, PCHAR Argv[]);
90c2c66affSColin Finck static BOOLEAN KdbpCmdReboot(ULONG Argc, PCHAR Argv[]);
91c2c66affSColin Finck static BOOLEAN KdbpCmdFilter(ULONG Argc, PCHAR Argv[]);
92c2c66affSColin Finck static BOOLEAN KdbpCmdSet(ULONG Argc, PCHAR Argv[]);
93c2c66affSColin Finck static BOOLEAN KdbpCmdHelp(ULONG Argc, PCHAR Argv[]);
94c2c66affSColin Finck static BOOLEAN KdbpCmdDmesg(ULONG Argc, PCHAR Argv[]);
95c2c66affSColin Finck 
96c2c66affSColin Finck BOOLEAN ExpKdbgExtPool(ULONG Argc, PCHAR Argv[]);
9778b55550SPierre Schweitzer BOOLEAN ExpKdbgExtPoolUsed(ULONG Argc, PCHAR Argv[]);
9812e57956SPierre Schweitzer BOOLEAN ExpKdbgExtPoolFind(ULONG Argc, PCHAR Argv[]);
99cb52c821SPierre Schweitzer BOOLEAN ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]);
100d35243d4SPierre Schweitzer BOOLEAN ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]);
10147b48520SPierre Schweitzer BOOLEAN ExpKdbgExtIrpFind(ULONG Argc, PCHAR Argv[]);
1022991f6e7SPierre Schweitzer BOOLEAN ExpKdbgExtHandle(ULONG Argc, PCHAR Argv[]);
103d6dc1fd2SPierre Schweitzer 
104c2c66affSColin Finck #ifdef __ROS_DWARF__
105c2c66affSColin Finck static BOOLEAN KdbpCmdPrintStruct(ULONG Argc, PCHAR Argv[]);
106c2c66affSColin Finck #endif
107c2c66affSColin Finck 
1083726b992SJérôme Gardou /* Be more descriptive than intrinsics */
1093726b992SJérôme Gardou #ifndef Ke386GetGlobalDescriptorTable
1103726b992SJérôme Gardou # define Ke386GetGlobalDescriptorTable __sgdt
1113726b992SJérôme Gardou #endif
1123726b992SJérôme Gardou #ifndef Ke386GetLocalDescriptorTable
1133726b992SJérôme Gardou # define Ke386GetLocalDescriptorTable __sldt
1143726b992SJérôme Gardou #endif
1153726b992SJérôme Gardou 
1163726b992SJérôme Gardou /* Portability */
1173726b992SJérôme Gardou FORCEINLINE
1183726b992SJérôme Gardou ULONG_PTR
1193726b992SJérôme Gardou strtoulptr(const char* nptr, char** endptr, int base)
1203726b992SJérôme Gardou {
1213726b992SJérôme Gardou #ifdef _M_IX86
1223726b992SJérôme Gardou     return strtoul(nptr, endptr, base);
1233726b992SJérôme Gardou #else
1243726b992SJérôme Gardou     return strtoull(nptr, endptr, base);
1253726b992SJérôme Gardou #endif
1263726b992SJérôme Gardou }
1273726b992SJérôme Gardou 
128c2c66affSColin Finck /* GLOBALS *******************************************************************/
129c2c66affSColin Finck 
130ba37323aSHervé Poussineau typedef
131ba37323aSHervé Poussineau BOOLEAN
132ba37323aSHervé Poussineau (NTAPI *PKDBG_CLI_ROUTINE)(
133ba37323aSHervé Poussineau     IN PCHAR Command,
134ba37323aSHervé Poussineau     IN ULONG Argc,
135ba37323aSHervé Poussineau     IN PCH Argv[]);
136ba37323aSHervé Poussineau 
137c2c66affSColin Finck static PKDBG_CLI_ROUTINE KdbCliCallbacks[10];
138c2c66affSColin Finck static BOOLEAN KdbUseIntelSyntax = FALSE; /* Set to TRUE for intel syntax */
139c2c66affSColin Finck static BOOLEAN KdbBreakOnModuleLoad = FALSE; /* Set to TRUE to break into KDB when a module is loaded */
140c2c66affSColin Finck 
141c2c66affSColin Finck static CHAR KdbCommandHistoryBuffer[2048]; /* Command history string ringbuffer */
142c2c66affSColin Finck static PCHAR KdbCommandHistory[sizeof(KdbCommandHistoryBuffer) / 8] = { NULL }; /* Command history ringbuffer */
143c2c66affSColin Finck static LONG KdbCommandHistoryBufferIndex = 0;
144c2c66affSColin Finck static LONG KdbCommandHistoryIndex = 0;
145c2c66affSColin Finck 
146c2c66affSColin Finck static ULONG KdbNumberOfRowsPrinted = 0;
147c2c66affSColin Finck static ULONG KdbNumberOfColsPrinted = 0;
148c2c66affSColin Finck static BOOLEAN KdbOutputAborted = FALSE;
149c2c66affSColin Finck static BOOLEAN KdbRepeatLastCommand = FALSE;
150c2c66affSColin Finck static LONG KdbNumberOfRowsTerminal = -1;
151c2c66affSColin Finck static LONG KdbNumberOfColsTerminal = -1;
152c2c66affSColin Finck 
153c2c66affSColin Finck PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
154c2c66affSColin Finck BOOLEAN KdbpBugCheckRequested = FALSE;
155c2c66affSColin Finck 
156c2c66affSColin Finck /* Vars for dmesg */
157c2c66affSColin Finck /* defined in ../kd/kdio.c, declare here: */
158c2c66affSColin Finck extern volatile BOOLEAN KdbpIsInDmesgMode;
159c2c66affSColin Finck extern const ULONG KdpDmesgBufferSize;
160c2c66affSColin Finck extern PCHAR KdpDmesgBuffer;
161c2c66affSColin Finck extern volatile ULONG KdpDmesgCurrentPosition;
162c2c66affSColin Finck extern volatile ULONG KdpDmesgFreeBytes;
163c2c66affSColin Finck extern volatile ULONG KdbDmesgTotalWritten;
164c2c66affSColin Finck 
165a890fc64SHermès Bélusca-Maïto STRING KdbPromptString = RTL_CONSTANT_STRING("kdb:> ");
166a890fc64SHermès Bélusca-Maïto 
16740c57de7SHermès Bélusca-Maïto //
16840c57de7SHermès Bélusca-Maïto // Debug Filter Component Table
16940c57de7SHermès Bélusca-Maïto //
1707d3dac32SHermès Bélusca-Maïto #define KD_DEBUG_PRINT_FILTER(Name) \
1717d3dac32SHermès Bélusca-Maïto     { #Name, DPFLTR_##Name##_ID }
1727d3dac32SHermès Bélusca-Maïto 
173c2c66affSColin Finck static struct
174c2c66affSColin Finck {
17540c57de7SHermès Bélusca-Maïto     PCSTR Name;
176c2c66affSColin Finck     ULONG Id;
177c2c66affSColin Finck }
178c2c66affSColin Finck ComponentTable[] =
179c2c66affSColin Finck {
1806c1aac69SHermès Bélusca-Maïto //
1816c1aac69SHermès Bélusca-Maïto // Default components
1826c1aac69SHermès Bélusca-Maïto //
1836c1aac69SHermès Bélusca-Maïto     { "WIN2000", MAXULONG },
1847d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DEFAULT),
1856c1aac69SHermès Bélusca-Maïto //
1866c1aac69SHermès Bélusca-Maïto // Standard components
1876c1aac69SHermès Bélusca-Maïto //
1887d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SYSTEM),
1897d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SMSS),
1907d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SETUP),
1917d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(NTFS),
1927d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FSTUB),
1937d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CRASHDUMP),
1947d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CDAUDIO),
1957d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CDROM),
1967d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CLASSPNP),
1977d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DISK),
1987d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(REDBOOK),
1997d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(STORPROP),
2007d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SCSIPORT),
2017d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SCSIMINIPORT),
2027d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CONFIG),
2037d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(I8042PRT),
2047d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SERMOUSE),
2057d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(LSERMOUS),
2067d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(KBDHID),
2077d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MOUHID),
2087d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(KBDCLASS),
2097d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MOUCLASS),
2107d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TWOTRACK),
2117d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WMILIB),
2127d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(ACPI),
2137d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(AMLI),
2147d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(HALIA64),
2157d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VIDEO),
2167d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SVCHOST),
2177d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VIDEOPRT),
2187d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TCPIP),
2197d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DMSYNTH),
2207d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(NTOSPNP),
2217d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FASTFAT),
2227d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SAMSS),
2237d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PNPMGR),
2247d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(NETAPI),
2257d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SCSERVER),
2267d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SCCLIENT),
2277d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SERIAL),
2287d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SERENUM),
2297d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(UHCD),
2307d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(RPCPROXY),
2317d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(AUTOCHK),
2327d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DCOMSS),
2337d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(UNIMODEM),
2347d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SIS),
2357d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FLTMGR),
2367d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WMICORE),
2377d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(BURNENG),
2387d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IMAPI),
2397d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SXS),
2407d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FUSION),
2417d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IDLETASK),
2427d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SOFTPCI),
2437d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TAPE),
2447d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MCHGR),
2457d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IDEP),
2467d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PCIIDE),
2477d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FLOPPY),
2487d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FDC),
2497d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TERMSRV),
2507d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(W32TIME),
2517d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PREFETCHER),
2527d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(RSFILTER),
2537d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FCPORT),
2547d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PCI),
2557d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DMIO),
2567d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DMCONFIG),
2577d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DMADMIN),
2587d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WSOCKTRANSPORT),
2597d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VSS),
2607d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PNPMEM),
2617d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PROCESSOR),
2627d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DMSERVER),
2637d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SR),
2647d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(INFINIBAND),
2657d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVDRIVER),
2667d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVVIDEO),
2677d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVAUDIO),
2687d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVNETWORK),
2697d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVSTREAMING),
2707d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IHVBUS),
2717d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(HPS),
2727d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(RTLTHREADPOOL),
2737d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(LDR),
2747d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TCPIP6),
2757d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(ISAPNP),
2767d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SHPC),
2777d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(STORPORT),
2787d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(STORMINIPORT),
2797d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PRINTSPOOLER),
2807d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VSSDYNDISK),
2817d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VERIFIER),
2827d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDS),
2837d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDSBAS),
2847d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDSDYN),  // Specified in Vista+
2857d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDSDYNDR),
2867d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDSLDR),  // Specified in Vista+
2877d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VDSUTIL),
2887d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DFRGIFC),
2897d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MM),
2907d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DFSC),
2917d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WOW64),
2926c1aac69SHermès Bélusca-Maïto //
2936c1aac69SHermès Bélusca-Maïto // Components specified in Vista+, some of which we also use in ReactOS
2946c1aac69SHermès Bélusca-Maïto //
2957d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(ALPC),
2967d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WDI),
2977d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PERFLIB),
2987d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(KTM),
2997d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(IOSTRESS),
3007d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(HEAP),
3017d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WHEA),
3027d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(USERGDI),
3037d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MMCSS),
3047d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TPM),
3057d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(THREADORDER),
3067d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(ENVIRON),
3077d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(EMS),
3087d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WDT),
3097d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FVEVOL),
3107d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(NDIS),
3117d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(NVCTRACE),
3127d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(LUAFV),
3137d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(APPCOMPAT),
3147d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(USBSTOR),
3157d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SBP2PORT),
3167d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(COVERAGE),
3177d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CACHEMGR),
3187d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MOUNTMGR),
3197d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CFR),
3207d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(TXF),
3217d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(KSECDD),
3227d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FLTREGRESS),
3237d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MPIO),
3247d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(MSDSM),
3257d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(UDFS),
3267d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(PSHED),
3277d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(STORVSP),
3287d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(LSASS),
3297d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SSPICLI),
3307d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CNG),
3317d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(EXFAT),
3327d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FILETRACE),
3337d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(XSAVE),
3347d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(SE),
3357d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(DRIVEEXTENDER),
336ceb58c82SHermès Bélusca-Maïto //
337ceb58c82SHermès Bélusca-Maïto // Components specified in Windows 8
338ceb58c82SHermès Bélusca-Maïto //
3397d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(POWER),
3407d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CRASHDUMPXHCI),
3417d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(GPIO),
3427d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(REFS),
3437d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(WER),
344ceb58c82SHermès Bélusca-Maïto //
345ceb58c82SHermès Bélusca-Maïto // Components specified in Windows 10
346ceb58c82SHermès Bélusca-Maïto //
3477d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(CAPIMG),
3487d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(VPCI),
3497d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(STORAGECLASSMEMORY),
3507d3dac32SHermès Bélusca-Maïto     KD_DEBUG_PRINT_FILTER(FSLIB),
351c2c66affSColin Finck };
3527d3dac32SHermès Bélusca-Maïto #undef KD_DEBUG_PRINT_FILTER
353c2c66affSColin Finck 
35440c57de7SHermès Bélusca-Maïto //
35540c57de7SHermès Bélusca-Maïto // Command Table
35640c57de7SHermès Bélusca-Maïto //
35740c57de7SHermès Bélusca-Maïto static const struct
358c2c66affSColin Finck {
35940c57de7SHermès Bélusca-Maïto     PCHAR Name;
36040c57de7SHermès Bélusca-Maïto     PCHAR Syntax;
36140c57de7SHermès Bélusca-Maïto     PCHAR Help;
36240c57de7SHermès Bélusca-Maïto     BOOLEAN (*Fn)(ULONG Argc, PCHAR Argv[]);
36340c57de7SHermès Bélusca-Maïto } KdbDebuggerCommands[] = {
36440c57de7SHermès Bélusca-Maïto     /* Data */
36540c57de7SHermès Bélusca-Maïto     { NULL, NULL, "Data", NULL },
36640c57de7SHermès Bélusca-Maïto     { "?", "? expression", "Evaluate expression.", KdbpCmdEvalExpression },
36740c57de7SHermès Bélusca-Maïto     { "disasm", "disasm [address] [L count]", "Disassemble count instructions at address.", KdbpCmdDisassembleX },
36840c57de7SHermès Bélusca-Maïto     { "x", "x [address] [L count]", "Display count dwords, starting at address.", KdbpCmdDisassembleX },
36940c57de7SHermès Bélusca-Maïto     { "regs", "regs", "Display general purpose registers.", KdbpCmdRegs },
37040c57de7SHermès Bélusca-Maïto     { "sregs", "sregs", "Display status registers.", KdbpCmdRegs },
37140c57de7SHermès Bélusca-Maïto     { "dregs", "dregs", "Display debug registers.", KdbpCmdRegs },
37240c57de7SHermès Bélusca-Maïto     { "bt", "bt [*frameaddr|thread id]", "Prints current backtrace or from given frame address.", KdbpCmdBackTrace },
37340c57de7SHermès Bélusca-Maïto #ifdef __ROS_DWARF__
37440c57de7SHermès Bélusca-Maïto     { "dt", "dt [mod] [type] [addr]", "Print a struct. The address is optional.", KdbpCmdPrintStruct },
37540c57de7SHermès Bélusca-Maïto #endif
376c2c66affSColin Finck 
37740c57de7SHermès Bélusca-Maïto     /* Flow control */
37840c57de7SHermès Bélusca-Maïto     { NULL, NULL, "Flow control", NULL },
37940c57de7SHermès Bélusca-Maïto     { "cont", "cont", "Continue execution (leave debugger).", KdbpCmdContinue },
38040c57de7SHermès Bélusca-Maïto     { "step", "step [count]", "Execute single instructions, stepping into interrupts.", KdbpCmdStep },
38140c57de7SHermès Bélusca-Maïto     { "next", "next [count]", "Execute single instructions, skipping calls and reps.", KdbpCmdStep },
38240c57de7SHermès Bélusca-Maïto     { "bl", "bl", "List breakpoints.", KdbpCmdBreakPointList },
38340c57de7SHermès Bélusca-Maïto     { "be", "be [breakpoint]", "Enable breakpoint.", KdbpCmdEnableDisableClearBreakPoint },
38440c57de7SHermès Bélusca-Maïto     { "bd", "bd [breakpoint]", "Disable breakpoint.", KdbpCmdEnableDisableClearBreakPoint },
38540c57de7SHermès Bélusca-Maïto     { "bc", "bc [breakpoint]", "Clear breakpoint.", KdbpCmdEnableDisableClearBreakPoint },
38640c57de7SHermès Bélusca-Maïto     { "bpx", "bpx [address] [IF condition]", "Set software execution breakpoint at address.", KdbpCmdBreakPoint },
38740c57de7SHermès Bélusca-Maïto     { "bpm", "bpm [r|w|rw|x] [byte|word|dword] [address] [IF condition]", "Set memory breakpoint at address.", KdbpCmdBreakPoint },
38840c57de7SHermès Bélusca-Maïto 
38940c57de7SHermès Bélusca-Maïto     /* Process/Thread */
39040c57de7SHermès Bélusca-Maïto     { NULL, NULL, "Process/Thread", NULL },
39140c57de7SHermè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 },
39240c57de7SHermès Bélusca-Maïto     { "proc", "proc [list|[attach ]pid]", "List processes, display process with given id or attach to process.", KdbpCmdProc },
39340c57de7SHermès Bélusca-Maïto 
39440c57de7SHermès Bélusca-Maïto     /* System information */
39540c57de7SHermès Bélusca-Maïto     { NULL, NULL, "System info", NULL },
39640c57de7SHermès Bélusca-Maïto     { "mod", "mod [address]", "List all modules or the one containing address.", KdbpCmdMod },
39740c57de7SHermès Bélusca-Maïto     { "gdt", "gdt", "Display the global descriptor table.", KdbpCmdGdtLdtIdt },
39840c57de7SHermès Bélusca-Maïto     { "ldt", "ldt", "Display the local descriptor table.", KdbpCmdGdtLdtIdt },
39940c57de7SHermès Bélusca-Maïto     { "idt", "idt", "Display the interrupt descriptor table.", KdbpCmdGdtLdtIdt },
40040c57de7SHermès Bélusca-Maïto     { "pcr", "pcr", "Display the processor control region.", KdbpCmdPcr },
4013726b992SJérôme Gardou #ifdef _M_IX86
40240c57de7SHermè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 },
4033726b992SJérôme Gardou #endif
40440c57de7SHermès Bélusca-Maïto 
40540c57de7SHermès Bélusca-Maïto     /* Others */
40640c57de7SHermès Bélusca-Maïto     { NULL, NULL, "Others", NULL },
40740c57de7SHermès Bélusca-Maïto     { "bugcheck", "bugcheck", "Bugchecks the system.", KdbpCmdBugCheck },
40840c57de7SHermès Bélusca-Maïto     { "reboot", "reboot", "Reboots the system.", KdbpCmdReboot},
40940c57de7SHermès Bélusca-Maïto     { "filter", "filter [error|warning|trace|info|level]+|-[componentname|default]", "Enable/disable debug channels.", KdbpCmdFilter },
41040c57de7SHermès Bélusca-Maïto     { "set", "set [var] [value]", "Sets var to value or displays value of var.", KdbpCmdSet },
41140c57de7SHermès Bélusca-Maïto     { "dmesg", "dmesg", "Display debug messages on screen, with navigation on pages.", KdbpCmdDmesg },
41240c57de7SHermès Bélusca-Maïto     { "kmsg", "kmsg", "Kernel dmesg. Alias for dmesg.", KdbpCmdDmesg },
41340c57de7SHermès Bélusca-Maïto     { "help", "help", "Display help screen.", KdbpCmdHelp },
41440c57de7SHermès Bélusca-Maïto     { "!pool", "!pool [Address [Flags]]", "Display information about pool allocations.", ExpKdbgExtPool },
41540c57de7SHermès Bélusca-Maïto     { "!poolused", "!poolused [Flags [Tag]]", "Display pool usage.", ExpKdbgExtPoolUsed },
41640c57de7SHermès Bélusca-Maïto     { "!poolfind", "!poolfind Tag [Pool]", "Search for pool tag allocations.", ExpKdbgExtPoolFind },
41740c57de7SHermès Bélusca-Maïto     { "!filecache", "!filecache", "Display cache usage.", ExpKdbgExtFileCache },
41840c57de7SHermès Bélusca-Maïto     { "!defwrites", "!defwrites", "Display cache write values.", ExpKdbgExtDefWrites },
41940c57de7SHermès Bélusca-Maïto     { "!irpfind", "!irpfind [Pool [startaddress [criteria data]]]", "Lists IRPs potentially matching criteria.", ExpKdbgExtIrpFind },
42040c57de7SHermès Bélusca-Maïto     { "!handle", "!handle [Handle]", "Displays info about handles.", ExpKdbgExtHandle },
42140c57de7SHermès Bélusca-Maïto };
42240c57de7SHermès Bélusca-Maïto 
42340c57de7SHermès Bélusca-Maïto /* FUNCTIONS *****************************************************************/
424c2c66affSColin Finck 
425c2c66affSColin Finck /*!\brief Evaluates an expression...
426c2c66affSColin Finck  *
427c2c66affSColin Finck  * Much like KdbpRpnEvaluateExpression, but prints the error message (if any)
428c2c66affSColin Finck  * at the given offset.
429c2c66affSColin Finck  *
430c2c66affSColin Finck  * \param Expression  Expression to evaluate.
431c2c66affSColin Finck  * \param ErrOffset   Offset (in characters) to print the error message at.
432c2c66affSColin Finck  * \param Result      Receives the result on success.
433c2c66affSColin Finck  *
434c2c66affSColin Finck  * \retval TRUE   Success.
435c2c66affSColin Finck  * \retval FALSE  Failure.
436c2c66affSColin Finck  */
437c2c66affSColin Finck static BOOLEAN
438c2c66affSColin Finck KdbpEvaluateExpression(
439c2c66affSColin Finck     IN  PCHAR Expression,
440c2c66affSColin Finck     IN  LONG ErrOffset,
441c2c66affSColin Finck     OUT PULONGLONG Result)
442c2c66affSColin Finck {
443c2c66affSColin Finck     static CHAR ErrMsgBuffer[130] = "^ ";
444c2c66affSColin Finck     LONG ExpressionErrOffset = -1;
445c2c66affSColin Finck     PCHAR ErrMsg = ErrMsgBuffer;
446c2c66affSColin Finck     BOOLEAN Ok;
447c2c66affSColin Finck 
448c2c66affSColin Finck     Ok = KdbpRpnEvaluateExpression(Expression, KdbCurrentTrapFrame, Result,
449c2c66affSColin Finck                                    &ExpressionErrOffset, ErrMsgBuffer + 2);
450c2c66affSColin Finck     if (!Ok)
451c2c66affSColin Finck     {
452c2c66affSColin Finck         if (ExpressionErrOffset >= 0)
453c2c66affSColin Finck             ExpressionErrOffset += ErrOffset;
454c2c66affSColin Finck         else
455c2c66affSColin Finck             ErrMsg += 2;
456c2c66affSColin Finck 
457c2c66affSColin Finck         KdbpPrint("%*s%s\n", ExpressionErrOffset, "", ErrMsg);
458c2c66affSColin Finck     }
459c2c66affSColin Finck 
460c2c66affSColin Finck     return Ok;
461c2c66affSColin Finck }
462c2c66affSColin Finck 
463c2c66affSColin Finck BOOLEAN
464c2c66affSColin Finck NTAPI
465c2c66affSColin Finck KdbpGetHexNumber(
466c2c66affSColin Finck     IN PCHAR pszNum,
467c2c66affSColin Finck     OUT ULONG_PTR *pulValue)
468c2c66affSColin Finck {
469c2c66affSColin Finck     char *endptr;
470c2c66affSColin Finck 
471c2c66affSColin Finck     /* Skip optional '0x' prefix */
472c2c66affSColin Finck     if ((pszNum[0] == '0') && ((pszNum[1] == 'x') || (pszNum[1] == 'X')))
473c2c66affSColin Finck         pszNum += 2;
474c2c66affSColin Finck 
475c2c66affSColin Finck     /* Make a number from the string (hex) */
476c2c66affSColin Finck     *pulValue = strtoul(pszNum, &endptr, 16);
477c2c66affSColin Finck 
478c2c66affSColin Finck     return (*endptr == '\0');
479c2c66affSColin Finck }
480c2c66affSColin Finck 
481c2c66affSColin Finck /*!\brief Evaluates an expression and displays the result.
482c2c66affSColin Finck  */
483c2c66affSColin Finck static BOOLEAN
484c2c66affSColin Finck KdbpCmdEvalExpression(
485c2c66affSColin Finck     ULONG Argc,
486c2c66affSColin Finck     PCHAR Argv[])
487c2c66affSColin Finck {
488c2c66affSColin Finck     ULONG i, len;
489c2c66affSColin Finck     ULONGLONG Result = 0;
490c2c66affSColin Finck     ULONG ul;
491c2c66affSColin Finck     LONG l = 0;
492c2c66affSColin Finck     BOOLEAN Ok;
493c2c66affSColin Finck 
494c2c66affSColin Finck     if (Argc < 2)
495c2c66affSColin Finck     {
496c2c66affSColin Finck         KdbpPrint("?: Argument required\n");
497c2c66affSColin Finck         return TRUE;
498c2c66affSColin Finck     }
499c2c66affSColin Finck 
500c2c66affSColin Finck     /* Put the arguments back together */
501c2c66affSColin Finck     Argc--;
502c2c66affSColin Finck     for (i = 1; i < Argc; i++)
503c2c66affSColin Finck     {
504c2c66affSColin Finck         len = strlen(Argv[i]);
505c2c66affSColin Finck         Argv[i][len] = ' ';
506c2c66affSColin Finck     }
507c2c66affSColin Finck 
508c2c66affSColin Finck     /* Evaluate the expression */
509a890fc64SHermès Bélusca-Maïto     Ok = KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result);
510c2c66affSColin Finck     if (Ok)
511c2c66affSColin Finck     {
512c2c66affSColin Finck         if (Result > 0x00000000ffffffffLL)
513c2c66affSColin Finck         {
514c2c66affSColin Finck             if (Result & 0x8000000000000000LL)
515c2c66affSColin Finck                 KdbpPrint("0x%016I64x  %20I64u  %20I64d\n", Result, Result, Result);
516c2c66affSColin Finck             else
517c2c66affSColin Finck                 KdbpPrint("0x%016I64x  %20I64u\n", Result, Result);
518c2c66affSColin Finck         }
519c2c66affSColin Finck         else
520c2c66affSColin Finck         {
521c2c66affSColin Finck             ul = (ULONG)Result;
522c2c66affSColin Finck 
523c2c66affSColin Finck             if (ul <= 0xff && ul >= 0x80)
524c2c66affSColin Finck                 l = (LONG)((CHAR)ul);
525c2c66affSColin Finck             else if (ul <= 0xffff && ul >= 0x8000)
526c2c66affSColin Finck                 l = (LONG)((SHORT)ul);
527c2c66affSColin Finck             else
528c2c66affSColin Finck                 l = (LONG)ul;
529c2c66affSColin Finck 
530c2c66affSColin Finck             if (l < 0)
531c2c66affSColin Finck                 KdbpPrint("0x%08lx  %10lu  %10ld\n", ul, ul, l);
532c2c66affSColin Finck             else
533c2c66affSColin Finck                 KdbpPrint("0x%08lx  %10lu\n", ul, ul);
534c2c66affSColin Finck         }
535c2c66affSColin Finck     }
536c2c66affSColin Finck 
537c2c66affSColin Finck     return TRUE;
538c2c66affSColin Finck }
539c2c66affSColin Finck 
540c2c66affSColin Finck #ifdef __ROS_DWARF__
541c2c66affSColin Finck 
542c2c66affSColin Finck /*!\brief Print a struct
543c2c66affSColin Finck  */
544c2c66affSColin Finck static VOID
545c2c66affSColin Finck KdbpPrintStructInternal
546c2c66affSColin Finck (PROSSYM_INFO Info,
547c2c66affSColin Finck  PCHAR Indent,
548c2c66affSColin Finck  BOOLEAN DoRead,
549c2c66affSColin Finck  PVOID BaseAddress,
550c2c66affSColin Finck  PROSSYM_AGGREGATE Aggregate)
551c2c66affSColin Finck {
552c2c66affSColin Finck     ULONG i;
553c2c66affSColin Finck     ULONGLONG Result;
554c2c66affSColin Finck     PROSSYM_AGGREGATE_MEMBER Member;
555c2c66affSColin Finck     ULONG IndentLen = strlen(Indent);
556c2c66affSColin Finck     ROSSYM_AGGREGATE MemberAggregate = {0 };
557c2c66affSColin Finck 
558c2c66affSColin Finck     for (i = 0; i < Aggregate->NumElements; i++) {
559c2c66affSColin Finck         Member = &Aggregate->Elements[i];
560c2c66affSColin Finck         KdbpPrint("%s%p+%x: %s", Indent, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size, Member->Name ? Member->Name : "<anoymous>");
561c2c66affSColin Finck         if (DoRead) {
562c2c66affSColin Finck             if (!strcmp(Member->Type, "_UNICODE_STRING")) {
563c2c66affSColin Finck                 KdbpPrint("\"%wZ\"\n", ((PCHAR)BaseAddress) + Member->BaseOffset);
564c2c66affSColin Finck                 continue;
565c2c66affSColin Finck             } else if (!strcmp(Member->Type, "PUNICODE_STRING")) {
566c2c66affSColin Finck                 KdbpPrint("\"%wZ\"\n", *(((PUNICODE_STRING*)((PCHAR)BaseAddress) + Member->BaseOffset)));
567c2c66affSColin Finck                 continue;
568c2c66affSColin Finck             }
569c2c66affSColin Finck             switch (Member->Size) {
570c2c66affSColin Finck             case 1:
571c2c66affSColin Finck             case 2:
572c2c66affSColin Finck             case 4:
573c2c66affSColin Finck             case 8: {
574c2c66affSColin Finck                 Result = 0;
575c2c66affSColin Finck                 if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) {
576c2c66affSColin Finck                     if (Member->Bits) {
577c2c66affSColin Finck                         Result >>= Member->FirstBit;
578c2c66affSColin Finck                         Result &= ((1 << Member->Bits) - 1);
579c2c66affSColin Finck                     }
580c2c66affSColin Finck                     KdbpPrint(" %lx\n", Result);
581c2c66affSColin Finck                 }
582c2c66affSColin Finck                 else goto readfail;
583c2c66affSColin Finck                 break;
584c2c66affSColin Finck             }
585c2c66affSColin Finck             default: {
586c2c66affSColin Finck                 if (Member->Size < 8) {
587c2c66affSColin Finck                     if (NT_SUCCESS(KdbpSafeReadMemory(&Result, ((PCHAR)BaseAddress) + Member->BaseOffset, Member->Size))) {
588c2c66affSColin Finck                         ULONG j;
589c2c66affSColin Finck                         for (j = 0; j < Member->Size; j++) {
590c2c66affSColin Finck                             KdbpPrint(" %02x", (int)(Result & 0xff));
591c2c66affSColin Finck                             Result >>= 8;
592c2c66affSColin Finck                         }
593c2c66affSColin Finck                     } else goto readfail;
594c2c66affSColin Finck                 } else {
595c2c66affSColin Finck                     KdbpPrint(" %s @ %p {\n", Member->Type, ((PCHAR)BaseAddress) + Member->BaseOffset);
596c2c66affSColin Finck                     Indent[IndentLen] = ' ';
597c2c66affSColin Finck                     if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) {
598c2c66affSColin Finck                         KdbpPrintStructInternal(Info, Indent, DoRead, ((PCHAR)BaseAddress) + Member->BaseOffset, &MemberAggregate);
599c2c66affSColin Finck                         RosSymFreeAggregate(&MemberAggregate);
600c2c66affSColin Finck                     }
601c2c66affSColin Finck                     Indent[IndentLen] = 0;
602c2c66affSColin Finck                     KdbpPrint("%s}\n", Indent);
603c2c66affSColin Finck                 } break;
604c2c66affSColin Finck             }
605c2c66affSColin Finck             }
606c2c66affSColin Finck         } else {
607c2c66affSColin Finck         readfail:
608c2c66affSColin Finck             if (Member->Size <= 8) {
609c2c66affSColin Finck                 KdbpPrint(" ??\n");
610c2c66affSColin Finck             } else {
611c2c66affSColin Finck                 KdbpPrint(" %s @ %x {\n", Member->Type, Member->BaseOffset);
612c2c66affSColin Finck                 Indent[IndentLen] = ' ';
613c2c66affSColin Finck                 if (RosSymAggregate(Info, Member->Type, &MemberAggregate)) {
614c2c66affSColin Finck                     KdbpPrintStructInternal(Info, Indent, DoRead, BaseAddress, &MemberAggregate);
615c2c66affSColin Finck                     RosSymFreeAggregate(&MemberAggregate);
616c2c66affSColin Finck                 }
617c2c66affSColin Finck                 Indent[IndentLen] = 0;
618c2c66affSColin Finck                 KdbpPrint("%s}\n", Indent);
619c2c66affSColin Finck             }
620c2c66affSColin Finck         }
621c2c66affSColin Finck     }
622c2c66affSColin Finck }
623c2c66affSColin Finck 
624c2c66affSColin Finck PROSSYM_INFO KdbpSymFindCachedFile(PUNICODE_STRING ModName);
625c2c66affSColin Finck 
626c2c66affSColin Finck static BOOLEAN
627c2c66affSColin Finck KdbpCmdPrintStruct(
628c2c66affSColin Finck     ULONG Argc,
629c2c66affSColin Finck     PCHAR Argv[])
630c2c66affSColin Finck {
631c2c66affSColin Finck     ULONG i;
632c2c66affSColin Finck     ULONGLONG Result = 0;
633c2c66affSColin Finck     PVOID BaseAddress = 0;
634c2c66affSColin Finck     ROSSYM_AGGREGATE Aggregate = {0};
635c2c66affSColin Finck     UNICODE_STRING ModName = {0};
636c2c66affSColin Finck     ANSI_STRING AnsiName = {0};
637c2c66affSColin Finck     CHAR Indent[100] = {0};
638c2c66affSColin Finck     PROSSYM_INFO Info;
639c2c66affSColin Finck 
640c2c66affSColin Finck     if (Argc < 3) goto end;
641c2c66affSColin Finck     AnsiName.Length = AnsiName.MaximumLength = strlen(Argv[1]);
642c2c66affSColin Finck     AnsiName.Buffer = Argv[1];
643c2c66affSColin Finck     RtlAnsiStringToUnicodeString(&ModName, &AnsiName, TRUE);
644c2c66affSColin Finck     Info = KdbpSymFindCachedFile(&ModName);
645c2c66affSColin Finck 
646c2c66affSColin Finck     if (!Info || !RosSymAggregate(Info, Argv[2], &Aggregate)) {
647c2c66affSColin Finck         DPRINT1("Could not get aggregate\n");
648c2c66affSColin Finck         goto end;
649c2c66affSColin Finck     }
650c2c66affSColin Finck 
651c2c66affSColin Finck     // Get an argument for location if it was given
652c2c66affSColin Finck     if (Argc > 3) {
653c2c66affSColin Finck         ULONG len;
654c2c66affSColin Finck         PCHAR ArgStart = Argv[3];
655c2c66affSColin Finck         DPRINT1("Trying to get expression\n");
656c2c66affSColin Finck         for (i = 3; i < Argc - 1; i++)
657c2c66affSColin Finck         {
658c2c66affSColin Finck             len = strlen(Argv[i]);
659c2c66affSColin Finck             Argv[i][len] = ' ';
660c2c66affSColin Finck         }
661c2c66affSColin Finck 
662c2c66affSColin Finck         /* Evaluate the expression */
663c2c66affSColin Finck         DPRINT1("Arg: %s\n", ArgStart);
664c2c66affSColin Finck         if (KdbpEvaluateExpression(ArgStart, strlen(ArgStart), &Result)) {
665c2c66affSColin Finck             BaseAddress = (PVOID)(ULONG_PTR)Result;
666c2c66affSColin Finck             DPRINT1("BaseAddress: %p\n", BaseAddress);
667c2c66affSColin Finck         }
668c2c66affSColin Finck     }
669c2c66affSColin Finck     DPRINT1("BaseAddress %p\n", BaseAddress);
670c2c66affSColin Finck     KdbpPrintStructInternal(Info, Indent, !!BaseAddress, BaseAddress, &Aggregate);
671c2c66affSColin Finck end:
672c2c66affSColin Finck     RosSymFreeAggregate(&Aggregate);
673c2c66affSColin Finck     RtlFreeUnicodeString(&ModName);
674c2c66affSColin Finck     return TRUE;
675c2c66affSColin Finck }
676c2c66affSColin Finck #endif
677c2c66affSColin Finck 
67840c57de7SHermès Bélusca-Maïto /*!\brief Retrieves the component ID corresponding to a given component name.
67940c57de7SHermès Bélusca-Maïto  *
68040c57de7SHermès Bélusca-Maïto  * \param ComponentName  The name of the component.
68140c57de7SHermès Bélusca-Maïto  * \param ComponentId    Receives the component id on success.
68240c57de7SHermès Bélusca-Maïto  *
68340c57de7SHermès Bélusca-Maïto  * \retval TRUE   Success.
68440c57de7SHermès Bélusca-Maïto  * \retval FALSE  Failure.
68540c57de7SHermès Bélusca-Maïto  */
68640c57de7SHermès Bélusca-Maïto static BOOLEAN
68740c57de7SHermès Bélusca-Maïto KdbpGetComponentId(
68840c57de7SHermès Bélusca-Maïto     IN  PCSTR ComponentName,
68940c57de7SHermès Bélusca-Maïto     OUT PULONG ComponentId)
69040c57de7SHermès Bélusca-Maïto {
69140c57de7SHermès Bélusca-Maïto     ULONG i;
69240c57de7SHermès Bélusca-Maïto 
693b2eaf905SHermès Bélusca-Maïto     for (i = 0; i < RTL_NUMBER_OF(ComponentTable); i++)
69440c57de7SHermès Bélusca-Maïto     {
69540c57de7SHermès Bélusca-Maïto         if (_stricmp(ComponentName, ComponentTable[i].Name) == 0)
69640c57de7SHermès Bélusca-Maïto         {
69740c57de7SHermès Bélusca-Maïto             *ComponentId = ComponentTable[i].Id;
69840c57de7SHermès Bélusca-Maïto             return TRUE;
69940c57de7SHermès Bélusca-Maïto         }
70040c57de7SHermès Bélusca-Maïto     }
70140c57de7SHermès Bélusca-Maïto 
70240c57de7SHermès Bélusca-Maïto     return FALSE;
70340c57de7SHermès Bélusca-Maïto }
70440c57de7SHermès Bélusca-Maïto 
70540c57de7SHermès Bélusca-Maïto /*!\brief Displays the list of active debug channels, or enable/disable debug channels.
706c2c66affSColin Finck  */
707c2c66affSColin Finck static BOOLEAN
708c2c66affSColin Finck KdbpCmdFilter(
709c2c66affSColin Finck     ULONG Argc,
710c2c66affSColin Finck     PCHAR Argv[])
711c2c66affSColin Finck {
712c2c66affSColin Finck     ULONG i, j, ComponentId, Level;
713c2c66affSColin Finck     ULONG set = DPFLTR_MASK, clear = DPFLTR_MASK;
714c2c66affSColin Finck     PCHAR pend;
71540c57de7SHermès Bélusca-Maïto     PCSTR opt, p;
716c2c66affSColin Finck 
717c2c66affSColin Finck     static struct
718c2c66affSColin Finck     {
71940c57de7SHermès Bélusca-Maïto         PCSTR Name;
720c2c66affSColin Finck         ULONG Level;
721c2c66affSColin Finck     }
722c2c66affSColin Finck     debug_classes[] =
723c2c66affSColin Finck     {
724c2c66affSColin Finck         { "error",   1 << DPFLTR_ERROR_LEVEL   },
725c2c66affSColin Finck         { "warning", 1 << DPFLTR_WARNING_LEVEL },
726c2c66affSColin Finck         { "trace",   1 << DPFLTR_TRACE_LEVEL   },
727c2c66affSColin Finck         { "info",    1 << DPFLTR_INFO_LEVEL    },
728c2c66affSColin Finck     };
729c2c66affSColin Finck 
73040c57de7SHermès Bélusca-Maïto     if (Argc <= 1)
73140c57de7SHermès Bélusca-Maïto     {
73240c57de7SHermès Bélusca-Maïto         /* Display the list of available debug filter components */
73340c57de7SHermès Bélusca-Maïto         KdbpPrint("REMARKS:\n"
73440c57de7SHermès Bélusca-Maïto                   "- The 'WIN2000' system-wide debug filter component is used for DbgPrint()\n"
73540c57de7SHermès Bélusca-Maïto                   "  messages without Component ID and Level.\n"
73640c57de7SHermès Bélusca-Maïto                   "- The 'DEFAULT' debug filter component is used for DbgPrint() messages with\n"
73740c57de7SHermès Bélusca-Maïto                   "  an unknown Component ID.\n\n");
73840c57de7SHermès Bélusca-Maïto         KdbpPrint("The list of debug filter components currently available on your system is:\n\n");
73940c57de7SHermès Bélusca-Maïto         KdbpPrint("    Component Name         Component ID\n"
74046416a62SHermès Bélusca-Maïto                   "  ==================     ================\n");
741b2eaf905SHermès Bélusca-Maïto         for (i = 0; i < RTL_NUMBER_OF(ComponentTable); i++)
74240c57de7SHermès Bélusca-Maïto         {
74346416a62SHermès Bélusca-Maïto             KdbpPrint("%20s        0x%08lx\n", ComponentTable[i].Name, ComponentTable[i].Id);
74440c57de7SHermès Bélusca-Maïto         }
74540c57de7SHermès Bélusca-Maïto         return TRUE;
74640c57de7SHermès Bélusca-Maïto     }
74740c57de7SHermès Bélusca-Maïto 
748c2c66affSColin Finck     for (i = 1; i < Argc; i++)
749c2c66affSColin Finck     {
750c2c66affSColin Finck         opt = Argv[i];
751c2c66affSColin Finck         p = opt + strcspn(opt, "+-");
75240c57de7SHermès Bélusca-Maïto         if (!p[0]) p = opt; /* Assume it's a debug channel name */
753c2c66affSColin Finck 
754c2c66affSColin Finck         if (p > opt)
755c2c66affSColin Finck         {
756b2eaf905SHermès Bélusca-Maïto             for (j = 0; j < RTL_NUMBER_OF(debug_classes); j++)
757c2c66affSColin Finck             {
758c2c66affSColin Finck                 SIZE_T len = strlen(debug_classes[j].Name);
759c2c66affSColin Finck                 if (len != (p - opt))
760c2c66affSColin Finck                     continue;
76140c57de7SHermès Bélusca-Maïto                 if (_strnicmp(opt, debug_classes[j].Name, len) == 0) /* Found it */
762c2c66affSColin Finck                 {
763c2c66affSColin Finck                     if (*p == '+')
764c2c66affSColin Finck                         set |= debug_classes[j].Level;
765c2c66affSColin Finck                     else
766c2c66affSColin Finck                         clear |= debug_classes[j].Level;
767c2c66affSColin Finck                     break;
768c2c66affSColin Finck                 }
769c2c66affSColin Finck             }
770b2eaf905SHermès Bélusca-Maïto             if (j == RTL_NUMBER_OF(debug_classes))
771c2c66affSColin Finck             {
772c2c66affSColin Finck                 Level = strtoul(opt, &pend, 0);
773c2c66affSColin Finck                 if (pend != p)
774c2c66affSColin Finck                 {
775c2c66affSColin Finck                     KdbpPrint("filter: bad class name '%.*s'\n", p - opt, opt);
776c2c66affSColin Finck                     continue;
777c2c66affSColin Finck                 }
778c2c66affSColin Finck                 if (*p == '+')
779c2c66affSColin Finck                     set |= Level;
780c2c66affSColin Finck                 else
781c2c66affSColin Finck                     clear |= Level;
782c2c66affSColin Finck             }
783c2c66affSColin Finck         }
784c2c66affSColin Finck         else
785c2c66affSColin Finck         {
786c2c66affSColin Finck             if (*p == '-')
787c2c66affSColin Finck                 clear = MAXULONG;
788c2c66affSColin Finck             else
789c2c66affSColin Finck                 set = MAXULONG;
790c2c66affSColin Finck         }
791c2c66affSColin Finck         if (*p == '+' || *p == '-')
792c2c66affSColin Finck             p++;
793c2c66affSColin Finck 
794c2c66affSColin Finck         if (!KdbpGetComponentId(p, &ComponentId))
795c2c66affSColin Finck         {
796c2c66affSColin Finck             KdbpPrint("filter: '%s' is not a valid component name!\n", p);
797c2c66affSColin Finck             return TRUE;
798c2c66affSColin Finck         }
799c2c66affSColin Finck 
800c2c66affSColin Finck         /* Get current mask value */
801c2c66affSColin Finck         NtSetDebugFilterState(ComponentId, set, TRUE);
802c2c66affSColin Finck         NtSetDebugFilterState(ComponentId, clear, FALSE);
803c2c66affSColin Finck     }
804c2c66affSColin Finck 
805c2c66affSColin Finck     return TRUE;
806c2c66affSColin Finck }
807c2c66affSColin Finck 
808c2c66affSColin Finck /*!\brief Disassembles 10 instructions at eip or given address or
809c2c66affSColin Finck  *        displays 16 dwords from memory at given address.
810c2c66affSColin Finck  */
811c2c66affSColin Finck static BOOLEAN
812c2c66affSColin Finck KdbpCmdDisassembleX(
813c2c66affSColin Finck     ULONG Argc,
814c2c66affSColin Finck     PCHAR Argv[])
815c2c66affSColin Finck {
816c2c66affSColin Finck     ULONG Count;
817c2c66affSColin Finck     ULONG ul;
818c2c66affSColin Finck     INT i;
819c2c66affSColin Finck     ULONGLONG Result = 0;
8203726b992SJérôme Gardou     ULONG_PTR Address = KeGetContextPc(KdbCurrentTrapFrame);
821c2c66affSColin Finck     LONG InstLen;
822c2c66affSColin Finck 
823c2c66affSColin Finck     if (Argv[0][0] == 'x') /* display memory */
824c2c66affSColin Finck         Count = 16;
825c2c66affSColin Finck     else /* disassemble */
826c2c66affSColin Finck         Count = 10;
827c2c66affSColin Finck 
828c2c66affSColin Finck     if (Argc >= 2)
829c2c66affSColin Finck     {
830c2c66affSColin Finck         /* Check for [L count] part */
831c2c66affSColin Finck         ul = 0;
832c2c66affSColin Finck         if (strcmp(Argv[Argc-2], "L") == 0)
833c2c66affSColin Finck         {
834c2c66affSColin Finck             ul = strtoul(Argv[Argc-1], NULL, 0);
835c2c66affSColin Finck             if (ul > 0)
836c2c66affSColin Finck             {
837c2c66affSColin Finck                 Count = ul;
838c2c66affSColin Finck                 Argc -= 2;
839c2c66affSColin Finck             }
840c2c66affSColin Finck         }
841c2c66affSColin Finck         else if (Argv[Argc-1][0] == 'L')
842c2c66affSColin Finck         {
843c2c66affSColin Finck             ul = strtoul(Argv[Argc-1] + 1, NULL, 0);
844c2c66affSColin Finck             if (ul > 0)
845c2c66affSColin Finck             {
846c2c66affSColin Finck                 Count = ul;
847c2c66affSColin Finck                 Argc--;
848c2c66affSColin Finck             }
849c2c66affSColin Finck         }
850c2c66affSColin Finck 
851c2c66affSColin Finck         /* Put the remaining arguments back together */
852c2c66affSColin Finck         Argc--;
853c2c66affSColin Finck         for (ul = 1; ul < Argc; ul++)
854c2c66affSColin Finck         {
855c2c66affSColin Finck             Argv[ul][strlen(Argv[ul])] = ' ';
856c2c66affSColin Finck         }
857c2c66affSColin Finck         Argc++;
858c2c66affSColin Finck     }
859c2c66affSColin Finck 
860c2c66affSColin Finck     /* Evaluate the expression */
861c2c66affSColin Finck     if (Argc > 1)
862c2c66affSColin Finck     {
863a890fc64SHermès Bélusca-Maïto         if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
864c2c66affSColin Finck             return TRUE;
865c2c66affSColin Finck 
866c2c66affSColin Finck         if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
867c2c66affSColin Finck             KdbpPrint("Warning: Address %I64x is beeing truncated\n",Result);
868c2c66affSColin Finck 
869c2c66affSColin Finck         Address = (ULONG_PTR)Result;
870c2c66affSColin Finck     }
871c2c66affSColin Finck     else if (Argv[0][0] == 'x')
872c2c66affSColin Finck     {
873c2c66affSColin Finck         KdbpPrint("x: Address argument required.\n");
874c2c66affSColin Finck         return TRUE;
875c2c66affSColin Finck     }
876c2c66affSColin Finck 
877c2c66affSColin Finck     if (Argv[0][0] == 'x')
878c2c66affSColin Finck     {
879c2c66affSColin Finck         /* Display dwords */
880c2c66affSColin Finck         ul = 0;
881c2c66affSColin Finck 
882c2c66affSColin Finck         while (Count > 0)
883c2c66affSColin Finck         {
884c2c66affSColin Finck             if (!KdbSymPrintAddress((PVOID)Address, NULL))
88589b44cfaSHermès Bélusca-Maïto                 KdbpPrint("<%08x>:", Address);
886c2c66affSColin Finck             else
887c2c66affSColin Finck                 KdbpPrint(":");
888c2c66affSColin Finck 
889c2c66affSColin Finck             i = min(4, Count);
890c2c66affSColin Finck             Count -= i;
891c2c66affSColin Finck 
892c2c66affSColin Finck             while (--i >= 0)
893c2c66affSColin Finck             {
894c2c66affSColin Finck                 if (!NT_SUCCESS(KdbpSafeReadMemory(&ul, (PVOID)Address, sizeof(ul))))
895c2c66affSColin Finck                     KdbpPrint(" ????????");
896c2c66affSColin Finck                 else
897c2c66affSColin Finck                     KdbpPrint(" %08x", ul);
898c2c66affSColin Finck 
899c2c66affSColin Finck                 Address += sizeof(ul);
900c2c66affSColin Finck             }
901c2c66affSColin Finck 
902c2c66affSColin Finck             KdbpPrint("\n");
903c2c66affSColin Finck         }
904c2c66affSColin Finck     }
905c2c66affSColin Finck     else
906c2c66affSColin Finck     {
907c2c66affSColin Finck         /* Disassemble */
908c2c66affSColin Finck         while (Count-- > 0)
909c2c66affSColin Finck         {
910c2c66affSColin Finck             if (!KdbSymPrintAddress((PVOID)Address, NULL))
911c2c66affSColin Finck                 KdbpPrint("<%08x>: ", Address);
912c2c66affSColin Finck             else
913c2c66affSColin Finck                 KdbpPrint(": ");
914c2c66affSColin Finck 
915c2c66affSColin Finck             InstLen = KdbpDisassemble(Address, KdbUseIntelSyntax);
916c2c66affSColin Finck             if (InstLen < 0)
917c2c66affSColin Finck             {
918c2c66affSColin Finck                 KdbpPrint("<INVALID>\n");
919c2c66affSColin Finck                 return TRUE;
920c2c66affSColin Finck             }
921c2c66affSColin Finck 
922c2c66affSColin Finck             KdbpPrint("\n");
923c2c66affSColin Finck             Address += InstLen;
924c2c66affSColin Finck         }
925c2c66affSColin Finck     }
926c2c66affSColin Finck 
927c2c66affSColin Finck     return TRUE;
928c2c66affSColin Finck }
929c2c66affSColin Finck 
930c2c66affSColin Finck /*!\brief Displays CPU registers.
931c2c66affSColin Finck  */
932c2c66affSColin Finck static BOOLEAN
933c2c66affSColin Finck KdbpCmdRegs(
934c2c66affSColin Finck     ULONG Argc,
935c2c66affSColin Finck     PCHAR Argv[])
936c2c66affSColin Finck {
937baa47fa5SHervé Poussineau     PCONTEXT Context = KdbCurrentTrapFrame;
938c2c66affSColin Finck     INT i;
939c2c66affSColin Finck     static const PCHAR EflagsBits[32] = { " CF", NULL, " PF", " BIT3", " AF", " BIT5",
940c2c66affSColin Finck                                           " ZF", " SF", " TF", " IF", " DF", " OF",
941c2c66affSColin Finck                                           NULL, NULL, " NT", " BIT15", " RF", " VF",
942c2c66affSColin Finck                                           " AC", " VIF", " VIP", " ID", " BIT22",
943c2c66affSColin Finck                                           " BIT23", " BIT24", " BIT25", " BIT26",
944c2c66affSColin Finck                                           " BIT27", " BIT28", " BIT29", " BIT30",
945c2c66affSColin Finck                                           " BIT31" };
946c2c66affSColin Finck 
947c2c66affSColin Finck     if (Argv[0][0] == 'r') /* regs */
948c2c66affSColin Finck     {
9493726b992SJérôme Gardou #ifdef _M_IX86
950c2c66affSColin Finck         KdbpPrint("CS:EIP  0x%04x:0x%08x\n"
951c2c66affSColin Finck                   "SS:ESP  0x%04x:0x%08x\n"
952c2c66affSColin Finck                   "   EAX  0x%08x   EBX  0x%08x\n"
953c2c66affSColin Finck                   "   ECX  0x%08x   EDX  0x%08x\n"
954c2c66affSColin Finck                   "   ESI  0x%08x   EDI  0x%08x\n"
955c2c66affSColin Finck                   "   EBP  0x%08x\n",
956baa47fa5SHervé Poussineau                   Context->SegCs & 0xFFFF, Context->Eip,
957baa47fa5SHervé Poussineau                   Context->SegSs, Context->Esp,
958baa47fa5SHervé Poussineau                   Context->Eax, Context->Ebx,
959baa47fa5SHervé Poussineau                   Context->Ecx, Context->Edx,
960baa47fa5SHervé Poussineau                   Context->Esi, Context->Edi,
961baa47fa5SHervé Poussineau                   Context->Ebp);
9623726b992SJérôme Gardou #else
9633726b992SJérôme Gardou         KdbpPrint("CS:RIP  0x%04x:0x%p\n"
9643726b992SJérôme Gardou                   "SS:RSP  0x%04x:0x%p\n"
9653726b992SJérôme Gardou                   "   RAX  0x%p     RBX  0x%p\n"
9663726b992SJérôme Gardou                   "   RCX  0x%p     RDX  0x%p\n"
9673726b992SJérôme Gardou                   "   RSI  0x%p     RDI  0x%p\n"
9683726b992SJérôme Gardou                   "   RBP  0x%p\n",
9693726b992SJérôme Gardou                   Context->SegCs & 0xFFFF, Context->Rip,
9703726b992SJérôme Gardou                   Context->SegSs, Context->Rsp,
9713726b992SJérôme Gardou                   Context->Rax, Context->Rbx,
9723726b992SJérôme Gardou                   Context->Rcx, Context->Rdx,
9733726b992SJérôme Gardou                   Context->Rsi, Context->Rdi,
9743726b992SJérôme Gardou                   Context->Rbp);
9753726b992SJérôme Gardou #endif
976dc0c721fSHermès Bélusca-Maïto         /* Display the EFlags */
977baa47fa5SHervé Poussineau         KdbpPrint("EFLAGS  0x%08x ", Context->EFlags);
978c2c66affSColin Finck         for (i = 0; i < 32; i++)
979c2c66affSColin Finck         {
980c2c66affSColin Finck             if (i == 1)
981c2c66affSColin Finck             {
982baa47fa5SHervé Poussineau                 if ((Context->EFlags & (1 << 1)) == 0)
983c2c66affSColin Finck                     KdbpPrint(" !BIT1");
984c2c66affSColin Finck             }
985c2c66affSColin Finck             else if (i == 12)
986c2c66affSColin Finck             {
987baa47fa5SHervé Poussineau                 KdbpPrint(" IOPL%d", (Context->EFlags >> 12) & 3);
988c2c66affSColin Finck             }
989c2c66affSColin Finck             else if (i == 13)
990c2c66affSColin Finck             {
991c2c66affSColin Finck             }
992baa47fa5SHervé Poussineau             else if ((Context->EFlags & (1 << i)) != 0)
993c2c66affSColin Finck             {
994c2c66affSColin Finck                 KdbpPrint(EflagsBits[i]);
995c2c66affSColin Finck             }
996c2c66affSColin Finck         }
997c2c66affSColin Finck         KdbpPrint("\n");
998c2c66affSColin Finck     }
999c2c66affSColin Finck     else if (Argv[0][0] == 's') /* sregs */
1000c2c66affSColin Finck     {
1001c2c66affSColin Finck         KdbpPrint("CS  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1002baa47fa5SHervé Poussineau                   Context->SegCs & 0xffff, (Context->SegCs & 0xffff) >> 3,
1003baa47fa5SHervé Poussineau                   (Context->SegCs & (1 << 2)) ? 'L' : 'G', Context->SegCs & 3);
1004c2c66affSColin Finck         KdbpPrint("DS  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1005baa47fa5SHervé Poussineau                   Context->SegDs, Context->SegDs >> 3, (Context->SegDs & (1 << 2)) ? 'L' : 'G', Context->SegDs & 3);
1006c2c66affSColin Finck         KdbpPrint("ES  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1007baa47fa5SHervé Poussineau                   Context->SegEs, Context->SegEs >> 3, (Context->SegEs & (1 << 2)) ? 'L' : 'G', Context->SegEs & 3);
1008c2c66affSColin Finck         KdbpPrint("FS  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1009baa47fa5SHervé Poussineau                   Context->SegFs, Context->SegFs >> 3, (Context->SegFs & (1 << 2)) ? 'L' : 'G', Context->SegFs & 3);
1010c2c66affSColin Finck         KdbpPrint("GS  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1011baa47fa5SHervé Poussineau                   Context->SegGs, Context->SegGs >> 3, (Context->SegGs & (1 << 2)) ? 'L' : 'G', Context->SegGs & 3);
1012c2c66affSColin Finck         KdbpPrint("SS  0x%04x  Index 0x%04x  %cDT RPL%d\n",
1013baa47fa5SHervé Poussineau                   Context->SegSs, Context->SegSs >> 3, (Context->SegSs & (1 << 2)) ? 'L' : 'G', Context->SegSs & 3);
1014c2c66affSColin Finck     }
1015c2c66affSColin Finck     else /* dregs */
1016c2c66affSColin Finck     {
1017c2c66affSColin Finck         ASSERT(Argv[0][0] == 'd');
1018c2c66affSColin Finck         KdbpPrint("DR0  0x%08x\n"
1019c2c66affSColin Finck                   "DR1  0x%08x\n"
1020c2c66affSColin Finck                   "DR2  0x%08x\n"
1021c2c66affSColin Finck                   "DR3  0x%08x\n"
1022c2c66affSColin Finck                   "DR6  0x%08x\n"
1023c2c66affSColin Finck                   "DR7  0x%08x\n",
1024baa47fa5SHervé Poussineau                   Context->Dr0, Context->Dr1, Context->Dr2, Context->Dr3,
1025baa47fa5SHervé Poussineau                   Context->Dr6, Context->Dr7);
1026c2c66affSColin Finck     }
1027c2c66affSColin Finck 
1028c2c66affSColin Finck     return TRUE;
1029c2c66affSColin Finck }
1030c2c66affSColin Finck 
10313726b992SJérôme Gardou #ifdef _M_IX86
10328826ee8fSHermès Bélusca-Maïto static PKTSS
10338826ee8fSHermès Bélusca-Maïto KdbpRetrieveTss(
10348826ee8fSHermès Bélusca-Maïto     IN USHORT TssSelector,
10358826ee8fSHermès Bélusca-Maïto     OUT PULONG pType OPTIONAL,
10368826ee8fSHermès Bélusca-Maïto     IN PKDESCRIPTOR pGdtr OPTIONAL)
10378826ee8fSHermès Bélusca-Maïto {
10388826ee8fSHermès Bélusca-Maïto     KDESCRIPTOR Gdtr;
10398826ee8fSHermès Bélusca-Maïto     KGDTENTRY Desc;
10408826ee8fSHermès Bélusca-Maïto     PKTSS Tss;
10418826ee8fSHermès Bélusca-Maïto 
10428826ee8fSHermès Bélusca-Maïto     /* Retrieve the Global Descriptor Table (user-provided or system) */
10438826ee8fSHermès Bélusca-Maïto     if (pGdtr)
10448826ee8fSHermès Bélusca-Maïto         Gdtr = *pGdtr;
10458826ee8fSHermès Bélusca-Maïto     else
10468826ee8fSHermès Bélusca-Maïto         Ke386GetGlobalDescriptorTable(&Gdtr.Limit);
10478826ee8fSHermès Bélusca-Maïto 
10488826ee8fSHermès Bélusca-Maïto     /* Check limits */
10498826ee8fSHermès Bélusca-Maïto     if ((TssSelector & (sizeof(KGDTENTRY) - 1)) ||
10508826ee8fSHermès Bélusca-Maïto         (TssSelector < sizeof(KGDTENTRY)) ||
10518826ee8fSHermès Bélusca-Maïto         (TssSelector + sizeof(KGDTENTRY) - 1 > Gdtr.Limit))
10528826ee8fSHermès Bélusca-Maïto     {
10538826ee8fSHermès Bélusca-Maïto         return NULL;
10548826ee8fSHermès Bélusca-Maïto     }
10558826ee8fSHermès Bélusca-Maïto 
10568826ee8fSHermès Bélusca-Maïto     /* Retrieve the descriptor */
10578826ee8fSHermès Bélusca-Maïto     if (!NT_SUCCESS(KdbpSafeReadMemory(&Desc,
10588826ee8fSHermès Bélusca-Maïto                                        (PVOID)(Gdtr.Base + TssSelector),
10598826ee8fSHermès Bélusca-Maïto                                        sizeof(KGDTENTRY))))
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 
10648826ee8fSHermès Bélusca-Maïto     /* Check for TSS32(Avl) or TSS32(Busy) */
10658826ee8fSHermès Bélusca-Maïto     if (Desc.HighWord.Bits.Type != 9 && Desc.HighWord.Bits.Type != 11)
10668826ee8fSHermès Bélusca-Maïto     {
10678826ee8fSHermès Bélusca-Maïto         return NULL;
10688826ee8fSHermès Bélusca-Maïto     }
10698826ee8fSHermès Bélusca-Maïto     if (pType) *pType = Desc.HighWord.Bits.Type;
10708826ee8fSHermès Bélusca-Maïto 
10718826ee8fSHermès Bélusca-Maïto     Tss = (PKTSS)(ULONG_PTR)(Desc.BaseLow |
10728826ee8fSHermès Bélusca-Maïto                              Desc.HighWord.Bytes.BaseMid << 16 |
10738826ee8fSHermès Bélusca-Maïto                              Desc.HighWord.Bytes.BaseHi << 24);
10748826ee8fSHermès Bélusca-Maïto 
10758826ee8fSHermès Bélusca-Maïto     return Tss;
10768826ee8fSHermès Bélusca-Maïto }
10778826ee8fSHermès Bélusca-Maïto 
1078d21ff0edSHermès Bélusca-Maïto FORCEINLINE BOOLEAN
1079d21ff0edSHermès Bélusca-Maïto KdbpIsNestedTss(
1080d21ff0edSHermès Bélusca-Maïto     IN USHORT TssSelector,
1081d21ff0edSHermès Bélusca-Maïto     IN PKTSS Tss)
1082c2c66affSColin Finck {
1083d21ff0edSHermès Bélusca-Maïto     USHORT Backlink;
1084c2c66affSColin Finck 
1085d21ff0edSHermès Bélusca-Maïto     if (!Tss)
1086c2c66affSColin Finck         return FALSE;
1087c2c66affSColin Finck 
1088d21ff0edSHermès Bélusca-Maïto     /* Retrieve the TSS Backlink */
1089d21ff0edSHermès Bélusca-Maïto     if (!NT_SUCCESS(KdbpSafeReadMemory(&Backlink,
1090c2c66affSColin Finck                                        (PVOID)&Tss->Backlink,
1091c2c66affSColin Finck                                        sizeof(USHORT))))
1092d21ff0edSHermès Bélusca-Maïto     {
1093c2c66affSColin Finck         return FALSE;
1094d21ff0edSHermès Bélusca-Maïto     }
1095c2c66affSColin Finck 
1096d21ff0edSHermès Bélusca-Maïto     return (Backlink != 0 && Backlink != TssSelector);
1097d21ff0edSHermès Bélusca-Maïto }
1098d21ff0edSHermès Bélusca-Maïto 
1099d21ff0edSHermès Bélusca-Maïto static BOOLEAN
1100baa47fa5SHervé Poussineau KdbpContextFromPrevTss(
1101baa47fa5SHervé Poussineau     IN OUT PCONTEXT Context,
1102d21ff0edSHermès Bélusca-Maïto     OUT PUSHORT TssSelector,
1103d21ff0edSHermès Bélusca-Maïto     IN OUT PKTSS* pTss,
1104d21ff0edSHermès Bélusca-Maïto     IN PKDESCRIPTOR pGdtr)
1105d21ff0edSHermès Bélusca-Maïto {
1106d21ff0edSHermès Bélusca-Maïto     ULONG_PTR Eip, Ebp;
1107d21ff0edSHermès Bélusca-Maïto     USHORT Backlink;
1108d21ff0edSHermès Bélusca-Maïto     PKTSS Tss = *pTss;
1109d21ff0edSHermès Bélusca-Maïto 
1110d21ff0edSHermès Bélusca-Maïto     /* Retrieve the TSS Backlink */
1111d21ff0edSHermès Bélusca-Maïto     if (!NT_SUCCESS(KdbpSafeReadMemory(&Backlink,
1112d21ff0edSHermès Bélusca-Maïto                                        (PVOID)&Tss->Backlink,
1113d21ff0edSHermès Bélusca-Maïto                                        sizeof(USHORT))))
1114d21ff0edSHermès Bélusca-Maïto     {
1115c2c66affSColin Finck         return FALSE;
1116d21ff0edSHermès Bélusca-Maïto     }
1117c2c66affSColin Finck 
1118d21ff0edSHermès Bélusca-Maïto     /* Retrieve the parent TSS */
1119d21ff0edSHermès Bélusca-Maïto     Tss = KdbpRetrieveTss(Backlink, NULL, pGdtr);
1120d21ff0edSHermès Bélusca-Maïto     if (!Tss)
1121c2c66affSColin Finck         return FALSE;
1122c2c66affSColin Finck 
1123c2c66affSColin Finck     if (!NT_SUCCESS(KdbpSafeReadMemory(&Eip,
1124c2c66affSColin Finck                                        (PVOID)&Tss->Eip,
1125c2c66affSColin Finck                                        sizeof(ULONG_PTR))))
1126d21ff0edSHermès Bélusca-Maïto     {
1127c2c66affSColin Finck         return FALSE;
1128d21ff0edSHermès Bélusca-Maïto     }
1129c2c66affSColin Finck 
1130c2c66affSColin Finck     if (!NT_SUCCESS(KdbpSafeReadMemory(&Ebp,
1131c2c66affSColin Finck                                        (PVOID)&Tss->Ebp,
1132c2c66affSColin Finck                                        sizeof(ULONG_PTR))))
1133d21ff0edSHermès Bélusca-Maïto     {
1134c2c66affSColin Finck         return FALSE;
1135d21ff0edSHermès Bélusca-Maïto     }
1136c2c66affSColin Finck 
1137d21ff0edSHermès Bélusca-Maïto     /* Return the parent TSS and its trap frame */
1138d21ff0edSHermès Bélusca-Maïto     *TssSelector = Backlink;
1139d21ff0edSHermès Bélusca-Maïto     *pTss = Tss;
1140baa47fa5SHervé Poussineau     Context->Eip = Eip;
1141baa47fa5SHervé Poussineau     Context->Ebp = Ebp;
1142c2c66affSColin Finck     return TRUE;
1143c2c66affSColin Finck }
11443726b992SJérôme Gardou #endif
1145c2c66affSColin Finck 
1146c2c66affSColin Finck /*!\brief Displays a backtrace.
1147c2c66affSColin Finck  */
1148c2c66affSColin Finck static BOOLEAN
1149c2c66affSColin Finck KdbpCmdBackTrace(
1150c2c66affSColin Finck     ULONG Argc,
1151c2c66affSColin Finck     PCHAR Argv[])
1152c2c66affSColin Finck {
1153c2c66affSColin Finck     ULONG ul;
1154c2c66affSColin Finck     ULONGLONG Result = 0;
1155baa47fa5SHervé Poussineau     CONTEXT Context = *KdbCurrentTrapFrame;
11563726b992SJérôme Gardou     ULONG_PTR Frame = KeGetContextFrameRegister(&Context);
1157c2c66affSColin Finck     ULONG_PTR Address;
1158c2c66affSColin Finck 
1159c2c66affSColin Finck     if (Argc >= 2)
1160c2c66affSColin Finck     {
1161c2c66affSColin Finck         /* Check for [L count] part */
1162c2c66affSColin Finck         ul = 0;
1163c2c66affSColin Finck         if (strcmp(Argv[Argc-2], "L") == 0)
1164c2c66affSColin Finck         {
1165c2c66affSColin Finck             ul = strtoul(Argv[Argc-1], NULL, 0);
1166c2c66affSColin Finck             if (ul > 0)
1167c2c66affSColin Finck             {
1168c2c66affSColin Finck                 Argc -= 2;
1169c2c66affSColin Finck             }
1170c2c66affSColin Finck         }
1171c2c66affSColin Finck         else if (Argv[Argc-1][0] == 'L')
1172c2c66affSColin Finck         {
1173c2c66affSColin Finck             ul = strtoul(Argv[Argc-1] + 1, NULL, 0);
1174c2c66affSColin Finck             if (ul > 0)
1175c2c66affSColin Finck             {
1176c2c66affSColin Finck                 Argc--;
1177c2c66affSColin Finck             }
1178c2c66affSColin Finck         }
1179c2c66affSColin Finck 
1180c2c66affSColin Finck         /* Put the remaining arguments back together */
1181c2c66affSColin Finck         Argc--;
1182c2c66affSColin Finck         for (ul = 1; ul < Argc; ul++)
1183c2c66affSColin Finck         {
1184c2c66affSColin Finck             Argv[ul][strlen(Argv[ul])] = ' ';
1185c2c66affSColin Finck         }
1186c2c66affSColin Finck         Argc++;
1187c2c66affSColin Finck     }
1188c2c66affSColin Finck 
1189d21ff0edSHermès Bélusca-Maïto     /* Check if a Frame Address or Thread ID is given */
1190c2c66affSColin Finck     if (Argc > 1)
1191c2c66affSColin Finck     {
1192c2c66affSColin Finck         if (Argv[1][0] == '*')
1193c2c66affSColin Finck         {
1194c2c66affSColin Finck             Argv[1]++;
1195c2c66affSColin Finck 
1196c2c66affSColin Finck             /* Evaluate the expression */
1197a890fc64SHermès Bélusca-Maïto             if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
1198c2c66affSColin Finck                 return TRUE;
1199c2c66affSColin Finck 
1200c2c66affSColin Finck             if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
1201c2c66affSColin Finck                 KdbpPrint("Warning: Address %I64x is beeing truncated\n", Result);
1202c2c66affSColin Finck 
1203c2c66affSColin Finck             Frame = (ULONG_PTR)Result;
1204c2c66affSColin Finck         }
1205c2c66affSColin Finck         else
1206c2c66affSColin Finck         {
1207c2c66affSColin Finck             KdbpPrint("Thread backtrace not supported yet!\n");
1208c2c66affSColin Finck             return TRUE;
1209c2c66affSColin Finck         }
1210c2c66affSColin Finck     }
1211d21ff0edSHermès Bélusca-Maïto 
12123726b992SJérôme Gardou #ifdef _M_IX86
12133726b992SJérôme Gardou     KDESCRIPTOR Gdtr;
12143726b992SJérôme Gardou     USHORT TssSelector;
12153726b992SJérôme Gardou     PKTSS Tss;
12163726b992SJérôme Gardou 
1217d21ff0edSHermès Bélusca-Maïto     /* Retrieve the Global Descriptor Table */
1218d21ff0edSHermès Bélusca-Maïto     Ke386GetGlobalDescriptorTable(&Gdtr.Limit);
1219d21ff0edSHermès Bélusca-Maïto 
1220d21ff0edSHermès Bélusca-Maïto     /* Retrieve the current (active) TSS */
1221d21ff0edSHermès Bélusca-Maïto     TssSelector = Ke386GetTr();
1222d21ff0edSHermès Bélusca-Maïto     Tss = KdbpRetrieveTss(TssSelector, NULL, &Gdtr);
1223d21ff0edSHermès Bélusca-Maïto     if (KdbpIsNestedTss(TssSelector, Tss))
1224d21ff0edSHermès Bélusca-Maïto     {
1225d21ff0edSHermès Bélusca-Maïto         /* Display the active TSS if it is nested */
1226d21ff0edSHermès Bélusca-Maïto         KdbpPrint("[Active TSS 0x%04x @ 0x%p]\n", TssSelector, Tss);
1227d21ff0edSHermès Bélusca-Maïto     }
12283726b992SJérôme Gardou #endif
1229d21ff0edSHermès Bélusca-Maïto 
1230d21ff0edSHermès Bélusca-Maïto     /* If no Frame Address or Thread ID was given, try printing the function at EIP */
1231d21ff0edSHermès Bélusca-Maïto     if (Argc <= 1)
1232c2c66affSColin Finck     {
1233c2c66affSColin Finck         KdbpPrint("Eip:\n");
12343726b992SJérôme Gardou         if (!KdbSymPrintAddress((PVOID)KeGetContextPc(&Context), &Context))
12353726b992SJérôme Gardou             KdbpPrint("<%p>\n", KeGetContextPc(&Context));
1236c2c66affSColin Finck         else
1237c2c66affSColin Finck             KdbpPrint("\n");
1238c2c66affSColin Finck     }
1239c2c66affSColin Finck 
1240d21ff0edSHermès Bélusca-Maïto     /* Walk through the frames */
1241c2c66affSColin Finck     KdbpPrint("Frames:\n");
1242c2c66affSColin Finck     for (;;)
1243c2c66affSColin Finck     {
1244c2c66affSColin Finck         BOOLEAN GotNextFrame;
1245c2c66affSColin Finck 
1246c2c66affSColin Finck         if (Frame == 0)
1247d21ff0edSHermès Bélusca-Maïto             goto CheckForParentTSS;
1248c2c66affSColin Finck 
1249d21ff0edSHermès Bélusca-Maïto         Address = 0;
1250c2c66affSColin Finck         if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, (PVOID)(Frame + sizeof(ULONG_PTR)), sizeof(ULONG_PTR))))
1251c2c66affSColin Finck         {
1252c2c66affSColin Finck             KdbpPrint("Couldn't access memory at 0x%p!\n", Frame + sizeof(ULONG_PTR));
1253d21ff0edSHermès Bélusca-Maïto             goto CheckForParentTSS;
1254c2c66affSColin Finck         }
1255c2c66affSColin Finck 
1256d21ff0edSHermès Bélusca-Maïto         if (Address == 0)
1257d21ff0edSHermès Bélusca-Maïto             goto CheckForParentTSS;
1258c2c66affSColin Finck 
1259d21ff0edSHermès Bélusca-Maïto         GotNextFrame = NT_SUCCESS(KdbpSafeReadMemory(&Frame, (PVOID)Frame, sizeof(ULONG_PTR)));
1260d21ff0edSHermès Bélusca-Maïto         if (GotNextFrame)
12613726b992SJérôme Gardou         {
12623726b992SJérôme Gardou             KeSetContextFrameRegister(&Context, Frame);
12633726b992SJérôme Gardou         }
1264d21ff0edSHermès Bélusca-Maïto         // else
1265d21ff0edSHermès Bélusca-Maïto             // Frame = 0;
1266d21ff0edSHermès Bélusca-Maïto 
1267d21ff0edSHermès Bélusca-Maïto         /* Print the location of the call instruction (assumed 5 bytes length) */
1268baa47fa5SHervé Poussineau         if (!KdbSymPrintAddress((PVOID)(Address - 5), &Context))
1269c2c66affSColin Finck             KdbpPrint("<%08x>\n", Address);
1270c2c66affSColin Finck         else
1271c2c66affSColin Finck             KdbpPrint("\n");
1272c2c66affSColin Finck 
1273d21ff0edSHermès Bélusca-Maïto         if (KdbOutputAborted)
1274c2c66affSColin Finck             break;
1275c2c66affSColin Finck 
1276d21ff0edSHermès Bélusca-Maïto         if (!GotNextFrame)
1277c2c66affSColin Finck         {
1278d21ff0edSHermès Bélusca-Maïto             KdbpPrint("Couldn't access memory at 0x%p!\n", Frame);
1279d21ff0edSHermès Bélusca-Maïto             goto CheckForParentTSS; // break;
1280d21ff0edSHermès Bélusca-Maïto         }
1281d21ff0edSHermès Bélusca-Maïto 
1282d21ff0edSHermès Bélusca-Maïto         continue;
1283d21ff0edSHermès Bélusca-Maïto 
1284d21ff0edSHermès Bélusca-Maïto CheckForParentTSS:
12853726b992SJérôme Gardou #ifndef _M_IX86
12863726b992SJérôme Gardou         break;
12873726b992SJérôme Gardou #else
1288d21ff0edSHermès Bélusca-Maïto         /*
1289d21ff0edSHermès Bélusca-Maïto          * We have ended the stack walking for the current (active) TSS.
1290d21ff0edSHermès Bélusca-Maïto          * Check whether this TSS was nested, and if so switch to its parent
1291d21ff0edSHermès Bélusca-Maïto          * and walk its stack.
1292d21ff0edSHermès Bélusca-Maïto          */
1293d21ff0edSHermès Bélusca-Maïto         if (!KdbpIsNestedTss(TssSelector, Tss))
1294d21ff0edSHermès Bélusca-Maïto             break; // The TSS is not nested, we stop there.
1295d21ff0edSHermès Bélusca-Maïto 
1296baa47fa5SHervé Poussineau         GotNextFrame = KdbpContextFromPrevTss(&Context, &TssSelector, &Tss, &Gdtr);
1297d21ff0edSHermès Bélusca-Maïto         if (!GotNextFrame)
1298c2c66affSColin Finck         {
1299d21ff0edSHermès Bélusca-Maïto             KdbpPrint("Couldn't access parent TSS 0x%04x\n", Tss->Backlink);
1300d21ff0edSHermès Bélusca-Maïto             break; // Cannot retrieve the parent TSS, we stop there.
1301d21ff0edSHermès Bélusca-Maïto         }
13023726b992SJérôme Gardou 
13033726b992SJérôme Gardou 
1304baa47fa5SHervé Poussineau         Address = Context.Eip;
1305baa47fa5SHervé Poussineau         Frame = Context.Ebp;
1306c2c66affSColin Finck 
1307d21ff0edSHermès Bélusca-Maïto         KdbpPrint("[Parent TSS 0x%04x @ 0x%p]\n", TssSelector, Tss);
1308d21ff0edSHermès Bélusca-Maïto 
1309baa47fa5SHervé Poussineau         if (!KdbSymPrintAddress((PVOID)Address, &Context))
1310c2c66affSColin Finck             KdbpPrint("<%08x>\n", Address);
1311c2c66affSColin Finck         else
1312c2c66affSColin Finck             KdbpPrint("\n");
13133726b992SJérôme Gardou #endif
1314c2c66affSColin Finck     }
1315c2c66affSColin Finck 
1316c2c66affSColin Finck     return TRUE;
1317c2c66affSColin Finck }
1318c2c66affSColin Finck 
1319c2c66affSColin Finck /*!\brief Continues execution of the system/leaves KDB.
1320c2c66affSColin Finck  */
1321c2c66affSColin Finck static BOOLEAN
1322c2c66affSColin Finck KdbpCmdContinue(
1323c2c66affSColin Finck     ULONG Argc,
1324c2c66affSColin Finck     PCHAR Argv[])
1325c2c66affSColin Finck {
1326c2c66affSColin Finck     /* Exit the main loop */
1327c2c66affSColin Finck     return FALSE;
1328c2c66affSColin Finck }
1329c2c66affSColin Finck 
1330c2c66affSColin Finck /*!\brief Continues execution of the system/leaves KDB.
1331c2c66affSColin Finck  */
1332c2c66affSColin Finck static BOOLEAN
1333c2c66affSColin Finck KdbpCmdStep(
1334c2c66affSColin Finck     ULONG Argc,
1335c2c66affSColin Finck     PCHAR Argv[])
1336c2c66affSColin Finck {
1337c2c66affSColin Finck     ULONG Count = 1;
1338c2c66affSColin Finck 
1339c2c66affSColin Finck     if (Argc > 1)
1340c2c66affSColin Finck     {
1341c2c66affSColin Finck         Count = strtoul(Argv[1], NULL, 0);
1342c2c66affSColin Finck         if (Count == 0)
1343c2c66affSColin Finck         {
1344c2c66affSColin Finck             KdbpPrint("%s: Integer argument required\n", Argv[0]);
1345c2c66affSColin Finck             return TRUE;
1346c2c66affSColin Finck         }
1347c2c66affSColin Finck     }
1348c2c66affSColin Finck 
1349c2c66affSColin Finck     if (Argv[0][0] == 'n')
1350c2c66affSColin Finck         KdbSingleStepOver = TRUE;
1351c2c66affSColin Finck     else
1352c2c66affSColin Finck         KdbSingleStepOver = FALSE;
1353c2c66affSColin Finck 
1354c2c66affSColin Finck     /* Set the number of single steps and return to the interrupted code. */
1355c2c66affSColin Finck     KdbNumSingleSteps = Count;
1356c2c66affSColin Finck 
1357c2c66affSColin Finck     return FALSE;
1358c2c66affSColin Finck }
1359c2c66affSColin Finck 
1360c2c66affSColin Finck /*!\brief Lists breakpoints.
1361c2c66affSColin Finck  */
1362c2c66affSColin Finck static BOOLEAN
1363c2c66affSColin Finck KdbpCmdBreakPointList(
1364c2c66affSColin Finck     ULONG Argc,
1365c2c66affSColin Finck     PCHAR Argv[])
1366c2c66affSColin Finck {
1367c2c66affSColin Finck     LONG l;
1368c2c66affSColin Finck     ULONG_PTR Address = 0;
1369c2c66affSColin Finck     KDB_BREAKPOINT_TYPE Type = 0;
1370c2c66affSColin Finck     KDB_ACCESS_TYPE AccessType = 0;
1371c2c66affSColin Finck     UCHAR Size = 0;
1372c2c66affSColin Finck     UCHAR DebugReg = 0;
1373c2c66affSColin Finck     BOOLEAN Enabled = FALSE;
1374c2c66affSColin Finck     BOOLEAN Global = FALSE;
1375c2c66affSColin Finck     PEPROCESS Process = NULL;
1376c2c66affSColin Finck     PCHAR str1, str2, ConditionExpr, GlobalOrLocal;
1377c2c66affSColin Finck     CHAR Buffer[20];
1378c2c66affSColin Finck 
1379c2c66affSColin Finck     l = KdbpGetNextBreakPointNr(0);
1380c2c66affSColin Finck     if (l < 0)
1381c2c66affSColin Finck     {
1382c2c66affSColin Finck         KdbpPrint("No breakpoints.\n");
1383c2c66affSColin Finck         return TRUE;
1384c2c66affSColin Finck     }
1385c2c66affSColin Finck 
1386c2c66affSColin Finck     KdbpPrint("Breakpoints:\n");
1387c2c66affSColin Finck     do
1388c2c66affSColin Finck     {
1389c2c66affSColin Finck         if (!KdbpGetBreakPointInfo(l, &Address, &Type, &Size, &AccessType, &DebugReg,
1390c2c66affSColin Finck                                    &Enabled, &Global, &Process, &ConditionExpr))
1391c2c66affSColin Finck         {
1392c2c66affSColin Finck             continue;
1393c2c66affSColin Finck         }
1394c2c66affSColin Finck 
1395c2c66affSColin Finck         if (l == KdbLastBreakPointNr)
1396c2c66affSColin Finck         {
1397c2c66affSColin Finck             str1 = "\x1b[1m*";
1398c2c66affSColin Finck             str2 = "\x1b[0m";
1399c2c66affSColin Finck         }
1400c2c66affSColin Finck         else
1401c2c66affSColin Finck         {
1402c2c66affSColin Finck             str1 = " ";
1403c2c66affSColin Finck             str2 = "";
1404c2c66affSColin Finck         }
1405c2c66affSColin Finck 
1406c2c66affSColin Finck         if (Global)
1407c2c66affSColin Finck         {
1408c2c66affSColin Finck             GlobalOrLocal = "  global";
1409c2c66affSColin Finck         }
1410c2c66affSColin Finck         else
1411c2c66affSColin Finck         {
1412c2c66affSColin Finck             GlobalOrLocal = Buffer;
14133726b992SJérôme Gardou             sprintf(Buffer, "  PID 0x%lx",
14143726b992SJérôme Gardou                     (ULONG_PTR)(Process ? Process->UniqueProcessId : INVALID_HANDLE_VALUE));
1415c2c66affSColin Finck         }
1416c2c66affSColin Finck 
1417c2c66affSColin Finck         if (Type == KdbBreakPointSoftware || Type == KdbBreakPointTemporary)
1418c2c66affSColin Finck         {
1419c2c66affSColin Finck             KdbpPrint(" %s%03d  BPX  0x%08x%s%s%s%s%s\n",
1420c2c66affSColin Finck                       str1, l, Address,
1421c2c66affSColin Finck                       Enabled ? "" : "  disabled",
1422c2c66affSColin Finck                       GlobalOrLocal,
1423c2c66affSColin Finck                       ConditionExpr ? "  IF " : "",
1424c2c66affSColin Finck                       ConditionExpr ? ConditionExpr : "",
1425c2c66affSColin Finck                       str2);
1426c2c66affSColin Finck         }
1427c2c66affSColin Finck         else if (Type == KdbBreakPointHardware)
1428c2c66affSColin Finck         {
1429c2c66affSColin Finck             if (!Enabled)
1430c2c66affSColin Finck             {
1431c2c66affSColin Finck                 KdbpPrint(" %s%03d  BPM  0x%08x  %-5s %-5s  disabled%s%s%s%s\n", str1, l, Address,
1432c2c66affSColin Finck                           KDB_ACCESS_TYPE_TO_STRING(AccessType),
1433c2c66affSColin Finck                           Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"),
1434c2c66affSColin Finck                           GlobalOrLocal,
1435c2c66affSColin Finck                           ConditionExpr ? "  IF " : "",
1436c2c66affSColin Finck                           ConditionExpr ? ConditionExpr : "",
1437c2c66affSColin Finck                           str2);
1438c2c66affSColin Finck             }
1439c2c66affSColin Finck             else
1440c2c66affSColin Finck             {
1441c2c66affSColin Finck                 KdbpPrint(" %s%03d  BPM  0x%08x  %-5s %-5s  DR%d%s%s%s%s\n", str1, l, Address,
1442c2c66affSColin Finck                           KDB_ACCESS_TYPE_TO_STRING(AccessType),
1443c2c66affSColin Finck                           Size == 1 ? "byte" : (Size == 2 ? "word" : "dword"),
1444c2c66affSColin Finck                           DebugReg,
1445c2c66affSColin Finck                           GlobalOrLocal,
1446c2c66affSColin Finck                           ConditionExpr ? "  IF " : "",
1447c2c66affSColin Finck                           ConditionExpr ? ConditionExpr : "",
1448c2c66affSColin Finck                           str2);
1449c2c66affSColin Finck             }
1450c2c66affSColin Finck         }
1451c2c66affSColin Finck     }
1452c2c66affSColin Finck     while ((l = KdbpGetNextBreakPointNr(l+1)) >= 0);
1453c2c66affSColin Finck 
1454c2c66affSColin Finck     return TRUE;
1455c2c66affSColin Finck }
1456c2c66affSColin Finck 
1457c2c66affSColin Finck /*!\brief Enables, disables or clears a breakpoint.
1458c2c66affSColin Finck  */
1459c2c66affSColin Finck static BOOLEAN
1460c2c66affSColin Finck KdbpCmdEnableDisableClearBreakPoint(
1461c2c66affSColin Finck     ULONG Argc,
1462c2c66affSColin Finck     PCHAR Argv[])
1463c2c66affSColin Finck {
1464c2c66affSColin Finck     PCHAR pend;
1465c2c66affSColin Finck     ULONG BreakPointNr;
1466c2c66affSColin Finck 
1467c2c66affSColin Finck     if (Argc < 2)
1468c2c66affSColin Finck     {
1469c2c66affSColin Finck         KdbpPrint("%s: argument required\n", Argv[0]);
1470c2c66affSColin Finck         return TRUE;
1471c2c66affSColin Finck     }
1472c2c66affSColin Finck 
1473c2c66affSColin Finck     pend = Argv[1];
1474c2c66affSColin Finck     BreakPointNr = strtoul(Argv[1], &pend, 0);
1475c2c66affSColin Finck     if (pend == Argv[1] || *pend != '\0')
1476c2c66affSColin Finck     {
1477c2c66affSColin Finck         KdbpPrint("%s: integer argument required\n", Argv[0]);
1478c2c66affSColin Finck         return TRUE;
1479c2c66affSColin Finck     }
1480c2c66affSColin Finck 
1481c2c66affSColin Finck     if (Argv[0][1] == 'e') /* enable */
1482c2c66affSColin Finck     {
1483c2c66affSColin Finck         KdbpEnableBreakPoint(BreakPointNr, NULL);
1484c2c66affSColin Finck     }
1485c2c66affSColin Finck     else if (Argv [0][1] == 'd') /* disable */
1486c2c66affSColin Finck     {
1487c2c66affSColin Finck         KdbpDisableBreakPoint(BreakPointNr, NULL);
1488c2c66affSColin Finck     }
1489c2c66affSColin Finck     else /* clear */
1490c2c66affSColin Finck     {
1491c2c66affSColin Finck         ASSERT(Argv[0][1] == 'c');
1492c2c66affSColin Finck         KdbpDeleteBreakPoint(BreakPointNr, NULL);
1493c2c66affSColin Finck     }
1494c2c66affSColin Finck 
1495c2c66affSColin Finck     return TRUE;
1496c2c66affSColin Finck }
1497c2c66affSColin Finck 
1498c2c66affSColin Finck /*!\brief Sets a software or hardware (memory) breakpoint at the given address.
1499c2c66affSColin Finck  */
1500c2c66affSColin Finck static BOOLEAN
1501c2c66affSColin Finck KdbpCmdBreakPoint(ULONG Argc, PCHAR Argv[])
1502c2c66affSColin Finck {
1503c2c66affSColin Finck     ULONGLONG Result = 0;
1504c2c66affSColin Finck     ULONG_PTR Address;
1505c2c66affSColin Finck     KDB_BREAKPOINT_TYPE Type;
1506c2c66affSColin Finck     UCHAR Size = 0;
1507c2c66affSColin Finck     KDB_ACCESS_TYPE AccessType = 0;
1508c2c66affSColin Finck     ULONG AddressArgIndex, i;
1509c2c66affSColin Finck     LONG ConditionArgIndex;
1510c2c66affSColin Finck     BOOLEAN Global = TRUE;
1511c2c66affSColin Finck 
1512c2c66affSColin Finck     if (Argv[0][2] == 'x') /* software breakpoint */
1513c2c66affSColin Finck     {
1514c2c66affSColin Finck         if (Argc < 2)
1515c2c66affSColin Finck         {
1516c2c66affSColin Finck             KdbpPrint("bpx: Address argument required.\n");
1517c2c66affSColin Finck             return TRUE;
1518c2c66affSColin Finck         }
1519c2c66affSColin Finck 
1520c2c66affSColin Finck         AddressArgIndex = 1;
1521c2c66affSColin Finck         Type = KdbBreakPointSoftware;
1522c2c66affSColin Finck     }
1523c2c66affSColin Finck     else /* memory breakpoint */
1524c2c66affSColin Finck     {
1525c2c66affSColin Finck         ASSERT(Argv[0][2] == 'm');
1526c2c66affSColin Finck 
1527c2c66affSColin Finck         if (Argc < 2)
1528c2c66affSColin Finck         {
1529c2c66affSColin Finck             KdbpPrint("bpm: Access type argument required (one of r, w, rw, x)\n");
1530c2c66affSColin Finck             return TRUE;
1531c2c66affSColin Finck         }
1532c2c66affSColin Finck 
1533c2c66affSColin Finck         if (_stricmp(Argv[1], "x") == 0)
1534c2c66affSColin Finck             AccessType = KdbAccessExec;
1535c2c66affSColin Finck         else if (_stricmp(Argv[1], "r") == 0)
1536c2c66affSColin Finck             AccessType = KdbAccessRead;
1537c2c66affSColin Finck         else if (_stricmp(Argv[1], "w") == 0)
1538c2c66affSColin Finck             AccessType = KdbAccessWrite;
1539c2c66affSColin Finck         else if (_stricmp(Argv[1], "rw") == 0)
1540c2c66affSColin Finck             AccessType = KdbAccessReadWrite;
1541c2c66affSColin Finck         else
1542c2c66affSColin Finck         {
1543c2c66affSColin Finck             KdbpPrint("bpm: Unknown access type '%s'\n", Argv[1]);
1544c2c66affSColin Finck             return TRUE;
1545c2c66affSColin Finck         }
1546c2c66affSColin Finck 
1547c2c66affSColin Finck         if (Argc < 3)
1548c2c66affSColin Finck         {
1549c2c66affSColin Finck             KdbpPrint("bpm: %s argument required.\n", AccessType == KdbAccessExec ? "Address" : "Memory size");
1550c2c66affSColin Finck             return TRUE;
1551c2c66affSColin Finck         }
1552c2c66affSColin Finck 
1553c2c66affSColin Finck         AddressArgIndex = 3;
1554c2c66affSColin Finck         if (_stricmp(Argv[2], "byte") == 0)
1555c2c66affSColin Finck             Size = 1;
1556c2c66affSColin Finck         else if (_stricmp(Argv[2], "word") == 0)
1557c2c66affSColin Finck             Size = 2;
1558c2c66affSColin Finck         else if (_stricmp(Argv[2], "dword") == 0)
1559c2c66affSColin Finck             Size = 4;
1560c2c66affSColin Finck         else if (AccessType == KdbAccessExec)
1561c2c66affSColin Finck         {
1562c2c66affSColin Finck             Size = 1;
1563c2c66affSColin Finck             AddressArgIndex--;
1564c2c66affSColin Finck         }
1565c2c66affSColin Finck         else
1566c2c66affSColin Finck         {
1567c2c66affSColin Finck             KdbpPrint("bpm: Unknown memory size '%s'\n", Argv[2]);
1568c2c66affSColin Finck             return TRUE;
1569c2c66affSColin Finck         }
1570c2c66affSColin Finck 
1571c2c66affSColin Finck         if (Argc <= AddressArgIndex)
1572c2c66affSColin Finck         {
1573c2c66affSColin Finck             KdbpPrint("bpm: Address argument required.\n");
1574c2c66affSColin Finck             return TRUE;
1575c2c66affSColin Finck         }
1576c2c66affSColin Finck 
1577c2c66affSColin Finck         Type = KdbBreakPointHardware;
1578c2c66affSColin Finck     }
1579c2c66affSColin Finck 
1580c2c66affSColin Finck     /* Put the arguments back together */
1581c2c66affSColin Finck     ConditionArgIndex = -1;
1582c2c66affSColin Finck     for (i = AddressArgIndex; i < (Argc-1); i++)
1583c2c66affSColin Finck     {
1584c2c66affSColin Finck         if (strcmp(Argv[i+1], "IF") == 0) /* IF found */
1585c2c66affSColin Finck         {
1586c2c66affSColin Finck             ConditionArgIndex = i + 2;
1587c2c66affSColin Finck             if ((ULONG)ConditionArgIndex >= Argc)
1588c2c66affSColin Finck             {
1589c2c66affSColin Finck                 KdbpPrint("%s: IF requires condition expression.\n", Argv[0]);
1590c2c66affSColin Finck                 return TRUE;
1591c2c66affSColin Finck             }
1592c2c66affSColin Finck 
1593c2c66affSColin Finck             for (i = ConditionArgIndex; i < (Argc-1); i++)
1594c2c66affSColin Finck                 Argv[i][strlen(Argv[i])] = ' ';
1595c2c66affSColin Finck 
1596c2c66affSColin Finck             break;
1597c2c66affSColin Finck         }
1598c2c66affSColin Finck 
1599c2c66affSColin Finck         Argv[i][strlen(Argv[i])] = ' ';
1600c2c66affSColin Finck     }
1601c2c66affSColin Finck 
1602c2c66affSColin Finck     /* Evaluate the address expression */
1603c2c66affSColin Finck     if (!KdbpEvaluateExpression(Argv[AddressArgIndex],
1604a890fc64SHermès Bélusca-Maïto                                 KdbPromptString.Length + (Argv[AddressArgIndex]-Argv[0]),
1605c2c66affSColin Finck                                 &Result))
1606c2c66affSColin Finck     {
1607c2c66affSColin Finck         return TRUE;
1608c2c66affSColin Finck     }
1609c2c66affSColin Finck 
1610c2c66affSColin Finck     if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
1611c2c66affSColin Finck         KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result);
1612c2c66affSColin Finck 
1613c2c66affSColin Finck     Address = (ULONG_PTR)Result;
1614c2c66affSColin Finck 
1615c2c66affSColin Finck     KdbpInsertBreakPoint(Address, Type, Size, AccessType,
1616c2c66affSColin Finck                          (ConditionArgIndex < 0) ? NULL : Argv[ConditionArgIndex],
1617c2c66affSColin Finck                          Global, NULL);
1618c2c66affSColin Finck 
1619c2c66affSColin Finck     return TRUE;
1620c2c66affSColin Finck }
1621c2c66affSColin Finck 
1622c2c66affSColin Finck /*!\brief Lists threads or switches to another thread context.
1623c2c66affSColin Finck  */
1624c2c66affSColin Finck static BOOLEAN
1625c2c66affSColin Finck KdbpCmdThread(
1626c2c66affSColin Finck     ULONG Argc,
1627c2c66affSColin Finck     PCHAR Argv[])
1628c2c66affSColin Finck {
1629c2c66affSColin Finck     PLIST_ENTRY Entry;
1630c2c66affSColin Finck     PETHREAD Thread = NULL;
1631c2c66affSColin Finck     PEPROCESS Process = NULL;
1632c2c66affSColin Finck     BOOLEAN ReferencedThread = FALSE, ReferencedProcess = FALSE;
16333726b992SJérôme Gardou     PULONG_PTR Stack;
16343726b992SJérôme Gardou     PULONG_PTR Frame;
16353726b992SJérôme Gardou     ULONG_PTR Pc;
16363726b992SJérôme Gardou     ULONG_PTR ul = 0;
1637c2c66affSColin Finck     PCHAR State, pend, str1, str2;
1638c2c66affSColin Finck     static const PCHAR ThreadStateToString[DeferredReady+1] =
1639c2c66affSColin Finck     {
1640c2c66affSColin Finck         "Initialized", "Ready", "Running",
1641c2c66affSColin Finck         "Standby", "Terminated", "Waiting",
1642c2c66affSColin Finck         "Transition", "DeferredReady"
1643c2c66affSColin Finck     };
1644c2c66affSColin Finck 
1645c2c66affSColin Finck     ASSERT(KdbCurrentProcess);
1646c2c66affSColin Finck 
1647c2c66affSColin Finck     if (Argc >= 2 && _stricmp(Argv[1], "list") == 0)
1648c2c66affSColin Finck     {
1649c2c66affSColin Finck         Process = KdbCurrentProcess;
1650c2c66affSColin Finck 
1651c2c66affSColin Finck         if (Argc >= 3)
1652c2c66affSColin Finck         {
16533726b992SJérôme Gardou             ul = strtoulptr(Argv[2], &pend, 0);
1654c2c66affSColin Finck             if (Argv[2] == pend)
1655c2c66affSColin Finck             {
1656c2c66affSColin Finck                 KdbpPrint("thread: '%s' is not a valid process id!\n", Argv[2]);
1657c2c66affSColin Finck                 return TRUE;
1658c2c66affSColin Finck             }
1659c2c66affSColin Finck 
1660c2c66affSColin Finck             if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process)))
1661c2c66affSColin Finck             {
1662c2c66affSColin Finck                 KdbpPrint("thread: Invalid process id!\n");
1663c2c66affSColin Finck                 return TRUE;
1664c2c66affSColin Finck             }
1665c2c66affSColin Finck 
1666c2c66affSColin Finck             /* Remember our reference */
1667c2c66affSColin Finck             ReferencedProcess = TRUE;
1668c2c66affSColin Finck         }
1669c2c66affSColin Finck 
1670c2c66affSColin Finck         Entry = Process->ThreadListHead.Flink;
1671c2c66affSColin Finck         if (Entry == &Process->ThreadListHead)
1672c2c66affSColin Finck         {
1673c2c66affSColin Finck             if (Argc >= 3)
16743726b992SJérôme Gardou                 KdbpPrint("No threads in process 0x%px!\n", (PVOID)ul);
1675c2c66affSColin Finck             else
1676c2c66affSColin Finck                 KdbpPrint("No threads in current process!\n");
1677c2c66affSColin Finck 
1678c2c66affSColin Finck             if (ReferencedProcess)
1679c2c66affSColin Finck                 ObDereferenceObject(Process);
1680c2c66affSColin Finck 
1681c2c66affSColin Finck             return TRUE;
1682c2c66affSColin Finck         }
1683c2c66affSColin Finck 
1684c2c66affSColin Finck         KdbpPrint("  TID         State        Prior.  Affinity    EBP         EIP\n");
1685c2c66affSColin Finck         do
1686c2c66affSColin Finck         {
1687c2c66affSColin Finck             Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
1688c2c66affSColin Finck 
1689c2c66affSColin Finck             if (Thread == KdbCurrentThread)
1690c2c66affSColin Finck             {
1691c2c66affSColin Finck                 str1 = "\x1b[1m*";
1692c2c66affSColin Finck                 str2 = "\x1b[0m";
1693c2c66affSColin Finck             }
1694c2c66affSColin Finck             else
1695c2c66affSColin Finck             {
1696c2c66affSColin Finck                 str1 = " ";
1697c2c66affSColin Finck                 str2 = "";
1698c2c66affSColin Finck             }
1699c2c66affSColin Finck 
1700c2c66affSColin Finck             if (!Thread->Tcb.InitialStack)
1701c2c66affSColin Finck             {
1702c2c66affSColin Finck                 /* Thread has no kernel stack (probably terminated) */
17033726b992SJérôme Gardou                 Stack = Frame = NULL;
17043726b992SJérôme Gardou                 Pc = 0;
1705c2c66affSColin Finck             }
1706c2c66affSColin Finck             else if (Thread->Tcb.TrapFrame)
1707c2c66affSColin Finck             {
17083726b992SJérôme Gardou                 Stack = (PULONG_PTR)KeGetTrapFrameStackRegister(Thread->Tcb.TrapFrame);
17093726b992SJérôme Gardou                 Frame = (PULONG_PTR)KeGetTrapFrameFrameRegister(Thread->Tcb.TrapFrame);
17103726b992SJérôme Gardou                 Pc = KeGetTrapFramePc(Thread->Tcb.TrapFrame);
1711c2c66affSColin Finck             }
1712c2c66affSColin Finck             else
1713c2c66affSColin Finck             {
17143726b992SJérôme Gardou                 Stack = (PULONG_PTR)Thread->Tcb.KernelStack;
17153726b992SJérôme Gardou                 Frame = (PULONG_PTR)Stack[4];
17163726b992SJérôme Gardou                 Pc = 0;
1717c2c66affSColin Finck 
17183726b992SJérôme Gardou                 if (Frame) /* FIXME: Should we attach to the process to read Ebp[1]? */
17193726b992SJérôme Gardou                     KdbpSafeReadMemory(&Pc, Frame + 1, sizeof(Pc));
1720c2c66affSColin Finck             }
1721c2c66affSColin Finck 
1722c2c66affSColin Finck             if (Thread->Tcb.State < (DeferredReady + 1))
1723c2c66affSColin Finck                 State = ThreadStateToString[Thread->Tcb.State];
1724c2c66affSColin Finck             else
1725c2c66affSColin Finck                 State = "Unknown";
1726c2c66affSColin Finck 
1727c2c66affSColin Finck             KdbpPrint(" %s0x%08x  %-11s  %3d     0x%08x  0x%08x  0x%08x%s\n",
1728c2c66affSColin Finck                       str1,
1729c2c66affSColin Finck                       Thread->Cid.UniqueThread,
1730c2c66affSColin Finck                       State,
1731c2c66affSColin Finck                       Thread->Tcb.Priority,
1732c2c66affSColin Finck                       Thread->Tcb.Affinity,
17333726b992SJérôme Gardou                       Frame,
17343726b992SJérôme Gardou                       Pc,
1735c2c66affSColin Finck                       str2);
1736c2c66affSColin Finck 
1737c2c66affSColin Finck             Entry = Entry->Flink;
1738c2c66affSColin Finck         }
1739c2c66affSColin Finck         while (Entry != &Process->ThreadListHead);
1740c2c66affSColin Finck 
1741c2c66affSColin Finck         /* Release our reference, if any */
1742c2c66affSColin Finck         if (ReferencedProcess)
1743c2c66affSColin Finck             ObDereferenceObject(Process);
1744c2c66affSColin Finck     }
1745c2c66affSColin Finck     else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0)
1746c2c66affSColin Finck     {
1747c2c66affSColin Finck         if (Argc < 3)
1748c2c66affSColin Finck         {
1749c2c66affSColin Finck             KdbpPrint("thread attach: thread id argument required!\n");
1750c2c66affSColin Finck             return TRUE;
1751c2c66affSColin Finck         }
1752c2c66affSColin Finck 
17533726b992SJérôme Gardou         ul = strtoulptr(Argv[2], &pend, 0);
1754c2c66affSColin Finck         if (Argv[2] == pend)
1755c2c66affSColin Finck         {
1756c2c66affSColin Finck             KdbpPrint("thread attach: '%s' is not a valid thread id!\n", Argv[2]);
1757c2c66affSColin Finck             return TRUE;
1758c2c66affSColin Finck         }
1759c2c66affSColin Finck 
1760c2c66affSColin Finck         if (!KdbpAttachToThread((PVOID)ul))
1761c2c66affSColin Finck         {
1762c2c66affSColin Finck             return TRUE;
1763c2c66affSColin Finck         }
1764c2c66affSColin Finck 
1765c2c66affSColin Finck         KdbpPrint("Attached to thread 0x%08x.\n", ul);
1766c2c66affSColin Finck     }
1767c2c66affSColin Finck     else
1768c2c66affSColin Finck     {
1769c2c66affSColin Finck         Thread = KdbCurrentThread;
1770c2c66affSColin Finck 
1771c2c66affSColin Finck         if (Argc >= 2)
1772c2c66affSColin Finck         {
17733726b992SJérôme Gardou             ul = strtoulptr(Argv[1], &pend, 0);
1774c2c66affSColin Finck             if (Argv[1] == pend)
1775c2c66affSColin Finck             {
1776c2c66affSColin Finck                 KdbpPrint("thread: '%s' is not a valid thread id!\n", Argv[1]);
1777c2c66affSColin Finck                 return TRUE;
1778c2c66affSColin Finck             }
1779c2c66affSColin Finck 
1780c2c66affSColin Finck             if (!NT_SUCCESS(PsLookupThreadByThreadId((PVOID)ul, &Thread)))
1781c2c66affSColin Finck             {
1782c2c66affSColin Finck                 KdbpPrint("thread: Invalid thread id!\n");
1783c2c66affSColin Finck                 return TRUE;
1784c2c66affSColin Finck             }
1785c2c66affSColin Finck 
1786c2c66affSColin Finck             /* Remember our reference */
1787c2c66affSColin Finck             ReferencedThread = TRUE;
1788c2c66affSColin Finck         }
1789c2c66affSColin Finck 
1790c2c66affSColin Finck         if (Thread->Tcb.State < (DeferredReady + 1))
1791c2c66affSColin Finck             State = ThreadStateToString[Thread->Tcb.State];
1792c2c66affSColin Finck         else
1793c2c66affSColin Finck             State = "Unknown";
1794c2c66affSColin Finck 
1795c2c66affSColin Finck         KdbpPrint("%s"
1796c2c66affSColin Finck                   "  TID:            0x%08x\n"
1797c2c66affSColin Finck                   "  State:          %s (0x%x)\n"
1798c2c66affSColin Finck                   "  Priority:       %d\n"
1799c2c66affSColin Finck                   "  Affinity:       0x%08x\n"
1800c2c66affSColin Finck                   "  Initial Stack:  0x%08x\n"
1801c2c66affSColin Finck                   "  Stack Limit:    0x%08x\n"
1802c2c66affSColin Finck                   "  Stack Base:     0x%08x\n"
1803c2c66affSColin Finck                   "  Kernel Stack:   0x%08x\n"
1804c2c66affSColin Finck                   "  Trap Frame:     0x%08x\n"
1805*b97d5fd2SJérôme Gardou #ifndef _M_AMD64
1806*b97d5fd2SJérôme Gardou                   "  NPX State:      %s (0x%x)\n"
1807*b97d5fd2SJérôme Gardou #endif
1808*b97d5fd2SJérôme Gardou                   , (Argc < 2) ? "Current Thread:\n" : ""
1809*b97d5fd2SJérôme Gardou                   , Thread->Cid.UniqueThread
1810*b97d5fd2SJérôme Gardou                   , State, Thread->Tcb.State
1811*b97d5fd2SJérôme Gardou                   , Thread->Tcb.Priority
1812*b97d5fd2SJérôme Gardou                   , Thread->Tcb.Affinity
1813*b97d5fd2SJérôme Gardou                   , Thread->Tcb.InitialStack
1814*b97d5fd2SJérôme Gardou                   , Thread->Tcb.StackLimit
1815*b97d5fd2SJérôme Gardou                   , Thread->Tcb.StackBase
1816*b97d5fd2SJérôme Gardou                   , Thread->Tcb.KernelStack
1817*b97d5fd2SJérôme Gardou                   , Thread->Tcb.TrapFrame
18183726b992SJérôme Gardou #ifndef _M_AMD64
18193726b992SJérôme Gardou                   , NPX_STATE_TO_STRING(Thread->Tcb.NpxState), Thread->Tcb.NpxState
18203726b992SJérôme Gardou #endif
18213726b992SJérôme Gardou             );
1822c2c66affSColin Finck 
1823c2c66affSColin Finck             /* Release our reference if we had one */
1824c2c66affSColin Finck             if (ReferencedThread)
1825c2c66affSColin Finck                 ObDereferenceObject(Thread);
1826c2c66affSColin Finck     }
1827c2c66affSColin Finck 
1828c2c66affSColin Finck     return TRUE;
1829c2c66affSColin Finck }
1830c2c66affSColin Finck 
1831c2c66affSColin Finck /*!\brief Lists processes or switches to another process context.
1832c2c66affSColin Finck  */
1833c2c66affSColin Finck static BOOLEAN
1834c2c66affSColin Finck KdbpCmdProc(
1835c2c66affSColin Finck     ULONG Argc,
1836c2c66affSColin Finck     PCHAR Argv[])
1837c2c66affSColin Finck {
1838c2c66affSColin Finck     PLIST_ENTRY Entry;
1839c2c66affSColin Finck     PEPROCESS Process;
1840c2c66affSColin Finck     BOOLEAN ReferencedProcess = FALSE;
1841c2c66affSColin Finck     PCHAR State, pend, str1, str2;
18423726b992SJérôme Gardou     ULONG_PTR ul;
1843c2c66affSColin Finck     extern LIST_ENTRY PsActiveProcessHead;
1844c2c66affSColin Finck 
1845c2c66affSColin Finck     if (Argc >= 2 && _stricmp(Argv[1], "list") == 0)
1846c2c66affSColin Finck     {
1847c2c66affSColin Finck         Entry = PsActiveProcessHead.Flink;
1848c2c66affSColin Finck         if (!Entry || Entry == &PsActiveProcessHead)
1849c2c66affSColin Finck         {
1850c2c66affSColin Finck             KdbpPrint("No processes in the system!\n");
1851c2c66affSColin Finck             return TRUE;
1852c2c66affSColin Finck         }
1853c2c66affSColin Finck 
1854c2c66affSColin Finck         KdbpPrint("  PID         State       Filename\n");
1855c2c66affSColin Finck         do
1856c2c66affSColin Finck         {
1857c2c66affSColin Finck             Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
1858c2c66affSColin Finck 
1859c2c66affSColin Finck             if (Process == KdbCurrentProcess)
1860c2c66affSColin Finck             {
1861c2c66affSColin Finck                 str1 = "\x1b[1m*";
1862c2c66affSColin Finck                 str2 = "\x1b[0m";
1863c2c66affSColin Finck             }
1864c2c66affSColin Finck             else
1865c2c66affSColin Finck             {
1866c2c66affSColin Finck                 str1 = " ";
1867c2c66affSColin Finck                 str2 = "";
1868c2c66affSColin Finck             }
1869c2c66affSColin Finck 
1870c2c66affSColin Finck             State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" :
1871c2c66affSColin Finck                     ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition"));
1872c2c66affSColin Finck 
1873c2c66affSColin Finck             KdbpPrint(" %s0x%08x  %-10s  %s%s\n",
1874c2c66affSColin Finck                       str1,
1875c2c66affSColin Finck                       Process->UniqueProcessId,
1876c2c66affSColin Finck                       State,
1877c2c66affSColin Finck                       Process->ImageFileName,
1878c2c66affSColin Finck                       str2);
1879c2c66affSColin Finck 
1880c2c66affSColin Finck             Entry = Entry->Flink;
1881c2c66affSColin Finck         }
1882c2c66affSColin Finck         while(Entry != &PsActiveProcessHead);
1883c2c66affSColin Finck     }
1884c2c66affSColin Finck     else if (Argc >= 2 && _stricmp(Argv[1], "attach") == 0)
1885c2c66affSColin Finck     {
1886c2c66affSColin Finck         if (Argc < 3)
1887c2c66affSColin Finck         {
1888c2c66affSColin Finck             KdbpPrint("process attach: process id argument required!\n");
1889c2c66affSColin Finck             return TRUE;
1890c2c66affSColin Finck         }
1891c2c66affSColin Finck 
18923726b992SJérôme Gardou         ul = strtoulptr(Argv[2], &pend, 0);
1893c2c66affSColin Finck         if (Argv[2] == pend)
1894c2c66affSColin Finck         {
1895c2c66affSColin Finck             KdbpPrint("process attach: '%s' is not a valid process id!\n", Argv[2]);
1896c2c66affSColin Finck             return TRUE;
1897c2c66affSColin Finck         }
1898c2c66affSColin Finck 
1899c2c66affSColin Finck         if (!KdbpAttachToProcess((PVOID)ul))
1900c2c66affSColin Finck         {
1901c2c66affSColin Finck             return TRUE;
1902c2c66affSColin Finck         }
1903c2c66affSColin Finck 
19043726b992SJérôme Gardou         KdbpPrint("Attached to process 0x%p, thread 0x%p.\n", (PVOID)ul,
19053726b992SJérôme Gardou                   KdbCurrentThread->Cid.UniqueThread);
1906c2c66affSColin Finck     }
1907c2c66affSColin Finck     else
1908c2c66affSColin Finck     {
1909c2c66affSColin Finck         Process = KdbCurrentProcess;
1910c2c66affSColin Finck 
1911c2c66affSColin Finck         if (Argc >= 2)
1912c2c66affSColin Finck         {
19133726b992SJérôme Gardou             ul = strtoulptr(Argv[1], &pend, 0);
1914c2c66affSColin Finck             if (Argv[1] == pend)
1915c2c66affSColin Finck             {
1916c2c66affSColin Finck                 KdbpPrint("proc: '%s' is not a valid process id!\n", Argv[1]);
1917c2c66affSColin Finck                 return TRUE;
1918c2c66affSColin Finck             }
1919c2c66affSColin Finck 
1920c2c66affSColin Finck             if (!NT_SUCCESS(PsLookupProcessByProcessId((PVOID)ul, &Process)))
1921c2c66affSColin Finck             {
1922c2c66affSColin Finck                 KdbpPrint("proc: Invalid process id!\n");
1923c2c66affSColin Finck                 return TRUE;
1924c2c66affSColin Finck             }
1925c2c66affSColin Finck 
1926c2c66affSColin Finck             /* Remember our reference */
1927c2c66affSColin Finck             ReferencedProcess = TRUE;
1928c2c66affSColin Finck         }
1929c2c66affSColin Finck 
1930c2c66affSColin Finck         State = ((Process->Pcb.State == ProcessInMemory) ? "In Memory" :
1931c2c66affSColin Finck                 ((Process->Pcb.State == ProcessOutOfMemory) ? "Out of Memory" : "In Transition"));
1932c2c66affSColin Finck         KdbpPrint("%s"
1933c2c66affSColin Finck                   "  PID:             0x%08x\n"
1934c2c66affSColin Finck                   "  State:           %s (0x%x)\n"
1935c2c66affSColin Finck                   "  Image Filename:  %s\n",
1936c2c66affSColin Finck                   (Argc < 2) ? "Current process:\n" : "",
1937c2c66affSColin Finck                   Process->UniqueProcessId,
1938c2c66affSColin Finck                   State, Process->Pcb.State,
1939c2c66affSColin Finck                   Process->ImageFileName);
1940c2c66affSColin Finck 
1941c2c66affSColin Finck         /* Release our reference, if any */
1942c2c66affSColin Finck         if (ReferencedProcess)
1943c2c66affSColin Finck             ObDereferenceObject(Process);
1944c2c66affSColin Finck     }
1945c2c66affSColin Finck 
1946c2c66affSColin Finck     return TRUE;
1947c2c66affSColin Finck }
1948c2c66affSColin Finck 
1949c2c66affSColin Finck /*!\brief Lists loaded modules or the one containing the specified address.
1950c2c66affSColin Finck  */
1951c2c66affSColin Finck static BOOLEAN
1952c2c66affSColin Finck KdbpCmdMod(
1953c2c66affSColin Finck     ULONG Argc,
1954c2c66affSColin Finck     PCHAR Argv[])
1955c2c66affSColin Finck {
1956c2c66affSColin Finck     ULONGLONG Result = 0;
1957c2c66affSColin Finck     ULONG_PTR Address;
1958c2c66affSColin Finck     PLDR_DATA_TABLE_ENTRY LdrEntry;
1959c2c66affSColin Finck     BOOLEAN DisplayOnlyOneModule = FALSE;
1960c2c66affSColin Finck     INT i = 0;
1961c2c66affSColin Finck 
1962c2c66affSColin Finck     if (Argc >= 2)
1963c2c66affSColin Finck     {
1964c2c66affSColin Finck         /* Put the arguments back together */
1965c2c66affSColin Finck         Argc--;
1966c2c66affSColin Finck         while (--Argc >= 1)
1967c2c66affSColin Finck             Argv[Argc][strlen(Argv[Argc])] = ' ';
1968c2c66affSColin Finck 
1969c2c66affSColin Finck         /* Evaluate the expression */
1970a890fc64SHermès Bélusca-Maïto         if (!KdbpEvaluateExpression(Argv[1], KdbPromptString.Length + (Argv[1]-Argv[0]), &Result))
1971c2c66affSColin Finck         {
1972c2c66affSColin Finck             return TRUE;
1973c2c66affSColin Finck         }
1974c2c66affSColin Finck 
1975c2c66affSColin Finck         if (Result > (ULONGLONG)(~((ULONG_PTR)0)))
1976c2c66affSColin Finck             KdbpPrint("%s: Warning: Address %I64x is beeing truncated\n", Argv[0],Result);
1977c2c66affSColin Finck 
1978c2c66affSColin Finck         Address = (ULONG_PTR)Result;
1979c2c66affSColin Finck 
1980c2c66affSColin Finck         if (!KdbpSymFindModule((PVOID)Address, NULL, -1, &LdrEntry))
1981c2c66affSColin Finck         {
1982c2c66affSColin Finck             KdbpPrint("No module containing address 0x%p found!\n", Address);
1983c2c66affSColin Finck             return TRUE;
1984c2c66affSColin Finck         }
1985c2c66affSColin Finck 
1986c2c66affSColin Finck         DisplayOnlyOneModule = TRUE;
1987c2c66affSColin Finck     }
1988c2c66affSColin Finck     else
1989c2c66affSColin Finck     {
1990c2c66affSColin Finck         if (!KdbpSymFindModule(NULL, NULL, 0, &LdrEntry))
1991c2c66affSColin Finck         {
1992c2c66affSColin Finck             ULONG_PTR ntoskrnlBase = ((ULONG_PTR)KdbpCmdMod) & 0xfff00000;
1993c2c66affSColin Finck             KdbpPrint("  Base      Size      Name\n");
1994c2c66affSColin Finck             KdbpPrint("  %08x  %08x  %s\n", ntoskrnlBase, 0, "ntoskrnl.exe");
1995c2c66affSColin Finck             return TRUE;
1996c2c66affSColin Finck         }
1997c2c66affSColin Finck 
1998c2c66affSColin Finck         i = 1;
1999c2c66affSColin Finck     }
2000c2c66affSColin Finck 
2001c2c66affSColin Finck     KdbpPrint("  Base      Size      Name\n");
2002c2c66affSColin Finck     for (;;)
2003c2c66affSColin Finck     {
2004c2c66affSColin Finck         KdbpPrint("  %08x  %08x  %wZ\n", LdrEntry->DllBase, LdrEntry->SizeOfImage, &LdrEntry->BaseDllName);
2005c2c66affSColin Finck 
2006c2c66affSColin Finck         if(DisplayOnlyOneModule || !KdbpSymFindModule(NULL, NULL, i++, &LdrEntry))
2007c2c66affSColin Finck             break;
2008c2c66affSColin Finck     }
2009c2c66affSColin Finck 
2010c2c66affSColin Finck     return TRUE;
2011c2c66affSColin Finck }
2012c2c66affSColin Finck 
2013f0d59e74SHermès Bélusca-Maïto /*!\brief Displays GDT, LDT or IDT.
2014c2c66affSColin Finck  */
2015c2c66affSColin Finck static BOOLEAN
2016c2c66affSColin Finck KdbpCmdGdtLdtIdt(
2017c2c66affSColin Finck     ULONG Argc,
2018c2c66affSColin Finck     PCHAR Argv[])
2019c2c66affSColin Finck {
2020c2c66affSColin Finck     KDESCRIPTOR Reg;
2021c2c66affSColin Finck     ULONG SegDesc[2];
2022c2c66affSColin Finck     ULONG SegBase;
2023c2c66affSColin Finck     ULONG SegLimit;
2024c2c66affSColin Finck     PCHAR SegType;
2025c2c66affSColin Finck     USHORT SegSel;
2026c2c66affSColin Finck     UCHAR Type, Dpl;
2027c2c66affSColin Finck     INT i;
2028c2c66affSColin Finck     ULONG ul;
2029c2c66affSColin Finck 
2030c2c66affSColin Finck     if (Argv[0][0] == 'i')
2031c2c66affSColin Finck     {
2032c2c66affSColin Finck         /* Read IDTR */
2033c2c66affSColin Finck         __sidt(&Reg.Limit);
2034c2c66affSColin Finck 
2035c2c66affSColin Finck         if (Reg.Limit < 7)
2036c2c66affSColin Finck         {
2037c2c66affSColin Finck             KdbpPrint("Interrupt descriptor table is empty.\n");
2038c2c66affSColin Finck             return TRUE;
2039c2c66affSColin Finck         }
2040c2c66affSColin Finck 
2041c2c66affSColin Finck         KdbpPrint("IDT Base: 0x%08x  Limit: 0x%04x\n", Reg.Base, Reg.Limit);
2042c2c66affSColin Finck         KdbpPrint("  Idx  Type        Seg. Sel.  Offset      DPL\n");
2043c2c66affSColin Finck 
2044c2c66affSColin Finck         for (i = 0; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8)
2045c2c66affSColin Finck         {
20463726b992SJérôme Gardou             if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)((ULONG_PTR)Reg.Base + i), sizeof(SegDesc))))
2047c2c66affSColin Finck             {
20483726b992SJérôme Gardou                 KdbpPrint("Couldn't access memory at 0x%p!\n", (PVOID)((ULONG_PTR)Reg.Base + i));
2049c2c66affSColin Finck                 return TRUE;
2050c2c66affSColin Finck             }
2051c2c66affSColin Finck 
2052c2c66affSColin Finck             Dpl = ((SegDesc[1] >> 13) & 3);
2053c2c66affSColin Finck             if ((SegDesc[1] & 0x1f00) == 0x0500)        /* Task gate */
2054c2c66affSColin Finck                 SegType = "TASKGATE";
2055c2c66affSColin Finck             else if ((SegDesc[1] & 0x1fe0) == 0x0e00)   /* 32 bit Interrupt gate */
2056c2c66affSColin Finck                 SegType = "INTGATE32";
2057c2c66affSColin Finck             else if ((SegDesc[1] & 0x1fe0) == 0x0600)   /* 16 bit Interrupt gate */
2058c2c66affSColin Finck                 SegType = "INTGATE16";
2059c2c66affSColin Finck             else if ((SegDesc[1] & 0x1fe0) == 0x0f00)   /* 32 bit Trap gate */
2060c2c66affSColin Finck                 SegType = "TRAPGATE32";
2061c2c66affSColin Finck             else if ((SegDesc[1] & 0x1fe0) == 0x0700)   /* 16 bit Trap gate */
2062c2c66affSColin Finck                 SegType = "TRAPGATE16";
2063c2c66affSColin Finck             else
2064c2c66affSColin Finck                 SegType = "UNKNOWN";
2065c2c66affSColin Finck 
2066c2c66affSColin Finck             if ((SegDesc[1] & (1 << 15)) == 0) /* not present */
2067c2c66affSColin Finck             {
2068c2c66affSColin Finck                 KdbpPrint("  %03d  %-10s  [NP]       [NP]        %02d\n",
2069c2c66affSColin Finck                           i / 8, SegType, Dpl);
2070c2c66affSColin Finck             }
2071c2c66affSColin Finck             else if ((SegDesc[1] & 0x1f00) == 0x0500) /* Task gate */
2072c2c66affSColin Finck             {
2073c2c66affSColin Finck                 SegSel = SegDesc[0] >> 16;
2074c2c66affSColin Finck                 KdbpPrint("  %03d  %-10s  0x%04x                 %02d\n",
2075c2c66affSColin Finck                           i / 8, SegType, SegSel, Dpl);
2076c2c66affSColin Finck             }
2077c2c66affSColin Finck             else
2078c2c66affSColin Finck             {
2079c2c66affSColin Finck                 SegSel = SegDesc[0] >> 16;
2080c2c66affSColin Finck                 SegBase = (SegDesc[1] & 0xffff0000) | (SegDesc[0] & 0x0000ffff);
2081c2c66affSColin Finck                 KdbpPrint("  %03d  %-10s  0x%04x     0x%08x  %02d\n",
2082c2c66affSColin Finck                           i / 8, SegType, SegSel, SegBase, Dpl);
2083c2c66affSColin Finck             }
2084c2c66affSColin Finck         }
2085c2c66affSColin Finck     }
2086c2c66affSColin Finck     else
2087c2c66affSColin Finck     {
2088c2c66affSColin Finck         ul = 0;
2089c2c66affSColin Finck 
2090c2c66affSColin Finck         if (Argv[0][0] == 'g')
2091c2c66affSColin Finck         {
2092c2c66affSColin Finck             /* Read GDTR */
2093c2c66affSColin Finck             Ke386GetGlobalDescriptorTable(&Reg.Limit);
2094c2c66affSColin Finck             i = 8;
2095c2c66affSColin Finck         }
2096c2c66affSColin Finck         else
2097c2c66affSColin Finck         {
2098c2c66affSColin Finck             ASSERT(Argv[0][0] == 'l');
2099c2c66affSColin Finck 
2100c2c66affSColin Finck             /* Read LDTR */
21013726b992SJérôme Gardou             Ke386GetLocalDescriptorTable(&Reg.Limit);
2102c2c66affSColin Finck             Reg.Base = 0;
2103c2c66affSColin Finck             i = 0;
2104c2c66affSColin Finck             ul = 1 << 2;
2105c2c66affSColin Finck         }
2106c2c66affSColin Finck 
2107c2c66affSColin Finck         if (Reg.Limit < 7)
2108c2c66affSColin Finck         {
2109c2c66affSColin Finck             KdbpPrint("%s descriptor table is empty.\n",
2110c2c66affSColin Finck                       Argv[0][0] == 'g' ? "Global" : "Local");
2111c2c66affSColin Finck             return TRUE;
2112c2c66affSColin Finck         }
2113c2c66affSColin Finck 
2114c2c66affSColin Finck         KdbpPrint("%cDT Base: 0x%08x  Limit: 0x%04x\n",
2115c2c66affSColin Finck                   Argv[0][0] == 'g' ? 'G' : 'L', Reg.Base, Reg.Limit);
2116c2c66affSColin Finck         KdbpPrint("  Idx  Sel.    Type         Base        Limit       DPL  Attribs\n");
2117c2c66affSColin Finck 
2118c2c66affSColin Finck         for (; (i + sizeof(SegDesc) - 1) <= Reg.Limit; i += 8)
2119c2c66affSColin Finck         {
21203726b992SJérôme Gardou             if (!NT_SUCCESS(KdbpSafeReadMemory(SegDesc, (PVOID)((ULONG_PTR)Reg.Base + i), sizeof(SegDesc))))
2121c2c66affSColin Finck             {
21223726b992SJérôme Gardou                 KdbpPrint("Couldn't access memory at 0x%p!\n", (ULONG_PTR)Reg.Base + i);
2123c2c66affSColin Finck                 return TRUE;
2124c2c66affSColin Finck             }
2125c2c66affSColin Finck 
2126c2c66affSColin Finck             Dpl = ((SegDesc[1] >> 13) & 3);
2127c2c66affSColin Finck             Type = ((SegDesc[1] >> 8) & 0xf);
2128c2c66affSColin Finck 
2129c2c66affSColin Finck             SegBase = SegDesc[0] >> 16;
2130c2c66affSColin Finck             SegBase |= (SegDesc[1] & 0xff) << 16;
2131c2c66affSColin Finck             SegBase |= SegDesc[1] & 0xff000000;
2132c2c66affSColin Finck             SegLimit = SegDesc[0] & 0x0000ffff;
2133c2c66affSColin Finck             SegLimit |= (SegDesc[1] >> 16) & 0xf;
2134c2c66affSColin Finck 
2135c2c66affSColin Finck             if ((SegDesc[1] & (1 << 23)) != 0)
2136c2c66affSColin Finck             {
2137c2c66affSColin Finck                 SegLimit *= 4096;
2138c2c66affSColin Finck                 SegLimit += 4095;
2139c2c66affSColin Finck             }
2140c2c66affSColin Finck             else
2141c2c66affSColin Finck             {
2142c2c66affSColin Finck                 SegLimit++;
2143c2c66affSColin Finck             }
2144c2c66affSColin Finck 
2145c2c66affSColin Finck             if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */
2146c2c66affSColin Finck             {
2147c2c66affSColin Finck                 switch (Type)
2148c2c66affSColin Finck                 {
2149c2c66affSColin Finck                     case  1: SegType = "TSS16(Avl)";    break;
2150c2c66affSColin Finck                     case  2: SegType = "LDT";           break;
2151c2c66affSColin Finck                     case  3: SegType = "TSS16(Busy)";   break;
2152c2c66affSColin Finck                     case  4: SegType = "CALLGATE16";    break;
2153c2c66affSColin Finck                     case  5: SegType = "TASKGATE";      break;
2154c2c66affSColin Finck                     case  6: SegType = "INTGATE16";     break;
2155c2c66affSColin Finck                     case  7: SegType = "TRAPGATE16";    break;
2156c2c66affSColin Finck                     case  9: SegType = "TSS32(Avl)";    break;
2157c2c66affSColin Finck                     case 11: SegType = "TSS32(Busy)";   break;
2158c2c66affSColin Finck                     case 12: SegType = "CALLGATE32";    break;
2159c2c66affSColin Finck                     case 14: SegType = "INTGATE32";     break;
216029f6d029SHermès Bélusca-Maïto                     case 15: SegType = "TRAPGATE32";    break;
2161c2c66affSColin Finck                     default: SegType = "UNKNOWN";       break;
2162c2c66affSColin Finck                 }
2163c2c66affSColin Finck 
2164c2c66affSColin Finck                 if (!(Type >= 1 && Type <= 3) &&
2165c2c66affSColin Finck                     Type != 9 && Type != 11)
2166c2c66affSColin Finck                 {
2167c2c66affSColin Finck                     SegBase = 0;
2168c2c66affSColin Finck                     SegLimit = 0;
2169c2c66affSColin Finck                 }
2170c2c66affSColin Finck             }
2171c2c66affSColin Finck             else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */
2172c2c66affSColin Finck             {
2173c2c66affSColin Finck                 if ((SegDesc[1] & (1 << 22)) != 0)
2174c2c66affSColin Finck                     SegType = "DATA32";
2175c2c66affSColin Finck                 else
2176c2c66affSColin Finck                     SegType = "DATA16";
2177c2c66affSColin Finck             }
2178c2c66affSColin Finck             else /* Code segment */
2179c2c66affSColin Finck             {
2180c2c66affSColin Finck                 if ((SegDesc[1] & (1 << 22)) != 0)
2181c2c66affSColin Finck                     SegType = "CODE32";
2182c2c66affSColin Finck                 else
2183c2c66affSColin Finck                     SegType = "CODE16";
2184c2c66affSColin Finck             }
2185c2c66affSColin Finck 
218629f6d029SHermès Bélusca-Maïto             if ((SegDesc[1] & (1 << 15)) == 0) /* Not present */
2187c2c66affSColin Finck             {
2188c2c66affSColin Finck                 KdbpPrint("  %03d  0x%04x  %-11s  [NP]        [NP]        %02d   NP\n",
2189c2c66affSColin Finck                           i / 8, i | Dpl | ul, SegType, Dpl);
2190c2c66affSColin Finck             }
2191c2c66affSColin Finck             else
2192c2c66affSColin Finck             {
2193c2c66affSColin Finck                 KdbpPrint("  %03d  0x%04x  %-11s  0x%08x  0x%08x  %02d  ",
2194c2c66affSColin Finck                           i / 8, i | Dpl | ul, SegType, SegBase, SegLimit, Dpl);
2195c2c66affSColin Finck 
2196c2c66affSColin Finck                 if ((SegDesc[1] & (1 << 12)) == 0) /* System segment */
2197c2c66affSColin Finck                 {
2198c2c66affSColin Finck                     /* FIXME: Display system segment */
2199c2c66affSColin Finck                 }
2200c2c66affSColin Finck                 else if ((SegDesc[1] & (1 << 11)) == 0) /* Data segment */
2201c2c66affSColin Finck                 {
2202c2c66affSColin Finck                     if ((SegDesc[1] & (1 << 10)) != 0) /* Expand-down */
2203c2c66affSColin Finck                         KdbpPrint(" E");
2204c2c66affSColin Finck 
2205c2c66affSColin Finck                     KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/W" : " R");
2206c2c66affSColin Finck 
2207c2c66affSColin Finck                     if ((SegDesc[1] & (1 << 8)) != 0)
2208c2c66affSColin Finck                         KdbpPrint(" A");
2209c2c66affSColin Finck                 }
2210c2c66affSColin Finck                 else /* Code segment */
2211c2c66affSColin Finck                 {
2212c2c66affSColin Finck                     if ((SegDesc[1] & (1 << 10)) != 0) /* Conforming */
2213c2c66affSColin Finck                         KdbpPrint(" C");
2214c2c66affSColin Finck 
2215c2c66affSColin Finck                     KdbpPrint((SegDesc[1] & (1 << 9)) ? " R/X" : " X");
2216c2c66affSColin Finck 
2217c2c66affSColin Finck                     if ((SegDesc[1] & (1 << 8)) != 0)
2218c2c66affSColin Finck                         KdbpPrint(" A");
2219c2c66affSColin Finck                 }
2220c2c66affSColin Finck 
2221c2c66affSColin Finck                 if ((SegDesc[1] & (1 << 20)) != 0)
2222c2c66affSColin Finck                     KdbpPrint(" AVL");
2223c2c66affSColin Finck 
2224c2c66affSColin Finck                 KdbpPrint("\n");
2225c2c66affSColin Finck             }
2226c2c66affSColin Finck         }
2227c2c66affSColin Finck     }
2228c2c66affSColin Finck 
2229c2c66affSColin Finck     return TRUE;
2230c2c66affSColin Finck }
2231c2c66affSColin Finck 
2232c2c66affSColin Finck /*!\brief Displays the KPCR
2233c2c66affSColin Finck  */
2234c2c66affSColin Finck static BOOLEAN
2235c2c66affSColin Finck KdbpCmdPcr(
2236c2c66affSColin Finck     ULONG Argc,
2237c2c66affSColin Finck     PCHAR Argv[])
2238c2c66affSColin Finck {
2239c2c66affSColin Finck     PKIPCR Pcr = (PKIPCR)KeGetPcr();
2240c2c66affSColin Finck 
224189b44cfaSHermès Bélusca-Maïto     KdbpPrint("Current PCR is at 0x%p.\n", Pcr);
2242c2c66affSColin Finck     KdbpPrint("  Tib.ExceptionList:         0x%08x\n"
2243c2c66affSColin Finck               "  Tib.StackBase:             0x%08x\n"
2244c2c66affSColin Finck               "  Tib.StackLimit:            0x%08x\n"
2245c2c66affSColin Finck               "  Tib.SubSystemTib:          0x%08x\n"
2246c2c66affSColin Finck               "  Tib.FiberData/Version:     0x%08x\n"
2247c2c66affSColin Finck               "  Tib.ArbitraryUserPointer:  0x%08x\n"
2248c2c66affSColin Finck               "  Tib.Self:                  0x%08x\n"
22493726b992SJérôme Gardou #ifdef _M_IX86
2250631a14ffSAmine Khaldi               "  SelfPcr:                   0x%08x\n"
22513726b992SJérôme Gardou #else
22523726b992SJérôme Gardou               "  Self:                      0x%p\n"
22533726b992SJérôme Gardou #endif
2254c2c66affSColin Finck               "  PCRCB:                     0x%08x\n"
2255c2c66affSColin Finck               "  Irql:                      0x%02x\n"
22563726b992SJérôme Gardou #ifdef _M_IX86
2257c2c66affSColin Finck               "  IRR:                       0x%08x\n"
2258c2c66affSColin Finck               "  IrrActive:                 0x%08x\n"
2259c2c66affSColin Finck               "  IDR:                       0x%08x\n"
22603726b992SJérôme Gardou #endif
2261c2c66affSColin Finck               "  KdVersionBlock:            0x%08x\n"
22623726b992SJérôme Gardou #ifdef _M_IX86
2263c2c66affSColin Finck               "  IDT:                       0x%08x\n"
2264c2c66affSColin Finck               "  GDT:                       0x%08x\n"
2265c2c66affSColin Finck               "  TSS:                       0x%08x\n"
22663726b992SJérôme Gardou #endif
2267c2c66affSColin Finck               "  MajorVersion:              0x%04x\n"
2268c2c66affSColin Finck               "  MinorVersion:              0x%04x\n"
22693726b992SJérôme Gardou #ifdef _M_IX86
2270c2c66affSColin Finck               "  SetMember:                 0x%08x\n"
22713726b992SJérôme Gardou #endif
2272c2c66affSColin Finck               "  StallScaleFactor:          0x%08x\n"
22733726b992SJérôme Gardou #ifdef _M_IX86
2274c2c66affSColin Finck               "  Number:                    0x%02x\n"
22753726b992SJérôme Gardou #endif
2276c2c66affSColin Finck               "  L2CacheAssociativity:      0x%02x\n"
22773726b992SJérôme Gardou #ifdef _M_IX86
2278c2c66affSColin Finck               "  VdmAlert:                  0x%08x\n"
22793726b992SJérôme Gardou #endif
2280c2c66affSColin Finck               "  L2CacheSize:               0x%08x\n"
22813726b992SJérôme Gardou #ifdef _M_IX86
22823726b992SJérôme Gardou               "  InterruptMode:             0x%08x\n"
22833726b992SJérôme Gardou #endif
22843726b992SJérôme Gardou               , Pcr->NtTib.ExceptionList, Pcr->NtTib.StackBase, Pcr->NtTib.StackLimit,
2285c2c66affSColin Finck               Pcr->NtTib.SubSystemTib, Pcr->NtTib.FiberData, Pcr->NtTib.ArbitraryUserPointer,
22863726b992SJérôme Gardou               Pcr->NtTib.Self
22873726b992SJérôme Gardou #ifdef _M_IX86
22883726b992SJérôme Gardou               , Pcr->SelfPcr
22893726b992SJérôme Gardou #else
22903726b992SJérôme Gardou               , Pcr->Self
22913726b992SJérôme Gardou #endif
22923726b992SJérôme Gardou               , Pcr->Prcb, Pcr->Irql
22933726b992SJérôme Gardou #ifdef _M_IX86
22943726b992SJérôme Gardou               , Pcr->IRR, Pcr->IrrActive , Pcr->IDR
22953726b992SJérôme Gardou #endif
22963726b992SJérôme Gardou               , Pcr->KdVersionBlock
22973726b992SJérôme Gardou #ifdef _M_IX86
22983726b992SJérôme Gardou               , Pcr->IDT, Pcr->GDT, Pcr->TSS
22993726b992SJérôme Gardou #endif
23003726b992SJérôme Gardou               , Pcr->MajorVersion, Pcr->MinorVersion
23013726b992SJérôme Gardou #ifdef _M_IX86
23023726b992SJérôme Gardou               , Pcr->SetMember
23033726b992SJérôme Gardou #endif
23043726b992SJérôme Gardou               , Pcr->StallScaleFactor
23053726b992SJérôme Gardou #ifdef _M_IX86
23063726b992SJérôme Gardou               , Pcr->Number
23073726b992SJérôme Gardou #endif
23083726b992SJérôme Gardou               , Pcr->SecondLevelCacheAssociativity
23093726b992SJérôme Gardou #ifdef _M_IX86
23103726b992SJérôme Gardou               , Pcr->VdmAlert
23113726b992SJérôme Gardou #endif
23123726b992SJérôme Gardou               , Pcr->SecondLevelCacheSize
23133726b992SJérôme Gardou #ifdef _M_IX86
23143726b992SJérôme Gardou               , Pcr->InterruptMode
23153726b992SJérôme Gardou #endif
23163726b992SJérôme Gardou               );
23173726b992SJérôme Gardou 
2318c2c66affSColin Finck 
2319c2c66affSColin Finck     return TRUE;
2320c2c66affSColin Finck }
2321c2c66affSColin Finck 
23223726b992SJérôme Gardou #ifdef _M_IX86
2323c2c66affSColin Finck /*!\brief Displays the TSS
2324c2c66affSColin Finck  */
2325c2c66affSColin Finck static BOOLEAN
2326c2c66affSColin Finck KdbpCmdTss(
2327c2c66affSColin Finck     ULONG Argc,
2328c2c66affSColin Finck     PCHAR Argv[])
2329c2c66affSColin Finck {
23308826ee8fSHermès Bélusca-Maïto     USHORT TssSelector;
23318826ee8fSHermès Bélusca-Maïto     PKTSS Tss = NULL;
2332c2c66affSColin Finck 
23338826ee8fSHermès Bélusca-Maïto     if (Argc >= 2)
23348826ee8fSHermès Bélusca-Maïto     {
23358826ee8fSHermès Bélusca-Maïto         /*
23368826ee8fSHermès Bélusca-Maïto          * Specified TSS via its selector [selector] or descriptor address [*descaddr].
23378826ee8fSHermès Bélusca-Maïto          * Note that we ignore any other argument values.
23388826ee8fSHermès Bélusca-Maïto          */
23398826ee8fSHermès Bélusca-Maïto         PCHAR Param, pszNext;
23408826ee8fSHermès Bélusca-Maïto         ULONG ulValue;
23418826ee8fSHermès Bélusca-Maïto 
23428826ee8fSHermès Bélusca-Maïto         Param = Argv[1];
23438826ee8fSHermès Bélusca-Maïto         if (Argv[1][0] == '*')
23448826ee8fSHermès Bélusca-Maïto             ++Param;
23458826ee8fSHermès Bélusca-Maïto 
23468826ee8fSHermès Bélusca-Maïto         ulValue = strtoul(Param, &pszNext, 0);
23478826ee8fSHermès Bélusca-Maïto         if (pszNext && *pszNext)
23488826ee8fSHermès Bélusca-Maïto         {
23498826ee8fSHermès Bélusca-Maïto             KdbpPrint("Invalid TSS specification.\n");
23508826ee8fSHermès Bélusca-Maïto             return TRUE;
23518826ee8fSHermès Bélusca-Maïto         }
23528826ee8fSHermès Bélusca-Maïto 
23538826ee8fSHermès Bélusca-Maïto         if (Argv[1][0] == '*')
23548826ee8fSHermès Bélusca-Maïto         {
23558826ee8fSHermès Bélusca-Maïto             /* Descriptor specified */
23568826ee8fSHermès Bélusca-Maïto             TssSelector = 0; // Unknown selector!
23578826ee8fSHermès Bélusca-Maïto             // TODO: Room for improvement: Find the TSS descriptor
23588826ee8fSHermès Bélusca-Maïto             // in the GDT so as to validate it.
23598826ee8fSHermès Bélusca-Maïto             Tss = (PKTSS)(ULONG_PTR)ulValue;
23608826ee8fSHermès Bélusca-Maïto             if (!Tss)
23618826ee8fSHermès Bélusca-Maïto             {
23628826ee8fSHermès Bélusca-Maïto                 KdbpPrint("Invalid 32-bit TSS descriptor.\n");
23638826ee8fSHermès Bélusca-Maïto                 return TRUE;
23648826ee8fSHermès Bélusca-Maïto             }
23658826ee8fSHermès Bélusca-Maïto         }
23668826ee8fSHermès Bélusca-Maïto         else
23678826ee8fSHermès Bélusca-Maïto         {
23688826ee8fSHermès Bélusca-Maïto             /* Selector specified, retrive the corresponding TSS */
23698826ee8fSHermès Bélusca-Maïto             TssSelector = (USHORT)ulValue;
23708826ee8fSHermès Bélusca-Maïto             Tss = KdbpRetrieveTss(TssSelector, NULL, NULL);
23718826ee8fSHermès Bélusca-Maïto             if (!Tss)
23728826ee8fSHermès Bélusca-Maïto             {
23738826ee8fSHermès Bélusca-Maïto                 KdbpPrint("Invalid 32-bit TSS selector.\n");
23748826ee8fSHermès Bélusca-Maïto                 return TRUE;
23758826ee8fSHermès Bélusca-Maïto             }
23768826ee8fSHermès Bélusca-Maïto         }
23778826ee8fSHermès Bélusca-Maïto     }
23788826ee8fSHermès Bélusca-Maïto 
23798826ee8fSHermès Bélusca-Maïto     if (!Tss)
23808826ee8fSHermès Bélusca-Maïto     {
23818826ee8fSHermès Bélusca-Maïto         /* If no TSS was specified, use the current TSS descriptor */
23828826ee8fSHermès Bélusca-Maïto         TssSelector = Ke386GetTr();
23838826ee8fSHermès Bélusca-Maïto         Tss = KeGetPcr()->TSS;
23848826ee8fSHermès Bélusca-Maïto         // NOTE: If everything works OK, Tss is the current TSS corresponding to the TR selector.
23858826ee8fSHermès Bélusca-Maïto     }
23868826ee8fSHermès Bélusca-Maïto 
23878826ee8fSHermès Bélusca-Maïto     KdbpPrint("%s TSS 0x%04x is at 0x%p.\n",
23888826ee8fSHermès Bélusca-Maïto               (Tss == KeGetPcr()->TSS) ? "Current" : "Specified", TssSelector, Tss);
23898826ee8fSHermès Bélusca-Maïto     KdbpPrint("  Backlink:  0x%04x\n"
23908826ee8fSHermès Bélusca-Maïto               "  Ss0:Esp0:  0x%04x:0x%08x\n"
23918826ee8fSHermès Bélusca-Maïto               // NOTE: Ss1:Esp1 and Ss2:Esp2: are in the NotUsed1 field.
23928826ee8fSHermès Bélusca-Maïto               "  CR3:       0x%08x\n"
23938826ee8fSHermès Bélusca-Maïto               "  EFlags:    0x%08x\n"
23948826ee8fSHermès Bélusca-Maïto               "  Eax:       0x%08x\n"
23958826ee8fSHermès Bélusca-Maïto               "  Ebx:       0x%08x\n"
23968826ee8fSHermès Bélusca-Maïto               "  Ecx:       0x%08x\n"
23978826ee8fSHermès Bélusca-Maïto               "  Edx:       0x%08x\n"
23988826ee8fSHermès Bélusca-Maïto               "  Esi:       0x%08x\n"
23998826ee8fSHermès Bélusca-Maïto               "  Edi:       0x%08x\n"
24008826ee8fSHermès Bélusca-Maïto               "  Eip:       0x%08x\n"
24018826ee8fSHermès Bélusca-Maïto               "  Esp:       0x%08x\n"
24028826ee8fSHermès Bélusca-Maïto               "  Ebp:       0x%08x\n"
2403c2c66affSColin Finck               "  Cs:        0x%04x\n"
2404c2c66affSColin Finck               "  Ss:        0x%04x\n"
2405c2c66affSColin Finck               "  Ds:        0x%04x\n"
24068826ee8fSHermès Bélusca-Maïto               "  Es:        0x%04x\n"
2407c2c66affSColin Finck               "  Fs:        0x%04x\n"
2408c2c66affSColin Finck               "  Gs:        0x%04x\n"
24098826ee8fSHermès Bélusca-Maïto               "  LDT:       0x%04x\n"
24108826ee8fSHermès Bélusca-Maïto               "  Flags:     0x%04x\n"
2411c2c66affSColin Finck               "  IoMapBase: 0x%04x\n",
24128826ee8fSHermès Bélusca-Maïto               Tss->Backlink, Tss->Ss0, Tss->Esp0, Tss->CR3, Tss->EFlags,
24138826ee8fSHermès Bélusca-Maïto               Tss->Eax, Tss->Ebx, Tss->Ecx, Tss->Edx, Tss->Esi, Tss->Edi,
24148826ee8fSHermès Bélusca-Maïto               Tss->Eip, Tss->Esp, Tss->Ebp,
24158826ee8fSHermès Bélusca-Maïto               Tss->Cs, Tss->Ss, Tss->Ds, Tss->Es, Tss->Fs, Tss->Gs,
24168826ee8fSHermès Bélusca-Maïto               Tss->LDT, Tss->Flags, Tss->IoMapBase);
2417c2c66affSColin Finck 
2418c2c66affSColin Finck     return TRUE;
2419c2c66affSColin Finck }
24203726b992SJérôme Gardou #endif
2421c2c66affSColin Finck 
2422c2c66affSColin Finck /*!\brief Bugchecks the system.
2423c2c66affSColin Finck  */
2424c2c66affSColin Finck static BOOLEAN
2425c2c66affSColin Finck KdbpCmdBugCheck(
2426c2c66affSColin Finck     ULONG Argc,
2427c2c66affSColin Finck     PCHAR Argv[])
2428c2c66affSColin Finck {
2429c2c66affSColin Finck     /* Set the flag and quit looping */
2430c2c66affSColin Finck     KdbpBugCheckRequested = TRUE;
2431c2c66affSColin Finck     return FALSE;
2432c2c66affSColin Finck }
2433c2c66affSColin Finck 
2434c2c66affSColin Finck static BOOLEAN
2435c2c66affSColin Finck KdbpCmdReboot(
2436c2c66affSColin Finck     ULONG Argc,
2437c2c66affSColin Finck     PCHAR Argv[])
2438c2c66affSColin Finck {
2439c2c66affSColin Finck     /* Reboot immediately (we do not return) */
2440c2c66affSColin Finck     HalReturnToFirmware(HalRebootRoutine);
2441c2c66affSColin Finck     return FALSE;
2442c2c66affSColin Finck }
2443c2c66affSColin Finck 
2444c2c66affSColin Finck 
2445c2c66affSColin Finck VOID
2446c2c66affSColin Finck KdbpPager(
2447c2c66affSColin Finck     IN PCHAR Buffer,
2448c2c66affSColin Finck     IN ULONG BufLength);
2449c2c66affSColin Finck 
2450c2c66affSColin Finck /*!\brief Display debug messages on screen, with paging.
2451c2c66affSColin Finck  *
2452c2c66affSColin Finck  * Keys for per-page view: Home, End, PageUp, Arrow Up, PageDown,
2453c2c66affSColin Finck  * all others are as PageDown.
2454c2c66affSColin Finck  */
2455c2c66affSColin Finck static BOOLEAN
2456c2c66affSColin Finck KdbpCmdDmesg(
2457c2c66affSColin Finck     ULONG Argc,
2458c2c66affSColin Finck     PCHAR Argv[])
2459c2c66affSColin Finck {
2460c2c66affSColin Finck     ULONG beg, end;
2461c2c66affSColin Finck 
2462c2c66affSColin Finck     KdbpIsInDmesgMode = TRUE; /* Toggle logging flag */
2463c2c66affSColin Finck     if (!KdpDmesgBuffer)
2464c2c66affSColin Finck     {
2465c2c66affSColin Finck         KdbpPrint("Dmesg: error, buffer is not allocated! /DEBUGPORT=SCREEN kernel param required for dmesg.\n");
2466c2c66affSColin Finck         return TRUE;
2467c2c66affSColin Finck     }
2468c2c66affSColin Finck 
2469c2c66affSColin Finck     KdbpPrint("*** Dmesg *** TotalWritten=%lu, BufferSize=%lu, CurrentPosition=%lu\n",
2470c2c66affSColin Finck               KdbDmesgTotalWritten, KdpDmesgBufferSize, KdpDmesgCurrentPosition);
2471c2c66affSColin Finck 
2472f0d59e74SHermès Bélusca-Maïto     /* Pass data to the pager */
2473c2c66affSColin Finck     end = KdpDmesgCurrentPosition;
2474c2c66affSColin Finck     beg = (end + KdpDmesgFreeBytes) % KdpDmesgBufferSize;
2475c2c66affSColin Finck 
2476f0d59e74SHermès Bélusca-Maïto     /* No roll-overs, and overwritten=lost bytes */
2477c2c66affSColin Finck     if (KdbDmesgTotalWritten <= KdpDmesgBufferSize)
2478c2c66affSColin Finck     {
2479f0d59e74SHermès Bélusca-Maïto         /* Show buffer (KdpDmesgBuffer + beg, num) */
2480c2c66affSColin Finck         KdbpPager(KdpDmesgBuffer, KdpDmesgCurrentPosition);
2481c2c66affSColin Finck     }
2482c2c66affSColin Finck     else
2483c2c66affSColin Finck     {
2484f0d59e74SHermès Bélusca-Maïto         /* Show 2 buffers: (KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg)
2485f0d59e74SHermès Bélusca-Maïto          *            and: (KdpDmesgBuffer,       end) */
2486c2c66affSColin Finck         KdbpPager(KdpDmesgBuffer + beg, KdpDmesgBufferSize - beg);
2487c2c66affSColin Finck         KdbpPrint("*** Dmesg: buffer rollup ***\n");
2488c2c66affSColin Finck         KdbpPager(KdpDmesgBuffer,       end);
2489c2c66affSColin Finck     }
2490c2c66affSColin Finck     KdbpPrint("*** Dmesg: end of output ***\n");
2491c2c66affSColin Finck 
2492c2c66affSColin Finck     KdbpIsInDmesgMode = FALSE; /* Toggle logging flag */
2493c2c66affSColin Finck 
2494c2c66affSColin Finck     return TRUE;
2495c2c66affSColin Finck }
2496c2c66affSColin Finck 
2497c2c66affSColin Finck /*!\brief Sets or displays a config variables value.
2498c2c66affSColin Finck  */
2499c2c66affSColin Finck static BOOLEAN
2500c2c66affSColin Finck KdbpCmdSet(
2501c2c66affSColin Finck     ULONG Argc,
2502c2c66affSColin Finck     PCHAR Argv[])
2503c2c66affSColin Finck {
2504c2c66affSColin Finck     LONG l;
2505c2c66affSColin Finck     BOOLEAN First;
2506c2c66affSColin Finck     PCHAR pend = 0;
2507c2c66affSColin Finck     KDB_ENTER_CONDITION ConditionFirst = KdbDoNotEnter;
2508c2c66affSColin Finck     KDB_ENTER_CONDITION ConditionLast = KdbDoNotEnter;
2509c2c66affSColin Finck 
2510c2c66affSColin Finck     static const PCHAR ExceptionNames[21] =
2511c2c66affSColin Finck     {
2512c2c66affSColin Finck         "ZERODEVIDE", "DEBUGTRAP", "NMI", "INT3", "OVERFLOW", "BOUND", "INVALIDOP",
2513c2c66affSColin Finck         "NOMATHCOP", "DOUBLEFAULT", "RESERVED(9)", "INVALIDTSS", "SEGMENTNOTPRESENT",
2514c2c66affSColin Finck         "STACKFAULT", "GPF", "PAGEFAULT", "RESERVED(15)", "MATHFAULT", "ALIGNMENTCHECK",
2515c2c66affSColin Finck         "MACHINECHECK", "SIMDFAULT", "OTHERS"
2516c2c66affSColin Finck     };
2517c2c66affSColin Finck 
2518c2c66affSColin Finck     if (Argc == 1)
2519c2c66affSColin Finck     {
2520c2c66affSColin Finck         KdbpPrint("Available settings:\n");
2521c2c66affSColin Finck         KdbpPrint("  syntax [intel|at&t]\n");
2522c2c66affSColin Finck         KdbpPrint("  condition [exception|*] [first|last] [never|always|kmode|umode]\n");
2523c2c66affSColin Finck         KdbpPrint("  break_on_module_load [true|false]\n");
2524c2c66affSColin Finck     }
2525c2c66affSColin Finck     else if (strcmp(Argv[1], "syntax") == 0)
2526c2c66affSColin Finck     {
2527c2c66affSColin Finck         if (Argc == 2)
2528c2c66affSColin Finck         {
2529c2c66affSColin Finck             KdbpPrint("syntax = %s\n", KdbUseIntelSyntax ? "intel" : "at&t");
2530c2c66affSColin Finck         }
2531c2c66affSColin Finck         else if (Argc >= 3)
2532c2c66affSColin Finck         {
2533c2c66affSColin Finck             if (_stricmp(Argv[2], "intel") == 0)
2534c2c66affSColin Finck                 KdbUseIntelSyntax = TRUE;
2535c2c66affSColin Finck             else if (_stricmp(Argv[2], "at&t") == 0)
2536c2c66affSColin Finck                 KdbUseIntelSyntax = FALSE;
2537c2c66affSColin Finck             else
2538c2c66affSColin Finck                 KdbpPrint("Unknown syntax '%s'.\n", Argv[2]);
2539c2c66affSColin Finck         }
2540c2c66affSColin Finck     }
2541c2c66affSColin Finck     else if (strcmp(Argv[1], "condition") == 0)
2542c2c66affSColin Finck     {
2543c2c66affSColin Finck         if (Argc == 2)
2544c2c66affSColin Finck         {
2545c2c66affSColin Finck             KdbpPrint("Conditions:                 (First)  (Last)\n");
2546c2c66affSColin Finck             for (l = 0; l < RTL_NUMBER_OF(ExceptionNames) - 1; l++)
2547c2c66affSColin Finck             {
2548c2c66affSColin Finck                 if (!ExceptionNames[l])
2549c2c66affSColin Finck                     continue;
2550c2c66affSColin Finck 
2551c2c66affSColin Finck                 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst))
2552f0d59e74SHermès Bélusca-Maïto                     ASSERT(FALSE);
2553c2c66affSColin Finck 
2554c2c66affSColin Finck                 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast))
2555f0d59e74SHermès Bélusca-Maïto                     ASSERT(FALSE);
2556c2c66affSColin Finck 
2557c2c66affSColin Finck                 KdbpPrint("  #%02d  %-20s %-8s %-8s\n", l, ExceptionNames[l],
2558c2c66affSColin Finck                           KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),
2559c2c66affSColin Finck                           KDB_ENTER_CONDITION_TO_STRING(ConditionLast));
2560c2c66affSColin Finck             }
2561c2c66affSColin Finck 
2562c2c66affSColin Finck             ASSERT(l == (RTL_NUMBER_OF(ExceptionNames) - 1));
2563c2c66affSColin Finck             KdbpPrint("       %-20s %-8s %-8s\n", ExceptionNames[l],
2564c2c66affSColin Finck                       KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),
2565c2c66affSColin Finck                       KDB_ENTER_CONDITION_TO_STRING(ConditionLast));
2566c2c66affSColin Finck         }
2567c2c66affSColin Finck         else
2568c2c66affSColin Finck         {
2569c2c66affSColin Finck             if (Argc >= 5 && strcmp(Argv[2], "*") == 0) /* Allow * only when setting condition */
2570c2c66affSColin Finck             {
2571c2c66affSColin Finck                 l = -1;
2572c2c66affSColin Finck             }
2573c2c66affSColin Finck             else
2574c2c66affSColin Finck             {
2575c2c66affSColin Finck                 l = strtoul(Argv[2], &pend, 0);
2576c2c66affSColin Finck 
2577c2c66affSColin Finck                 if (Argv[2] == pend)
2578c2c66affSColin Finck                 {
2579c2c66affSColin Finck                     for (l = 0; l < RTL_NUMBER_OF(ExceptionNames); l++)
2580c2c66affSColin Finck                     {
2581c2c66affSColin Finck                         if (!ExceptionNames[l])
2582c2c66affSColin Finck                             continue;
2583c2c66affSColin Finck 
2584c2c66affSColin Finck                         if (_stricmp(ExceptionNames[l], Argv[2]) == 0)
2585c2c66affSColin Finck                             break;
2586c2c66affSColin Finck                     }
2587c2c66affSColin Finck                 }
2588c2c66affSColin Finck 
2589c2c66affSColin Finck                 if (l >= RTL_NUMBER_OF(ExceptionNames))
2590c2c66affSColin Finck                 {
2591c2c66affSColin Finck                     KdbpPrint("Unknown exception '%s'.\n", Argv[2]);
2592c2c66affSColin Finck                     return TRUE;
2593c2c66affSColin Finck                 }
2594c2c66affSColin Finck             }
2595c2c66affSColin Finck 
2596c2c66affSColin Finck             if (Argc > 4)
2597c2c66affSColin Finck             {
2598c2c66affSColin Finck                 if (_stricmp(Argv[3], "first") == 0)
2599c2c66affSColin Finck                     First = TRUE;
2600c2c66affSColin Finck                 else if (_stricmp(Argv[3], "last") == 0)
2601c2c66affSColin Finck                     First = FALSE;
2602c2c66affSColin Finck                 else
2603c2c66affSColin Finck                 {
2604c2c66affSColin Finck                     KdbpPrint("set condition: second argument must be 'first' or 'last'\n");
2605c2c66affSColin Finck                     return TRUE;
2606c2c66affSColin Finck                 }
2607c2c66affSColin Finck 
2608c2c66affSColin Finck                 if (_stricmp(Argv[4], "never") == 0)
2609c2c66affSColin Finck                     ConditionFirst = KdbDoNotEnter;
2610c2c66affSColin Finck                 else if (_stricmp(Argv[4], "always") == 0)
2611c2c66affSColin Finck                     ConditionFirst = KdbEnterAlways;
2612c2c66affSColin Finck                 else if (_stricmp(Argv[4], "umode") == 0)
2613c2c66affSColin Finck                     ConditionFirst = KdbEnterFromUmode;
2614c2c66affSColin Finck                 else if (_stricmp(Argv[4], "kmode") == 0)
2615c2c66affSColin Finck                     ConditionFirst = KdbEnterFromKmode;
2616c2c66affSColin Finck                 else
2617c2c66affSColin Finck                 {
2618c2c66affSColin Finck                     KdbpPrint("set condition: third argument must be 'never', 'always', 'umode' or 'kmode'\n");
2619c2c66affSColin Finck                     return TRUE;
2620c2c66affSColin Finck                 }
2621c2c66affSColin Finck 
2622c2c66affSColin Finck                 if (!KdbpSetEnterCondition(l, First, ConditionFirst))
2623c2c66affSColin Finck                 {
2624c2c66affSColin Finck                     if (l >= 0)
2625c2c66affSColin Finck                         KdbpPrint("Couldn't change condition for exception #%02d\n", l);
2626c2c66affSColin Finck                     else
2627c2c66affSColin Finck                         KdbpPrint("Couldn't change condition for all exceptions\n", l);
2628c2c66affSColin Finck                 }
2629c2c66affSColin Finck             }
2630c2c66affSColin Finck             else /* Argc >= 3 */
2631c2c66affSColin Finck             {
2632c2c66affSColin Finck                 if (!KdbpGetEnterCondition(l, TRUE, &ConditionFirst))
2633f0d59e74SHermès Bélusca-Maïto                     ASSERT(FALSE);
2634c2c66affSColin Finck 
2635c2c66affSColin Finck                 if (!KdbpGetEnterCondition(l, FALSE, &ConditionLast))
2636f0d59e74SHermès Bélusca-Maïto                     ASSERT(FALSE);
2637c2c66affSColin Finck 
2638c2c66affSColin Finck                 if (l < (RTL_NUMBER_OF(ExceptionNames) - 1))
2639c2c66affSColin Finck                 {
2640c2c66affSColin Finck                     KdbpPrint("Condition for exception #%02d (%s): FirstChance %s  LastChance %s\n",
2641c2c66affSColin Finck                               l, ExceptionNames[l],
2642c2c66affSColin Finck                               KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),
2643c2c66affSColin Finck                               KDB_ENTER_CONDITION_TO_STRING(ConditionLast));
2644c2c66affSColin Finck                 }
2645c2c66affSColin Finck                 else
2646c2c66affSColin Finck                 {
2647c2c66affSColin Finck                     KdbpPrint("Condition for all other exceptions: FirstChance %s  LastChance %s\n",
2648c2c66affSColin Finck                               KDB_ENTER_CONDITION_TO_STRING(ConditionFirst),
2649c2c66affSColin Finck                               KDB_ENTER_CONDITION_TO_STRING(ConditionLast));
2650c2c66affSColin Finck                 }
2651c2c66affSColin Finck             }
2652c2c66affSColin Finck         }
2653c2c66affSColin Finck     }
2654c2c66affSColin Finck     else if (strcmp(Argv[1], "break_on_module_load") == 0)
2655c2c66affSColin Finck     {
2656c2c66affSColin Finck         if (Argc == 2)
2657c2c66affSColin Finck             KdbpPrint("break_on_module_load = %s\n", KdbBreakOnModuleLoad ? "enabled" : "disabled");
2658c2c66affSColin Finck         else if (Argc >= 3)
2659c2c66affSColin Finck         {
2660c2c66affSColin Finck             if (_stricmp(Argv[2], "enable") == 0 || _stricmp(Argv[2], "enabled") == 0 || _stricmp(Argv[2], "true") == 0)
2661c2c66affSColin Finck                 KdbBreakOnModuleLoad = TRUE;
2662c2c66affSColin Finck             else if (_stricmp(Argv[2], "disable") == 0 || _stricmp(Argv[2], "disabled") == 0 || _stricmp(Argv[2], "false") == 0)
2663c2c66affSColin Finck                 KdbBreakOnModuleLoad = FALSE;
2664c2c66affSColin Finck             else
2665c2c66affSColin Finck                 KdbpPrint("Unknown setting '%s'.\n", Argv[2]);
2666c2c66affSColin Finck         }
2667c2c66affSColin Finck     }
2668c2c66affSColin Finck     else
2669c2c66affSColin Finck     {
2670c2c66affSColin Finck         KdbpPrint("Unknown setting '%s'.\n", Argv[1]);
2671c2c66affSColin Finck     }
2672c2c66affSColin Finck 
2673c2c66affSColin Finck     return TRUE;
2674c2c66affSColin Finck }
2675c2c66affSColin Finck 
2676c2c66affSColin Finck /*!\brief Displays help screen.
2677c2c66affSColin Finck  */
2678c2c66affSColin Finck static BOOLEAN
2679c2c66affSColin Finck KdbpCmdHelp(
2680c2c66affSColin Finck     ULONG Argc,
2681c2c66affSColin Finck     PCHAR Argv[])
2682c2c66affSColin Finck {
2683c2c66affSColin Finck     ULONG i;
2684c2c66affSColin Finck 
2685c2c66affSColin Finck     KdbpPrint("Kernel debugger commands:\n");
2686c2c66affSColin Finck     for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++)
2687c2c66affSColin Finck     {
2688c2c66affSColin Finck         if (!KdbDebuggerCommands[i].Syntax) /* Command group */
2689c2c66affSColin Finck         {
2690c2c66affSColin Finck             if (i > 0)
2691c2c66affSColin Finck                 KdbpPrint("\n");
2692c2c66affSColin Finck 
2693c2c66affSColin Finck             KdbpPrint("\x1b[7m* %s:\x1b[0m\n", KdbDebuggerCommands[i].Help);
2694c2c66affSColin Finck             continue;
2695c2c66affSColin Finck         }
2696c2c66affSColin Finck 
2697c2c66affSColin Finck         KdbpPrint("  %-20s - %s\n",
2698c2c66affSColin Finck                   KdbDebuggerCommands[i].Syntax,
2699c2c66affSColin Finck                   KdbDebuggerCommands[i].Help);
2700c2c66affSColin Finck     }
2701c2c66affSColin Finck 
2702c2c66affSColin Finck     return TRUE;
2703c2c66affSColin Finck }
2704c2c66affSColin Finck 
2705c2c66affSColin Finck /*!\brief Prints the given string with printf-like formatting.
2706c2c66affSColin Finck  *
2707c2c66affSColin Finck  * \param Format  Format of the string/arguments.
2708c2c66affSColin Finck  * \param ...     Variable number of arguments matching the format specified in \a Format.
2709c2c66affSColin Finck  *
2710c2c66affSColin Finck  * \note Doesn't correctly handle \\t and terminal escape sequences when calculating the
2711c2c66affSColin Finck  *       number of lines required to print a single line from the Buffer in the terminal.
2712c2c66affSColin Finck  *       Prints maximum 4096 chars, because of its buffer size.
2713c2c66affSColin Finck  */
2714c2c66affSColin Finck VOID
2715c2c66affSColin Finck KdbpPrint(
2716c2c66affSColin Finck     IN PCHAR Format,
2717c2c66affSColin Finck     IN ...  OPTIONAL)
2718c2c66affSColin Finck {
2719c2c66affSColin Finck     static CHAR Buffer[4096];
2720c2c66affSColin Finck     static BOOLEAN TerminalInitialized = FALSE;
2721c2c66affSColin Finck     static BOOLEAN TerminalConnected = FALSE;
2722c2c66affSColin Finck     static BOOLEAN TerminalReportsSize = TRUE;
2723c2c66affSColin Finck     CHAR c = '\0';
2724c2c66affSColin Finck     PCHAR p, p2;
2725c2c66affSColin Finck     ULONG Length;
2726c2c66affSColin Finck     ULONG i, j;
2727c2c66affSColin Finck     LONG RowsPrintedByTerminal;
2728c2c66affSColin Finck     ULONG ScanCode;
2729c2c66affSColin Finck     va_list ap;
2730c2c66affSColin Finck 
2731c2c66affSColin Finck     /* Check if the user has aborted output of the current command */
2732c2c66affSColin Finck     if (KdbOutputAborted)
2733c2c66affSColin Finck         return;
2734c2c66affSColin Finck 
2735c2c66affSColin Finck     /* Initialize the terminal */
2736c2c66affSColin Finck     if (!TerminalInitialized)
2737c2c66affSColin Finck     {
2738c2c66affSColin Finck         DbgPrint("\x1b[7h");      /* Enable linewrap */
2739c2c66affSColin Finck 
2740c2c66affSColin Finck         /* Query terminal type */
2741c2c66affSColin Finck         /*DbgPrint("\x1b[Z");*/
2742c2c66affSColin Finck         DbgPrint("\x05");
2743c2c66affSColin Finck 
2744c2c66affSColin Finck         TerminalInitialized = TRUE;
2745c2c66affSColin Finck         Length = 0;
2746c2c66affSColin Finck         KeStallExecutionProcessor(100000);
2747c2c66affSColin Finck 
2748c2c66affSColin Finck         for (;;)
2749c2c66affSColin Finck         {
2750c2c66affSColin Finck             c = KdbpTryGetCharSerial(5000);
2751c2c66affSColin Finck             if (c == -1)
2752c2c66affSColin Finck                 break;
2753c2c66affSColin Finck 
2754c2c66affSColin Finck             Buffer[Length++] = c;
2755c2c66affSColin Finck             if (Length >= (sizeof(Buffer) - 1))
2756c2c66affSColin Finck                 break;
2757c2c66affSColin Finck         }
2758c2c66affSColin Finck 
2759c2c66affSColin Finck         Buffer[Length] = '\0';
2760c2c66affSColin Finck         if (Length > 0)
2761c2c66affSColin Finck             TerminalConnected = TRUE;
2762c2c66affSColin Finck     }
2763c2c66affSColin Finck 
2764c2c66affSColin Finck     /* Get number of rows and columns in terminal */
2765c2c66affSColin Finck     if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
2766c2c66affSColin Finck         (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */
2767c2c66affSColin Finck     {
2768c2c66affSColin Finck         if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize)
2769c2c66affSColin Finck         {
2770c2c66affSColin Finck             /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */
2771c2c66affSColin Finck             TerminalReportsSize = FALSE;
2772c2c66affSColin Finck             KeStallExecutionProcessor(100000);
2773c2c66affSColin Finck             DbgPrint("\x1b[18t");
2774c2c66affSColin Finck             c = KdbpTryGetCharSerial(5000);
2775c2c66affSColin Finck 
2776c2c66affSColin Finck             if (c == KEY_ESC)
2777c2c66affSColin Finck             {
2778c2c66affSColin Finck                 c = KdbpTryGetCharSerial(5000);
2779c2c66affSColin Finck                 if (c == '[')
2780c2c66affSColin Finck                 {
2781c2c66affSColin Finck                     Length = 0;
2782c2c66affSColin Finck 
2783c2c66affSColin Finck                     for (;;)
2784c2c66affSColin Finck                     {
2785c2c66affSColin Finck                         c = KdbpTryGetCharSerial(5000);
2786c2c66affSColin Finck                         if (c == -1)
2787c2c66affSColin Finck                             break;
2788c2c66affSColin Finck 
2789c2c66affSColin Finck                         Buffer[Length++] = c;
2790c2c66affSColin Finck                         if (isalpha(c) || Length >= (sizeof(Buffer) - 1))
2791c2c66affSColin Finck                             break;
2792c2c66affSColin Finck                     }
2793c2c66affSColin Finck 
2794c2c66affSColin Finck                     Buffer[Length] = '\0';
2795c2c66affSColin Finck                     if (Buffer[0] == '8' && Buffer[1] == ';')
2796c2c66affSColin Finck                     {
2797c2c66affSColin Finck                         for (i = 2; (i < Length) && (Buffer[i] != ';'); i++);
2798c2c66affSColin Finck 
2799c2c66affSColin Finck                         if (Buffer[i] == ';')
2800c2c66affSColin Finck                         {
2801c2c66affSColin Finck                             Buffer[i++] = '\0';
2802c2c66affSColin Finck 
2803c2c66affSColin Finck                             /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */
2804c2c66affSColin Finck                             KdbNumberOfRowsTerminal = strtoul(Buffer + 2, NULL, 0);
2805c2c66affSColin Finck                             KdbNumberOfColsTerminal = strtoul(Buffer + i, NULL, 0);
2806c2c66affSColin Finck                             TerminalReportsSize = TRUE;
2807c2c66affSColin Finck                         }
2808c2c66affSColin Finck                     }
2809c2c66affSColin Finck                 }
2810c2c66affSColin Finck                 /* Clear further characters */
2811c2c66affSColin Finck                 while ((c = KdbpTryGetCharSerial(5000)) != -1);
2812c2c66affSColin Finck             }
2813c2c66affSColin Finck         }
2814c2c66affSColin Finck 
2815c2c66affSColin Finck         if (KdbNumberOfRowsTerminal <= 0)
2816c2c66affSColin Finck         {
2817c2c66affSColin Finck             /* Set number of rows to the default. */
2818c2c66affSColin Finck             KdbNumberOfRowsTerminal = 23; //24; //Mna.: 23 for SCREEN debugport
2819c2c66affSColin Finck         }
2820c2c66affSColin Finck         else if (KdbNumberOfColsTerminal <= 0)
2821c2c66affSColin Finck         {
2822c2c66affSColin Finck             /* Set number of cols to the default. */
2823c2c66affSColin Finck             KdbNumberOfColsTerminal = 75; //80; //Mna.: 75 for SCREEN debugport
2824c2c66affSColin Finck         }
2825c2c66affSColin Finck     }
2826c2c66affSColin Finck 
2827c2c66affSColin Finck     /* Get the string */
2828c2c66affSColin Finck     va_start(ap, Format);
2829c2c66affSColin Finck     Length = _vsnprintf(Buffer, sizeof(Buffer) - 1, Format, ap);
2830c2c66affSColin Finck     Buffer[Length] = '\0';
2831c2c66affSColin Finck     va_end(ap);
2832c2c66affSColin Finck 
2833c2c66affSColin Finck     p = Buffer;
2834c2c66affSColin Finck     while (p[0] != '\0')
2835c2c66affSColin Finck     {
2836c2c66affSColin Finck         i = strcspn(p, "\n");
2837c2c66affSColin Finck 
2838c2c66affSColin Finck         /* Calculate the number of lines which will be printed in the terminal
2839c2c66affSColin Finck          * when outputting the current line
2840c2c66affSColin Finck          */
2841c2c66affSColin Finck         if (i > 0)
2842c2c66affSColin Finck             RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal;
2843c2c66affSColin Finck         else
2844c2c66affSColin Finck             RowsPrintedByTerminal = 0;
2845c2c66affSColin Finck 
2846c2c66affSColin Finck         if (p[i] == '\n')
2847c2c66affSColin Finck             RowsPrintedByTerminal++;
2848c2c66affSColin Finck 
2849c2c66affSColin Finck         /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/
2850c2c66affSColin Finck 
2851c2c66affSColin Finck         /* Display a prompt if we printed one screen full of text */
2852c2c66affSColin Finck         if (KdbNumberOfRowsTerminal > 0 &&
2853c2c66affSColin Finck             (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
2854c2c66affSColin Finck         {
2855c2c66affSColin Finck             KdbRepeatLastCommand = FALSE;
2856c2c66affSColin Finck 
2857c2c66affSColin Finck             if (KdbNumberOfColsPrinted > 0)
2858c2c66affSColin Finck                 DbgPrint("\n");
2859c2c66affSColin Finck 
2860c2c66affSColin Finck             DbgPrint("--- Press q to abort, any other key to continue ---");
2861c2c66affSColin Finck             RowsPrintedByTerminal++; /* added by Mna. */
2862c2c66affSColin Finck 
2863c2c66affSColin Finck             if (KdbDebugState & KD_DEBUG_KDSERIAL)
2864c2c66affSColin Finck                 c = KdbpGetCharSerial();
2865c2c66affSColin Finck             else
2866c2c66affSColin Finck                 c = KdbpGetCharKeyboard(&ScanCode);
2867c2c66affSColin Finck 
2868c2c66affSColin Finck             if (c == '\r')
2869c2c66affSColin Finck             {
2870c2c66affSColin Finck                 /* Try to read '\n' which might follow '\r' - if \n is not received here
2871c2c66affSColin Finck                  * it will be interpreted as "return" when the next command should be read.
2872c2c66affSColin Finck                  */
2873c2c66affSColin Finck                 if (KdbDebugState & KD_DEBUG_KDSERIAL)
2874c2c66affSColin Finck                     c = KdbpTryGetCharSerial(5);
2875c2c66affSColin Finck                 else
2876c2c66affSColin Finck                     c = KdbpTryGetCharKeyboard(&ScanCode, 5);
2877c2c66affSColin Finck             }
2878c2c66affSColin Finck 
2879c2c66affSColin Finck             DbgPrint("\n");
2880c2c66affSColin Finck             if (c == 'q')
2881c2c66affSColin Finck             {
2882c2c66affSColin Finck                 KdbOutputAborted = TRUE;
2883c2c66affSColin Finck                 return;
2884c2c66affSColin Finck             }
2885c2c66affSColin Finck 
2886c2c66affSColin Finck             KdbNumberOfRowsPrinted = 0;
2887c2c66affSColin Finck             KdbNumberOfColsPrinted = 0;
2888c2c66affSColin Finck         }
2889c2c66affSColin Finck 
2890c2c66affSColin Finck         /* Insert a NUL after the line and print only the current line. */
2891c2c66affSColin Finck         if (p[i] == '\n' && p[i + 1] != '\0')
2892c2c66affSColin Finck         {
2893c2c66affSColin Finck             c = p[i + 1];
2894c2c66affSColin Finck             p[i + 1] = '\0';
2895c2c66affSColin Finck         }
2896c2c66affSColin Finck         else
2897c2c66affSColin Finck         {
2898c2c66affSColin Finck             c = '\0';
2899c2c66affSColin Finck         }
2900c2c66affSColin Finck 
2901c2c66affSColin Finck         /* Remove escape sequences from the line if there's no terminal connected */
2902c2c66affSColin Finck         if (!TerminalConnected)
2903c2c66affSColin Finck         {
2904c2c66affSColin Finck             while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */
2905c2c66affSColin Finck             {
29063af7cb82STimo Kreuzer                 size_t len = strlen(p2);
2907c2c66affSColin Finck                 if (p2[1] == '[')
2908c2c66affSColin Finck                 {
2909c2c66affSColin Finck                     j = 2;
2910c2c66affSColin Finck                     while (!isalpha(p2[j++]));
29113af7cb82STimo Kreuzer                     memmove(p2, p2 + j, len + 1 - j);
2912c2c66affSColin Finck                 }
2913c2c66affSColin Finck                 else
2914c2c66affSColin Finck                 {
29153af7cb82STimo Kreuzer                     memmove(p2, p2 + 1, len);
2916c2c66affSColin Finck                 }
2917c2c66affSColin Finck             }
2918c2c66affSColin Finck         }
2919c2c66affSColin Finck 
2920c2c66affSColin Finck         DbgPrint("%s", p);
2921c2c66affSColin Finck 
2922c2c66affSColin Finck         if (c != '\0')
2923c2c66affSColin Finck             p[i + 1] = c;
2924c2c66affSColin Finck 
2925c2c66affSColin Finck         /* Set p to the start of the next line and
2926c2c66affSColin Finck          * remember the number of rows/cols printed
2927c2c66affSColin Finck          */
2928c2c66affSColin Finck         p += i;
2929c2c66affSColin Finck         if (p[0] == '\n')
2930c2c66affSColin Finck         {
2931c2c66affSColin Finck             p++;
2932c2c66affSColin Finck             KdbNumberOfColsPrinted = 0;
2933c2c66affSColin Finck         }
2934c2c66affSColin Finck         else
2935c2c66affSColin Finck         {
2936c2c66affSColin Finck             ASSERT(p[0] == '\0');
2937c2c66affSColin Finck             KdbNumberOfColsPrinted += i;
2938c2c66affSColin Finck         }
2939c2c66affSColin Finck 
2940c2c66affSColin Finck         KdbNumberOfRowsPrinted += RowsPrintedByTerminal;
2941c2c66affSColin Finck     }
2942c2c66affSColin Finck }
2943c2c66affSColin Finck 
2944c2c66affSColin Finck /** memrchr(), explicitly defined, since was absent in MinGW of RosBE. */
2945c2c66affSColin Finck /*
2946c2c66affSColin Finck  * Reverse memchr()
2947c2c66affSColin Finck  * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
2948c2c66affSColin Finck  */
2949c2c66affSColin Finck void *
2950c2c66affSColin Finck memrchr(const void *s, int c, size_t n)
2951c2c66affSColin Finck {
2952c2c66affSColin Finck     const unsigned char *cp;
2953c2c66affSColin Finck 
2954c2c66affSColin Finck     if (n != 0)
2955c2c66affSColin Finck     {
2956c2c66affSColin Finck         cp = (unsigned char *)s + n;
2957c2c66affSColin Finck         do
2958c2c66affSColin Finck         {
2959c2c66affSColin Finck             if (*(--cp) == (unsigned char)c)
2960c2c66affSColin Finck                 return (void *)cp;
2961c2c66affSColin Finck         } while (--n != 0);
2962c2c66affSColin Finck     }
2963c2c66affSColin Finck     return NULL;
2964c2c66affSColin Finck }
2965c2c66affSColin Finck 
2966c2c66affSColin Finck /*!\brief Calculate pointer position for N lines upper of current position.
2967c2c66affSColin Finck  *
2968c2c66affSColin Finck  * \param Buffer     Characters buffer to operate on.
2969c2c66affSColin Finck  * \param BufLength  Buffer size.
2970c2c66affSColin Finck  *
2971c2c66affSColin Finck  * \note Calculate pointer position for N lines upper of current displaying
2972c2c66affSColin Finck  *       position within the given buffer.
2973c2c66affSColin Finck  *
2974c2c66affSColin Finck  * Used by KdbpPager().
2975c2c66affSColin Finck  * Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
2976c2c66affSColin Finck  */
2977c2c66affSColin Finck PCHAR
2978c2c66affSColin Finck CountOnePageUp(PCHAR Buffer, ULONG BufLength, PCHAR pCurPos)
2979c2c66affSColin Finck {
2980c2c66affSColin Finck     PCHAR p;
2981c2c66affSColin Finck     // p0 is initial guess of Page Start
2982c2c66affSColin Finck     ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
2983c2c66affSColin Finck     PCHAR p0 = pCurPos - p0len;
2984c2c66affSColin Finck     PCHAR prev_p = p0, p1;
2985c2c66affSColin Finck     ULONG j;
2986c2c66affSColin Finck 
2987c2c66affSColin Finck     if (pCurPos < Buffer)
2988c2c66affSColin Finck         pCurPos = Buffer;
2989c2c66affSColin Finck     ASSERT(pCurPos <= Buffer + BufLength);
2990c2c66affSColin Finck 
2991c2c66affSColin Finck     p = memrchr(p0, '\n', p0len);
2992c2c66affSColin Finck     if (NULL == p)
2993c2c66affSColin Finck         p = p0;
2994c2c66affSColin Finck     for (j = KdbNumberOfRowsTerminal; j--; )
2995c2c66affSColin Finck     {
2996c2c66affSColin Finck         int linesCnt;
2997c2c66affSColin Finck         p1 = memrchr(p0, '\n', p-p0);
2998c2c66affSColin Finck         prev_p = p;
2999c2c66affSColin Finck         p = p1;
3000c2c66affSColin Finck         if (NULL == p)
3001c2c66affSColin Finck         {
3002c2c66affSColin Finck             p = prev_p;
3003c2c66affSColin Finck             if (NULL == p)
3004c2c66affSColin Finck                 p = p0;
3005c2c66affSColin Finck             break;
3006c2c66affSColin Finck         }
3007c2c66affSColin Finck         linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / KdbNumberOfColsTerminal;
3008c2c66affSColin Finck         if (linesCnt > 1)
3009c2c66affSColin Finck             j -= linesCnt-1;
3010c2c66affSColin Finck     }
3011c2c66affSColin Finck 
3012c2c66affSColin Finck     ASSERT(p != 0);
3013c2c66affSColin Finck     ++p;
3014c2c66affSColin Finck     return p;
3015c2c66affSColin Finck }
3016c2c66affSColin Finck 
3017c2c66affSColin Finck /*!\brief Prints the given string with, page by page.
3018c2c66affSColin Finck  *
3019c2c66affSColin Finck  * \param Buffer     Characters buffer to print.
3020c2c66affSColin Finck  * \param BufferLen  Buffer size.
3021c2c66affSColin Finck  *
3022c2c66affSColin Finck  * \note Doesn't correctly handle \\t and terminal escape sequences when calculating the
3023c2c66affSColin Finck  *       number of lines required to print a single line from the Buffer in the terminal.
3024c2c66affSColin Finck  *       Maximum length of buffer is limited only by memory size.
3025c2c66affSColin Finck  *
3026c2c66affSColin Finck  * Note: BufLength should be greater then (KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal).
3027c2c66affSColin Finck  *
3028c2c66affSColin Finck  */
3029c2c66affSColin Finck VOID
3030c2c66affSColin Finck KdbpPager(
3031c2c66affSColin Finck     IN PCHAR Buffer,
3032c2c66affSColin Finck     IN ULONG BufLength)
3033c2c66affSColin Finck {
3034c2c66affSColin Finck     static CHAR InBuffer[4096];
3035c2c66affSColin Finck     static BOOLEAN TerminalInitialized = FALSE;
3036c2c66affSColin Finck     static BOOLEAN TerminalConnected = FALSE;
3037c2c66affSColin Finck     static BOOLEAN TerminalReportsSize = TRUE;
3038c2c66affSColin Finck     CHAR c = '\0';
3039c2c66affSColin Finck     PCHAR p, p2;
3040c2c66affSColin Finck     ULONG Length;
3041c2c66affSColin Finck     ULONG i, j;
3042c2c66affSColin Finck     LONG RowsPrintedByTerminal;
3043c2c66affSColin Finck     ULONG ScanCode;
3044c2c66affSColin Finck 
3045c2c66affSColin Finck     if( BufLength == 0)
3046c2c66affSColin Finck       return;
3047c2c66affSColin Finck 
3048c2c66affSColin Finck     /* Check if the user has aborted output of the current command */
3049c2c66affSColin Finck     if (KdbOutputAborted)
3050c2c66affSColin Finck         return;
3051c2c66affSColin Finck 
3052c2c66affSColin Finck     /* Initialize the terminal */
3053c2c66affSColin Finck     if (!TerminalInitialized)
3054c2c66affSColin Finck     {
3055c2c66affSColin Finck         DbgPrint("\x1b[7h");      /* Enable linewrap */
3056c2c66affSColin Finck 
3057c2c66affSColin Finck         /* Query terminal type */
3058c2c66affSColin Finck         /*DbgPrint("\x1b[Z");*/
3059c2c66affSColin Finck         DbgPrint("\x05");
3060c2c66affSColin Finck 
3061c2c66affSColin Finck         TerminalInitialized = TRUE;
3062c2c66affSColin Finck         Length = 0;
3063c2c66affSColin Finck         KeStallExecutionProcessor(100000);
3064c2c66affSColin Finck 
3065c2c66affSColin Finck         for (;;)
3066c2c66affSColin Finck         {
3067c2c66affSColin Finck             c = KdbpTryGetCharSerial(5000);
3068c2c66affSColin Finck             if (c == -1)
3069c2c66affSColin Finck                 break;
3070c2c66affSColin Finck 
3071c2c66affSColin Finck             InBuffer[Length++] = c;
3072c2c66affSColin Finck             if (Length >= (sizeof(InBuffer) - 1))
3073c2c66affSColin Finck                 break;
3074c2c66affSColin Finck         }
3075c2c66affSColin Finck 
3076c2c66affSColin Finck         InBuffer[Length] = '\0';
3077c2c66affSColin Finck         if (Length > 0)
3078c2c66affSColin Finck             TerminalConnected = TRUE;
3079c2c66affSColin Finck     }
3080c2c66affSColin Finck 
3081c2c66affSColin Finck     /* Get number of rows and columns in terminal */
3082c2c66affSColin Finck     if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
3083c2c66affSColin Finck         (KdbNumberOfRowsPrinted) == 0) /* Refresh terminal size each time when number of rows printed is 0 */
3084c2c66affSColin Finck     {
3085c2c66affSColin Finck         if ((KdbDebugState & KD_DEBUG_KDSERIAL) && TerminalConnected && TerminalReportsSize)
3086c2c66affSColin Finck         {
3087c2c66affSColin Finck             /* Try to query number of rows from terminal. A reply looks like "\x1b[8;24;80t" */
3088c2c66affSColin Finck             TerminalReportsSize = FALSE;
3089c2c66affSColin Finck             KeStallExecutionProcessor(100000);
3090c2c66affSColin Finck             DbgPrint("\x1b[18t");
3091c2c66affSColin Finck             c = KdbpTryGetCharSerial(5000);
3092c2c66affSColin Finck 
3093c2c66affSColin Finck             if (c == KEY_ESC)
3094c2c66affSColin Finck             {
3095c2c66affSColin Finck                 c = KdbpTryGetCharSerial(5000);
3096c2c66affSColin Finck                 if (c == '[')
3097c2c66affSColin Finck                 {
3098c2c66affSColin Finck                     Length = 0;
3099c2c66affSColin Finck 
3100c2c66affSColin Finck                     for (;;)
3101c2c66affSColin Finck                     {
3102c2c66affSColin Finck                         c = KdbpTryGetCharSerial(5000);
3103c2c66affSColin Finck                         if (c == -1)
3104c2c66affSColin Finck                             break;
3105c2c66affSColin Finck 
3106c2c66affSColin Finck                         InBuffer[Length++] = c;
3107c2c66affSColin Finck                         if (isalpha(c) || Length >= (sizeof(InBuffer) - 1))
3108c2c66affSColin Finck                             break;
3109c2c66affSColin Finck                     }
3110c2c66affSColin Finck 
3111c2c66affSColin Finck                     InBuffer[Length] = '\0';
3112c2c66affSColin Finck                     if (InBuffer[0] == '8' && InBuffer[1] == ';')
3113c2c66affSColin Finck                     {
3114c2c66affSColin Finck                         for (i = 2; (i < Length) && (InBuffer[i] != ';'); i++);
3115c2c66affSColin Finck 
3116c2c66affSColin Finck                         if (Buffer[i] == ';')
3117c2c66affSColin Finck                         {
3118c2c66affSColin Finck                             Buffer[i++] = '\0';
3119c2c66affSColin Finck 
3120c2c66affSColin Finck                             /* Number of rows is now at Buffer + 2 and number of cols at Buffer + i */
3121c2c66affSColin Finck                             KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, NULL, 0);
3122c2c66affSColin Finck                             KdbNumberOfColsTerminal = strtoul(InBuffer + i, NULL, 0);
3123c2c66affSColin Finck                             TerminalReportsSize = TRUE;
3124c2c66affSColin Finck                         }
3125c2c66affSColin Finck                     }
3126c2c66affSColin Finck                 }
3127c2c66affSColin Finck                 /* Clear further characters */
3128c2c66affSColin Finck                 while ((c = KdbpTryGetCharSerial(5000)) != -1);
3129c2c66affSColin Finck             }
3130c2c66affSColin Finck         }
3131c2c66affSColin Finck 
3132c2c66affSColin Finck         if (KdbNumberOfRowsTerminal <= 0)
3133c2c66affSColin Finck         {
3134c2c66affSColin Finck             /* Set number of rows to the default. */
3135c2c66affSColin Finck             KdbNumberOfRowsTerminal = 24;
3136c2c66affSColin Finck         }
3137c2c66affSColin Finck         else if (KdbNumberOfColsTerminal <= 0)
3138c2c66affSColin Finck         {
3139c2c66affSColin Finck             /* Set number of cols to the default. */
3140c2c66affSColin Finck             KdbNumberOfColsTerminal = 80;
3141c2c66affSColin Finck         }
3142c2c66affSColin Finck     }
3143c2c66affSColin Finck 
3144c2c66affSColin Finck     /* Get the string */
3145c2c66affSColin Finck     p = Buffer;
3146c2c66affSColin Finck 
3147c2c66affSColin Finck     while (p[0] != '\0')
3148c2c66affSColin Finck     {
3149c2c66affSColin Finck         if ( p > Buffer+BufLength)
3150c2c66affSColin Finck         {
3151c2c66affSColin Finck           DbgPrint("Dmesg: error, p > Buffer+BufLength,d=%d", p - (Buffer+BufLength));
3152c2c66affSColin Finck           return;
3153c2c66affSColin Finck         }
3154c2c66affSColin Finck         i = strcspn(p, "\n");
3155c2c66affSColin Finck 
3156c2c66affSColin Finck         // Are we out of buffer?
3157c2c66affSColin Finck         if (p + i > Buffer + BufLength)
3158c2c66affSColin Finck           // Leaving pager function:
3159c2c66affSColin Finck           break;
3160c2c66affSColin Finck 
3161c2c66affSColin Finck         /* Calculate the number of lines which will be printed in the terminal
3162f0d59e74SHermès Bélusca-Maïto          * when outputting the current line.
3163c2c66affSColin Finck          */
3164c2c66affSColin Finck         if (i > 0)
3165c2c66affSColin Finck             RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / KdbNumberOfColsTerminal;
3166c2c66affSColin Finck         else
3167c2c66affSColin Finck             RowsPrintedByTerminal = 0;
3168c2c66affSColin Finck 
3169c2c66affSColin Finck         if (p[i] == '\n')
3170c2c66affSColin Finck             RowsPrintedByTerminal++;
3171c2c66affSColin Finck 
3172c2c66affSColin Finck         /*DbgPrint("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);*/
3173c2c66affSColin Finck 
3174c2c66affSColin Finck         /* Display a prompt if we printed one screen full of text */
3175c2c66affSColin Finck         if (KdbNumberOfRowsTerminal > 0 &&
3176c2c66affSColin Finck             (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= KdbNumberOfRowsTerminal)
3177c2c66affSColin Finck         {
3178c2c66affSColin Finck             KdbRepeatLastCommand = FALSE;
3179c2c66affSColin Finck 
3180c2c66affSColin Finck             if (KdbNumberOfColsPrinted > 0)
3181c2c66affSColin Finck                 DbgPrint("\n");
3182c2c66affSColin Finck 
3183c2c66affSColin Finck             DbgPrint("--- Press q to abort, e/End,h/Home,u/PgUp, other key/PgDn ---");
3184c2c66affSColin Finck             RowsPrintedByTerminal++;
3185c2c66affSColin Finck 
3186c2c66affSColin Finck             if (KdbDebugState & KD_DEBUG_KDSERIAL)
3187c2c66affSColin Finck                 c = KdbpGetCharSerial();
3188c2c66affSColin Finck             else
3189c2c66affSColin Finck                 c = KdbpGetCharKeyboard(&ScanCode);
3190c2c66affSColin Finck 
3191c2c66affSColin Finck             if (c == '\r')
3192c2c66affSColin Finck             {
3193c2c66affSColin Finck                 /* Try to read '\n' which might follow '\r' - if \n is not received here
3194c2c66affSColin Finck                  * it will be interpreted as "return" when the next command should be read.
3195c2c66affSColin Finck                  */
3196c2c66affSColin Finck                 if (KdbDebugState & KD_DEBUG_KDSERIAL)
3197c2c66affSColin Finck                     c = KdbpTryGetCharSerial(5);
3198c2c66affSColin Finck                 else
3199c2c66affSColin Finck                     c = KdbpTryGetCharKeyboard(&ScanCode, 5);
3200c2c66affSColin Finck             }
3201c2c66affSColin Finck 
3202c2c66affSColin Finck             //DbgPrint("\n"); //Consize version: don't show pressed key
3203c2c66affSColin Finck             DbgPrint(" '%c'/scan=%04x\n", c, ScanCode); // Shows pressed key
3204c2c66affSColin Finck 
3205c2c66affSColin Finck             if (c == 'q')
3206c2c66affSColin Finck             {
3207c2c66affSColin Finck                 KdbOutputAborted = TRUE;
3208c2c66affSColin Finck                 return;
3209c2c66affSColin Finck             }
3210c2c66affSColin Finck             if (     ScanCode == KEYSC_END || c=='e')
3211c2c66affSColin Finck             {
3212c2c66affSColin Finck               PCHAR pBufEnd = Buffer + BufLength;
3213c2c66affSColin Finck               p = CountOnePageUp(Buffer, BufLength, pBufEnd);
3214c2c66affSColin Finck               i = strcspn(p, "\n");
3215c2c66affSColin Finck             }
3216c2c66affSColin Finck             else if (ScanCode == KEYSC_PAGEUP  || c=='u')
3217c2c66affSColin Finck             {
3218c2c66affSColin Finck               p = CountOnePageUp(Buffer, BufLength, p);
3219c2c66affSColin Finck               i = strcspn(p, "\n");
3220c2c66affSColin Finck             }
3221c2c66affSColin Finck             else if (ScanCode == KEYSC_HOME || c=='h')
3222c2c66affSColin Finck             {
3223c2c66affSColin Finck               p = Buffer;
3224c2c66affSColin Finck               i = strcspn(p, "\n");
3225c2c66affSColin Finck             }
3226c2c66affSColin Finck             else if (ScanCode == KEYSC_ARROWUP)
3227c2c66affSColin Finck             {
3228c2c66affSColin Finck               p = CountOnePageUp(Buffer, BufLength, p);
3229c2c66affSColin Finck               i = strcspn(p, "\n");
3230c2c66affSColin Finck             }
3231c2c66affSColin Finck 
3232c2c66affSColin Finck             KdbNumberOfRowsPrinted = 0;
3233c2c66affSColin Finck             KdbNumberOfColsPrinted = 0;
3234c2c66affSColin Finck         }
3235c2c66affSColin Finck 
3236c2c66affSColin Finck         /* Insert a NUL after the line and print only the current line. */
3237c2c66affSColin Finck         if (p[i] == '\n' && p[i + 1] != '\0')
3238c2c66affSColin Finck         {
3239c2c66affSColin Finck             c = p[i + 1];
3240c2c66affSColin Finck             p[i + 1] = '\0';
3241c2c66affSColin Finck         }
3242c2c66affSColin Finck         else
3243c2c66affSColin Finck         {
3244c2c66affSColin Finck             c = '\0';
3245c2c66affSColin Finck         }
3246c2c66affSColin Finck 
3247c2c66affSColin Finck         /* Remove escape sequences from the line if there's no terminal connected */
3248c2c66affSColin Finck         if (!TerminalConnected)
3249c2c66affSColin Finck         {
3250c2c66affSColin Finck             while ((p2 = strrchr(p, '\x1b'))) /* Look for escape character */
3251c2c66affSColin Finck             {
32523af7cb82STimo Kreuzer                 size_t len = strlen(p2);
3253c2c66affSColin Finck                 if (p2[1] == '[')
3254c2c66affSColin Finck                 {
3255c2c66affSColin Finck                     j = 2;
3256c2c66affSColin Finck                     while (!isalpha(p2[j++]));
32573af7cb82STimo Kreuzer                     memmove(p2, p2 + j, len + 1 - j);
3258c2c66affSColin Finck                 }
3259c2c66affSColin Finck                 else
3260c2c66affSColin Finck                 {
32613af7cb82STimo Kreuzer                     memmove(p2, p2 + 1, len);
3262c2c66affSColin Finck                 }
3263c2c66affSColin Finck             }
3264c2c66affSColin Finck         }
3265c2c66affSColin Finck 
3266c2c66affSColin Finck         // The main printing of the current line:
3267c2c66affSColin Finck         DbgPrint(p);
3268c2c66affSColin Finck 
3269c2c66affSColin Finck         // restore not null char with saved:
3270c2c66affSColin Finck         if (c != '\0')
3271c2c66affSColin Finck             p[i + 1] = c;
3272c2c66affSColin Finck 
3273c2c66affSColin Finck         /* Set p to the start of the next line and
3274c2c66affSColin Finck          * remember the number of rows/cols printed
3275c2c66affSColin Finck          */
3276c2c66affSColin Finck         p += i;
3277c2c66affSColin Finck         if (p[0] == '\n')
3278c2c66affSColin Finck         {
3279c2c66affSColin Finck             p++;
3280c2c66affSColin Finck             KdbNumberOfColsPrinted = 0;
3281c2c66affSColin Finck         }
3282c2c66affSColin Finck         else
3283c2c66affSColin Finck         {
3284c2c66affSColin Finck             ASSERT(p[0] == '\0');
3285c2c66affSColin Finck             KdbNumberOfColsPrinted += i;
3286c2c66affSColin Finck         }
3287c2c66affSColin Finck 
3288c2c66affSColin Finck         KdbNumberOfRowsPrinted += RowsPrintedByTerminal;
3289c2c66affSColin Finck     }
3290c2c66affSColin Finck }
3291c2c66affSColin Finck 
3292c2c66affSColin Finck /*!\brief Appends a command to the command history
3293c2c66affSColin Finck  *
3294c2c66affSColin Finck  * \param Command  Pointer to the command to append to the history.
3295c2c66affSColin Finck  */
3296c2c66affSColin Finck static VOID
3297c2c66affSColin Finck KdbpCommandHistoryAppend(
3298c2c66affSColin Finck     IN PCHAR Command)
3299c2c66affSColin Finck {
3300c2c66affSColin Finck     ULONG Length1 = strlen(Command) + 1;
3301c2c66affSColin Finck     ULONG Length2 = 0;
3302c2c66affSColin Finck     INT i;
3303c2c66affSColin Finck     PCHAR Buffer;
3304c2c66affSColin Finck 
3305c2c66affSColin Finck     ASSERT(Length1 <= RTL_NUMBER_OF(KdbCommandHistoryBuffer));
3306c2c66affSColin Finck 
3307c2c66affSColin Finck     if (Length1 <= 1 ||
3308c2c66affSColin Finck         (KdbCommandHistory[KdbCommandHistoryIndex] &&
3309c2c66affSColin Finck          strcmp(KdbCommandHistory[KdbCommandHistoryIndex], Command) == 0))
3310c2c66affSColin Finck     {
3311c2c66affSColin Finck         return;
3312c2c66affSColin Finck     }
3313c2c66affSColin Finck 
3314c2c66affSColin Finck     /* Calculate Length1 and Length2 */
3315c2c66affSColin Finck     Buffer = KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex;
3316c2c66affSColin Finck     KdbCommandHistoryBufferIndex += Length1;
3317c2c66affSColin Finck     if (KdbCommandHistoryBufferIndex >= (LONG)RTL_NUMBER_OF(KdbCommandHistoryBuffer))
3318c2c66affSColin Finck     {
3319c2c66affSColin Finck         KdbCommandHistoryBufferIndex -= RTL_NUMBER_OF(KdbCommandHistoryBuffer);
3320c2c66affSColin Finck         Length2 = KdbCommandHistoryBufferIndex;
3321c2c66affSColin Finck         Length1 -= Length2;
3322c2c66affSColin Finck     }
3323c2c66affSColin Finck 
3324c2c66affSColin Finck     /* Remove previous commands until there is enough space to append the new command */
3325c2c66affSColin Finck     for (i = KdbCommandHistoryIndex; KdbCommandHistory[i];)
3326c2c66affSColin Finck     {
3327c2c66affSColin Finck         if ((Length2 > 0 &&
3328c2c66affSColin Finck             (KdbCommandHistory[i] >= Buffer ||
3329c2c66affSColin Finck              KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))) ||
3330c2c66affSColin Finck             (Length2 <= 0 &&
3331c2c66affSColin Finck              (KdbCommandHistory[i] >= Buffer &&
3332c2c66affSColin Finck               KdbCommandHistory[i] < (KdbCommandHistoryBuffer + KdbCommandHistoryBufferIndex))))
3333c2c66affSColin Finck         {
3334c2c66affSColin Finck             KdbCommandHistory[i] = NULL;
3335c2c66affSColin Finck         }
3336c2c66affSColin Finck 
3337c2c66affSColin Finck         i--;
3338c2c66affSColin Finck         if (i < 0)
3339c2c66affSColin Finck             i = RTL_NUMBER_OF(KdbCommandHistory) - 1;
3340c2c66affSColin Finck 
3341c2c66affSColin Finck         if (i == KdbCommandHistoryIndex)
3342c2c66affSColin Finck             break;
3343c2c66affSColin Finck     }
3344c2c66affSColin Finck 
3345c2c66affSColin Finck     /* Make sure the new command history entry is free */
3346c2c66affSColin Finck     KdbCommandHistoryIndex++;
3347c2c66affSColin Finck     KdbCommandHistoryIndex %= RTL_NUMBER_OF(KdbCommandHistory);
3348c2c66affSColin Finck     if (KdbCommandHistory[KdbCommandHistoryIndex])
3349c2c66affSColin Finck     {
3350c2c66affSColin Finck         KdbCommandHistory[KdbCommandHistoryIndex] = NULL;
3351c2c66affSColin Finck     }
3352c2c66affSColin Finck 
3353c2c66affSColin Finck     /* Append command */
3354c2c66affSColin Finck     KdbCommandHistory[KdbCommandHistoryIndex] = Buffer;
3355c2c66affSColin Finck     ASSERT((KdbCommandHistory[KdbCommandHistoryIndex] + Length1) <= KdbCommandHistoryBuffer + RTL_NUMBER_OF(KdbCommandHistoryBuffer));
3356c2c66affSColin Finck     memcpy(KdbCommandHistory[KdbCommandHistoryIndex], Command, Length1);
3357c2c66affSColin Finck     if (Length2 > 0)
3358c2c66affSColin Finck     {
3359c2c66affSColin Finck         memcpy(KdbCommandHistoryBuffer, Command + Length1, Length2);
3360c2c66affSColin Finck     }
3361c2c66affSColin Finck }
3362c2c66affSColin Finck 
3363c2c66affSColin Finck /*!\brief Reads a line of user-input.
3364c2c66affSColin Finck  *
3365c2c66affSColin Finck  * \param Buffer  Buffer to store the input into. Trailing newlines are removed.
3366c2c66affSColin Finck  * \param Size    Size of \a Buffer.
3367c2c66affSColin Finck  *
3368c2c66affSColin Finck  * \note Accepts only \n newlines, \r is ignored.
3369c2c66affSColin Finck  */
3370c2c66affSColin Finck static VOID
3371c2c66affSColin Finck KdbpReadCommand(
3372c2c66affSColin Finck     OUT PCHAR Buffer,
3373c2c66affSColin Finck     IN  ULONG Size)
3374c2c66affSColin Finck {
3375c2c66affSColin Finck     CHAR Key;
3376c2c66affSColin Finck     PCHAR Orig = Buffer;
3377c2c66affSColin Finck     ULONG ScanCode = 0;
3378c2c66affSColin Finck     BOOLEAN EchoOn;
3379c2c66affSColin Finck     static CHAR LastCommand[1024];
3380c2c66affSColin Finck     static CHAR NextKey = '\0';
3381c2c66affSColin Finck     INT CmdHistIndex = -1;
3382c2c66affSColin Finck     INT i;
3383c2c66affSColin Finck 
3384c2c66affSColin Finck     EchoOn = !((KdbDebugState & KD_DEBUG_KDNOECHO) != 0);
3385c2c66affSColin Finck 
3386c2c66affSColin Finck     for (;;)
3387c2c66affSColin Finck     {
3388c2c66affSColin Finck         if (KdbDebugState & KD_DEBUG_KDSERIAL)
3389c2c66affSColin Finck         {
3390c2c66affSColin Finck             Key = (NextKey == '\0') ? KdbpGetCharSerial() : NextKey;
3391c2c66affSColin Finck             NextKey = '\0';
3392c2c66affSColin Finck             ScanCode = 0;
3393c2c66affSColin Finck             if (Key == KEY_ESC) /* ESC */
3394c2c66affSColin Finck             {
3395c2c66affSColin Finck                 Key = KdbpGetCharSerial();
3396c2c66affSColin Finck                 if (Key == '[')
3397c2c66affSColin Finck                 {
3398c2c66affSColin Finck                     Key = KdbpGetCharSerial();
3399c2c66affSColin Finck 
3400c2c66affSColin Finck                     switch (Key)
3401c2c66affSColin Finck                     {
3402c2c66affSColin Finck                         case 'A':
3403c2c66affSColin Finck                             ScanCode = KEY_SCAN_UP;
3404c2c66affSColin Finck                             break;
3405c2c66affSColin Finck                         case 'B':
3406c2c66affSColin Finck                             ScanCode = KEY_SCAN_DOWN;
3407c2c66affSColin Finck                             break;
3408c2c66affSColin Finck                         case 'C':
3409c2c66affSColin Finck                             break;
3410c2c66affSColin Finck                         case 'D':
3411c2c66affSColin Finck                             break;
3412c2c66affSColin Finck                     }
3413c2c66affSColin Finck                 }
3414c2c66affSColin Finck             }
3415c2c66affSColin Finck         }
3416c2c66affSColin Finck         else
3417c2c66affSColin Finck         {
3418c2c66affSColin Finck             ScanCode = 0;
3419c2c66affSColin Finck             Key = (NextKey == '\0') ? KdbpGetCharKeyboard(&ScanCode) : NextKey;
3420c2c66affSColin Finck             NextKey = '\0';
3421c2c66affSColin Finck         }
3422c2c66affSColin Finck 
3423c2c66affSColin Finck         if ((ULONG)(Buffer - Orig) >= (Size - 1))
3424c2c66affSColin Finck         {
3425c2c66affSColin Finck             /* Buffer is full, accept only newlines */
3426c2c66affSColin Finck             if (Key != '\n')
3427c2c66affSColin Finck                 continue;
3428c2c66affSColin Finck         }
3429c2c66affSColin Finck 
3430c2c66affSColin Finck         if (Key == '\r')
3431c2c66affSColin Finck         {
3432c2c66affSColin Finck             /* Read the next char - this is to throw away a \n which most clients should
3433c2c66affSColin Finck              * send after \r.
3434c2c66affSColin Finck              */
3435c2c66affSColin Finck             KeStallExecutionProcessor(100000);
3436c2c66affSColin Finck 
3437c2c66affSColin Finck             if (KdbDebugState & KD_DEBUG_KDSERIAL)
3438c2c66affSColin Finck                 NextKey = KdbpTryGetCharSerial(5);
3439c2c66affSColin Finck             else
3440c2c66affSColin Finck                 NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5);
3441c2c66affSColin Finck 
3442c2c66affSColin Finck             if (NextKey == '\n' || NextKey == -1) /* \n or no response at all */
3443c2c66affSColin Finck                 NextKey = '\0';
3444c2c66affSColin Finck 
3445c2c66affSColin Finck             KdbpPrint("\n");
3446c2c66affSColin Finck 
3447c2c66affSColin Finck             /*
3448c2c66affSColin Finck              * Repeat the last command if the user presses enter. Reduces the
3449c2c66affSColin Finck              * risk of RSI when single-stepping.
3450c2c66affSColin Finck              */
3451c2c66affSColin Finck             if (Buffer != Orig)
3452c2c66affSColin Finck             {
3453c2c66affSColin Finck                 KdbRepeatLastCommand = TRUE;
3454c2c66affSColin Finck                 *Buffer = '\0';
3455c2c66affSColin Finck                 RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Orig);
3456c2c66affSColin Finck             }
3457c2c66affSColin Finck             else if (KdbRepeatLastCommand)
3458c2c66affSColin Finck                 RtlStringCbCopyA(Buffer, Size, LastCommand);
3459c2c66affSColin Finck             else
3460c2c66affSColin Finck                 *Buffer = '\0';
3461c2c66affSColin Finck 
3462c2c66affSColin Finck             return;
3463c2c66affSColin Finck         }
3464c2c66affSColin Finck         else if (Key == KEY_BS || Key == KEY_DEL)
3465c2c66affSColin Finck         {
3466c2c66affSColin Finck             if (Buffer > Orig)
3467c2c66affSColin Finck             {
3468c2c66affSColin Finck                 Buffer--;
3469c2c66affSColin Finck                 *Buffer = 0;
3470c2c66affSColin Finck 
3471c2c66affSColin Finck                 if (EchoOn)
3472c2c66affSColin Finck                     KdbpPrint("%c %c", KEY_BS, KEY_BS);
3473c2c66affSColin Finck                 else
3474c2c66affSColin Finck                     KdbpPrint(" %c", KEY_BS);
3475c2c66affSColin Finck             }
3476c2c66affSColin Finck         }
3477c2c66affSColin Finck         else if (ScanCode == KEY_SCAN_UP)
3478c2c66affSColin Finck         {
3479c2c66affSColin Finck             BOOLEAN Print = TRUE;
3480c2c66affSColin Finck 
3481c2c66affSColin Finck             if (CmdHistIndex < 0)
3482c2c66affSColin Finck             {
3483c2c66affSColin Finck                 CmdHistIndex = KdbCommandHistoryIndex;
3484c2c66affSColin Finck             }
3485c2c66affSColin Finck             else
3486c2c66affSColin Finck             {
3487c2c66affSColin Finck                 i = CmdHistIndex - 1;
3488c2c66affSColin Finck 
3489c2c66affSColin Finck                 if (i < 0)
3490c2c66affSColin Finck                     CmdHistIndex = RTL_NUMBER_OF(KdbCommandHistory) - 1;
3491c2c66affSColin Finck 
3492c2c66affSColin Finck                 if (KdbCommandHistory[i] && i != KdbCommandHistoryIndex)
3493c2c66affSColin Finck                     CmdHistIndex = i;
3494c2c66affSColin Finck                 else
3495c2c66affSColin Finck                     Print = FALSE;
3496c2c66affSColin Finck             }
3497c2c66affSColin Finck 
3498c2c66affSColin Finck             if (Print && KdbCommandHistory[CmdHistIndex])
3499c2c66affSColin Finck             {
3500c2c66affSColin Finck                 while (Buffer > Orig)
3501c2c66affSColin Finck                 {
3502c2c66affSColin Finck                     Buffer--;
3503c2c66affSColin Finck                     *Buffer = 0;
3504c2c66affSColin Finck 
3505c2c66affSColin Finck                     if (EchoOn)
3506c2c66affSColin Finck                         KdbpPrint("%c %c", KEY_BS, KEY_BS);
3507c2c66affSColin Finck                     else
3508c2c66affSColin Finck                         KdbpPrint(" %c", KEY_BS);
3509c2c66affSColin Finck                 }
3510c2c66affSColin Finck 
3511c2c66affSColin Finck                 i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);
3512c2c66affSColin Finck                 memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);
3513c2c66affSColin Finck                 Orig[i] = '\0';
3514c2c66affSColin Finck                 Buffer = Orig + i;
3515c2c66affSColin Finck                 KdbpPrint("%s", Orig);
3516c2c66affSColin Finck             }
3517c2c66affSColin Finck         }
3518c2c66affSColin Finck         else if (ScanCode == KEY_SCAN_DOWN)
3519c2c66affSColin Finck         {
3520c2c66affSColin Finck             if (CmdHistIndex > 0 && CmdHistIndex != KdbCommandHistoryIndex)
3521c2c66affSColin Finck             {
3522c2c66affSColin Finck                 i = CmdHistIndex + 1;
3523c2c66affSColin Finck                 if (i >= (INT)RTL_NUMBER_OF(KdbCommandHistory))
3524c2c66affSColin Finck                     i = 0;
3525c2c66affSColin Finck 
3526c2c66affSColin Finck                 if (KdbCommandHistory[i])
3527c2c66affSColin Finck                 {
3528c2c66affSColin Finck                     CmdHistIndex = i;
3529c2c66affSColin Finck                     while (Buffer > Orig)
3530c2c66affSColin Finck                     {
3531c2c66affSColin Finck                         Buffer--;
3532c2c66affSColin Finck                         *Buffer = 0;
3533c2c66affSColin Finck 
3534c2c66affSColin Finck                         if (EchoOn)
3535c2c66affSColin Finck                             KdbpPrint("%c %c", KEY_BS, KEY_BS);
3536c2c66affSColin Finck                         else
3537c2c66affSColin Finck                             KdbpPrint(" %c", KEY_BS);
3538c2c66affSColin Finck                     }
3539c2c66affSColin Finck 
3540c2c66affSColin Finck                     i = min(strlen(KdbCommandHistory[CmdHistIndex]), Size - 1);
3541c2c66affSColin Finck                     memcpy(Orig, KdbCommandHistory[CmdHistIndex], i);
3542c2c66affSColin Finck                     Orig[i] = '\0';
3543c2c66affSColin Finck                     Buffer = Orig + i;
3544c2c66affSColin Finck                     KdbpPrint("%s", Orig);
3545c2c66affSColin Finck                 }
3546c2c66affSColin Finck             }
3547c2c66affSColin Finck         }
3548c2c66affSColin Finck         else
3549c2c66affSColin Finck         {
3550c2c66affSColin Finck             if (EchoOn)
3551c2c66affSColin Finck                 KdbpPrint("%c", Key);
3552c2c66affSColin Finck 
3553c2c66affSColin Finck             *Buffer = Key;
3554c2c66affSColin Finck             Buffer++;
3555c2c66affSColin Finck         }
3556c2c66affSColin Finck     }
3557c2c66affSColin Finck }
3558c2c66affSColin Finck 
3559c2c66affSColin Finck 
3560c2c66affSColin Finck BOOLEAN
3561c2c66affSColin Finck NTAPI
3562c2c66affSColin Finck KdbRegisterCliCallback(
3563c2c66affSColin Finck     PVOID Callback,
3564c2c66affSColin Finck     BOOLEAN Deregister)
3565c2c66affSColin Finck {
3566c2c66affSColin Finck     ULONG i;
3567c2c66affSColin Finck 
3568c2c66affSColin Finck     /* Loop all entries */
3569c2c66affSColin Finck     for (i = 0; i < _countof(KdbCliCallbacks); i++)
3570c2c66affSColin Finck     {
3571c2c66affSColin Finck         /* Check if deregistering was requested */
3572c2c66affSColin Finck         if (Deregister)
3573c2c66affSColin Finck         {
3574c2c66affSColin Finck             /* Check if this entry is the one that was registered */
3575c2c66affSColin Finck             if (KdbCliCallbacks[i] == Callback)
3576c2c66affSColin Finck             {
3577c2c66affSColin Finck                 /* Delete it and report success */
3578c2c66affSColin Finck                 KdbCliCallbacks[i] = NULL;
3579c2c66affSColin Finck                 return TRUE;
3580c2c66affSColin Finck             }
3581c2c66affSColin Finck         }
3582c2c66affSColin Finck         else
3583c2c66affSColin Finck         {
3584c2c66affSColin Finck             /* Check if this entry is free */
3585c2c66affSColin Finck             if (KdbCliCallbacks[i] == NULL)
3586c2c66affSColin Finck             {
3587c2c66affSColin Finck                 /* Set it and and report success */
3588c2c66affSColin Finck                 KdbCliCallbacks[i] = Callback;
3589c2c66affSColin Finck                 return TRUE;
3590c2c66affSColin Finck             }
3591c2c66affSColin Finck         }
3592c2c66affSColin Finck     }
3593c2c66affSColin Finck 
3594c2c66affSColin Finck     /* Unsuccessful */
3595c2c66affSColin Finck     return FALSE;
3596c2c66affSColin Finck }
3597c2c66affSColin Finck 
3598c2c66affSColin Finck /*! \brief Invokes registered CLI callbacks until one of them handled the
3599c2c66affSColin Finck  *         Command.
3600c2c66affSColin Finck  *
3601c2c66affSColin Finck  * \param Command - Command line to parse and execute if possible.
3602c2c66affSColin Finck  * \param Argc - Number of arguments in Argv
3603c2c66affSColin Finck  * \param Argv - Array of strings, each of them containing one argument.
3604c2c66affSColin Finck  *
3605c2c66affSColin Finck  * \return TRUE, if the command was handled, FALSE if it was not handled.
3606c2c66affSColin Finck  */
3607c2c66affSColin Finck static
3608c2c66affSColin Finck BOOLEAN
3609c2c66affSColin Finck KdbpInvokeCliCallbacks(
3610c2c66affSColin Finck     IN PCHAR Command,
3611c2c66affSColin Finck     IN ULONG Argc,
361240c57de7SHermès Bélusca-Maïto     IN PCHAR Argv[])
3613c2c66affSColin Finck {
3614c2c66affSColin Finck     ULONG i;
3615c2c66affSColin Finck 
3616c2c66affSColin Finck     /* Loop all entries */
3617c2c66affSColin Finck     for (i = 0; i < _countof(KdbCliCallbacks); i++)
3618c2c66affSColin Finck     {
3619c2c66affSColin Finck         /* Check if this entry is registered */
3620c2c66affSColin Finck         if (KdbCliCallbacks[i])
3621c2c66affSColin Finck         {
3622c2c66affSColin Finck             /* Invoke the callback and check if it handled the command */
3623c2c66affSColin Finck             if (KdbCliCallbacks[i](Command, Argc, Argv))
3624c2c66affSColin Finck             {
3625c2c66affSColin Finck                 return TRUE;
3626c2c66affSColin Finck             }
3627c2c66affSColin Finck         }
3628c2c66affSColin Finck     }
3629c2c66affSColin Finck 
3630c2c66affSColin Finck     /* None of the callbacks handled the command */
3631c2c66affSColin Finck     return FALSE;
3632c2c66affSColin Finck }
3633c2c66affSColin Finck 
3634c2c66affSColin Finck 
3635c2c66affSColin Finck /*!\brief Parses command line and executes command if found
3636c2c66affSColin Finck  *
3637c2c66affSColin Finck  * \param Command    Command line to parse and execute if possible.
3638c2c66affSColin Finck  *
3639c2c66affSColin Finck  * \retval TRUE   Don't continue execution.
3640c2c66affSColin Finck  * \retval FALSE  Continue execution (leave KDB)
3641c2c66affSColin Finck  */
3642c2c66affSColin Finck static BOOLEAN
3643c2c66affSColin Finck KdbpDoCommand(
3644c2c66affSColin Finck     IN PCHAR Command)
3645c2c66affSColin Finck {
3646c2c66affSColin Finck     ULONG i;
3647c2c66affSColin Finck     PCHAR p;
3648c2c66affSColin Finck     ULONG Argc;
3649c2c66affSColin Finck     // FIXME: for what do we need a 1024 characters command line and 256 tokens?
365040c57de7SHermès Bélusca-Maïto     static PCHAR Argv[256];
3651c2c66affSColin Finck     static CHAR OrigCommand[1024];
3652c2c66affSColin Finck 
3653c2c66affSColin Finck     RtlStringCbCopyA(OrigCommand, sizeof(OrigCommand), Command);
3654c2c66affSColin Finck 
3655c2c66affSColin Finck     Argc = 0;
3656c2c66affSColin Finck     p = Command;
3657c2c66affSColin Finck 
3658c2c66affSColin Finck     for (;;)
3659c2c66affSColin Finck     {
3660c2c66affSColin Finck         while (*p == '\t' || *p == ' ')
3661c2c66affSColin Finck             p++;
3662c2c66affSColin Finck 
3663c2c66affSColin Finck         if (*p == '\0')
3664c2c66affSColin Finck             break;
3665c2c66affSColin Finck 
3666c2c66affSColin Finck         i = strcspn(p, "\t ");
3667c2c66affSColin Finck         Argv[Argc++] = p;
3668c2c66affSColin Finck         p += i;
3669c2c66affSColin Finck         if (*p == '\0')
3670c2c66affSColin Finck             break;
3671c2c66affSColin Finck 
3672c2c66affSColin Finck         *p = '\0';
3673c2c66affSColin Finck         p++;
3674c2c66affSColin Finck     }
3675c2c66affSColin Finck 
3676c2c66affSColin Finck     if (Argc < 1)
3677c2c66affSColin Finck         return TRUE;
3678c2c66affSColin Finck 
3679c2c66affSColin Finck     for (i = 0; i < RTL_NUMBER_OF(KdbDebuggerCommands); i++)
3680c2c66affSColin Finck     {
3681c2c66affSColin Finck         if (!KdbDebuggerCommands[i].Name)
3682c2c66affSColin Finck             continue;
3683c2c66affSColin Finck 
3684c2c66affSColin Finck         if (strcmp(KdbDebuggerCommands[i].Name, Argv[0]) == 0)
3685c2c66affSColin Finck         {
3686c2c66affSColin Finck             return KdbDebuggerCommands[i].Fn(Argc, Argv);
3687c2c66affSColin Finck         }
3688c2c66affSColin Finck     }
3689c2c66affSColin Finck 
3690c2c66affSColin Finck     /* Now invoke the registered callbacks */
3691c2c66affSColin Finck     if (KdbpInvokeCliCallbacks(Command, Argc, Argv))
3692c2c66affSColin Finck     {
3693c2c66affSColin Finck         return TRUE;
3694c2c66affSColin Finck     }
3695c2c66affSColin Finck 
3696c2c66affSColin Finck     KdbpPrint("Command '%s' is unknown.\n", OrigCommand);
3697c2c66affSColin Finck     return TRUE;
3698c2c66affSColin Finck }
3699c2c66affSColin Finck 
3700c2c66affSColin Finck /*!\brief KDB Main Loop.
3701c2c66affSColin Finck  *
3702c2c66affSColin Finck  * \param EnteredOnSingleStep  TRUE if KDB was entered on single step.
3703c2c66affSColin Finck  */
3704c2c66affSColin Finck VOID
3705c2c66affSColin Finck KdbpCliMainLoop(
3706c2c66affSColin Finck     IN BOOLEAN EnteredOnSingleStep)
3707c2c66affSColin Finck {
3708c2c66affSColin Finck     static CHAR Command[1024];
3709c2c66affSColin Finck     BOOLEAN Continue;
3710c2c66affSColin Finck 
3711c2c66affSColin Finck     if (EnteredOnSingleStep)
3712c2c66affSColin Finck     {
37133726b992SJérôme Gardou         if (!KdbSymPrintAddress((PVOID)KeGetContextPc(KdbCurrentTrapFrame), KdbCurrentTrapFrame))
3714c2c66affSColin Finck         {
37153726b992SJérôme Gardou             KdbpPrint("<%p>", KeGetContextPc(KdbCurrentTrapFrame));
3716c2c66affSColin Finck         }
3717c2c66affSColin Finck 
3718c2c66affSColin Finck         KdbpPrint(": ");
37193726b992SJérôme Gardou         if (KdbpDisassemble(KeGetContextPc(KdbCurrentTrapFrame), KdbUseIntelSyntax) < 0)
3720c2c66affSColin Finck         {
3721c2c66affSColin Finck             KdbpPrint("<INVALID>");
3722c2c66affSColin Finck         }
3723c2c66affSColin Finck         KdbpPrint("\n");
3724c2c66affSColin Finck     }
3725c2c66affSColin Finck 
3726c2c66affSColin Finck     /* Flush the input buffer */
3727c2c66affSColin Finck     if (KdbDebugState & KD_DEBUG_KDSERIAL)
3728c2c66affSColin Finck     {
3729c2c66affSColin Finck         while (KdbpTryGetCharSerial(1) != -1);
3730c2c66affSColin Finck     }
3731c2c66affSColin Finck     else
3732c2c66affSColin Finck     {
3733c2c66affSColin Finck         ULONG ScanCode;
3734c2c66affSColin Finck         while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
3735c2c66affSColin Finck     }
3736c2c66affSColin Finck 
3737c2c66affSColin Finck     /* Main loop */
3738c2c66affSColin Finck     do
3739c2c66affSColin Finck     {
3740c2c66affSColin Finck         /* Reset the number of rows/cols printed */
3741c2c66affSColin Finck         KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;
3742c2c66affSColin Finck 
3743c2c66affSColin Finck         /* Print the prompt */
3744a890fc64SHermès Bélusca-Maïto         KdbpPrint(KdbPromptString.Buffer);
3745c2c66affSColin Finck 
3746c2c66affSColin Finck         /* Read a command and remember it */
3747c2c66affSColin Finck         KdbpReadCommand(Command, sizeof(Command));
3748c2c66affSColin Finck         KdbpCommandHistoryAppend(Command);
3749c2c66affSColin Finck 
3750c2c66affSColin Finck         /* Reset the number of rows/cols printed and output aborted state */
3751c2c66affSColin Finck         KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;
3752c2c66affSColin Finck         KdbOutputAborted = FALSE;
3753c2c66affSColin Finck 
3754c2c66affSColin Finck         /* Call the command */
3755c2c66affSColin Finck         Continue = KdbpDoCommand(Command);
3756c2c66affSColin Finck         KdbOutputAborted = FALSE;
3757c2c66affSColin Finck     }
3758c2c66affSColin Finck     while (Continue);
3759c2c66affSColin Finck }
3760c2c66affSColin Finck 
3761c2c66affSColin Finck /*!\brief Called when a module is loaded.
3762c2c66affSColin Finck  *
3763c2c66affSColin Finck  * \param Name  Filename of the module which was loaded.
3764c2c66affSColin Finck  */
3765c2c66affSColin Finck VOID
3766c2c66affSColin Finck KdbpCliModuleLoaded(
3767c2c66affSColin Finck     IN PUNICODE_STRING Name)
3768c2c66affSColin Finck {
3769c2c66affSColin Finck     if (!KdbBreakOnModuleLoad)
3770c2c66affSColin Finck         return;
3771c2c66affSColin Finck 
3772c2c66affSColin Finck     KdbpPrint("Module %wZ loaded.\n", Name);
3773c2c66affSColin Finck     DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
3774c2c66affSColin Finck }
3775c2c66affSColin Finck 
3776c2c66affSColin Finck /*!\brief This function is called by KdbEnterDebuggerException...
3777c2c66affSColin Finck  *
3778c2c66affSColin Finck  * Used to interpret the init file in a context with a trapframe setup
3779c2c66affSColin Finck  * (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will
3780c2c66affSColin Finck  * call this function if KdbInitFileBuffer is not NULL.
3781c2c66affSColin Finck  */
3782c2c66affSColin Finck VOID
3783c2c66affSColin Finck KdbpCliInterpretInitFile(VOID)
3784c2c66affSColin Finck {
3785c2c66affSColin Finck     PCHAR p1, p2;
3786c2c66affSColin Finck     INT i;
3787c2c66affSColin Finck     CHAR c;
3788c2c66affSColin Finck 
3789c2c66affSColin Finck     /* Execute the commands in the init file */
3790c2c66affSColin Finck     DPRINT("KDB: Executing KDBinit file...\n");
3791c2c66affSColin Finck     p1 = KdbInitFileBuffer;
3792c2c66affSColin Finck     while (p1[0] != '\0')
3793c2c66affSColin Finck     {
3794c2c66affSColin Finck         i = strcspn(p1, "\r\n");
3795c2c66affSColin Finck         if (i > 0)
3796c2c66affSColin Finck         {
3797c2c66affSColin Finck             c = p1[i];
3798c2c66affSColin Finck             p1[i] = '\0';
3799c2c66affSColin Finck 
3800c2c66affSColin Finck             /* Look for "break" command and comments */
3801c2c66affSColin Finck             p2 = p1;
3802c2c66affSColin Finck 
3803c2c66affSColin Finck             while (isspace(p2[0]))
3804c2c66affSColin Finck                 p2++;
3805c2c66affSColin Finck 
3806c2c66affSColin Finck             if (strncmp(p2, "break", sizeof("break")-1) == 0 &&
3807c2c66affSColin Finck                 (p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1])))
3808c2c66affSColin Finck             {
3809c2c66affSColin Finck                 /* break into the debugger */
3810c2c66affSColin Finck                 KdbpCliMainLoop(FALSE);
3811c2c66affSColin Finck             }
3812c2c66affSColin Finck             else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */
3813c2c66affSColin Finck             {
3814c2c66affSColin Finck                 KdbpDoCommand(p1);
3815c2c66affSColin Finck             }
3816c2c66affSColin Finck 
3817c2c66affSColin Finck             p1[i] = c;
3818c2c66affSColin Finck         }
3819c2c66affSColin Finck 
3820c2c66affSColin Finck         p1 += i;
3821c2c66affSColin Finck         while (p1[0] == '\r' || p1[0] == '\n')
3822c2c66affSColin Finck             p1++;
3823c2c66affSColin Finck     }
3824c2c66affSColin Finck     DPRINT("KDB: KDBinit executed\n");
3825c2c66affSColin Finck }
3826c2c66affSColin Finck 
3827c2c66affSColin Finck /*!\brief Called when KDB is initialized
3828c2c66affSColin Finck  *
3829c2c66affSColin Finck  * Reads the KDBinit file from the SystemRoot\System32\drivers\etc directory and executes it.
3830c2c66affSColin Finck  */
3831c2c66affSColin Finck VOID
3832c2c66affSColin Finck KdbpCliInit(VOID)
3833c2c66affSColin Finck {
3834c2c66affSColin Finck     NTSTATUS Status;
3835c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
3836c2c66affSColin Finck     UNICODE_STRING FileName;
3837c2c66affSColin Finck     IO_STATUS_BLOCK Iosb;
3838c2c66affSColin Finck     FILE_STANDARD_INFORMATION FileStdInfo;
3839c2c66affSColin Finck     HANDLE hFile = NULL;
3840c2c66affSColin Finck     INT FileSize;
3841c2c66affSColin Finck     PCHAR FileBuffer;
3842c2c66affSColin Finck     ULONG OldEflags;
3843c2c66affSColin Finck 
3844c2c66affSColin Finck     /* Initialize the object attributes */
3845c2c66affSColin Finck     RtlInitUnicodeString(&FileName, L"\\SystemRoot\\System32\\drivers\\etc\\KDBinit");
3846b910409aSSerge Gautherie     InitializeObjectAttributes(&ObjectAttributes,
3847b910409aSSerge Gautherie                                &FileName,
3848b910409aSSerge Gautherie                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3849b910409aSSerge Gautherie                                NULL,
3850b910409aSSerge Gautherie                                NULL);
3851c2c66affSColin Finck 
3852c2c66affSColin Finck     /* Open the file */
3853c2c66affSColin Finck     Status = ZwOpenFile(&hFile, FILE_READ_DATA | SYNCHRONIZE,
3854c2c66affSColin Finck                         &ObjectAttributes, &Iosb, 0,
3855c2c66affSColin Finck                         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
3856c2c66affSColin Finck                         FILE_NO_INTERMEDIATE_BUFFERING);
3857c2c66affSColin Finck     if (!NT_SUCCESS(Status))
3858c2c66affSColin Finck     {
3859c2c66affSColin Finck         DPRINT("Could not open \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status);
3860c2c66affSColin Finck         return;
3861c2c66affSColin Finck     }
3862c2c66affSColin Finck 
3863c2c66affSColin Finck     /* Get the size of the file */
3864c2c66affSColin Finck     Status = ZwQueryInformationFile(hFile, &Iosb, &FileStdInfo, sizeof(FileStdInfo),
3865c2c66affSColin Finck                                     FileStandardInformation);
3866c2c66affSColin Finck     if (!NT_SUCCESS(Status))
3867c2c66affSColin Finck     {
3868c2c66affSColin Finck         ZwClose(hFile);
3869c2c66affSColin Finck         DPRINT("Could not query size of \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status);
3870c2c66affSColin Finck         return;
3871c2c66affSColin Finck     }
3872c2c66affSColin Finck     FileSize = FileStdInfo.EndOfFile.u.LowPart;
3873c2c66affSColin Finck 
3874c2c66affSColin Finck     /* Allocate memory for the file */
3875c2c66affSColin Finck     FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */
3876c2c66affSColin Finck     if (!FileBuffer)
3877c2c66affSColin Finck     {
3878c2c66affSColin Finck         ZwClose(hFile);
3879c2c66affSColin Finck         DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize);
3880c2c66affSColin Finck         return;
3881c2c66affSColin Finck     }
3882c2c66affSColin Finck 
3883c2c66affSColin Finck     /* Load file into memory */
388411baa0d7SSerge Gautherie     Status = ZwReadFile(hFile, NULL, NULL, NULL, &Iosb, FileBuffer, FileSize, NULL, NULL);
3885c2c66affSColin Finck     ZwClose(hFile);
3886c2c66affSColin Finck 
3887c2c66affSColin Finck     if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
3888c2c66affSColin Finck     {
3889c2c66affSColin Finck         ExFreePool(FileBuffer);
3890c2c66affSColin Finck         DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status);
3891c2c66affSColin Finck         return;
3892c2c66affSColin Finck     }
3893c2c66affSColin Finck 
3894c2c66affSColin Finck     FileSize = min(FileSize, (INT)Iosb.Information);
3895c2c66affSColin Finck     FileBuffer[FileSize] = '\0';
3896c2c66affSColin Finck 
3897c2c66affSColin Finck     /* Enter critical section */
3898c2c66affSColin Finck     OldEflags = __readeflags();
3899c2c66affSColin Finck     _disable();
3900c2c66affSColin Finck 
3901c2c66affSColin Finck     /* Interpret the init file... */
3902c2c66affSColin Finck     KdbInitFileBuffer = FileBuffer;
3903baa47fa5SHervé Poussineau     //KdbEnter(); // FIXME
3904c2c66affSColin Finck     KdbInitFileBuffer = NULL;
3905c2c66affSColin Finck 
3906c2c66affSColin Finck     /* Leave critical section */
3907c2c66affSColin Finck     __writeeflags(OldEflags);
3908c2c66affSColin Finck 
3909c2c66affSColin Finck     ExFreePool(FileBuffer);
3910c2c66affSColin Finck }
3911