VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp@ 31510

Last change on this file since 31510 was 31510, checked in by vboxsync, 15 years ago

The debugger is back in the OSE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 178.0 KB
Line 
1/* $Id: DBGCEmulateCodeView.cpp 31510 2010-08-10 08:48:11Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, CodeView / WinDbg Emulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13/*******************************************************************************
14* Header Files *
15*******************************************************************************/
16#define LOG_GROUP LOG_GROUP_DBGC
17#include <VBox/dbg.h>
18#include <VBox/dbgf.h>
19#include <VBox/pgm.h>
20#include <VBox/selm.h>
21#include <VBox/cpum.h>
22#include <VBox/dis.h>
23#include <VBox/param.h>
24#include <VBox/err.h>
25#include <VBox/log.h>
26
27#include <iprt/asm.h>
28#include <iprt/alloca.h>
29#include <iprt/mem.h>
30#include <iprt/string.h>
31#include <iprt/assert.h>
32#include <iprt/ctype.h>
33
34#include <stdlib.h>
35#include <stdio.h>
36
37#include "DBGCInternal.h"
38
39
40/*******************************************************************************
41* Internal Functions *
42*******************************************************************************/
43static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
44static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
45static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
46static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
47static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
48static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
49static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
50static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
51static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
52static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
53static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
54static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
55static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
56static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
57static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
58static DECLCALLBACK(int) dbgcCmdEditMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
59static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
60static DECLCALLBACK(int) dbgcCmdListModules(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
61static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
62static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
63static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
64static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
65static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
66static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
67static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
68static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
69static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
70static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
71static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
72static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
73
74
75/*******************************************************************************
76* Global Variables *
77*******************************************************************************/
78/** 'ba' arguments. */
79static const DBGCVARDESC g_aArgBrkAcc[] =
80{
81 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
82 { 1, 1, DBGCVAR_CAT_STRING, 0, "access", "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." },
83 { 1, 1, DBGCVAR_CAT_NUMBER, 0, "size", "The access size: 1, 2, 4, or 8. 'x' access requires 1, and 8 requires amd64 long mode." },
84 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
85 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
86 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
87 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
88};
89
90
91/** 'bc', 'bd', 'be' arguments. */
92static const DBGCVARDESC g_aArgBrks[] =
93{
94 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
95 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "#bp", "Breakpoint number." },
96 { 0, 1, DBGCVAR_CAT_STRING, 0, "all", "All breakpoints." },
97};
98
99
100/** 'bp' arguments. */
101static const DBGCVARDESC g_aArgBrkSet[] =
102{
103 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
104 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
105 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
106 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
107 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
108};
109
110
111/** 'br' arguments. */
112static const DBGCVARDESC g_aArgBrkREM[] =
113{
114 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
115 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
116 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
117 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
118 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
119};
120
121
122/** 'd?' arguments. */
123static const DBGCVARDESC g_aArgDumpMem[] =
124{
125 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
126 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start dumping memory." },
127};
128
129
130/** 'dg', 'dga', 'dl', 'dla' arguments. */
131static const DBGCVARDESC g_aArgDumpDT[] =
132{
133 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
134 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." },
135 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." },
136};
137
138
139/** 'di', 'dia' arguments. */
140static const DBGCVARDESC g_aArgDumpIDT[] =
141{
142 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
143 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." },
144};
145
146
147/** 'dpd*' arguments. */
148static const DBGCVARDESC g_aArgDumpPD[] =
149{
150 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
151 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." },
152 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },
153};
154
155
156/** 'dpda' arguments. */
157static const DBGCVARDESC g_aArgDumpPDAddr[] =
158{
159 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
160 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },
161};
162
163
164/** 'dpt?' arguments. */
165static const DBGCVARDESC g_aArgDumpPT[] =
166{
167 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
168 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },
169};
170
171
172/** 'dpta' arguments. */
173static const DBGCVARDESC g_aArgDumpPTAddr[] =
174{
175 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
176 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },
177};
178
179
180/** 'dt' arguments. */
181static const DBGCVARDESC g_aArgDumpTSS[] =
182{
183 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
184 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." },
185 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }
186};
187
188
189/** 'e?' arguments. */
190static const DBGCVARDESC g_aArgEditMem[] =
191{
192 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
193 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to write." },
194 { 1, ~0, DBGCVAR_CAT_NUMBER, 0, "value", "Value to write." },
195};
196
197
198/** 'lm' arguments. */
199static const DBGCVARDESC g_aArgListMods[] =
200{
201 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
202 { 0, ~0, DBGCVAR_CAT_STRING, 0, "module", "Module name." },
203};
204
205
206/** 'ln' arguments. */
207static const DBGCVARDESC g_aArgListNear[] =
208{
209 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
210 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Address of the symbol to look up." },
211 { 0, ~0, DBGCVAR_CAT_SYMBOL, 0, "symbol", "Symbol to lookup." },
212};
213
214/** 'ln' return. */
215static const DBGCVARDESC g_RetListNear =
216{
217 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The last resolved symbol/address with adjusted range."
218};
219
220
221/** 'ls' arguments. */
222static const DBGCVARDESC g_aArgListSource[] =
223{
224 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
225 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start looking for source lines." },
226};
227
228
229/** 'm' argument. */
230static const DBGCVARDESC g_aArgMemoryInfo[] =
231{
232 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
233 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Pointer to obtain info about." },
234};
235
236
237/** 'r' arguments. */
238static const DBGCVARDESC g_aArgReg[] =
239{
240 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
241 { 0, 1, DBGCVAR_CAT_SYMBOL, 0, "register", "Register to show or set." },
242 { 0, 1, DBGCVAR_CAT_NUMBER_NO_RANGE, DBGCVD_FLAGS_DEP_PREV, "value", "New register value." },
243};
244
245
246/** 's' arguments. */
247static const DBGCVARDESC g_aArgSearchMem[] =
248{
249 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
250 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-b", "Byte string." },
251 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-w", "Word string." },
252 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-d", "DWord string." },
253 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-q", "QWord string." },
254 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-a", "ASCII string." },
255 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-u", "Unicode string." },
256 { 0, 1, DBGCVAR_CAT_OPTION_NUMBER, 0, "-n <Hits>", "Maximum number of hits." },
257 { 0, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." },
258 { 0, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." },
259};
260
261
262/** 's?' arguments. */
263static const DBGCVARDESC g_aArgSearchMemType[] =
264{
265 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
266 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." },
267 { 1, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." },
268};
269
270
271/** 'u' arguments. */
272static const DBGCVARDESC g_aArgUnassemble[] =
273{
274 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
275 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start disassembling." },
276};
277
278
279/** Command descriptors for the CodeView / WinDbg emulation.
280 * The emulation isn't attempting to be identical, only somewhat similar.
281 */
282const DBGCCMD g_aCmdsCodeView[] =
283{
284 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
285 { "ba", 3, 6, &g_aArgBrkAcc[0], RT_ELEMENTS(g_aArgBrkAcc), NULL, 0, dbgcCmdBrkAccess, "<access> <size> <address> [passes [max passes]] [cmds]",
286 "Sets a data access breakpoint." },
287 { "bc", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkClear, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
288 { "bd", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkDisable, "all | <bp#> [bp# []]", "Disables a set of breakpoints." },
289 { "be", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkEnable, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
290 { "bl", 0, 0, NULL, 0, NULL, 0, dbgcCmdBrkList, "", "Lists all the breakpoints." },
291 { "bp", 1, 4, &g_aArgBrkSet[0], RT_ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]",
292 "Sets a breakpoint (int 3)." },
293 { "br", 1, 4, &g_aArgBrkREM[0], RT_ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]",
294 "Sets a recompiler specific breakpoint." },
295 { "d", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." },
296 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." },
297 { "db", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." },
298 { "dd", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." },
299 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." },
300 { "dg", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." },
301 { "dga", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." },
302 { "di", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." },
303 { "dia", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." },
304 { "dl", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." },
305 { "dla", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." },
306 { "dpd", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." },
307 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],RT_ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." },
308 { "dpdb", 1, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " },
309 { "dpdg", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." },
310 { "dpdh", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " },
311 { "dpt", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." },
312 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],RT_ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." },
313 { "dptb", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." },
314 { "dptg", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." },
315 { "dpth", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." },
316 { "dq", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." },
317 { "dt", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." },
318 { "dt16", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the 16-bit task state segment (TSS)." },
319 { "dt32", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the 32-bit task state segment (TSS)." },
320 { "dt64", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the 64-bit task state segment (TSS)." },
321 { "dw", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." },
322 /** @todo add 'e', 'ea str', 'eza str', 'eu str' and 'ezu str'. See also
323 * dbgcCmdSearchMem and its dbgcVarsToBytes usage. */
324 { "eb", 2, 2, &g_aArgEditMem[0], RT_ELEMENTS(g_aArgEditMem), NULL, 0, dbgcCmdEditMem, "<addr> <value>", "Write a 1-byte value to memory." },
325 { "ew", 2, 2, &g_aArgEditMem[0], RT_ELEMENTS(g_aArgEditMem), NULL, 0, dbgcCmdEditMem, "<addr> <value>", "Write a 2-byte value to memory." },
326 { "ed", 2, 2, &g_aArgEditMem[0], RT_ELEMENTS(g_aArgEditMem), NULL, 0, dbgcCmdEditMem, "<addr> <value>", "Write a 4-byte value to memory." },
327 { "eq", 2, 2, &g_aArgEditMem[0], RT_ELEMENTS(g_aArgEditMem), NULL, 0, dbgcCmdEditMem, "<addr> <value>", "Write a 8-byte value to memory." },
328 { "g", 0, 0, NULL, 0, NULL, 0, dbgcCmdGo, "", "Continue execution." },
329 { "k", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack." },
330 { "kg", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - guest." },
331 { "kh", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - hypervisor." },
332 { "lm", 0, ~0, &g_aArgListMods[0], RT_ELEMENTS(g_aArgListMods), NULL, 0, dbgcCmdListModules, "[module [..]]", "List modules." },
333 { "lmo", 0, ~0, &g_aArgListMods[0], RT_ELEMENTS(g_aArgListMods), NULL, 0, dbgcCmdListModules, "[module [..]]", "List modules and their segments." },
334 { "ln", 0, ~0, &g_aArgListNear[0], RT_ELEMENTS(g_aArgListNear), &g_RetListNear, 0, dbgcCmdListNear, "[addr/sym [..]]", "List symbols near to the address. Default address is CS:EIP." },
335 { "ls", 0, 1, &g_aArgListSource[0],RT_ELEMENTS(g_aArgListSource),NULL, 0, dbgcCmdListSource, "[addr]", "Source." },
336 { "m", 1, 1, &g_aArgMemoryInfo[0],RT_ELEMENTS(g_aArgMemoryInfo),NULL, 0, dbgcCmdMemoryInfo, "<addr>", "Display information about that piece of memory." },
337 { "r", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdReg, "[reg [newval]]", "Show or set register(s) - active reg set." },
338 { "rg", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegGuest, "[reg [newval]]", "Show or set register(s) - guest reg set." },
339 { "rh", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegHyper, "[reg [newval]]", "Show or set register(s) - hypervisor reg set." },
340 { "rt", 0, 0, NULL, 0, NULL, 0, dbgcCmdRegTerse, "", "Toggles terse / verbose register info." },
341 { "s", 0, ~0, &g_aArgSearchMem[0], RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "[options] <range> <pattern>", "Continue last search." },
342 { "sa", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for an ascii string." },
343 { "sb", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more bytes." },
344 { "sd", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more double words." },
345 { "sq", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more quad words." },
346 { "su", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for an unicode string." },
347 { "sw", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more words." },
348 { "t", 0, 0, NULL, 0, NULL, 0, dbgcCmdTrace, "", "Instruction trace (step into)." },
349 { "u", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble." },
350 { "u64", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble 64-bit code." },
351 { "u32", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble 32-bit code." },
352 { "u16", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble 16-bit code." },
353 { "uv86", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble 16-bit code with v8086/real mode addressing." },
354};
355
356/** The number of commands in the CodeView/WinDbg emulation. */
357const unsigned g_cCmdsCodeView = RT_ELEMENTS(g_aCmdsCodeView);
358
359
360
361/**
362 * The 'go' command.
363 *
364 * @returns VBox status.
365 * @param pCmd Pointer to the command descriptor (as registered).
366 * @param pCmdHlp Pointer to command helper functions.
367 * @param pVM Pointer to the current VM (if any).
368 * @param paArgs Pointer to (readonly) array of arguments.
369 * @param cArgs Number of arguments in the array.
370 */
371static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
372{
373 /*
374 * Check if the VM is halted or not before trying to resume it.
375 */
376 if (!DBGFR3IsHalted(pVM))
377 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already running...\n");
378 else
379 {
380 int rc = DBGFR3Resume(pVM);
381 if (RT_FAILURE(rc))
382 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Resume().");
383 }
384
385 NOREF(pCmd);
386 NOREF(paArgs);
387 NOREF(cArgs);
388 NOREF(pResult);
389 return 0;
390}
391
392
393/**
394 * The 'ba' command.
395 *
396 * @returns VBox status.
397 * @param pCmd Pointer to the command descriptor (as registered).
398 * @param pCmdHlp Pointer to command helper functions.
399 * @param pVM Pointer to the current VM (if any).
400 * @param paArgs Pointer to (readonly) array of arguments.
401 * @param cArgs Number of arguments in the array.
402 */
403static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
404{
405 /*
406 * Interpret access type.
407 */
408 if ( !strchr("xrwi", paArgs[0].u.pszString[0])
409 || paArgs[0].u.pszString[1])
410 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n",
411 paArgs[0].u.pszString, pCmd->pszCmd);
412 uint8_t fType = 0;
413 switch (paArgs[0].u.pszString[0])
414 {
415 case 'x': fType = X86_DR7_RW_EO; break;
416 case 'r': fType = X86_DR7_RW_RW; break;
417 case 'w': fType = X86_DR7_RW_WO; break;
418 case 'i': fType = X86_DR7_RW_IO; break;
419 }
420
421 /*
422 * Validate size.
423 */
424 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1)
425 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n",
426 paArgs[1].u.u64Number, pCmd->pszCmd);
427 switch (paArgs[1].u.u64Number)
428 {
429 case 1:
430 case 2:
431 case 4:
432 break;
433 /*case 8: - later*/
434 default:
435 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 1, 2 or 4!\n",
436 paArgs[1].u.u64Number, pCmd->pszCmd);
437 }
438 uint8_t cb = (uint8_t)paArgs[1].u.u64Number;
439
440 /*
441 * Convert the pointer to a DBGF address.
442 */
443 DBGFADDRESS Address;
444 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address);
445 if (RT_FAILURE(rc))
446 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Rrc.\n", &paArgs[2], rc);
447
448 /*
449 * Pick out the optional arguments.
450 */
451 uint64_t iHitTrigger = 0;
452 uint64_t iHitDisable = ~0;
453 const char *pszCmds = NULL;
454 unsigned iArg = 3;
455 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
456 {
457 iHitTrigger = paArgs[iArg].u.u64Number;
458 iArg++;
459 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
460 {
461 iHitDisable = paArgs[iArg].u.u64Number;
462 iArg++;
463 }
464 }
465 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
466 {
467 pszCmds = paArgs[iArg].u.pszString;
468 iArg++;
469 }
470
471 /*
472 * Try set the breakpoint.
473 */
474 RTUINT iBp;
475 rc = DBGFR3BpSetReg(pVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp);
476 if (RT_SUCCESS(rc))
477 {
478 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
479 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
480 if (RT_SUCCESS(rc))
481 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
482 if (rc == VERR_DBGC_BP_EXISTS)
483 {
484 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
485 if (RT_SUCCESS(rc))
486 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
487 }
488 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
489 AssertRC(rc2);
490 }
491 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %RGv, rc=%Rrc.\n", Address.FlatPtr, rc);
492}
493
494
495/**
496 * The 'bc' command.
497 *
498 * @returns VBox status.
499 * @param pCmd Pointer to the command descriptor (as registered).
500 * @param pCmdHlp Pointer to command helper functions.
501 * @param pVM Pointer to the current VM (if any).
502 * @param paArgs Pointer to (readonly) array of arguments.
503 * @param cArgs Number of arguments in the array.
504 */
505static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
506{
507 /*
508 * Enumerate the arguments.
509 */
510 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
511 int rc = VINF_SUCCESS;
512 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
513 {
514 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
515 {
516 /* one */
517 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
518 if (iBp != paArgs[iArg].u.u64Number)
519 {
520 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
521 break;
522 }
523 int rc2 = DBGFR3BpClear(pVM, iBp);
524 if (RT_FAILURE(rc2))
525 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
526 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
527 dbgcBpDelete(pDbgc, iBp);
528 }
529 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
530 {
531 /* all */
532 PDBGCBP pBp = pDbgc->pFirstBp;
533 while (pBp)
534 {
535 RTUINT iBp = pBp->iBp;
536 pBp = pBp->pNext;
537
538 int rc2 = DBGFR3BpClear(pVM, iBp);
539 if (RT_FAILURE(rc2))
540 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
541 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
542 dbgcBpDelete(pDbgc, iBp);
543 }
544 }
545 else
546 {
547 /* invalid parameter */
548 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
549 break;
550 }
551 }
552 return rc;
553}
554
555
556/**
557 * The 'bd' command.
558 *
559 * @returns VBox status.
560 * @param pCmd Pointer to the command descriptor (as registered).
561 * @param pCmdHlp Pointer to command helper functions.
562 * @param pVM Pointer to the current VM (if any).
563 * @param paArgs Pointer to (readonly) array of arguments.
564 * @param cArgs Number of arguments in the array.
565 */
566static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
567{
568 /*
569 * Enumerate the arguments.
570 */
571 int rc = VINF_SUCCESS;
572 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
573 {
574 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
575 {
576 /* one */
577 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
578 if (iBp != paArgs[iArg].u.u64Number)
579 {
580 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
581 break;
582 }
583 rc = DBGFR3BpDisable(pVM, iBp);
584 if (RT_FAILURE(rc))
585 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", iBp);
586 }
587 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
588 {
589 /* all */
590 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
591 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
592 {
593 rc = DBGFR3BpDisable(pVM, pBp->iBp);
594 if (RT_FAILURE(rc))
595 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", pBp->iBp);
596 }
597 }
598 else
599 {
600 /* invalid parameter */
601 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
602 break;
603 }
604 }
605 return rc;
606}
607
608
609/**
610 * The 'be' command.
611 *
612 * @returns VBox status.
613 * @param pCmd Pointer to the command descriptor (as registered).
614 * @param pCmdHlp Pointer to command helper functions.
615 * @param pVM Pointer to the current VM (if any).
616 * @param paArgs Pointer to (readonly) array of arguments.
617 * @param cArgs Number of arguments in the array.
618 */
619static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
620{
621 /*
622 * Enumerate the arguments.
623 */
624 int rc = VINF_SUCCESS;
625 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
626 {
627 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
628 {
629 /* one */
630 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
631 if (iBp != paArgs[iArg].u.u64Number)
632 {
633 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
634 break;
635 }
636 rc = DBGFR3BpEnable(pVM, iBp);
637 if (RT_FAILURE(rc))
638 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", iBp);
639 }
640 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
641 {
642 /* all */
643 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
644 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
645 {
646 rc = DBGFR3BpEnable(pVM, pBp->iBp);
647 if (RT_FAILURE(rc))
648 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", pBp->iBp);
649 }
650 }
651 else
652 {
653 /* invalid parameter */
654 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
655 break;
656 }
657 }
658 return rc;
659}
660
661
662/**
663 * Breakpoint enumeration callback function.
664 *
665 * @returns VBox status code. Any failure will stop the enumeration.
666 * @param pVM The VM handle.
667 * @param pvUser The user argument.
668 * @param pBp Pointer to the breakpoint information. (readonly)
669 */
670static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PVM pVM, void *pvUser, PCDBGFBP pBp)
671{
672 PDBGC pDbgc = (PDBGC)pvUser;
673 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp);
674
675 /*
676 * BP type and size.
677 */
678 char chType;
679 char cb = 1;
680 switch (pBp->enmType)
681 {
682 case DBGFBPTYPE_INT3:
683 chType = 'p';
684 break;
685 case DBGFBPTYPE_REG:
686 switch (pBp->u.Reg.fType)
687 {
688 case X86_DR7_RW_EO: chType = 'x'; break;
689 case X86_DR7_RW_WO: chType = 'w'; break;
690 case X86_DR7_RW_IO: chType = 'i'; break;
691 case X86_DR7_RW_RW: chType = 'r'; break;
692 default: chType = '?'; break;
693
694 }
695 cb = pBp->u.Reg.cb;
696 break;
697 case DBGFBPTYPE_REM:
698 chType = 'r';
699 break;
700 default:
701 chType = '?';
702 break;
703 }
704
705 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%2u %c %d %c %RGv %04RX64 (%04RX64 to ",
706 pBp->iBp, pBp->fEnabled ? 'e' : 'd', cb, chType,
707 pBp->GCPtr, pBp->cHits, pBp->iHitTrigger);
708 if (pBp->iHitDisable == ~(uint64_t)0)
709 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "~0) ");
710 else
711 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%04RX64)");
712
713 /*
714 * Try resolve the address.
715 */
716 RTDBGSYMBOL Sym;
717 RTINTPTR off;
718 DBGFADDRESS Addr;
719 int rc = DBGFR3AsSymbolByAddr(pVM, pDbgc->hDbgAs, DBGFR3AddrFromFlat(pVM, &Addr, pBp->GCPtr), &off, &Sym, NULL);
720 if (RT_SUCCESS(rc))
721 {
722 if (!off)
723 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", Sym.szName);
724 else if (off > 0)
725 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%RGv", Sym.szName, off);
726 else
727 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%RGv", Sym.szName, -off);
728 }
729
730 /*
731 * The commands.
732 */
733 if (pDbgcBp)
734 {
735 if (pDbgcBp->cchCmd)
736 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n cmds: '%s'\n",
737 pDbgcBp->szCmd);
738 else
739 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");
740 }
741 else
742 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " [unknown bp]\n");
743
744 return VINF_SUCCESS;
745}
746
747
748/**
749 * The 'bl' command.
750 *
751 * @returns VBox status.
752 * @param pCmd Pointer to the command descriptor (as registered).
753 * @param pCmdHlp Pointer to command helper functions.
754 * @param pVM Pointer to the current VM (if any).
755 * @param paArgs Pointer to (readonly) array of arguments.
756 * @param cArgs Number of arguments in the array.
757 */
758static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
759{
760 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
761
762 /*
763 * Enumerate the breakpoints.
764 */
765 int rc = DBGFR3BpEnum(pVM, dbgcEnumBreakpointsCallback, pDbgc);
766 if (RT_FAILURE(rc))
767 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnum failed.\n");
768 return rc;
769}
770
771
772/**
773 * The 'bp' command.
774 *
775 * @returns VBox status.
776 * @param pCmd Pointer to the command descriptor (as registered).
777 * @param pCmdHlp Pointer to command helper functions.
778 * @param pVM Pointer to the current VM (if any).
779 * @param paArgs Pointer to (readonly) array of arguments.
780 * @param cArgs Number of arguments in the array.
781 */
782static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
783{
784 /*
785 * Convert the pointer to a DBGF address.
786 */
787 DBGFADDRESS Address;
788 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
789 if (RT_FAILURE(rc))
790 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Rrc.\n", &paArgs[0], rc);
791
792 /*
793 * Pick out the optional arguments.
794 */
795 uint64_t iHitTrigger = 0;
796 uint64_t iHitDisable = ~0;
797 const char *pszCmds = NULL;
798 unsigned iArg = 1;
799 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
800 {
801 iHitTrigger = paArgs[iArg].u.u64Number;
802 iArg++;
803 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
804 {
805 iHitDisable = paArgs[iArg].u.u64Number;
806 iArg++;
807 }
808 }
809 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
810 {
811 pszCmds = paArgs[iArg].u.pszString;
812 iArg++;
813 }
814
815 /*
816 * Try set the breakpoint.
817 */
818 RTUINT iBp;
819 rc = DBGFR3BpSet(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
820 if (RT_SUCCESS(rc))
821 {
822 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
823 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
824 if (RT_SUCCESS(rc))
825 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
826 if (rc == VERR_DBGC_BP_EXISTS)
827 {
828 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
829 if (RT_SUCCESS(rc))
830 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
831 }
832 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
833 AssertRC(rc2);
834 }
835 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %RGv, rc=%Rrc.\n", Address.FlatPtr, rc);
836}
837
838
839/**
840 * The 'br' command.
841 *
842 * @returns VBox status.
843 * @param pCmd Pointer to the command descriptor (as registered).
844 * @param pCmdHlp Pointer to command helper functions.
845 * @param pVM Pointer to the current VM (if any).
846 * @param paArgs Pointer to (readonly) array of arguments.
847 * @param cArgs Number of arguments in the array.
848 */
849static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
850{
851 /*
852 * Convert the pointer to a DBGF address.
853 */
854 DBGFADDRESS Address;
855 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
856 if (RT_FAILURE(rc))
857 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Rrc.\n", &paArgs[0], rc);
858
859 /*
860 * Pick out the optional arguments.
861 */
862 uint64_t iHitTrigger = 0;
863 uint64_t iHitDisable = ~0;
864 const char *pszCmds = NULL;
865 unsigned iArg = 1;
866 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
867 {
868 iHitTrigger = paArgs[iArg].u.u64Number;
869 iArg++;
870 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
871 {
872 iHitDisable = paArgs[iArg].u.u64Number;
873 iArg++;
874 }
875 }
876 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
877 {
878 pszCmds = paArgs[iArg].u.pszString;
879 iArg++;
880 }
881
882 /*
883 * Try set the breakpoint.
884 */
885 RTUINT iBp;
886 rc = DBGFR3BpSetREM(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
887 if (RT_SUCCESS(rc))
888 {
889 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
890 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
891 if (RT_SUCCESS(rc))
892 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
893 if (rc == VERR_DBGC_BP_EXISTS)
894 {
895 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
896 if (RT_SUCCESS(rc))
897 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr);
898 }
899 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
900 AssertRC(rc2);
901 }
902 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %RGv, rc=%Rrc.\n", Address.FlatPtr, rc);
903}
904
905
906/**
907 * The 'u' command.
908 *
909 * @returns VBox status.
910 * @param pCmd Pointer to the command descriptor (as registered).
911 * @param pCmdHlp Pointer to command helper functions.
912 * @param pVM Pointer to the current VM (if any).
913 * @param paArgs Pointer to (readonly) array of arguments.
914 * @param cArgs Number of arguments in the array.
915 */
916static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
917{
918 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
919
920 /*
921 * Validate input.
922 */
923 if ( cArgs > 1
924 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
925 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
926 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
927 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
928 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
929 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
930
931 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS;
932
933 /*
934 * Check the desired mode.
935 */
936 switch (pCmd->pszCmd[1])
937 {
938 default: AssertFailed();
939 case '\0': fFlags |= DBGF_DISAS_FLAGS_DEFAULT_MODE; break;
940 case '6': fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break;
941 case '3': fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break;
942 case '1': fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE; break;
943 case 'v': fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE; break;
944 }
945
946 /*
947 * Find address.
948 */
949 if (!cArgs)
950 {
951 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
952 {
953 PVMCPU pVCpu = VMMGetCpuById(pVM, pDbgc->idCpu);
954 if ( pDbgc->fRegCtxGuest
955 && CPUMIsGuestIn64BitCodeEx(CPUMQueryGuestCtxPtr(pVCpu)))
956 {
957 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FLAT;
958 pDbgc->SourcePos.u.GCFlat = CPUMGetGuestRIP(pVCpu);
959 }
960 else
961 {
962 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR;
963 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu);
964 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu);
965 }
966
967 if (pDbgc->fRegCtxGuest)
968 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST;
969 else
970 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER;
971 }
972 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE;
973 }
974 else
975 pDbgc->DisasmPos = paArgs[0];
976
977 /*
978 * Range.
979 */
980 switch (pDbgc->DisasmPos.enmRangeType)
981 {
982 case DBGCVAR_RANGE_NONE:
983 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
984 pDbgc->DisasmPos.u64Range = 10;
985 break;
986
987 case DBGCVAR_RANGE_ELEMENTS:
988 if (pDbgc->DisasmPos.u64Range > 2048)
989 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
990 break;
991
992 case DBGCVAR_RANGE_BYTES:
993 if (pDbgc->DisasmPos.u64Range > 65536)
994 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
995 break;
996
997 default:
998 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType);
999 }
1000
1001 /*
1002 * Convert physical and host addresses to guest addresses.
1003 */
1004 int rc;
1005 switch (pDbgc->DisasmPos.enmType)
1006 {
1007 case DBGCVAR_TYPE_GC_FLAT:
1008 case DBGCVAR_TYPE_GC_FAR:
1009 break;
1010 case DBGCVAR_TYPE_GC_PHYS:
1011 case DBGCVAR_TYPE_HC_FLAT:
1012 case DBGCVAR_TYPE_HC_PHYS:
1013 case DBGCVAR_TYPE_HC_FAR:
1014 {
1015 DBGCVAR VarTmp;
1016 rc = DBGCCmdHlpEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos);
1017 if (RT_FAILURE(rc))
1018 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Rrc .\n", &pDbgc->DisasmPos, rc);
1019 pDbgc->DisasmPos = VarTmp;
1020 break;
1021 }
1022 default: AssertFailed(); break;
1023 }
1024
1025 /*
1026 * Print address.
1027 * todo: Change to list near.
1028 */
1029#if 0
1030 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DisasmPos);
1031 if (RT_FAILURE(rc))
1032 return rc;
1033#endif
1034
1035 /*
1036 * Do the disassembling.
1037 */
1038 unsigned cTries = 32;
1039 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range;
1040 if (iRangeLeft == 0) /* klugde for 'r'. */
1041 iRangeLeft = -1;
1042 for (;;)
1043 {
1044 /*
1045 * Disassemble the instruction.
1046 */
1047 char szDis[256];
1048 uint32_t cbInstr = 1;
1049 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT)
1050 rc = DBGFR3DisasInstrEx(pVM, pDbgc->idCpu, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags,
1051 &szDis[0], sizeof(szDis), &cbInstr);
1052 else
1053 rc = DBGFR3DisasInstrEx(pVM, pDbgc->idCpu, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags,
1054 &szDis[0], sizeof(szDis), &cbInstr);
1055 if (RT_SUCCESS(rc))
1056 {
1057 /* print it */
1058 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]);
1059 if (RT_FAILURE(rc))
1060 return rc;
1061 }
1062 else
1063 {
1064 /* bitch. */
1065 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");
1066 if (RT_FAILURE(rc))
1067 return rc;
1068 if (cTries-- > 0)
1069 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Too many disassembly failures. Giving up.\n");
1070 cbInstr = 1;
1071 }
1072
1073 /* advance */
1074 if (iRangeLeft < 0) /* 'r' */
1075 break;
1076 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
1077 iRangeLeft--;
1078 else
1079 iRangeLeft -= cbInstr;
1080 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr);
1081 if (RT_FAILURE(rc))
1082 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DisasmPos, cbInstr);
1083 if (iRangeLeft <= 0)
1084 break;
1085 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER);
1086 }
1087
1088 NOREF(pCmd); NOREF(pResult);
1089 return 0;
1090}
1091
1092
1093/**
1094 * The 'ls' command.
1095 *
1096 * @returns VBox status.
1097 * @param pCmd Pointer to the command descriptor (as registered).
1098 * @param pCmdHlp Pointer to command helper functions.
1099 * @param pVM Pointer to the current VM (if any).
1100 * @param paArgs Pointer to (readonly) array of arguments.
1101 * @param cArgs Number of arguments in the array.
1102 */
1103static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1104{
1105 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1106
1107 /*
1108 * Validate input.
1109 */
1110 if ( cArgs > 1
1111 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
1112 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
1113 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
1114 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
1115 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
1116 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
1117
1118 /*
1119 * Find address.
1120 */
1121 if (!cArgs)
1122 {
1123 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
1124 {
1125 PVMCPU pVCpu = VMMGetCpuById(pVM, pDbgc->idCpu);
1126 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR;
1127 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu);
1128 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu);
1129 }
1130 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE;
1131 }
1132 else
1133 pDbgc->SourcePos = paArgs[0];
1134
1135 /*
1136 * Ensure the source address is flat GC.
1137 */
1138 switch (pDbgc->SourcePos.enmType)
1139 {
1140 case DBGCVAR_TYPE_GC_FLAT:
1141 break;
1142 case DBGCVAR_TYPE_GC_PHYS:
1143 case DBGCVAR_TYPE_GC_FAR:
1144 case DBGCVAR_TYPE_HC_FLAT:
1145 case DBGCVAR_TYPE_HC_PHYS:
1146 case DBGCVAR_TYPE_HC_FAR:
1147 {
1148 int rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos);
1149 if (RT_FAILURE(rc))
1150 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid address or address type. (rc=%d)\n", rc);
1151 break;
1152 }
1153 default: AssertFailed(); break;
1154 }
1155
1156 /*
1157 * Range.
1158 */
1159 switch (pDbgc->SourcePos.enmRangeType)
1160 {
1161 case DBGCVAR_RANGE_NONE:
1162 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
1163 pDbgc->SourcePos.u64Range = 10;
1164 break;
1165
1166 case DBGCVAR_RANGE_ELEMENTS:
1167 if (pDbgc->SourcePos.u64Range > 2048)
1168 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
1169 break;
1170
1171 case DBGCVAR_RANGE_BYTES:
1172 if (pDbgc->SourcePos.u64Range > 65536)
1173 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
1174 break;
1175
1176 default:
1177 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);
1178 }
1179
1180 /*
1181 * Do the disassembling.
1182 */
1183 bool fFirst = 1;
1184 DBGFLINE LinePrev = { 0, 0, "" };
1185 int iRangeLeft = (int)pDbgc->SourcePos.u64Range;
1186 if (iRangeLeft == 0) /* klugde for 'r'. */
1187 iRangeLeft = -1;
1188 for (;;)
1189 {
1190 /*
1191 * Get line info.
1192 */
1193 DBGFLINE Line;
1194 RTGCINTPTR off;
1195 int rc = DBGFR3LineByAddr(pVM, pDbgc->SourcePos.u.GCFlat, &off, &Line);
1196 if (RT_FAILURE(rc))
1197 return VINF_SUCCESS;
1198
1199 unsigned cLines = 0;
1200 if (memcmp(&Line, &LinePrev, sizeof(Line)))
1201 {
1202 /*
1203 * Print filenamename
1204 */
1205 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename))
1206 fFirst = true;
1207 if (fFirst)
1208 {
1209 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "[%s @ %d]\n", Line.szFilename, Line.uLineNo);
1210 if (RT_FAILURE(rc))
1211 return rc;
1212 }
1213
1214 /*
1215 * Try open the file and read the line.
1216 */
1217 FILE *phFile = fopen(Line.szFilename, "r");
1218 if (phFile)
1219 {
1220 /* Skip ahead to the desired line. */
1221 char szLine[4096];
1222 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1;
1223 if (cBefore > 7)
1224 cBefore = 0;
1225 unsigned cLeft = Line.uLineNo - cBefore;
1226 while (cLeft > 0)
1227 {
1228 szLine[0] = '\0';
1229 if (!fgets(szLine, sizeof(szLine), phFile))
1230 break;
1231 cLeft--;
1232 }
1233 if (!cLeft)
1234 {
1235 /* print the before lines */
1236 for (;;)
1237 {
1238 size_t cch = strlen(szLine);
1239 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || RT_C_IS_SPACE(szLine[cch - 1])) )
1240 szLine[--cch] = '\0';
1241 if (cBefore-- <= 0)
1242 break;
1243
1244 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine);
1245 szLine[0] = '\0';
1246 fgets(szLine, sizeof(szLine), phFile);
1247 cLines++;
1248 }
1249 /* print the actual line */
1250 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine);
1251 }
1252 fclose(phFile);
1253 if (RT_FAILURE(rc))
1254 return rc;
1255 fFirst = false;
1256 }
1257 else
1258 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);
1259
1260 LinePrev = Line;
1261 }
1262
1263
1264 /*
1265 * Advance
1266 */
1267 if (iRangeLeft < 0) /* 'r' */
1268 break;
1269 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
1270 iRangeLeft -= cLines;
1271 else
1272 iRangeLeft -= 1;
1273 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1);
1274 if (RT_FAILURE(rc))
1275 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1);
1276 if (iRangeLeft <= 0)
1277 break;
1278 }
1279
1280 NOREF(pCmd); NOREF(pResult);
1281 return 0;
1282}
1283
1284
1285/**
1286 * The 'r' command.
1287 *
1288 * @returns VBox status.
1289 * @param pCmd Pointer to the command descriptor (as registered).
1290 * @param pCmdHlp Pointer to command helper functions.
1291 * @param pVM Pointer to the current VM (if any).
1292 * @param paArgs Pointer to (readonly) array of arguments.
1293 * @param cArgs Number of arguments in the array.
1294 */
1295static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1296{
1297 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1298 if (!pDbgc->fRegCtxGuest)
1299 return dbgcCmdRegHyper(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
1300 return dbgcCmdRegGuest(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
1301}
1302
1303
1304/**
1305 * Common worker for the dbgcCmdReg*() commands.
1306 *
1307 * @returns VBox status.
1308 * @param pCmd Pointer to the command descriptor (as registered).
1309 * @param pCmdHlp Pointer to command helper functions.
1310 * @param pVM Pointer to the current VM (if any).
1311 * @param paArgs Pointer to (readonly) array of arguments.
1312 * @param cArgs Number of arguments in the array.
1313 * @param pszPrefix The symbol prefix.
1314 */
1315static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs,
1316 PDBGCVAR pResult, const char *pszPrefix)
1317{
1318 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1319
1320 /*
1321 * cArgs == 0: Show all
1322 */
1323 if (cArgs == 0)
1324 {
1325 /*
1326 * Get register context.
1327 */
1328 PVMCPU pVCpu = VMMGetCpuById(pVM, pDbgc->idCpu);
1329 int rc;
1330 PCPUMCTX pCtx;
1331 PCCPUMCTXCORE pCtxCore;
1332 if (!*pszPrefix)
1333 {
1334 pCtx = CPUMQueryGuestCtxPtr(pVCpu);
1335 pCtxCore = CPUMCTX2CORE(pCtx);
1336 rc = VINF_SUCCESS;
1337 }
1338 else
1339 {
1340 rc = CPUMQueryHyperCtxPtr(pVCpu, &pCtx);
1341 pCtxCore = CPUMGetHyperCtxCore(pVCpu);
1342 }
1343 if (RT_FAILURE(rc))
1344 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Getting register context\n");
1345
1346 /*
1347 * Format the flags.
1348 */
1349 static struct
1350 {
1351 const char *pszSet; const char *pszClear; uint32_t fFlag;
1352 } aFlags[] =
1353 {
1354 { "vip",NULL, X86_EFL_VIP },
1355 { "vif",NULL, X86_EFL_VIF },
1356 { "ac", NULL, X86_EFL_AC },
1357 { "vm", NULL, X86_EFL_VM },
1358 { "rf", NULL, X86_EFL_RF },
1359 { "nt", NULL, X86_EFL_NT },
1360 { "ov", "nv", X86_EFL_OF },
1361 { "dn", "up", X86_EFL_DF },
1362 { "ei", "di", X86_EFL_IF },
1363 { "tf", NULL, X86_EFL_TF },
1364 { "ng", "pl", X86_EFL_SF },
1365 { "zr", "nz", X86_EFL_ZF },
1366 { "ac", "na", X86_EFL_AF },
1367 { "po", "pe", X86_EFL_PF },
1368 { "cy", "nc", X86_EFL_CF },
1369 };
1370 char szEFlags[80];
1371 char *psz = szEFlags;
1372 uint32_t efl = pCtxCore->eflags.u32;
1373 for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
1374 {
1375 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
1376 if (pszAdd)
1377 {
1378 strcpy(psz, pszAdd);
1379 psz += strlen(pszAdd);
1380 *psz++ = ' ';
1381 }
1382 }
1383 psz[-1] = '\0';
1384
1385
1386 /*
1387 * Format the registers.
1388 */
1389 if (pDbgc->fRegTerse)
1390 {
1391 if (CPUMIsGuestIn64BitCodeEx(pCtx))
1392 {
1393 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1394 "%srax=%016RX64 %srbx=%016RX64 %srcx=%016RX64 %srdx=%016RX64\n"
1395 "%srsi=%016RX64 %srdi=%016RX64 %sr8 =%016RX64 %sr9 =%016RX64\n"
1396 "%sr10=%016RX64 %sr11=%016RX64 %sr12=%016RX64 %sr13=%016RX64\n"
1397 "%sr14=%016RX64 %sr15=%016RX64\n"
1398 "%srip=%016RX64 %srsp=%016RX64 %srbp=%016RX64 %siopl=%d %*s\n"
1399 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",
1400 pszPrefix, pCtxCore->rax, pszPrefix, pCtxCore->rbx, pszPrefix, pCtxCore->rcx, pszPrefix, pCtxCore->rdx, pszPrefix, pCtxCore->rsi, pszPrefix, pCtxCore->rdi,
1401 pszPrefix, pCtxCore->r8, pszPrefix, pCtxCore->r9, pszPrefix, pCtxCore->r10, pszPrefix, pCtxCore->r11, pszPrefix, pCtxCore->r12, pszPrefix, pCtxCore->r13,
1402 pszPrefix, pCtxCore->r14, pszPrefix, pCtxCore->r15,
1403 pszPrefix, pCtxCore->rip, pszPrefix, pCtxCore->rsp, pszPrefix, pCtxCore->rbp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,
1404 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
1405 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);
1406 }
1407 else
1408 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1409 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
1410 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
1411 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",
1412 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
1413 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,
1414 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
1415 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);
1416 }
1417 else
1418 {
1419 if (CPUMIsGuestIn64BitCodeEx(pCtx))
1420 {
1421 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1422 "%srax=%016RX64 %srbx=%016RX64 %srcx=%016RX64 %srdx=%016RX64\n"
1423 "%srsi=%016RX64 %srdi=%016RX64 %sr8 =%016RX64 %sr9 =%016RX64\n"
1424 "%sr10=%016RX64 %sr11=%016RX64 %sr12=%016RX64 %sr13=%016RX64\n"
1425 "%sr14=%016RX64 %sr15=%016RX64\n"
1426 "%srip=%016RX64 %srsp=%016RX64 %srbp=%016RX64 %siopl=%d %*s\n"
1427 "%scs={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1428 "%sds={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1429 "%ses={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1430 "%sfs={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1431 "%sgs={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1432 "%sss={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1433 "%scr0=%016RX64 %scr2=%016RX64 %scr3=%016RX64 %scr4=%016RX64\n"
1434 "%sdr0=%016RX64 %sdr1=%016RX64 %sdr2=%016RX64 %sdr3=%016RX64\n"
1435 "%sdr4=%016RX64 %sdr5=%016RX64 %sdr6=%016RX64 %sdr7=%016RX64\n"
1436 "%sgdtr=%016RX64:%04x %sidtr=%016RX64:%04x %seflags=%08x\n"
1437 "%sldtr={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1438 "%str ={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1439 "%sSysEnter={cs=%04llx eip=%016RX64 esp=%016RX64}\n"
1440 ,
1441 pszPrefix, pCtxCore->rax, pszPrefix, pCtxCore->rbx, pszPrefix, pCtxCore->rcx, pszPrefix, pCtxCore->rdx, pszPrefix, pCtxCore->rsi, pszPrefix, pCtxCore->rdi,
1442 pszPrefix, pCtxCore->r8, pszPrefix, pCtxCore->r9, pszPrefix, pCtxCore->r10, pszPrefix, pCtxCore->r11, pszPrefix, pCtxCore->r12, pszPrefix, pCtxCore->r13,
1443 pszPrefix, pCtxCore->r14, pszPrefix, pCtxCore->r15,
1444 pszPrefix, pCtxCore->rip, pszPrefix, pCtxCore->rsp, pszPrefix, pCtxCore->rbp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
1445 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u64Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u,
1446 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u64Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u,
1447 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u64Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u,
1448 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u64Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u,
1449 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u64Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u,
1450 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u64Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u,
1451 pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
1452 pszPrefix, pCtx->dr[0], pszPrefix, pCtx->dr[1], pszPrefix, pCtx->dr[2], pszPrefix, pCtx->dr[3],
1453 pszPrefix, pCtx->dr[4], pszPrefix, pCtx->dr[5], pszPrefix, pCtx->dr[6], pszPrefix, pCtx->dr[7],
1454 pszPrefix, pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, efl,
1455 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u64Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
1456 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u64Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
1457 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp);
1458
1459 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1460 "MSR:\n"
1461 "%sEFER =%016RX64\n"
1462 "%sPAT =%016RX64\n"
1463 "%sSTAR =%016RX64\n"
1464 "%sCSTAR =%016RX64\n"
1465 "%sLSTAR =%016RX64\n"
1466 "%sSFMASK =%016RX64\n"
1467 "%sKERNELGSBASE =%016RX64\n",
1468 pszPrefix, pCtx->msrEFER,
1469 pszPrefix, pCtx->msrPAT,
1470 pszPrefix, pCtx->msrSTAR,
1471 pszPrefix, pCtx->msrCSTAR,
1472 pszPrefix, pCtx->msrLSTAR,
1473 pszPrefix, pCtx->msrSFMASK,
1474 pszPrefix, pCtx->msrKERNELGSBASE);
1475 }
1476 else
1477 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1478 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
1479 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
1480 "%scs={%04x base=%016RX64 limit=%08x flags=%08x} %sdr0=%016RX64 %sdr1=%016RX64\n"
1481 "%sds={%04x base=%016RX64 limit=%08x flags=%08x} %sdr2=%016RX64 %sdr3=%016RX64\n"
1482 "%ses={%04x base=%016RX64 limit=%08x flags=%08x} %sdr4=%016RX64 %sdr5=%016RX64\n"
1483 "%sfs={%04x base=%016RX64 limit=%08x flags=%08x} %sdr6=%016RX64 %sdr7=%016RX64\n"
1484 "%sgs={%04x base=%016RX64 limit=%08x flags=%08x} %scr0=%016RX64 %scr2=%016RX64\n"
1485 "%sss={%04x base=%016RX64 limit=%08x flags=%08x} %scr3=%016RX64 %scr4=%016RX64\n"
1486 "%sgdtr=%016RX64:%04x %sidtr=%016RX64:%04x %seflags=%08x\n"
1487 "%sldtr={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1488 "%str ={%04x base=%016RX64 limit=%08x flags=%08x}\n"
1489 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
1490 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"
1491 ,
1492 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
1493 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
1494 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u64Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr[0], pszPrefix, pCtx->dr[1],
1495 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u64Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr[2], pszPrefix, pCtx->dr[3],
1496 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u64Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr[4], pszPrefix, pCtx->dr[5],
1497 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u64Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr[6], pszPrefix, pCtx->dr[7],
1498 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u64Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,
1499 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u64Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
1500 pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,
1501 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u64Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
1502 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u64Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
1503 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
1504 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);
1505 }
1506
1507 /*
1508 * Disassemble one instruction at cs:[r|e]ip.
1509 */
1510 if (CPUMIsGuestIn64BitCodeEx(pCtx))
1511 return pCmdHlp->pfnExec(pCmdHlp, "u %016RX64 L 0", pCtx->rip);
1512 return pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pCtx->cs, pCtx->eip);
1513 }
1514
1515 /*
1516 * cArgs == 1: Show the register.
1517 * cArgs == 2: Modify the register.
1518 */
1519 if ( cArgs == 1
1520 || cArgs == 2)
1521 {
1522 /* locate the register symbol. */
1523 const char *pszReg = paArgs[0].u.pszString;
1524 if ( *pszPrefix
1525 && pszReg[0] != *pszPrefix)
1526 {
1527 /* prepend the prefix. */
1528 char *psz = (char *)alloca(strlen(pszReg) + 2);
1529 psz[0] = *pszPrefix;
1530 strcpy(psz + 1, paArgs[0].u.pszString);
1531 pszReg = psz;
1532 }
1533 PCDBGCSYM pSym = dbgcLookupRegisterSymbol(pDbgc, pszReg);
1534 if (!pSym)
1535 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);
1536
1537 /* show the register */
1538 if (cArgs == 1)
1539 {
1540 DBGCVAR Var;
1541 memset(&Var, 0, sizeof(Var));
1542 int rc = pSym->pfnGet(pSym, pCmdHlp, DBGCVAR_TYPE_NUMBER, &Var);
1543 if (RT_FAILURE(rc))
1544 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed getting value for register '%s'.\n", pszReg);
1545 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s=%Dv\n", pszReg, &Var);
1546 }
1547
1548 /* change the register */
1549 int rc = pSym->pfnSet(pSym, pCmdHlp, &paArgs[1]);
1550 if (RT_FAILURE(rc))
1551 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed setting value for register '%s'.\n", pszReg);
1552 return VINF_SUCCESS;
1553 }
1554
1555
1556 NOREF(pCmd); NOREF(paArgs); NOREF(pResult);
1557 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Huh? cArgs=%d Expected 0, 1 or 2!\n", cArgs);
1558}
1559
1560
1561/**
1562 * The 'rg' command.
1563 *
1564 * @returns VBox status.
1565 * @param pCmd Pointer to the command descriptor (as registered).
1566 * @param pCmdHlp Pointer to command helper functions.
1567 * @param pVM Pointer to the current VM (if any).
1568 * @param paArgs Pointer to (readonly) array of arguments.
1569 * @param cArgs Number of arguments in the array.
1570 */
1571static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1572{
1573 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, "");
1574}
1575
1576
1577/**
1578 * The 'rh' command.
1579 *
1580 * @returns VBox status.
1581 * @param pCmd Pointer to the command descriptor (as registered).
1582 * @param pCmdHlp Pointer to command helper functions.
1583 * @param pVM Pointer to the current VM (if any).
1584 * @param paArgs Pointer to (readonly) array of arguments.
1585 * @param cArgs Number of arguments in the array.
1586 */
1587static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1588{
1589 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, ".");
1590}
1591
1592
1593/**
1594 * The 'rt' command.
1595 *
1596 * @returns VBox status.
1597 * @param pCmd Pointer to the command descriptor (as registered).
1598 * @param pCmdHlp Pointer to command helper functions.
1599 * @param pVM Pointer to the current VM (if any).
1600 * @param paArgs Pointer to (readonly) array of arguments.
1601 * @param cArgs Number of arguments in the array.
1602 */
1603static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1604{
1605 NOREF(pCmd); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1606
1607 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1608 pDbgc->fRegTerse = !pDbgc->fRegTerse;
1609 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");
1610}
1611
1612
1613/**
1614 * The 't' command.
1615 *
1616 * @returns VBox status.
1617 * @param pCmd Pointer to the command descriptor (as registered).
1618 * @param pCmdHlp Pointer to command helper functions.
1619 * @param pVM Pointer to the current VM (if any).
1620 * @param paArgs Pointer to (readonly) array of arguments.
1621 * @param cArgs Number of arguments in the array.
1622 */
1623static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1624{
1625 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1626
1627 int rc = DBGFR3Step(pVM, pDbgc->idCpu);
1628 if (RT_SUCCESS(rc))
1629 pDbgc->fReady = false;
1630 else
1631 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);
1632
1633 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1634 return rc;
1635}
1636
1637
1638/**
1639 * The 'k', 'kg' and 'kh' commands.
1640 *
1641 * @returns VBox status.
1642 * @param pCmd Pointer to the command descriptor (as registered).
1643 * @param pCmdHlp Pointer to command helper functions.
1644 * @param pVM Pointer to the current VM (if any).
1645 * @param paArgs Pointer to (readonly) array of arguments.
1646 * @param cArgs Number of arguments in the array.
1647 */
1648static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1649{
1650 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1651
1652 /*
1653 * Figure which context we're called for and start walking that stack.
1654 */
1655 int rc;
1656 PCDBGFSTACKFRAME pFirstFrame;
1657 bool const fGuest = pCmd->pszCmd[1] == 'g'
1658 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest);
1659 rc = DBGFR3StackWalkBegin(pVM, pDbgc->idCpu, fGuest ? DBGFCODETYPE_GUEST : DBGFCODETYPE_HYPER, &pFirstFrame);
1660 if (RT_FAILURE(rc))
1661 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to begin stack walk, rc=%Rrc\n", rc);
1662
1663 /*
1664 * Print header.
1665 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol
1666 */
1667 uint32_t fBitFlags = 0;
1668 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1669 pFrame;
1670 pFrame = DBGFR3StackWalkNext(pFrame))
1671 {
1672 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1673 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1674 {
1675 if (fCurBitFlags != fBitFlags)
1676 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1677 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1678 pFrame->AddrFrame.Sel,
1679 (uint16_t)pFrame->AddrFrame.off,
1680 pFrame->AddrReturnFrame.Sel,
1681 (uint16_t)pFrame->AddrReturnFrame.off,
1682 (uint32_t)pFrame->AddrReturnPC.Sel,
1683 (uint32_t)pFrame->AddrReturnPC.off,
1684 pFrame->Args.au32[0],
1685 pFrame->Args.au32[1],
1686 pFrame->Args.au32[2],
1687 pFrame->Args.au32[3]);
1688 }
1689 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1690 {
1691 if (fCurBitFlags != fBitFlags)
1692 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1693 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1694 (uint32_t)pFrame->AddrFrame.off,
1695 (uint32_t)pFrame->AddrReturnFrame.off,
1696 (uint32_t)pFrame->AddrReturnPC.Sel,
1697 (uint32_t)pFrame->AddrReturnPC.off,
1698 pFrame->Args.au32[0],
1699 pFrame->Args.au32[1],
1700 pFrame->Args.au32[2],
1701 pFrame->Args.au32[3]);
1702 }
1703 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1704 {
1705 if (fCurBitFlags != fBitFlags)
1706 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
1707 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%016RX64 %04RX16:%016RX64 %016RX64",
1708 (uint64_t)pFrame->AddrFrame.off,
1709 pFrame->AddrReturnFrame.Sel,
1710 (uint64_t)pFrame->AddrReturnFrame.off,
1711 (uint64_t)pFrame->AddrReturnPC.off);
1712 }
1713 if (RT_FAILURE(rc))
1714 break;
1715 if (!pFrame->pSymPC)
1716 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1717 fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1718 ? " %RTsel:%016RGv"
1719 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1720 ? " %RTsel:%08RGv"
1721 : " %RTsel:%04RGv"
1722 , pFrame->AddrPC.Sel, pFrame->AddrPC.off);
1723 else
1724 {
1725 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */
1726 if (offDisp > 0)
1727 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
1728 else if (offDisp < 0)
1729 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
1730 else
1731 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s", pFrame->pSymPC->szName);
1732 }
1733 if (RT_SUCCESS(rc) && pFrame->pLinePC)
1734 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
1735 if (RT_SUCCESS(rc))
1736 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
1737 if (RT_FAILURE(rc))
1738 break;
1739
1740 fBitFlags = fCurBitFlags;
1741 }
1742
1743 DBGFR3StackWalkEnd(pFirstFrame);
1744
1745 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1746 return rc;
1747}
1748
1749
1750static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP pCmdHlp, PCX86DESC64 pDesc, unsigned iEntry, bool fHyper, bool *pfDblEntry)
1751{
1752 /* GUEST64 */
1753 int rc;
1754
1755 const char *pszHyper = fHyper ? " HYPER" : "";
1756 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";
1757 if (pDesc->Gen.u1DescType)
1758 {
1759 static const char * const s_apszTypes[] =
1760 {
1761 "DataRO", /* 0 Read-Only */
1762 "DataRO", /* 1 Read-Only - Accessed */
1763 "DataRW", /* 2 Read/Write */
1764 "DataRW", /* 3 Read/Write - Accessed */
1765 "DownRO", /* 4 Expand-down, Read-Only */
1766 "DownRO", /* 5 Expand-down, Read-Only - Accessed */
1767 "DownRW", /* 6 Expand-down, Read/Write */
1768 "DownRO", /* 7 Expand-down, Read/Write - Accessed */
1769 "CodeEO", /* 8 Execute-Only */
1770 "CodeEO", /* 9 Execute-Only - Accessed */
1771 "CodeER", /* A Execute/Readable */
1772 "CodeER", /* B Execute/Readable - Accessed */
1773 "ConfE0", /* C Conforming, Execute-Only */
1774 "ConfE0", /* D Conforming, Execute-Only - Accessed */
1775 "ConfER", /* E Conforming, Execute/Readable */
1776 "ConfER" /* F Conforming, Execute/Readable - Accessed */
1777 };
1778 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";
1779 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
1780 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1781 uint32_t u32Base = X86DESC_BASE(*pDesc);
1782 uint32_t cbLimit = X86DESC_LIMIT(*pDesc);
1783 if (pDesc->Gen.u1Granularity)
1784 cbLimit <<= PAGE_SHIFT;
1785
1786 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n",
1787 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1788 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,
1789 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper);
1790 }
1791 else
1792 {
1793 static const char * const s_apszTypes[] =
1794 {
1795 "Ill-0 ", /* 0 0000 Reserved (Illegal) */
1796 "Ill-1 ", /* 1 0001 Available 16-bit TSS */
1797 "LDT ", /* 2 0010 LDT */
1798 "Ill-3 ", /* 3 0011 Busy 16-bit TSS */
1799 "Ill-4 ", /* 4 0100 16-bit Call Gate */
1800 "Ill-5 ", /* 5 0101 Task Gate */
1801 "Ill-6 ", /* 6 0110 16-bit Interrupt Gate */
1802 "Ill-7 ", /* 7 0111 16-bit Trap Gate */
1803 "Ill-8 ", /* 8 1000 Reserved (Illegal) */
1804 "Tss64A", /* 9 1001 Available 32-bit TSS */
1805 "Ill-A ", /* A 1010 Reserved (Illegal) */
1806 "Tss64B", /* B 1011 Busy 32-bit TSS */
1807 "Call64", /* C 1100 32-bit Call Gate */
1808 "Ill-D ", /* D 1101 Reserved (Illegal) */
1809 "Int64 ", /* E 1110 32-bit Interrupt Gate */
1810 "Trap64" /* F 1111 32-bit Trap Gate */
1811 };
1812 switch (pDesc->Gen.u4Type)
1813 {
1814 /* raw */
1815 case X86_SEL_TYPE_SYS_UNDEFINED:
1816 case X86_SEL_TYPE_SYS_UNDEFINED2:
1817 case X86_SEL_TYPE_SYS_UNDEFINED4:
1818 case X86_SEL_TYPE_SYS_UNDEFINED3:
1819 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
1820 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1821 case X86_SEL_TYPE_SYS_286_CALL_GATE:
1822 case X86_SEL_TYPE_SYS_286_INT_GATE:
1823 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
1824 case X86_SEL_TYPE_SYS_TASK_GATE:
1825 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs DPL=%d %s%s\n",
1826 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,
1827 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1828 break;
1829
1830 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
1831 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1832 case X86_SEL_TYPE_SYS_LDT:
1833 {
1834 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";
1835 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1836 const char *pszLong = pDesc->Gen.u1Long ? "LONG" : " ";
1837
1838 uint64_t u32Base = X86DESC64_BASE(*pDesc);
1839 uint32_t cbLimit = X86DESC_LIMIT(*pDesc);
1840
1841 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%016RX64 Lim=%08x DPL=%d %s %s %s %sAVL=%d R=%d%s\n",
1842 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1843 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszLong, pszBig,
1844 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1),
1845 pszHyper);
1846 if (pfDblEntry)
1847 *pfDblEntry = true;
1848 break;
1849 }
1850
1851 case X86_SEL_TYPE_SYS_386_CALL_GATE:
1852 {
1853 unsigned cParams = pDesc->au8[4] & 0x1f;
1854 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";
1855 RTSEL sel = pDesc->au16[1];
1856 uint64_t off = pDesc->au16[0]
1857 | ((uint64_t)pDesc->au16[3] << 16)
1858 | ((uint64_t)pDesc->Gen.u32BaseHigh3 << 32);
1859 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%016RX64 DPL=%d %s %s=%d%s\n",
1860 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
1861 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);
1862 if (pfDblEntry)
1863 *pfDblEntry = true;
1864 break;
1865 }
1866
1867 case X86_SEL_TYPE_SYS_386_INT_GATE:
1868 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
1869 {
1870 RTSEL sel = pDesc->au16[1];
1871 uint64_t off = pDesc->au16[0]
1872 | ((uint64_t)pDesc->au16[3] << 16)
1873 | ((uint64_t)pDesc->Gen.u32BaseHigh3 << 32);
1874 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%016RX64 DPL=%d %s%s\n",
1875 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
1876 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1877 if (pfDblEntry)
1878 *pfDblEntry = true;
1879 break;
1880 }
1881
1882 /* impossible, just it's necessary to keep gcc happy. */
1883 default:
1884 return VINF_SUCCESS;
1885 }
1886 }
1887 return VINF_SUCCESS;
1888}
1889
1890
1891/**
1892 * Worker function that displays one descriptor entry (GDT, LDT, IDT).
1893 *
1894 * @returns pfnPrintf status code.
1895 * @param pCmdHlp The DBGC command helpers.
1896 * @param pDesc The descriptor to display.
1897 * @param iEntry The descriptor entry number.
1898 * @param fHyper Whether the selector belongs to the hypervisor or not.
1899 */
1900static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper)
1901{
1902 int rc;
1903
1904 const char *pszHyper = fHyper ? " HYPER" : "";
1905 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";
1906 if (pDesc->Gen.u1DescType)
1907 {
1908 static const char * const s_apszTypes[] =
1909 {
1910 "DataRO", /* 0 Read-Only */
1911 "DataRO", /* 1 Read-Only - Accessed */
1912 "DataRW", /* 2 Read/Write */
1913 "DataRW", /* 3 Read/Write - Accessed */
1914 "DownRO", /* 4 Expand-down, Read-Only */
1915 "DownRO", /* 5 Expand-down, Read-Only - Accessed */
1916 "DownRW", /* 6 Expand-down, Read/Write */
1917 "DownRO", /* 7 Expand-down, Read/Write - Accessed */
1918 "CodeEO", /* 8 Execute-Only */
1919 "CodeEO", /* 9 Execute-Only - Accessed */
1920 "CodeER", /* A Execute/Readable */
1921 "CodeER", /* B Execute/Readable - Accessed */
1922 "ConfE0", /* C Conforming, Execute-Only */
1923 "ConfE0", /* D Conforming, Execute-Only - Accessed */
1924 "ConfER", /* E Conforming, Execute/Readable */
1925 "ConfER" /* F Conforming, Execute/Readable - Accessed */
1926 };
1927 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";
1928 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
1929 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1930 uint32_t u32Base = pDesc->Gen.u16BaseLow
1931 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
1932 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
1933 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
1934 if (pDesc->Gen.u1Granularity)
1935 cbLimit <<= PAGE_SHIFT;
1936
1937 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n",
1938 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1939 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,
1940 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper);
1941 }
1942 else
1943 {
1944 static const char * const s_apszTypes[] =
1945 {
1946 "Ill-0 ", /* 0 0000 Reserved (Illegal) */
1947 "Tss16A", /* 1 0001 Available 16-bit TSS */
1948 "LDT ", /* 2 0010 LDT */
1949 "Tss16B", /* 3 0011 Busy 16-bit TSS */
1950 "Call16", /* 4 0100 16-bit Call Gate */
1951 "TaskG ", /* 5 0101 Task Gate */
1952 "Int16 ", /* 6 0110 16-bit Interrupt Gate */
1953 "Trap16", /* 7 0111 16-bit Trap Gate */
1954 "Ill-8 ", /* 8 1000 Reserved (Illegal) */
1955 "Tss32A", /* 9 1001 Available 32-bit TSS */
1956 "Ill-A ", /* A 1010 Reserved (Illegal) */
1957 "Tss32B", /* B 1011 Busy 32-bit TSS */
1958 "Call32", /* C 1100 32-bit Call Gate */
1959 "Ill-D ", /* D 1101 Reserved (Illegal) */
1960 "Int32 ", /* E 1110 32-bit Interrupt Gate */
1961 "Trap32" /* F 1111 32-bit Trap Gate */
1962 };
1963 switch (pDesc->Gen.u4Type)
1964 {
1965 /* raw */
1966 case X86_SEL_TYPE_SYS_UNDEFINED:
1967 case X86_SEL_TYPE_SYS_UNDEFINED2:
1968 case X86_SEL_TYPE_SYS_UNDEFINED4:
1969 case X86_SEL_TYPE_SYS_UNDEFINED3:
1970 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs DPL=%d %s%s\n",
1971 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,
1972 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1973 break;
1974
1975 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
1976 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
1977 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1978 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1979 case X86_SEL_TYPE_SYS_LDT:
1980 {
1981 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
1982 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";
1983 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1984 uint32_t u32Base = pDesc->Gen.u16BaseLow
1985 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
1986 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
1987 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
1988 if (pDesc->Gen.u1Granularity)
1989 cbLimit <<= PAGE_SHIFT;
1990
1991 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",
1992 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1993 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig,
1994 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1),
1995 pszHyper);
1996 break;
1997 }
1998
1999 case X86_SEL_TYPE_SYS_TASK_GATE:
2000 {
2001 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s TSS=%04x DPL=%d %s%s\n",
2002 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1],
2003 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
2004 break;
2005 }
2006
2007 case X86_SEL_TYPE_SYS_286_CALL_GATE:
2008 case X86_SEL_TYPE_SYS_386_CALL_GATE:
2009 {
2010 unsigned cParams = pDesc->au8[4] & 0x1f;
2011 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";
2012 RTSEL sel = pDesc->au16[1];
2013 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
2014 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n",
2015 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
2016 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);
2017 break;
2018 }
2019
2020 case X86_SEL_TYPE_SYS_286_INT_GATE:
2021 case X86_SEL_TYPE_SYS_386_INT_GATE:
2022 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
2023 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
2024 {
2025 RTSEL sel = pDesc->au16[1];
2026 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
2027 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n",
2028 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
2029 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
2030 break;
2031 }
2032
2033 /* impossible, just it's necessary to keep gcc happy. */
2034 default:
2035 return VINF_SUCCESS;
2036 }
2037 }
2038 return rc;
2039}
2040
2041
2042/**
2043 * The 'dg', 'dga', 'dl' and 'dla' commands.
2044 *
2045 * @returns VBox status.
2046 * @param pCmd Pointer to the command descriptor (as registered).
2047 * @param pCmdHlp Pointer to command helper functions.
2048 * @param pVM Pointer to the current VM (if any).
2049 * @param paArgs Pointer to (readonly) array of arguments.
2050 * @param cArgs Number of arguments in the array.
2051 */
2052static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2053{
2054 /*
2055 * Validate input.
2056 */
2057 if (!pVM)
2058 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2059
2060 /*
2061 * Get the CPU mode, check which command variation this is
2062 * and fix a default parameter if needed.
2063 */
2064 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2065 PVMCPU pVCpu = VMMGetCpuById(pVM, pDbgc->idCpu);
2066 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu);
2067 bool fGdt = pCmd->pszCmd[1] == 'g';
2068 bool fAll = pCmd->pszCmd[2] == 'a';
2069 RTSEL SelTable = fGdt ? 0 : X86_SEL_LDT;
2070
2071 DBGCVAR Var;
2072 if (!cArgs)
2073 {
2074 cArgs = 1;
2075 paArgs = &Var;
2076 Var.enmType = DBGCVAR_TYPE_NUMBER;
2077 Var.u.u64Number = 0;
2078 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
2079 Var.u64Range = 1024;
2080 }
2081
2082 /*
2083 * Process the arguments.
2084 */
2085 for (unsigned i = 0; i < cArgs; i++)
2086 {
2087 /*
2088 * Retrive the selector value from the argument.
2089 * The parser may confuse pointers and numbers if more than one
2090 * argument is given, that that into account.
2091 */
2092 /* check that what've got makes sense as we don't trust the parser yet. */
2093 if ( paArgs[i].enmType != DBGCVAR_TYPE_NUMBER
2094 && !DBGCVAR_ISPOINTER(paArgs[i].enmType))
2095 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number or pointer type but %d.\n", i, paArgs[i].enmType);
2096 uint64_t u64;
2097 unsigned cSels = 1;
2098 switch (paArgs[i].enmType)
2099 {
2100 case DBGCVAR_TYPE_NUMBER:
2101 u64 = paArgs[i].u.u64Number;
2102 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE)
2103 cSels = RT_MIN(paArgs[i].u64Range, 1024);
2104 break;
2105 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break;
2106 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break;
2107 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break;
2108 case DBGCVAR_TYPE_HC_FAR: u64 = paArgs[i].u.HCFar.sel; break;
2109 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break;
2110 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break;
2111 default: u64 = _64K; break;
2112 }
2113 if (u64 < _64K)
2114 {
2115 unsigned Sel = (RTSEL)u64;
2116
2117 /*
2118 * Dump the specified range.
2119 */
2120 bool fSingle = cSels == 1;
2121 while ( cSels-- > 0
2122 && Sel < _64K)
2123 {
2124 DBGFSELINFO SelInfo;
2125 int rc = DBGFR3SelQueryInfo(pVM, pDbgc->idCpu, Sel | SelTable, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo);
2126 if (RT_SUCCESS(rc))
2127 {
2128 if (SelInfo.fFlags & DBGFSELINFO_FLAGS_REAL_MODE)
2129 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x RealM Bas=%04x Lim=%04x\n",
2130 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit);
2131 else if ( fAll
2132 || fSingle
2133 || SelInfo.u.Raw.Gen.u1Present)
2134 {
2135 if (enmMode == CPUMMODE_PROTECTED)
2136 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &SelInfo.u.Raw, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER));
2137 else
2138 {
2139 bool fDblSkip = false;
2140 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &SelInfo.u.Raw64, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER), &fDblSkip);
2141 if (fDblSkip)
2142 Sel += 4;
2143 }
2144 }
2145 }
2146 else
2147 {
2148 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %Rrc\n", Sel, rc);
2149 if (!fAll)
2150 return rc;
2151 }
2152 if (RT_FAILURE(rc))
2153 return rc;
2154
2155 /* next */
2156 Sel += 8;
2157 }
2158 }
2159 else
2160 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds\n", u64);
2161 }
2162
2163 NOREF(pResult);
2164 return VINF_SUCCESS;
2165}
2166
2167
2168/**
2169 * The 'di' and 'dia' commands.
2170 *
2171 * @returns VBox status.
2172 * @param pCmd Pointer to the command descriptor (as registered).
2173 * @param pCmdHlp Pointer to command helper functions.
2174 * @param pVM Pointer to the current VM (if any).
2175 * @param paArgs Pointer to (readonly) array of arguments.
2176 * @param cArgs Number of arguments in the array.
2177 */
2178static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2179{
2180 /*
2181 * Validate input.
2182 */
2183 if (!pVM)
2184 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2185
2186 /*
2187 * Establish some stuff like the current IDTR and CPU mode,
2188 * and fix a default parameter.
2189 */
2190 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2191 PVMCPU pVCpu = VMMGetCpuById(pVM, pDbgc->idCpu);
2192 uint16_t cbLimit;
2193 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVCpu, &cbLimit);
2194 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu);
2195 unsigned cbEntry;
2196 switch (enmMode)
2197 {
2198 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break;
2199 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break;
2200 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break;
2201 default:
2202 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid CPU mode %d.\n", enmMode);
2203 }
2204
2205 bool fAll = pCmd->pszCmd[2] == 'a';
2206 DBGCVAR Var;
2207 if (!cArgs)
2208 {
2209 cArgs = 1;
2210 paArgs = &Var;
2211 Var.enmType = DBGCVAR_TYPE_NUMBER;
2212 Var.u.u64Number = 0;
2213 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
2214 Var.u64Range = 256;
2215 }
2216
2217 /*
2218 * Process the arguments.
2219 */
2220 for (unsigned i = 0; i < cArgs; i++)
2221 {
2222 /* check that what've got makes sense as we don't trust the parser yet. */
2223 if (paArgs[i].enmType != DBGCVAR_TYPE_NUMBER)
2224 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number type but %d.\n", i, paArgs[i].enmType);
2225 if (paArgs[i].u.u64Number < 256)
2226 {
2227 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number;
2228 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE
2229 ? paArgs[i].u64Range
2230 : 1;
2231 bool fSingle = cInts == 1;
2232 while ( cInts-- > 0
2233 && iInt < 256)
2234 {
2235 /*
2236 * Try read it.
2237 */
2238 union
2239 {
2240 RTFAR16 Real;
2241 X86DESC Prot;
2242 X86DESC64 Long;
2243 } u;
2244 if (iInt * cbEntry + (cbEntry - 1) > cbLimit)
2245 {
2246 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x not within the IDT\n", (unsigned)iInt);
2247 if (!fAll && !fSingle)
2248 return VINF_SUCCESS;
2249 }
2250 DBGCVAR AddrVar;
2251 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT;
2252 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry;
2253 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE;
2254 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &u, cbEntry, &AddrVar, NULL);
2255 if (RT_FAILURE(rc))
2256 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt);
2257
2258 /*
2259 * Display it.
2260 */
2261 switch (enmMode)
2262 {
2263 case CPUMMODE_REAL:
2264 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %RTfp16\n", (unsigned)iInt, u.Real);
2265 /** @todo resolve 16:16 IDTE to a symbol */
2266 break;
2267 case CPUMMODE_PROTECTED:
2268 if (fAll || fSingle || u.Prot.Gen.u1Present)
2269 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false);
2270 break;
2271 case CPUMMODE_LONG:
2272 if (fAll || fSingle || u.Long.Gen.u1Present)
2273 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL);
2274 break;
2275 default: break; /* to shut up gcc */
2276 }
2277 if (RT_FAILURE(rc))
2278 return rc;
2279
2280 /* next */
2281 iInt++;
2282 }
2283 }
2284 else
2285 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number);
2286 }
2287
2288 NOREF(pResult);
2289 return VINF_SUCCESS;
2290}
2291
2292
2293/**
2294 * The 'da', 'dq', 'dd', 'dw' and 'db' commands.
2295 *
2296 * @returns VBox status.
2297 * @param pCmd Pointer to the command descriptor (as registered).
2298 * @param pCmdHlp Pointer to command helper functions.
2299 * @param pVM Pointer to the current VM (if any).
2300 * @param paArgs Pointer to (readonly) array of arguments.
2301 * @param cArgs Number of arguments in the array.
2302 */
2303static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2304{
2305 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2306
2307 /*
2308 * Validate input.
2309 */
2310 if ( cArgs > 1
2311 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2312 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2313 if (!pVM)
2314 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2315
2316 /*
2317 * Figure out the element size.
2318 */
2319 unsigned cbElement;
2320 bool fAscii = false;
2321 switch (pCmd->pszCmd[1])
2322 {
2323 default:
2324 case 'b': cbElement = 1; break;
2325 case 'w': cbElement = 2; break;
2326 case 'd': cbElement = 4; break;
2327 case 'q': cbElement = 8; break;
2328 case 'a':
2329 cbElement = 1;
2330 fAscii = true;
2331 break;
2332 case '\0':
2333 fAscii = !!(pDbgc->cbDumpElement & 0x80000000);
2334 cbElement = pDbgc->cbDumpElement & 0x7fffffff;
2335 if (!cbElement)
2336 cbElement = 1;
2337 break;
2338 }
2339
2340 /*
2341 * Find address.
2342 */
2343 if (!cArgs)
2344 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE;
2345 else
2346 pDbgc->DumpPos = paArgs[0];
2347
2348 /*
2349 * Range.
2350 */
2351 switch (pDbgc->DumpPos.enmRangeType)
2352 {
2353 case DBGCVAR_RANGE_NONE:
2354 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
2355 pDbgc->DumpPos.u64Range = 0x60;
2356 break;
2357
2358 case DBGCVAR_RANGE_ELEMENTS:
2359 if (pDbgc->DumpPos.u64Range > 2048)
2360 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");
2361 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
2362 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range;
2363 break;
2364
2365 case DBGCVAR_RANGE_BYTES:
2366 if (pDbgc->DumpPos.u64Range > 65536)
2367 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
2368 break;
2369
2370 default:
2371 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);
2372 }
2373
2374 /*
2375 * Do the dumping.
2376 */
2377 pDbgc->cbDumpElement = cbElement | (fAscii << 31);
2378 int cbLeft = (int)pDbgc->DumpPos.u64Range;
2379 uint8_t u8Prev = '\0';
2380 for (;;)
2381 {
2382 /*
2383 * Read memory.
2384 */
2385 char achBuffer[16];
2386 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft);
2387 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft);
2388 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &achBuffer, cbReq, &pDbgc->DumpPos, &cb);
2389 if (RT_FAILURE(rc))
2390 {
2391 if (u8Prev && u8Prev != '\n')
2392 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2393 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos);
2394 }
2395
2396 /*
2397 * Display it.
2398 */
2399 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb);
2400 if (!fAscii)
2401 {
2402 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:", &pDbgc->DumpPos);
2403 unsigned i;
2404 for (i = 0; i < cb; i += cbElement)
2405 {
2406 const char *pszSpace = " ";
2407 if (cbElement <= 2 && i == 8 && !fAscii)
2408 pszSpace = "-";
2409 switch (cbElement)
2410 {
2411 case 1: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break;
2412 case 2: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break;
2413 case 4: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break;
2414 case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;
2415 }
2416 }
2417
2418 /* chars column */
2419 if (pDbgc->cbDumpElement == 1)
2420 {
2421 while (i++ < sizeof(achBuffer))
2422 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");
2423 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");
2424 for (i = 0; i < cb; i += cbElement)
2425 {
2426 uint8_t u8 = *(uint8_t *)&achBuffer[i];
2427 if (RT_C_IS_PRINT(u8) && u8 < 127 && u8 >= 32)
2428 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
2429 else
2430 pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");
2431 }
2432 }
2433 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2434 }
2435 else
2436 {
2437 /*
2438 * We print up to the first zero and stop there.
2439 * Only printables + '\t' and '\n' are printed.
2440 */
2441 if (!u8Prev)
2442 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DumpPos);
2443 uint8_t u8 = '\0';
2444 unsigned i;
2445 for (i = 0; i < cb; i++)
2446 {
2447 u8Prev = u8;
2448 u8 = *(uint8_t *)&achBuffer[i];
2449 if ( u8 < 127
2450 && ( (RT_C_IS_PRINT(u8) && u8 >= 32)
2451 || u8 == '\t'
2452 || u8 == '\n'))
2453 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
2454 else if (!u8)
2455 break;
2456 else
2457 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\\x%x", u8);
2458 }
2459 if (u8 == '\0')
2460 cb = cbLeft = i + 1;
2461 if (cbLeft - cb <= 0 && u8Prev != '\n')
2462 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2463 }
2464
2465 /*
2466 * Advance
2467 */
2468 cbLeft -= (int)cb;
2469 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb);
2470 if (RT_FAILURE(rc))
2471 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb);
2472 if (cbLeft <= 0)
2473 break;
2474 }
2475
2476 NOREF(pCmd); NOREF(pResult);
2477 return VINF_SUCCESS;
2478}
2479
2480
2481/**
2482 * Best guess at which paging mode currently applies to the guest
2483 * paging structures.
2484 *
2485 * This have to come up with a decent answer even when the guest
2486 * is in non-paged protected mode or real mode.
2487 *
2488 * @returns cr3.
2489 * @param pDbgc The DBGC instance.
2490 * @param pfPAE Where to store the page address extension indicator.
2491 * @param pfLME Where to store the long mode enabled indicator.
2492 * @param pfPSE Where to store the page size extension indicator.
2493 * @param pfPGE Where to store the page global enabled indicator.
2494 * @param pfNXE Where to store the no-execution enabled inidicator.
2495 */
2496static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
2497{
2498 PVMCPU pVCpu = VMMGetCpuById(pDbgc->pVM, pDbgc->idCpu);
2499 RTGCUINTREG cr4 = CPUMGetGuestCR4(pVCpu);
2500 *pfPSE = !!(cr4 & X86_CR4_PSE);
2501 *pfPGE = !!(cr4 & X86_CR4_PGE);
2502 if (cr4 & X86_CR4_PAE)
2503 {
2504 *pfPSE = true;
2505 *pfPAE = true;
2506 }
2507 else
2508 *pfPAE = false;
2509
2510 *pfLME = CPUMGetGuestMode(pVCpu) == CPUMMODE_LONG;
2511 *pfNXE = false; /* GUEST64 GUESTNX */
2512 return CPUMGetGuestCR3(pVCpu);
2513}
2514
2515
2516/**
2517 * Determine the shadow paging mode.
2518 *
2519 * @returns cr3.
2520 * @param pDbgc The DBGC instance.
2521 * @param pfPAE Where to store the page address extension indicator.
2522 * @param pfLME Where to store the long mode enabled indicator.
2523 * @param pfPSE Where to store the page size extension indicator.
2524 * @param pfPGE Where to store the page global enabled indicator.
2525 * @param pfNXE Where to store the no-execution enabled inidicator.
2526 */
2527static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
2528{
2529 PVMCPU pVCpu = VMMGetCpuById(pDbgc->pVM, pDbgc->idCpu);
2530
2531 *pfPSE = true;
2532 *pfPGE = false;
2533 switch (PGMGetShadowMode(pVCpu))
2534 {
2535 default:
2536 case PGMMODE_32_BIT:
2537 *pfPAE = *pfLME = *pfNXE = false;
2538 break;
2539 case PGMMODE_PAE:
2540 *pfLME = *pfNXE = false;
2541 *pfPAE = true;
2542 break;
2543 case PGMMODE_PAE_NX:
2544 *pfLME = false;
2545 *pfPAE = *pfNXE = true;
2546 break;
2547 case PGMMODE_AMD64:
2548 *pfNXE = false;
2549 *pfPAE = *pfLME = true;
2550 break;
2551 case PGMMODE_AMD64_NX:
2552 *pfPAE = *pfLME = *pfNXE = true;
2553 break;
2554 }
2555 return PGMGetHyperCR3(pVCpu);
2556}
2557
2558
2559/**
2560 * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands.
2561 *
2562 * @returns VBox status.
2563 * @param pCmd Pointer to the command descriptor (as registered).
2564 * @param pCmdHlp Pointer to command helper functions.
2565 * @param pVM Pointer to the current VM (if any).
2566 * @param paArgs Pointer to (readonly) array of arguments.
2567 * @param cArgs Number of arguments in the array.
2568 */
2569static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2570{
2571 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2572
2573 /*
2574 * Validate input.
2575 */
2576 if ( cArgs > 1
2577 || (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
2578 || (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2579 )
2580 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2581 if (!pVM)
2582 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2583
2584 /*
2585 * Guest or shadow page directories? Get the paging parameters.
2586 */
2587 bool fGuest = pCmd->pszCmd[3] != 'h';
2588 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
2589 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
2590 ? pDbgc->fRegCtxGuest
2591 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
2592
2593 bool fPAE, fLME, fPSE, fPGE, fNXE;
2594 uint64_t cr3 = fGuest
2595 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
2596 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
2597 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
2598
2599 /*
2600 * Setup default arugment if none was specified.
2601 * Fix address / index confusion.
2602 */
2603 DBGCVAR VarDefault;
2604 if (!cArgs)
2605 {
2606 if (pCmd->pszCmd[3] == 'a')
2607 {
2608 if (fLME || fPAE)
2609 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n");
2610 if (fGuest)
2611 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3);
2612 else
2613 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3);
2614 }
2615 else
2616 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0);
2617 paArgs = &VarDefault;
2618 cArgs = 1;
2619 }
2620 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)
2621 {
2622 Assert(pCmd->pszCmd[3] != 'a');
2623 VarDefault = paArgs[0];
2624 if (VarDefault.u.u64Number <= 1024)
2625 {
2626 if (fPAE)
2627 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n");
2628 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry)
2629 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1);
2630 VarDefault.u.u64Number <<= X86_PD_SHIFT;
2631 }
2632 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT;
2633 paArgs = &VarDefault;
2634 }
2635
2636 /*
2637 * Locate the PDE to start displaying at.
2638 *
2639 * The 'dpda' command takes the address of a PDE, while the others are guest
2640 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple
2641 * while the others require us to do all the tedious walking thru the paging
2642 * hierarchy to find the intended PDE.
2643 */
2644 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */
2645 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */
2646 DBGCVAR VarPDEAddr; /* The address of the current PDE. */
2647 unsigned cEntries; /* The number of entries to display. */
2648 unsigned cEntriesMax; /* The max number of entries to display. */
2649 int rc;
2650 if (pCmd->pszCmd[3] == 'a')
2651 {
2652 VarPDEAddr = paArgs[0];
2653 switch (VarPDEAddr.enmRangeType)
2654 {
2655 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break;
2656 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break;
2657 default: cEntries = 10; break;
2658 }
2659 cEntriesMax = PAGE_SIZE / cbEntry;
2660 }
2661 else
2662 {
2663 /*
2664 * Determin the range.
2665 */
2666 switch (paArgs[0].enmRangeType)
2667 {
2668 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
2669 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;
2670 default: cEntries = 10; break;
2671 }
2672
2673 /*
2674 * Normalize the input address, it must be a flat GC address.
2675 */
2676 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
2677 if (RT_FAILURE(rc))
2678 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
2679 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
2680 {
2681 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
2682 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
2683 }
2684 if (fPAE)
2685 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1);
2686 else
2687 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1);
2688
2689 /*
2690 * Do the paging walk until we get to the page directory.
2691 */
2692 DBGCVAR VarCur;
2693 if (fGuest)
2694 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
2695 else
2696 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
2697 if (fLME)
2698 {
2699 /* Page Map Level 4 Lookup. */
2700 /* Check if it's a valid address first? */
2701 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
2702 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
2703 X86PML4E Pml4e;
2704 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
2705 if (RT_FAILURE(rc))
2706 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
2707 if (!Pml4e.n.u1Present)
2708 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
2709
2710 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
2711 Assert(fPAE);
2712 }
2713 if (fPAE)
2714 {
2715 /* Page directory pointer table. */
2716 X86PDPE Pdpe;
2717 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe);
2718 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
2719 if (RT_FAILURE(rc))
2720 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
2721 if (!Pdpe.n.u1Present)
2722 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
2723
2724 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
2725 VarPDEAddr = VarCur;
2726 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
2727 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE);
2728 }
2729 else
2730 {
2731 /* 32-bit legacy - CR3 == page directory. */
2732 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK;
2733 VarPDEAddr = VarCur;
2734 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE);
2735 }
2736 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
2737 iEntry /= cbEntry;
2738 }
2739
2740 /* adjust cEntries */
2741 cEntries = RT_MAX(1, cEntries);
2742 cEntries = RT_MIN(cEntries, cEntriesMax);
2743
2744 /*
2745 * The display loop.
2746 */
2747 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n",
2748 &VarPDEAddr, iEntry);
2749 do
2750 {
2751 /*
2752 * Read.
2753 */
2754 X86PDEPAE Pde;
2755 Pde.u = 0;
2756 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL);
2757 if (RT_FAILURE(rc))
2758 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr);
2759
2760 /*
2761 * Display.
2762 */
2763 if (iEntry != ~0U)
2764 {
2765 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
2766 iEntry++;
2767 }
2768 if (fPSE && Pde.b.u1Size)
2769 DBGCCmdHlpPrintf(pCmdHlp,
2770 fPAE
2771 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
2772 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
2773 Pde.u,
2774 Pde.u & X86_PDE_PAE_PG_MASK,
2775 Pde.b.u1Present ? "p " : "np",
2776 Pde.b.u1Write ? "w" : "r",
2777 Pde.b.u1User ? "u" : "s",
2778 Pde.b.u1Accessed ? "a " : "na",
2779 Pde.b.u1Dirty ? "d " : "nd",
2780 Pde.b.u3Available,
2781 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ",
2782 Pde.b.u1WriteThru ? "pwt" : " ",
2783 Pde.b.u1CacheDisable ? "pcd" : " ",
2784 Pde.b.u1PAT ? "pat" : "",
2785 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");
2786 else
2787 DBGCCmdHlpPrintf(pCmdHlp,
2788 fPAE
2789 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s"
2790 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s",
2791 Pde.u,
2792 Pde.u & X86_PDE_PAE_PG_MASK,
2793 Pde.n.u1Present ? "p " : "np",
2794 Pde.n.u1Write ? "w" : "r",
2795 Pde.n.u1User ? "u" : "s",
2796 Pde.n.u1Accessed ? "a " : "na",
2797 Pde.u & RT_BIT(6) ? "6 " : " ",
2798 Pde.n.u3Available,
2799 Pde.u & RT_BIT(8) ? "8" : " ",
2800 Pde.n.u1WriteThru ? "pwt" : " ",
2801 Pde.n.u1CacheDisable ? "pcd" : " ",
2802 Pde.u & RT_BIT(7) ? "7" : "",
2803 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");
2804 if (Pde.u & UINT64_C(0x7fff000000000000))
2805 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000)));
2806 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
2807 if (RT_FAILURE(rc))
2808 return rc;
2809
2810 /*
2811 * Advance.
2812 */
2813 VarPDEAddr.u.u64Number += cbEntry;
2814 if (iEntry != ~0U)
2815 VarGCPtr.u.GCFlat += fPAE ? RT_BIT_32(X86_PD_PAE_SHIFT) : RT_BIT_32(X86_PD_SHIFT);
2816 } while (cEntries-- > 0);
2817
2818 NOREF(pResult);
2819 return VINF_SUCCESS;
2820}
2821
2822
2823/**
2824 * The 'dpdb' command.
2825 *
2826 * @returns VBox status.
2827 * @param pCmd Pointer to the command descriptor (as registered).
2828 * @param pCmdHlp Pointer to command helper functions.
2829 * @param pVM Pointer to the current VM (if any).
2830 * @param paArgs Pointer to (readonly) array of arguments.
2831 * @param cArgs Number of arguments in the array.
2832 */
2833static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2834{
2835 if (!pVM)
2836 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2837 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
2838 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
2839 if (RT_FAILURE(rc1))
2840 return rc1;
2841 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
2842 return rc2;
2843}
2844
2845
2846/**
2847 * The 'dpg*' commands.
2848 *
2849 * @returns VBox status.
2850 * @param pCmd Pointer to the command descriptor (as registered).
2851 * @param pCmdHlp Pointer to command helper functions.
2852 * @param pVM Pointer to the current VM (if any).
2853 * @param paArgs Pointer to (readonly) array of arguments.
2854 * @param cArgs Number of arguments in the array.
2855 */
2856static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2857{
2858 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2859
2860 /*
2861 * Validate input.
2862 */
2863 if ( cArgs != 1
2864 || (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
2865 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2866 )
2867 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2868 if (!pVM)
2869 return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n");
2870
2871 /*
2872 * Guest or shadow page tables? Get the paging parameters.
2873 */
2874 bool fGuest = pCmd->pszCmd[3] != 'h';
2875 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
2876 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
2877 ? pDbgc->fRegCtxGuest
2878 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
2879
2880 bool fPAE, fLME, fPSE, fPGE, fNXE;
2881 uint64_t cr3 = fGuest
2882 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
2883 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
2884 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
2885
2886 /*
2887 * Locate the PTE to start displaying at.
2888 *
2889 * The 'dpta' command takes the address of a PTE, while the others are guest
2890 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple
2891 * while the others require us to do all the tedious walking thru the paging
2892 * hierarchy to find the intended PTE.
2893 */
2894 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */
2895 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */
2896 DBGCVAR VarPTEAddr; /* The address of the current PTE. */
2897 unsigned cEntries; /* The number of entries to display. */
2898 unsigned cEntriesMax; /* The max number of entries to display. */
2899 int rc;
2900 if (pCmd->pszCmd[3] == 'a')
2901 {
2902 VarPTEAddr = paArgs[0];
2903 switch (VarPTEAddr.enmRangeType)
2904 {
2905 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break;
2906 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break;
2907 default: cEntries = 10; break;
2908 }
2909 cEntriesMax = PAGE_SIZE / cbEntry;
2910 }
2911 else
2912 {
2913 /*
2914 * Determin the range.
2915 */
2916 switch (paArgs[0].enmRangeType)
2917 {
2918 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
2919 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;
2920 default: cEntries = 10; break;
2921 }
2922
2923 /*
2924 * Normalize the input address, it must be a flat GC address.
2925 */
2926 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
2927 if (RT_FAILURE(rc))
2928 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
2929 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
2930 {
2931 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
2932 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
2933 }
2934 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;
2935
2936 /*
2937 * Do the paging walk until we get to the page table.
2938 */
2939 DBGCVAR VarCur;
2940 if (fGuest)
2941 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
2942 else
2943 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
2944 if (fLME)
2945 {
2946 /* Page Map Level 4 Lookup. */
2947 /* Check if it's a valid address first? */
2948 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
2949 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
2950 X86PML4E Pml4e;
2951 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
2952 if (RT_FAILURE(rc))
2953 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
2954 if (!Pml4e.n.u1Present)
2955 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
2956
2957 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
2958 Assert(fPAE);
2959 }
2960 if (fPAE)
2961 {
2962 /* Page directory pointer table. */
2963 X86PDPE Pdpe;
2964 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe);
2965 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
2966 if (RT_FAILURE(rc))
2967 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
2968 if (!Pdpe.n.u1Present)
2969 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
2970
2971 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
2972
2973 /* Page directory (PAE). */
2974 X86PDEPAE Pde;
2975 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);
2976 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
2977 if (RT_FAILURE(rc))
2978 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
2979 if (!Pde.n.u1Present)
2980 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
2981 if (fPSE && Pde.n.u1Size)
2982 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
2983
2984 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
2985 VarPTEAddr = VarCur;
2986 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;
2987 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);
2988 }
2989 else
2990 {
2991 /* Page directory (legacy). */
2992 X86PDE Pde;
2993 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);
2994 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
2995 if (RT_FAILURE(rc))
2996 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
2997 if (!Pde.n.u1Present)
2998 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
2999 if (fPSE && Pde.n.u1Size)
3000 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
3001
3002 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;
3003 VarPTEAddr = VarCur;
3004 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;
3005 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);
3006 }
3007 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
3008 iEntry /= cbEntry;
3009 }
3010
3011 /* adjust cEntries */
3012 cEntries = RT_MAX(1, cEntries);
3013 cEntries = RT_MIN(cEntries, cEntriesMax);
3014
3015 /*
3016 * The display loop.
3017 */
3018 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",
3019 &VarPTEAddr, &VarGCPtr, iEntry);
3020 do
3021 {
3022 /*
3023 * Read.
3024 */
3025 X86PTEPAE Pte;
3026 Pte.u = 0;
3027 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL);
3028 if (RT_FAILURE(rc))
3029 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);
3030
3031 /*
3032 * Display.
3033 */
3034 if (iEntry != ~0U)
3035 {
3036 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
3037 iEntry++;
3038 }
3039 DBGCCmdHlpPrintf(pCmdHlp,
3040 fPAE
3041 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
3042 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
3043 Pte.u,
3044 Pte.u & X86_PTE_PAE_PG_MASK,
3045 Pte.n.u1Present ? "p " : "np",
3046 Pte.n.u1Write ? "w" : "r",
3047 Pte.n.u1User ? "u" : "s",
3048 Pte.n.u1Accessed ? "a " : "na",
3049 Pte.n.u1Dirty ? "d " : "nd",
3050 Pte.n.u3Available,
3051 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ",
3052 Pte.n.u1WriteThru ? "pwt" : " ",
3053 Pte.n.u1CacheDisable ? "pcd" : " ",
3054 Pte.n.u1PAT ? "pat" : " ",
3055 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "
3056 );
3057 if (Pte.u & UINT64_C(0x7fff000000000000))
3058 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));
3059 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
3060 if (RT_FAILURE(rc))
3061 return rc;
3062
3063 /*
3064 * Advance.
3065 */
3066 VarPTEAddr.u.u64Number += cbEntry;
3067 if (iEntry != ~0U)
3068 VarGCPtr.u.GCFlat += PAGE_SIZE;
3069 } while (cEntries-- > 0);
3070
3071 NOREF(pResult);
3072 return VINF_SUCCESS;
3073}
3074
3075
3076/**
3077 * The 'dptb' command.
3078 *
3079 * @returns VBox status.
3080 * @param pCmd Pointer to the command descriptor (as registered).
3081 * @param pCmdHlp Pointer to command helper functions.
3082 * @param pVM Pointer to the current VM (if any).
3083 * @param paArgs Pointer to (readonly) array of arguments.
3084 * @param cArgs Number of arguments in the array.
3085 */
3086static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3087{
3088 if (!pVM)
3089 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3090 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
3091 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
3092 if (RT_FAILURE(rc1))
3093 return rc1;
3094 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3095 return rc2;
3096}
3097
3098
3099/**
3100 * The 'dt' command.
3101 *
3102 * @returns VBox status.
3103 * @param pCmd Pointer to the command descriptor (as registered).
3104 * @param pCmdHlp Pointer to command helper functions.
3105 * @param pVM Pointer to the current VM (if any).
3106 * @param paArgs Pointer to (readonly) array of arguments.
3107 * @param cArgs Number of arguments in the array.
3108 */
3109static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
3110{
3111 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3112 int rc;
3113
3114 if (!pVM)
3115 return DBGCCmdHlpFail(pCmdHlp, pCmd, "No VM.\n");
3116 if ( cArgs > 1
3117 || (cArgs == 1 && paArgs[0].enmType == DBGCVAR_TYPE_STRING)
3118 || (cArgs == 1 && paArgs[0].enmType == DBGCVAR_TYPE_SYMBOL))
3119 return DBGCCmdHlpFail(pCmdHlp, pCmd, "internal error: The parser doesn't do its job properly yet...\n");
3120
3121 /*
3122 * Check if the command indicates the type.
3123 */
3124 enum { kTss16, kTss32, kTss64, kTssToBeDetermined } enmTssType = kTssToBeDetermined;
3125 if (!strcmp(pCmd->pszCmd, "dt16"))
3126 enmTssType = kTss16;
3127 else if (!strcmp(pCmd->pszCmd, "dt32"))
3128 enmTssType = kTss32;
3129 else if (!strcmp(pCmd->pszCmd, "dt64"))
3130 enmTssType = kTss64;
3131
3132 /*
3133 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.
3134 */
3135 uint32_t SelTss = UINT32_MAX;
3136 DBGCVAR VarTssAddr;
3137 if (cArgs == 0)
3138 {
3139 /** @todo consider querying the hidden bits instead (missing API). */
3140 uint16_t SelTR;
3141 rc = DBGFR3RegQueryU16(pVM, pDbgc->idCpu, DBGFREG_TR, &SelTR);
3142 if (RT_FAILURE(rc))
3143 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query TR, rc=%Rrc\n", rc);
3144 DBGCVAR_INIT_GC_FAR(&VarTssAddr, SelTR, 0);
3145 SelTss = SelTR;
3146 }
3147 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)
3148 {
3149 if (paArgs[0].u.u64Number < 0xffff)
3150 DBGCVAR_INIT_GC_FAR(&VarTssAddr, (RTSEL)paArgs[0].u.u64Number, 0);
3151 else
3152 {
3153 if (VarTssAddr.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
3154 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Element count doesn't combine with a TSS address.\n");
3155 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, paArgs[0].u.u64Number);
3156 if (VarTssAddr.enmRangeType == DBGCVAR_RANGE_BYTES)
3157 {
3158 VarTssAddr.enmRangeType = paArgs[0].enmRangeType;
3159 VarTssAddr.u64Range = paArgs[0].u64Range;
3160 }
3161 }
3162 }
3163 else
3164 VarTssAddr = paArgs[0];
3165
3166 /*
3167 * Deal with TSS:ign by means of the GDT.
3168 */
3169 if (VarTssAddr.enmType == DBGCVAR_TYPE_GC_FAR)
3170 {
3171 SelTss = VarTssAddr.u.GCFar.sel;
3172 DBGFSELINFO SelInfo;
3173 rc = DBGFR3SelQueryInfo(pVM, pDbgc->idCpu, VarTssAddr.u.GCFar.sel, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo);
3174 if (RT_FAILURE(rc))
3175 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3SelQueryInfo(,%u,%d,,) -> %Rrc.\n",
3176 pDbgc->idCpu, VarTssAddr.u.GCFar.sel, rc);
3177
3178 if (SelInfo.u.Raw.Gen.u1DescType)
3179 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (!sys)\n", VarTssAddr.u.GCFar.sel);
3180
3181 switch (SelInfo.u.Raw.Gen.u4Type)
3182 {
3183 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
3184 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
3185 if (enmTssType == kTssToBeDetermined)
3186 enmTssType = kTss16;
3187 break;
3188
3189 case X86_SEL_TYPE_SYS_386_TSS_BUSY: /* AMD64 too */
3190 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
3191 if (enmTssType == kTssToBeDetermined)
3192 enmTssType = SelInfo.fFlags & DBGFSELINFO_FLAGS_LONG_MODE ? kTss64 : kTss32;
3193 break;
3194
3195 default:
3196 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (type=%x)\n",
3197 VarTssAddr.u.GCFar.sel, SelInfo.u.Raw.Gen.u4Type);
3198 }
3199
3200 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, SelInfo.GCPtrBase);
3201 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, RT_MAX(SelInfo.cbLimit + 1, SelInfo.cbLimit));
3202 }
3203
3204 /*
3205 * Determin the TSS type if none is currently given.
3206 */
3207 if (enmTssType == kTssToBeDetermined)
3208 {
3209 if ( VarTssAddr.u64Range > 0
3210 && VarTssAddr.u64Range < sizeof(X86TSS32) - 4)
3211 enmTssType == kTss16;
3212 else
3213 {
3214 uint64_t uEfer;
3215 rc = DBGFR3RegQueryU64(pVM, pDbgc->idCpu, DBGFREG_MSR_K6_EFER, &uEfer);
3216 if ( RT_FAILURE(rc)
3217 || !(uEfer & MSR_K6_EFER_LMA) )
3218 enmTssType = kTss32;
3219 else
3220 enmTssType = kTss64;
3221 }
3222 }
3223
3224 /*
3225 * Figure the min/max sizes.
3226 * ASSUMES max TSS size is 64 KB.
3227 */
3228 uint32_t cbTssMin;
3229 uint32_t cbTssMax;
3230 switch (enmTssType)
3231 {
3232 case kTss16:
3233 cbTssMin = cbTssMax = sizeof(X86TSS16);
3234 break;
3235 case kTss32:
3236 cbTssMin = RT_OFFSETOF(X86TSS32, IntRedirBitmap);
3237 cbTssMax = _64K;
3238 break;
3239 case kTss64:
3240 cbTssMin = RT_OFFSETOF(X86TSS64, IntRedirBitmap);
3241 cbTssMax = _64K;
3242 break;
3243 default:
3244 AssertFailedReturn(VERR_INTERNAL_ERROR);
3245 }
3246 uint32_t cbTss = VarTssAddr.enmRangeType == DBGCVAR_RANGE_BYTES ? (uint32_t)VarTssAddr.u64Range : 0;
3247 if (cbTss == 0)
3248 cbTss = cbTssMin;
3249 else if (cbTss < cbTssMin)
3250 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Minimum TSS size is %u bytes, you specified %llu (%llx) bytes.\n",
3251 cbTssMin, VarTssAddr.u64Range, VarTssAddr.u64Range);
3252 else if (cbTss > cbTssMax)
3253 cbTss = cbTssMax;
3254 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, cbTss);
3255
3256 /*
3257 * Read the TSS into a temporary buffer.
3258 */
3259 uint8_t abBuf[_64K];
3260 size_t cbTssRead;
3261 rc = DBGCCmdHlpMemRead(pCmdHlp, pVM, abBuf, cbTss, &VarTssAddr, &cbTssRead);
3262 if (RT_FAILURE(rc))
3263 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read TSS at %Dv: %Rrc\n", &VarTssAddr, rc);
3264 if (cbTssRead < cbTssMin)
3265 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read essential parts of the TSS (read %zu, min %zu).\n",
3266 cbTssRead, cbTssMin);
3267 if (cbTssRead < cbTss)
3268 memset(&abBuf[cbTssRead], 0xff, cbTss - cbTssRead);
3269
3270
3271 /*
3272 * Format the TSS.
3273 */
3274 uint16_t offIoBitmap;
3275 switch (enmTssType)
3276 {
3277 case kTss16:
3278 {
3279 PCX86TSS16 pTss = (PCX86TSS16)&abBuf[0];
3280 if (SelTss != UINT32_MAX)
3281 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS16 at %Dv\n", SelTss, &VarTssAddr);
3282 else
3283 DBGCCmdHlpPrintf(pCmdHlp, "TSS16 at %Dv\n", &VarTssAddr);
3284 DBGCCmdHlpPrintf(pCmdHlp,
3285 "ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x\n"
3286 "ip=%04x sp=%04x bp=%04x\n"
3287 "cs=%04x ss=%04x ds=%04x es=%04x flags=%04x\n"
3288 "ss:sp0=%04x:%04x ss:sp1=%04x:%04x ss:sp2=%04x:%04x\n"
3289 "prev=%04x ldtr=%04x\n"
3290 ,
3291 pTss->ax, pTss->bx, pTss->cx, pTss->dx, pTss->si, pTss->di,
3292 pTss->ip, pTss->sp, pTss->bp,
3293 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->flags,
3294 pTss->ss0, pTss->sp0, pTss->ss1, pTss->sp1, pTss->ss2, pTss->sp2,
3295 pTss->selPrev, pTss->selLdt);
3296 if (pTss->cs != 0)
3297 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%04x L 0", pTss->cs, pTss->ip);
3298 offIoBitmap = 0;
3299 break;
3300 }
3301
3302 case kTss32:
3303 {
3304 PCX86TSS32 pTss = (PCX86TSS32)&abBuf[0];
3305 if (SelTss != UINT32_MAX)
3306 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS32 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin);
3307 else
3308 DBGCCmdHlpPrintf(pCmdHlp, "TSS32 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin);
3309 DBGCCmdHlpPrintf(pCmdHlp,
3310 "eax=%08x bx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
3311 "eip=%08x esp=%08x ebp=%08x\n"
3312 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n"
3313 "ss:esp0=%04x:%08x ss:esp1=%04x:%08x ss:esp2=%04x:%08x\n"
3314 "prev=%04x ldtr=%04x cr3=%08x debug=%u iomap=%04x\n"
3315 ,
3316 pTss->eax, pTss->ebx, pTss->ecx, pTss->edx, pTss->esi, pTss->edi,
3317 pTss->eip, pTss->esp, pTss->ebp,
3318 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->fs, pTss->gs, pTss->eflags,
3319 pTss->ss0, pTss->esp0, pTss->ss1, pTss->esp1, pTss->ss2, pTss->esp2,
3320 pTss->selPrev, pTss->selLdt, pTss->cr3, pTss->fDebugTrap, pTss->offIoBitmap);
3321 if (pTss->cs != 0)
3322 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pTss->cs, pTss->eip);
3323 offIoBitmap = pTss->offIoBitmap;
3324 break;
3325 }
3326
3327 case kTss64:
3328 {
3329 PCX86TSS64 pTss = (PCX86TSS64)&abBuf[0];
3330 if (SelTss != UINT32_MAX)
3331 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS64 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin);
3332 else
3333 DBGCCmdHlpPrintf(pCmdHlp, "TSS64 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin);
3334 DBGCCmdHlpPrintf(pCmdHlp,
3335 "rsp0=%016RX16 rsp1=%016RX16 rsp2=%016RX16\n"
3336 "ist1=%016RX16 ist2=%016RX16\n"
3337 "ist3=%016RX16 ist4=%016RX16\n"
3338 "ist5=%016RX16 ist6=%016RX16\n"
3339 "ist7=%016RX16 iomap=%04x\n"
3340 ,
3341 pTss->rsp0, pTss->rsp1, pTss->rsp2,
3342 pTss->ist1, pTss->ist2,
3343 pTss->ist3, pTss->ist4,
3344 pTss->ist5, pTss->ist6,
3345 pTss->ist7, pTss->offIoBitmap);
3346 offIoBitmap = pTss->offIoBitmap;
3347 break;
3348 }
3349
3350 default:
3351 AssertFailedReturn(VERR_INTERNAL_ERROR);
3352 }
3353
3354 /*
3355 * Dump the interrupt redirection bitmap.
3356 */
3357 if (enmTssType != kTss16)
3358 {
3359 if ( offIoBitmap > cbTssMin
3360 && offIoBitmap < cbTss) /** @todo check exactly what the edge cases are here. */
3361 {
3362 if (offIoBitmap - cbTssMin >= 32)
3363 {
3364 DBGCCmdHlpPrintf(pCmdHlp, "Interrupt redirection:\n");
3365 uint8_t const *pbIntRedirBitmap = &abBuf[offIoBitmap - 32];
3366 uint32_t iStart = 0;
3367 bool fPrev = ASMBitTest(pbIntRedirBitmap, 0); /* LE/BE issue */
3368 for (uint32_t i = 0; i < 256; i++)
3369 {
3370 bool fThis = ASMBitTest(pbIntRedirBitmap, i);
3371 if (fThis != fPrev)
3372 {
3373 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, i - 1, fPrev ? "Protected mode" : "Redirected");
3374 fPrev = fThis;
3375 iStart = i;
3376 }
3377 }
3378 if (iStart != 255)
3379 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, 255, fPrev ? "Protected mode" : "Redirected");
3380 }
3381 else
3382 DBGCCmdHlpPrintf(pCmdHlp, "Invalid interrupt redirection bitmap size: %u (%#x), expected 32 bytes.\n",
3383 offIoBitmap - cbTssMin, offIoBitmap - cbTssMin);
3384 }
3385 else if (offIoBitmap > 0)
3386 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap (-%#x)\n", cbTssMin - offIoBitmap);
3387 else
3388 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap\n");
3389 }
3390
3391 /*
3392 * Dump the I/O bitmap if present.
3393 */
3394 if (enmTssType != kTss16)
3395 {
3396 if (offIoBitmap < cbTss)
3397 {
3398 uint32_t cPorts = RT_MIN((cbTss - offIoBitmap) * 8, _64K);
3399 DBGCVAR VarAddr;
3400 DBGCCmdHlpEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarTssAddr, offIoBitmap);
3401 DBGCCmdHlpPrintf(pCmdHlp, "I/O bitmap at %DV - %#x ports:\n", &VarAddr, cPorts);
3402
3403 uint8_t const *pbIoBitmap = &abBuf[offIoBitmap];
3404 uint32_t iStart = 0;
3405 bool fPrev = ASMBitTest(pbIoBitmap, 0);
3406 uint32_t cLine = 0;
3407 for (uint32_t i = 1; i < cPorts; i++)
3408 {
3409 bool fThis = ASMBitTest(pbIoBitmap, i);
3410 if (fThis != fPrev)
3411 {
3412 cLine++;
3413 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s%s", iStart, i-1,
3414 fPrev ? "GP" : "OK", (cLine % 6) == 0 ? "\n" : " ");
3415 fPrev = fThis;
3416 iStart = i;
3417 }
3418 }
3419 if (iStart != _64K-1)
3420 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s\n", iStart, _64K-1, fPrev ? "GP" : "OK");
3421 }
3422 else if (offIoBitmap > 0)
3423 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap (-%#x)\n", cbTssMin - offIoBitmap);
3424 else
3425 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap\n");
3426 }
3427
3428 return VINF_SUCCESS;
3429}
3430
3431
3432/**
3433 * The 'm' command.
3434 *
3435 * @returns VBox status.
3436 * @param pCmd Pointer to the command descriptor (as registered).
3437 * @param pCmdHlp Pointer to command helper functions.
3438 * @param pVM Pointer to the current VM (if any).
3439 * @param paArgs Pointer to (readonly) array of arguments.
3440 * @param cArgs Number of arguments in the array.
3441 */
3442static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3443{
3444 DBGCCmdHlpPrintf(pCmdHlp, "Address: %DV\n", &paArgs[0]);
3445 if (!pVM)
3446 return DBGCCmdHlpFail(pCmdHlp, pCmd, "No VM.\n");
3447
3448 DBGCCmdHlpPrintf(pCmdHlp, "guest pd (dpdg %DV):\n", &paArgs[0]);
3449 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
3450 DBGCCmdHlpPrintf(pCmdHlp, "hyper pd (dpdh %DV):\n", &paArgs[0]);
3451 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
3452 DBGCCmdHlpPrintf(pCmdHlp, "guest pt (dptg %DV):\n", &paArgs[0]);
3453 int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
3454 DBGCCmdHlpPrintf(pCmdHlp, "hyper pt (dpth %DV):\n", &paArgs[0]);
3455 int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
3456 if (RT_FAILURE(rc1))
3457 return rc1;
3458 if (RT_FAILURE(rc2))
3459 return rc2;
3460 if (RT_FAILURE(rc3))
3461 return rc3;
3462 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3463 return rc4;
3464}
3465
3466
3467/**
3468 * Converts one or more variables into a byte buffer for a
3469 * given unit size.
3470 *
3471 * @returns VBox status codes:
3472 * @retval VERR_TOO_MUCH_DATA if the buffer is too small, bitched.
3473 * @retval VERR_INTERNAL_ERROR on bad variable type, bitched.
3474 * @retval VINF_SUCCESS on success.
3475 *
3476 * @param pvBuf The buffer to convert into.
3477 * @param pcbBuf The buffer size on input. The size of the result on output.
3478 * @param cbUnit The unit size to apply when converting.
3479 * The high bit is used to indicate unicode string.
3480 * @param paVars The array of variables to convert.
3481 * @param cVars The number of variables.
3482 */
3483int dbgcVarsToBytes(PDBGCCMDHLP pCmdHlp, void *pvBuf, uint32_t *pcbBuf, size_t cbUnit, PCDBGCVAR paVars, unsigned cVars)
3484{
3485 union
3486 {
3487 uint8_t *pu8;
3488 uint16_t *pu16;
3489 uint32_t *pu32;
3490 uint64_t *pu64;
3491 } u, uEnd;
3492 u.pu8 = (uint8_t *)pvBuf;
3493 uEnd.pu8 = u.pu8 + *pcbBuf;
3494
3495 unsigned i;
3496 for (i = 0; i < cVars && u.pu8 < uEnd.pu8; i++)
3497 {
3498 switch (paVars[i].enmType)
3499 {
3500 case DBGCVAR_TYPE_GC_FAR:
3501 case DBGCVAR_TYPE_HC_FAR:
3502 case DBGCVAR_TYPE_GC_FLAT:
3503 case DBGCVAR_TYPE_GC_PHYS:
3504 case DBGCVAR_TYPE_HC_FLAT:
3505 case DBGCVAR_TYPE_HC_PHYS:
3506 case DBGCVAR_TYPE_NUMBER:
3507 {
3508 uint64_t u64 = paVars[i].u.u64Number;
3509 switch (cbUnit & 0x1f)
3510 {
3511 case 1:
3512 do
3513 {
3514 *u.pu8++ = u64;
3515 u64 >>= 8;
3516 } while (u64);
3517 break;
3518 case 2:
3519 do
3520 {
3521 *u.pu16++ = u64;
3522 u64 >>= 16;
3523 } while (u64);
3524 break;
3525 case 4:
3526 *u.pu32++ = u64;
3527 u64 >>= 32;
3528 if (u64)
3529 *u.pu32++ = u64;
3530 break;
3531 case 8:
3532 *u.pu64++ = u64;
3533 break;
3534 }
3535 break;
3536 }
3537
3538 case DBGCVAR_TYPE_STRING:
3539 case DBGCVAR_TYPE_SYMBOL:
3540 {
3541 const char *psz = paVars[i].u.pszString;
3542 size_t cbString = strlen(psz);
3543 if (cbUnit & RT_BIT_32(31))
3544 {
3545 /* Explode char to unit. */
3546 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8) * (cbUnit & 0x1f))
3547 {
3548 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
3549 return VERR_TOO_MUCH_DATA;
3550 }
3551 while (*psz)
3552 {
3553 switch (cbUnit & 0x1f)
3554 {
3555 case 1: *u.pu8++ = *psz; break;
3556 case 2: *u.pu16++ = *psz; break;
3557 case 4: *u.pu32++ = *psz; break;
3558 case 8: *u.pu64++ = *psz; break;
3559 }
3560 psz++;
3561 }
3562 }
3563 else
3564 {
3565 /* Raw copy with zero padding if the size isn't aligned. */
3566 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8))
3567 {
3568 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
3569 return VERR_TOO_MUCH_DATA;
3570 }
3571
3572 size_t cbCopy = cbString & ~(cbUnit - 1);
3573 memcpy(u.pu8, psz, cbCopy);
3574 u.pu8 += cbCopy;
3575 psz += cbCopy;
3576
3577 size_t cbReminder = cbString & (cbUnit - 1);
3578 if (cbReminder)
3579 {
3580 memcpy(u.pu8, psz, cbString & (cbUnit - 1));
3581 memset(u.pu8 + cbReminder, 0, cbUnit - cbReminder);
3582 u.pu8 += cbUnit;
3583 }
3584 }
3585 break;
3586 }
3587
3588 default:
3589 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
3590 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INTERNAL_ERROR,
3591 "i=%d enmType=%d\n", i, paVars[i].enmType);
3592 return VERR_INTERNAL_ERROR;
3593 }
3594 }
3595 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
3596 if (i != cVars)
3597 {
3598 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
3599 return VERR_TOO_MUCH_DATA;
3600 }
3601 return VINF_SUCCESS;
3602}
3603
3604
3605/**
3606 * The 'eb', 'ew', 'ed' and 'eq' commands.
3607 *
3608 * @returns VBox status.
3609 * @param pCmd Pointer to the command descriptor (as registered).
3610 * @param pCmdHlp Pointer to command helper functions.
3611 * @param pVM Pointer to the current VM (if any).
3612 * @param paArgs Pointer to (readonly) array of arguments.
3613 * @param cArgs Number of arguments in the array.
3614 */
3615static DECLCALLBACK(int) dbgcCmdEditMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3616{
3617 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3618
3619 /*
3620 * Validate input.
3621 */
3622 if ( cArgs >= 2
3623 || !DBGCVAR_ISPOINTER(paArgs[0].enmType))
3624 return DBGCCmdHlpFail(pCmdHlp, pCmd, "internal error: The parser doesn't do its job properly yet... It might help to use the '%%' operator.\n");
3625 for (unsigned iArg = 2; iArg < cArgs; iArg++)
3626 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
3627 return DBGCCmdHlpFail(pCmdHlp, pCmd, "internal error: The parser doesn't do its job properly yet: Arg #%u is not a number.\n", iArg);
3628 if (!pVM)
3629 return DBGCCmdHlpFail(pCmdHlp, pCmd, "error: No VM.\n");
3630
3631 /*
3632 * Figure out the element size.
3633 */
3634 unsigned cbElement;
3635 switch (pCmd->pszCmd[1])
3636 {
3637 default:
3638 case 'b': cbElement = 1; break;
3639 case 'w': cbElement = 2; break;
3640 case 'd': cbElement = 4; break;
3641 case 'q': cbElement = 8; break;
3642 }
3643
3644 /*
3645 * Do setting.
3646 */
3647 DBGCVAR Addr = paArgs[0];
3648 unsigned iArg = 1;
3649 for (;;)
3650 {
3651 size_t cbWritten;
3652 int rc = pCmdHlp->pfnMemWrite(pCmdHlp, pVM, &paArgs[iArg].u, cbElement, &Addr, &cbWritten);
3653 if (RT_FAILURE(rc))
3654 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Writing memory at %DV.\n", &Addr);
3655 if (cbWritten != cbElement)
3656 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Only wrote %u out of %u bytes!\n", cbWritten, cbElement);
3657
3658 /* advance. */
3659 iArg++;
3660 if (iArg >= cArgs)
3661 break;
3662 rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%Dv + %#x", &Addr, cbElement);
3663 if (RT_FAILURE(rc))
3664 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
3665 }
3666
3667 NOREF(pResult);
3668 return VINF_SUCCESS;
3669}
3670
3671
3672/**
3673 * Executes the search.
3674 *
3675 * @returns VBox status code.
3676 * @param pCmdHlp The command helpers.
3677 * @param pVM The VM handle.
3678 * @param pAddress The address to start searching from. (undefined on output)
3679 * @param cbRange The address range to search. Must not wrap.
3680 * @param pabBytes The byte pattern to search for.
3681 * @param cbBytes The size of the pattern.
3682 * @param cbUnit The search unit.
3683 * @param cMaxHits The max number of hits.
3684 * @param pResult Where to store the result if it's a function invocation.
3685 */
3686static int dbgcCmdWorkerSearchMemDoIt(PDBGCCMDHLP pCmdHlp, PVM pVM, PDBGFADDRESS pAddress, RTGCUINTPTR cbRange,
3687 const uint8_t *pabBytes, uint32_t cbBytes,
3688 uint32_t cbUnit, uint64_t cMaxHits, PDBGCVAR pResult)
3689{
3690 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3691
3692 /*
3693 * Do the search.
3694 */
3695 uint64_t cHits = 0;
3696 for (;;)
3697 {
3698 /* search */
3699 DBGFADDRESS HitAddress;
3700 int rc = DBGFR3MemScan(pVM, pDbgc->idCpu, pAddress, cbRange, 1, pabBytes, cbBytes, &HitAddress);
3701 if (RT_FAILURE(rc))
3702 {
3703 if (rc != VERR_DBGF_MEM_NOT_FOUND)
3704 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3MemScan\n");
3705
3706 /* update the current address so we can save it (later). */
3707 pAddress->off += cbRange;
3708 pAddress->FlatPtr += cbRange;
3709 cbRange = 0;
3710 break;
3711 }
3712
3713 /* report result */
3714 DBGCVAR VarCur;
3715 dbgcVarInit(&VarCur);
3716 dbgcVarSetDbgfAddr(&VarCur, &HitAddress);
3717 if (!pResult)
3718 pCmdHlp->pfnExec(pCmdHlp, "db %DV LB 10", &VarCur);
3719 else
3720 dbgcVarSetDbgfAddr(pResult, &HitAddress);
3721
3722 /* advance */
3723 cbRange -= HitAddress.FlatPtr - pAddress->FlatPtr;
3724 *pAddress = HitAddress;
3725 pAddress->FlatPtr += cbBytes;
3726 pAddress->off += cbBytes;
3727 if (cbRange <= cbBytes)
3728 {
3729 cbRange = 0;
3730 break;
3731 }
3732 cbRange -= cbBytes;
3733
3734 if (++cHits >= cMaxHits)
3735 {
3736 /// @todo save the search.
3737 break;
3738 }
3739 }
3740
3741 /*
3742 * Save the search so we can resume it...
3743 */
3744 if (pDbgc->abSearch != pabBytes)
3745 {
3746 memcpy(pDbgc->abSearch, pabBytes, cbBytes);
3747 pDbgc->cbSearch = cbBytes;
3748 pDbgc->cbSearchUnit = cbUnit;
3749 }
3750 pDbgc->cMaxSearchHits = cMaxHits;
3751 pDbgc->SearchAddr = *pAddress;
3752 pDbgc->cbSearchRange = cbRange;
3753
3754 return cHits ? VINF_SUCCESS : VERR_DBGC_COMMAND_FAILED;
3755}
3756
3757
3758/**
3759 * Resumes the previous search.
3760 *
3761 * @returns VBox status code.
3762 * @param pCmdHlp Pointer to the command helper functions.
3763 * @param pVM Pointer to the current VM (if any).
3764 * @param pResult Where to store the result of a function invocation.
3765 */
3766static int dbgcCmdWorkerSearchMemResume(PDBGCCMDHLP pCmdHlp, PVM pVM, PDBGCVAR pResult)
3767{
3768 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3769
3770 /*
3771 * Make sure there is a previous command.
3772 */
3773 if (!pDbgc->cbSearch)
3774 {
3775 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Error: No previous search\n");
3776 return VERR_DBGC_COMMAND_FAILED;
3777 }
3778
3779 /*
3780 * Make range and address adjustments.
3781 */
3782 DBGFADDRESS Address = pDbgc->SearchAddr;
3783 if (Address.FlatPtr == ~(RTGCUINTPTR)0)
3784 {
3785 Address.FlatPtr -= Address.off;
3786 Address.off = 0;
3787 }
3788
3789 RTGCUINTPTR cbRange = pDbgc->cbSearchRange;
3790 if (!cbRange)
3791 cbRange = ~(RTGCUINTPTR)0;
3792 if (Address.FlatPtr + cbRange < pDbgc->SearchAddr.FlatPtr)
3793 cbRange = ~(RTGCUINTPTR)0 - pDbgc->SearchAddr.FlatPtr + !!pDbgc->SearchAddr.FlatPtr;
3794
3795 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pVM, &Address, cbRange, pDbgc->abSearch, pDbgc->cbSearch,
3796 pDbgc->cbSearchUnit, pDbgc->cMaxSearchHits, pResult);
3797}
3798
3799
3800/**
3801 * Search memory, worker for the 's' and 's?' functions.
3802 *
3803 * @returns VBox status.
3804 * @param pCmdHlp Pointer to the command helper functions.
3805 * @param pVM Pointer to the current VM (if any).
3806 * @param pAddress Where to start searching. If no range, search till end of address space.
3807 * @param cMaxHits The maximum number of hits.
3808 * @param chType The search type.
3809 * @param paPatArgs The pattern variable array.
3810 * @param cPatArgs Number of pattern variables.
3811 * @param pResult Where to store the result of a function invocation.
3812 */
3813static int dbgcCmdWorkerSearchMem(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pAddress, uint64_t cMaxHits, char chType,
3814 PCDBGCVAR paPatArgs, unsigned cPatArgs, PDBGCVAR pResult)
3815{
3816 dbgcVarSetGCFlat(pResult, 0);
3817
3818 /*
3819 * Convert the search pattern into bytes and DBGFR3MemScan can deal with.
3820 */
3821 uint32_t cbUnit;
3822 switch (chType)
3823 {
3824 case 'a':
3825 case 'b': cbUnit = 1; break;
3826 case 'u': cbUnit = 2 | RT_BIT_32(31); break;
3827 case 'w': cbUnit = 2; break;
3828 case 'd': cbUnit = 4; break;
3829 case 'q': cbUnit = 8; break;
3830 default:
3831 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "chType=%c\n", chType);
3832 }
3833 uint8_t abBytes[RT_SIZEOFMEMB(DBGC, abSearch)];
3834 uint32_t cbBytes = sizeof(abBytes);
3835 int rc = dbgcVarsToBytes(pCmdHlp, abBytes, &cbBytes, cbUnit, paPatArgs, cPatArgs);
3836 if (RT_FAILURE(rc))
3837 return VERR_DBGC_COMMAND_FAILED;
3838
3839 /*
3840 * Make DBGF address and fix the range.
3841 */
3842 DBGFADDRESS Address;
3843 rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pAddress, &Address);
3844 if (RT_FAILURE(rc))
3845 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", pAddress);
3846
3847 RTGCUINTPTR cbRange;
3848 switch (pAddress->enmRangeType)
3849 {
3850 case DBGCVAR_RANGE_BYTES:
3851 cbRange = pAddress->u64Range;
3852 if (cbRange != pAddress->u64Range)
3853 cbRange = ~(RTGCUINTPTR)0;
3854 break;
3855
3856 case DBGCVAR_RANGE_ELEMENTS:
3857 cbRange = (RTGCUINTPTR)(pAddress->u64Range * cbUnit);
3858 if ( cbRange != pAddress->u64Range * cbUnit
3859 || cbRange < pAddress->u64Range)
3860 cbRange = ~(RTGCUINTPTR)0;
3861 break;
3862
3863 default:
3864 cbRange = ~(RTGCUINTPTR)0;
3865 break;
3866 }
3867 if (Address.FlatPtr + cbRange < Address.FlatPtr)
3868 cbRange = ~(RTGCUINTPTR)0 - Address.FlatPtr + !!Address.FlatPtr;
3869
3870 /*
3871 * Ok, do it.
3872 */
3873 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pVM, &Address, cbRange, abBytes, cbBytes, cbUnit, cMaxHits, pResult);
3874}
3875
3876
3877/**
3878 * The 's' command.
3879 *
3880 * @returns VBox status.
3881 * @param pCmd Pointer to the command descriptor (as registered).
3882 * @param pCmdHlp Pointer to command helper functions.
3883 * @param pVM Pointer to the current VM (if any).
3884 * @param paArgs Pointer to (readonly) array of arguments.
3885 * @param cArgs Number of arguments in the array.
3886 */
3887static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3888{
3889 /* check that the parser did what it's supposed to do. */
3890 //if ( cArgs <= 2
3891 // && paArgs[0].enmType != DBGCVAR_TYPE_STRING)
3892 // return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
3893
3894 /*
3895 * Repeate previous search?
3896 */
3897 if (cArgs == 0)
3898 return dbgcCmdWorkerSearchMemResume(pCmdHlp, pVM, pResult);
3899
3900 /*
3901 * Parse arguments.
3902 */
3903
3904 return -1;
3905}
3906
3907
3908/**
3909 * The 's?' command.
3910 *
3911 * @returns VBox status.
3912 * @param pCmd Pointer to the command descriptor (as registered).
3913 * @param pCmdHlp Pointer to command helper functions.
3914 * @param pVM Pointer to the current VM (if any).
3915 * @param paArgs Pointer to (readonly) array of arguments.
3916 * @param cArgs Number of arguments in the array.
3917 */
3918static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3919{
3920 /* check that the parser did what it's supposed to do. */
3921 if ( cArgs < 2
3922 || !DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
3923 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
3924 return dbgcCmdWorkerSearchMem(pCmdHlp, pVM, &paArgs[0], pResult ? 1 : 25, pCmd->pszCmd[1], paArgs + 1, cArgs - 1, pResult);
3925}
3926
3927
3928/**
3929 * List near symbol.
3930 *
3931 * @returns VBox status code.
3932 * @param pCmdHlp Pointer to command helper functions.
3933 * @param pVM Pointer to the current VM (if any).
3934 * @param pArg Pointer to the address or symbol to lookup.
3935 */
3936static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)
3937{
3938 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3939 dbgcVarSetGCFlat(pResult, 0);
3940
3941 RTDBGSYMBOL Symbol;
3942 int rc;
3943 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)
3944 {
3945 /*
3946 * Lookup the symbol address.
3947 */
3948 rc = DBGFR3AsSymbolByName(pVM, pDbgc->hDbgAs, pArg->u.pszString, &Symbol, NULL);
3949 if (RT_FAILURE(rc))
3950 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsSymbolByName(,,%s,)\n", pArg->u.pszString);
3951
3952 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%Rptr %s\n", Symbol.Value, Symbol.szName);
3953 dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);
3954 }
3955 else
3956 {
3957 /*
3958 * Convert it to a flat GC address and lookup that address.
3959 */
3960 DBGCVAR AddrVar;
3961 rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);
3962 if (RT_FAILURE(rc))
3963 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);
3964
3965 dbgcVarSetVar(pResult, &AddrVar);
3966
3967 RTINTPTR offDisp;
3968 DBGFADDRESS Addr;
3969 rc = DBGFR3AsSymbolByAddr(pVM, pDbgc->hDbgAs, DBGFR3AddrFromFlat(pVM, &Addr, AddrVar.u.GCFlat), &offDisp, &Symbol, NULL);
3970 if (RT_FAILURE(rc))
3971 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ASymbolByAddr(,,%RGv,,)\n", AddrVar.u.GCFlat);
3972
3973 if (!offDisp)
3974 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);
3975 else if (offDisp > 0)
3976 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);
3977 else
3978 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);
3979 if ((RTGCINTPTR)Symbol.cb > -offDisp)
3980 {
3981 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);
3982 dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);
3983 }
3984 else
3985 {
3986 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
3987 dbgcVarSetNoRange(pResult);
3988 }
3989 }
3990
3991 return rc;
3992}
3993
3994
3995/**
3996 * The 'ln' (listnear) command.
3997 *
3998 * @returns VBox status.
3999 * @param pCmd Pointer to the command descriptor (as registered).
4000 * @param pCmdHlp Pointer to command helper functions.
4001 * @param pVM Pointer to the current VM (if any).
4002 * @param paArgs Pointer to (readonly) array of arguments.
4003 * @param cArgs Number of arguments in the array.
4004 */
4005static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4006{
4007 dbgcVarSetGCFlat(pResult, 0);
4008 if (!cArgs)
4009 {
4010 /*
4011 * Current cs:eip symbol.
4012 */
4013 DBGCVAR AddrVar;
4014 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(cs:eip)");
4015 if (RT_FAILURE(rc))
4016 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");
4017 return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);
4018 }
4019
4020/** @todo Fix the darn parser, it's resolving symbols specified as arguments before we get in here. */
4021 /*
4022 * Iterate arguments.
4023 */
4024 for (unsigned iArg = 0; iArg < cArgs; iArg++)
4025 {
4026 int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);
4027 if (RT_FAILURE(rc))
4028 return rc;
4029 }
4030
4031 NOREF(pCmd); NOREF(pResult);
4032 return VINF_SUCCESS;
4033}
4034
4035
4036/**
4037 * Matches the module patters against a module name.
4038 *
4039 * @returns true if matching, otherwise false.
4040 * @param pszName The module name.
4041 * @param paArgs The module pattern argument list.
4042 * @param cArgs Number of arguments.
4043 */
4044static bool dbgcCmdListModuleMatch(const char *pszName, PCDBGCVAR paArgs, unsigned cArgs)
4045{
4046 for (uint32_t i = 0; i < cArgs; i++)
4047 if (RTStrSimplePatternMatch(paArgs[i].u.pszString, pszName))
4048 return true;
4049 return false;
4050}
4051
4052
4053/**
4054 * The 'ln' (listnear) command.
4055 *
4056 * @returns VBox status.
4057 * @param pCmd Pointer to the command descriptor (as registered).
4058 * @param pCmdHlp Pointer to command helper functions.
4059 * @param pVM Pointer to the current VM (if any).
4060 * @param paArgs Pointer to (readonly) array of arguments.
4061 * @param cArgs Number of arguments in the array.
4062 */
4063static DECLCALLBACK(int) dbgcCmdListModules(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4064{
4065 bool const fMappings = pCmd->pszCmd[2] == 'o';
4066 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4067
4068 /*
4069 * Iterate the modules in the current address space and print info about
4070 * those matching the input.
4071 */
4072 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pVM, pDbgc->hDbgAs);
4073 uint32_t cMods = RTDbgAsModuleCount(hAs);
4074 for (uint32_t iMod = 0; iMod < cMods; iMod++)
4075 {
4076 RTDBGMOD hMod = RTDbgAsModuleByIndex(hAs, iMod);
4077 if (hMod != NIL_RTDBGMOD)
4078 {
4079 uint32_t const cSegs = RTDbgModSegmentCount(hMod);
4080 const char * const pszName = RTDbgModName(hMod);
4081 if ( cArgs == 0
4082 || dbgcCmdListModuleMatch(pszName, paArgs, cArgs))
4083 {
4084 /*
4085 * Find the mapping with the lower address, preferring a full
4086 * image mapping, for the main line.
4087 */
4088 RTDBGASMAPINFO aMappings[128];
4089 uint32_t cMappings = RT_ELEMENTS(aMappings);
4090 int rc = RTDbgAsModuleQueryMapByIndex(hAs, iMod, &aMappings[0], &cMappings, 0 /*fFlags*/);
4091 if (RT_SUCCESS(rc))
4092 {
4093 bool fFull = false;
4094 RTUINTPTR uMin = RTUINTPTR_MAX;
4095 for (uint32_t iMap = 0; iMap < cMappings; iMap++)
4096 if ( aMappings[iMap].Address < uMin
4097 && ( !fFull
4098 || aMappings[iMap].iSeg == NIL_RTDBGSEGIDX))
4099 uMin = aMappings[iMap].Address;
4100 DBGCCmdHlpPrintf(pCmdHlp, "%RGv %04x %s\n", (RTGCUINTPTR)uMin, cSegs, pszName);
4101
4102 if (fMappings)
4103 {
4104 /* sort by address first - not very efficient. */
4105 for (uint32_t i = 0; i + 1 < cMappings; i++)
4106 for (uint32_t j = i + 1; j < cMappings; j++)
4107 if (aMappings[j].Address < aMappings[i].Address)
4108 {
4109 RTDBGASMAPINFO Tmp = aMappings[j];
4110 aMappings[j] = aMappings[i];
4111 aMappings[i] = Tmp;
4112 }
4113
4114 /* print */
4115 for (uint32_t iMap = 0; iMap < cMappings; iMap++)
4116 if (aMappings[iMap].iSeg != NIL_RTDBGSEGIDX)
4117 DBGCCmdHlpPrintf(pCmdHlp, " %RGv %RGv #%02x %s\n",
4118 (RTGCUINTPTR)aMappings[iMap].Address,
4119 (RTGCUINTPTR)RTDbgModSegmentSize(hMod, aMappings[iMap].iSeg),
4120 aMappings[iMap].iSeg,
4121 /** @todo RTDbgModSegmentName(hMod, aMappings[iMap].iSeg)*/ "noname");
4122 else
4123 DBGCCmdHlpPrintf(pCmdHlp, " %RGv %RGv <everything>\n",
4124 (RTGCUINTPTR)aMappings[iMap].Address,
4125 (RTGCUINTPTR)RTDbgModImageSize(hMod));
4126 }
4127 }
4128 else
4129 DBGCCmdHlpPrintf(pCmdHlp, "%.*s %04x %s (rc=%Rrc)\n",
4130 sizeof(RTGCPTR) * 2, "???????????", cSegs, pszName, rc);
4131 /** @todo missing address space API for enumerating the mappings. */
4132 }
4133 RTDbgModRelease(hMod);
4134 }
4135 }
4136 RTDbgAsRelease(hAs);
4137
4138 NOREF(pCmd); NOREF(pResult);
4139 return VINF_SUCCESS;
4140}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette