VirtualBox

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

Last change on this file since 8725 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 138.1 KB
Line 
1/** $Id: DBGCEmulateCodeView.cpp 8155 2008-04-18 15:16:47Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, CodeView / WinDbg Emulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DBGC
26#include <VBox/dbg.h>
27#include <VBox/dbgf.h>
28#include <VBox/pgm.h>
29#include <VBox/selm.h>
30#include <VBox/cpum.h>
31#include <VBox/dis.h>
32#include <VBox/param.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35
36#include <iprt/alloc.h>
37#include <iprt/alloca.h>
38#include <iprt/string.h>
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41
42#include <stdlib.h>
43#include <stdio.h>
44
45#include "DBGCInternal.h"
46
47
48/*******************************************************************************
49* Internal Functions *
50*******************************************************************************/
51static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
52static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
53static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
54static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
55static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
56static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
57static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
58static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
59static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
60static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
61static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
62static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
63static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
64static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
65static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
66static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
67static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
68static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
69static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
70static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
71static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
72static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
73static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
74static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
75static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
76static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
77static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
78static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
79
80
81/*******************************************************************************
82* Global Variables *
83*******************************************************************************/
84/** 'ba' arguments. */
85static const DBGCVARDESC g_aArgBrkAcc[] =
86{
87 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
88 { 1, 1, DBGCVAR_CAT_STRING, 0, "access", "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." },
89 { 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." },
90 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
91 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
92 { 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)" },
93 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
94};
95
96
97/** 'bc', 'bd', 'be' arguments. */
98static const DBGCVARDESC g_aArgBrks[] =
99{
100 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
101 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "#bp", "Breakpoint number." },
102 { 0, 1, DBGCVAR_CAT_STRING, 0, "all", "All breakpoints." },
103};
104
105
106/** 'bp' arguments. */
107static const DBGCVARDESC g_aArgBrkSet[] =
108{
109 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
110 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
111 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
112 { 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)" },
113 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
114};
115
116
117/** 'br' arguments. */
118static const DBGCVARDESC g_aArgBrkREM[] =
119{
120 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
121 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },
122 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
123 { 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)" },
124 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
125};
126
127
128/** 'd?' arguments. */
129static const DBGCVARDESC g_aArgDumpMem[] =
130{
131 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
132 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start dumping memory." },
133};
134
135
136/** 'dg', 'dga', 'dl', 'dla' arguments. */
137static const DBGCVARDESC g_aArgDumpDT[] =
138{
139 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
140 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." },
141 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." },
142};
143
144
145/** 'di', 'dia' arguments. */
146static const DBGCVARDESC g_aArgDumpIDT[] =
147{
148 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
149 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." },
150};
151
152
153/** 'dpd*' arguments. */
154static const DBGCVARDESC g_aArgDumpPD[] =
155{
156 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
157 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." },
158 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },
159};
160
161
162/** 'dpda' arguments. */
163static const DBGCVARDESC g_aArgDumpPDAddr[] =
164{
165 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
166 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },
167};
168
169
170/** 'dpt?' arguments. */
171static const DBGCVARDESC g_aArgDumpPT[] =
172{
173 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
174 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },
175};
176
177
178/** 'dpta' arguments. */
179static const DBGCVARDESC g_aArgDumpPTAddr[] =
180{
181 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
182 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },
183};
184
185
186/** 'dt' arguments. */
187static const DBGCVARDESC g_aArgDumpTSS[] =
188{
189 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
190 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." },
191 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }
192};
193
194
195/** 'ln' arguments. */
196static const DBGCVARDESC g_aArgListNear[] =
197{
198 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
199 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Address of the symbol to look up." },
200 { 0, ~0, DBGCVAR_CAT_SYMBOL, 0, "symbol", "Symbol to lookup." },
201};
202
203/** 'ln' return. */
204static const DBGCVARDESC g_RetListNear =
205{
206 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The last resolved symbol/address with adjusted range."
207};
208
209
210/** 'ls' arguments. */
211static const DBGCVARDESC g_aArgListSource[] =
212{
213 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
214 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start looking for source lines." },
215};
216
217
218/** 'm' argument. */
219static const DBGCVARDESC g_aArgMemoryInfo[] =
220{
221 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
222 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Pointer to obtain info about." },
223};
224
225
226/** 'r' arguments. */
227static const DBGCVARDESC g_aArgReg[] =
228{
229 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
230 { 0, 1, DBGCVAR_CAT_SYMBOL, 0, "register", "Register to show or set." },
231 { 0, 1, DBGCVAR_CAT_NUMBER_NO_RANGE, DBGCVD_FLAGS_DEP_PREV, "value", "New register value." },
232};
233
234
235/** 's' arguments. */
236static const DBGCVARDESC g_aArgSearchMem[] =
237{
238 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
239 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-b", "Byte string." },
240 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-w", "Word string." },
241 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-d", "DWord string." },
242 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-q", "QWord string." },
243 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-a", "ASCII string." },
244 { 0, 1, DBGCVAR_CAT_OPTION, 0, "-u", "Unicode string." },
245 { 0, 1, DBGCVAR_CAT_OPTION_NUMBER, 0, "-n <Hits>", "Maximum number of hits." },
246 { 0, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." },
247 { 0, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." },
248};
249
250
251/** 's?' arguments. */
252static const DBGCVARDESC g_aArgSearchMemType[] =
253{
254 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
255 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." },
256 { 1, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." },
257};
258
259
260/** 'u' arguments. */
261static const DBGCVARDESC g_aArgUnassemble[] =
262{
263 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
264 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start disassembling." },
265};
266
267
268/** Command descriptors for the CodeView / WinDbg emulation.
269 * The emulation isn't attempting to be identical, only somewhat similar.
270 */
271const DBGCCMD g_aCmdsCodeView[] =
272{
273 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
274 { "ba", 3, 6, &g_aArgBrkAcc[0], RT_ELEMENTS(g_aArgBrkAcc), NULL, 0, dbgcCmdBrkAccess, "<access> <size> <address> [passes [max passes]] [cmds]",
275 "Sets a data access breakpoint." },
276 { "bc", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkClear, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
277 { "bd", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkDisable, "all | <bp#> [bp# []]", "Disables a set of breakpoints." },
278 { "be", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkEnable, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
279 { "bl", 0, 0, NULL, 0, NULL, 0, dbgcCmdBrkList, "", "Lists all the breakpoints." },
280 { "bp", 1, 4, &g_aArgBrkSet[0], RT_ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]",
281 "Sets a breakpoint (int 3)." },
282 { "br", 1, 4, &g_aArgBrkREM[0], RT_ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]",
283 "Sets a recompiler specific breakpoint." },
284 { "d", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." },
285 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." },
286 { "db", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." },
287 { "dd", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." },
288 { "dg", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." },
289 { "dga", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." },
290 { "di", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." },
291 { "dia", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." },
292 { "dl", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." },
293 { "dla", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." },
294 { "dpd", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." },
295 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],RT_ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." },
296 { "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. " },
297 { "dpdg", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." },
298 { "dpdh", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " },
299 { "dpt", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." },
300 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],RT_ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." },
301 { "dptb", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." },
302 { "dptg", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." },
303 { "dpth", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." },
304 { "dq", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." },
305 { "dt", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." },
306 { "dw", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." },
307 { "g", 0, 0, NULL, 0, NULL, 0, dbgcCmdGo, "", "Continue execution." },
308 { "k", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack." },
309 { "kg", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - guest." },
310 { "kh", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - hypervisor." },
311 { "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." },
312 { "ls", 0, 1, &g_aArgListSource[0],RT_ELEMENTS(g_aArgListSource),NULL, 0, dbgcCmdListSource, "[addr]", "Source." },
313 { "m", 1, 1, &g_aArgMemoryInfo[0],RT_ELEMENTS(g_aArgMemoryInfo),NULL, 0, dbgcCmdMemoryInfo, "<addr>", "Display information about that piece of memory." },
314 { "r", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdReg, "[reg [newval]]", "Show or set register(s) - active reg set." },
315 { "rg", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegGuest, "[reg [newval]]", "Show or set register(s) - guest reg set." },
316 { "rh", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegHyper, "[reg [newval]]", "Show or set register(s) - hypervisor reg set." },
317 { "rt", 0, 0, NULL, 0, NULL, 0, dbgcCmdRegTerse, "", "Toggles terse / verbose register info." },
318 { "s", 0, ~0, &g_aArgSearchMem[0], RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "[options] <range> <pattern>", "Continue last search." },
319 { "sa", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for an ascii string." },
320 { "sb", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more bytes." },
321 { "sd", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more double words." },
322 { "sq", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more quad words." },
323 { "su", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for an unicode string." },
324 { "sw", 2, ~0, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType), NULL, 0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more words." },
325 { "t", 0, 0, NULL, 0, NULL, 0, dbgcCmdTrace, "", "Instruction trace (step into)." },
326 { "u", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble." },
327};
328
329/** The number of commands in the CodeView/WinDbg emulation. */
330const unsigned g_cCmdsCodeView = RT_ELEMENTS(g_aCmdsCodeView);
331
332
333
334/**
335 * The 'go' command.
336 *
337 * @returns VBox status.
338 * @param pCmd Pointer to the command descriptor (as registered).
339 * @param pCmdHlp Pointer to command helper functions.
340 * @param pVM Pointer to the current VM (if any).
341 * @param paArgs Pointer to (readonly) array of arguments.
342 * @param cArgs Number of arguments in the array.
343 */
344static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
345{
346 /*
347 * Check if the VM is halted or not before trying to resume it.
348 */
349 if (!DBGFR3IsHalted(pVM))
350 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already running...\n");
351 else
352 {
353 int rc = DBGFR3Resume(pVM);
354 if (VBOX_FAILURE(rc))
355 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Resume().");
356 }
357
358 NOREF(pCmd);
359 NOREF(paArgs);
360 NOREF(cArgs);
361 NOREF(pResult);
362 return 0;
363}
364
365
366/**
367 * The 'ba' command.
368 *
369 * @returns VBox status.
370 * @param pCmd Pointer to the command descriptor (as registered).
371 * @param pCmdHlp Pointer to command helper functions.
372 * @param pVM Pointer to the current VM (if any).
373 * @param paArgs Pointer to (readonly) array of arguments.
374 * @param cArgs Number of arguments in the array.
375 */
376static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
377{
378 /*
379 * Interpret access type.
380 */
381 if ( !strchr("xrwi", paArgs[0].u.pszString[0])
382 || paArgs[0].u.pszString[1])
383 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n",
384 paArgs[0].u.pszString, pCmd->pszCmd);
385 uint8_t fType = 0;
386 switch (paArgs[0].u.pszString[0])
387 {
388 case 'x': fType = X86_DR7_RW_EO; break;
389 case 'r': fType = X86_DR7_RW_RW; break;
390 case 'w': fType = X86_DR7_RW_WO; break;
391 case 'i': fType = X86_DR7_RW_IO; break;
392 }
393
394 /*
395 * Validate size.
396 */
397 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1)
398 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n",
399 paArgs[1].u.u64Number, pCmd->pszCmd);
400 switch (paArgs[1].u.u64Number)
401 {
402 case 1:
403 case 2:
404 case 4:
405 break;
406 /*case 8: - later*/
407 default:
408 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 1, 2 or 4!\n",
409 paArgs[1].u.u64Number, pCmd->pszCmd);
410 }
411 uint8_t cb = (uint8_t)paArgs[1].u.u64Number;
412
413 /*
414 * Convert the pointer to a DBGF address.
415 */
416 DBGFADDRESS Address;
417 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address);
418 if (VBOX_FAILURE(rc))
419 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[2], rc);
420
421 /*
422 * Pick out the optional arguments.
423 */
424 uint64_t iHitTrigger = 0;
425 uint64_t iHitDisable = ~0;
426 const char *pszCmds = NULL;
427 unsigned iArg = 3;
428 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
429 {
430 iHitTrigger = paArgs[iArg].u.u64Number;
431 iArg++;
432 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
433 {
434 iHitDisable = paArgs[iArg].u.u64Number;
435 iArg++;
436 }
437 }
438 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
439 {
440 pszCmds = paArgs[iArg].u.pszString;
441 iArg++;
442 }
443
444 /*
445 * Try set the breakpoint.
446 */
447 RTUINT iBp;
448 rc = DBGFR3BpSetReg(pVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp);
449 if (VBOX_SUCCESS(rc))
450 {
451 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
452 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
453 if (VBOX_SUCCESS(rc))
454 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
455 if (rc == VERR_DBGC_BP_EXISTS)
456 {
457 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
458 if (VBOX_SUCCESS(rc))
459 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
460 }
461 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
462 AssertRC(rc2);
463 }
464 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
465}
466
467
468/**
469 * The 'bc' command.
470 *
471 * @returns VBox status.
472 * @param pCmd Pointer to the command descriptor (as registered).
473 * @param pCmdHlp Pointer to command helper functions.
474 * @param pVM Pointer to the current VM (if any).
475 * @param paArgs Pointer to (readonly) array of arguments.
476 * @param cArgs Number of arguments in the array.
477 */
478static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
479{
480 /*
481 * Enumerate the arguments.
482 */
483 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
484 int rc = VINF_SUCCESS;
485 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
486 {
487 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
488 {
489 /* one */
490 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
491 if (iBp != paArgs[iArg].u.u64Number)
492 {
493 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
494 break;
495 }
496 int rc2 = DBGFR3BpClear(pVM, iBp);
497 if (VBOX_FAILURE(rc2))
498 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
499 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
500 dbgcBpDelete(pDbgc, iBp);
501 }
502 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
503 {
504 /* all */
505 PDBGCBP pBp = pDbgc->pFirstBp;
506 while (pBp)
507 {
508 RTUINT iBp = pBp->iBp;
509 pBp = pBp->pNext;
510
511 int rc2 = DBGFR3BpClear(pVM, iBp);
512 if (VBOX_FAILURE(rc2))
513 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
514 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
515 dbgcBpDelete(pDbgc, iBp);
516 }
517 }
518 else
519 {
520 /* invalid parameter */
521 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
522 break;
523 }
524 }
525 return rc;
526}
527
528
529/**
530 * The 'bd' command.
531 *
532 * @returns VBox status.
533 * @param pCmd Pointer to the command descriptor (as registered).
534 * @param pCmdHlp Pointer to command helper functions.
535 * @param pVM Pointer to the current VM (if any).
536 * @param paArgs Pointer to (readonly) array of arguments.
537 * @param cArgs Number of arguments in the array.
538 */
539static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
540{
541 /*
542 * Enumerate the arguments.
543 */
544 int rc = VINF_SUCCESS;
545 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
546 {
547 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
548 {
549 /* one */
550 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
551 if (iBp != paArgs[iArg].u.u64Number)
552 {
553 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
554 break;
555 }
556 rc = DBGFR3BpDisable(pVM, iBp);
557 if (VBOX_FAILURE(rc))
558 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", iBp);
559 }
560 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
561 {
562 /* all */
563 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
564 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
565 {
566 rc = DBGFR3BpDisable(pVM, pBp->iBp);
567 if (VBOX_FAILURE(rc))
568 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", pBp->iBp);
569 }
570 }
571 else
572 {
573 /* invalid parameter */
574 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
575 break;
576 }
577 }
578 return rc;
579}
580
581
582/**
583 * The 'be' command.
584 *
585 * @returns VBox status.
586 * @param pCmd Pointer to the command descriptor (as registered).
587 * @param pCmdHlp Pointer to command helper functions.
588 * @param pVM Pointer to the current VM (if any).
589 * @param paArgs Pointer to (readonly) array of arguments.
590 * @param cArgs Number of arguments in the array.
591 */
592static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
593{
594 /*
595 * Enumerate the arguments.
596 */
597 int rc = VINF_SUCCESS;
598 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
599 {
600 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
601 {
602 /* one */
603 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
604 if (iBp != paArgs[iArg].u.u64Number)
605 {
606 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
607 break;
608 }
609 rc = DBGFR3BpEnable(pVM, iBp);
610 if (VBOX_FAILURE(rc))
611 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", iBp);
612 }
613 else if (!strcmp(paArgs[iArg].u.pszString, "all"))
614 {
615 /* all */
616 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
617 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
618 {
619 rc = DBGFR3BpEnable(pVM, pBp->iBp);
620 if (VBOX_FAILURE(rc))
621 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", pBp->iBp);
622 }
623 }
624 else
625 {
626 /* invalid parameter */
627 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
628 break;
629 }
630 }
631 return rc;
632}
633
634
635/**
636 * Breakpoint enumeration callback function.
637 *
638 * @returns VBox status code. Any failure will stop the enumeration.
639 * @param pVM The VM handle.
640 * @param pvUser The user argument.
641 * @param pBp Pointer to the breakpoint information. (readonly)
642 */
643static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PVM pVM, void *pvUser, PCDBGFBP pBp)
644{
645 PDBGC pDbgc = (PDBGC)pvUser;
646 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp);
647
648 /*
649 * BP type and size.
650 */
651 char chType;
652 char cb = 1;
653 switch (pBp->enmType)
654 {
655 case DBGFBPTYPE_INT3:
656 chType = 'p';
657 break;
658 case DBGFBPTYPE_REG:
659 switch (pBp->u.Reg.fType)
660 {
661 case X86_DR7_RW_EO: chType = 'x'; break;
662 case X86_DR7_RW_WO: chType = 'w'; break;
663 case X86_DR7_RW_IO: chType = 'i'; break;
664 case X86_DR7_RW_RW: chType = 'r'; break;
665 default: chType = '?'; break;
666
667 }
668 cb = pBp->u.Reg.cb;
669 break;
670 case DBGFBPTYPE_REM:
671 chType = 'r';
672 break;
673 default:
674 chType = '?';
675 break;
676 }
677
678 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%2u %c %d %c %VGv %04RX64 (%04RX64 to ",
679 pBp->iBp, pBp->fEnabled ? 'e' : 'd', cb, chType,
680 pBp->GCPtr, pBp->cHits, pBp->iHitTrigger);
681 if (pBp->iHitDisable == ~(uint64_t)0)
682 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "~0) ");
683 else
684 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%04RX64)");
685
686 /*
687 * Try resolve the address.
688 */
689 DBGFSYMBOL Sym;
690 RTGCINTPTR off;
691 int rc = DBGFR3SymbolByAddr(pVM, pBp->GCPtr, &off, &Sym);
692 if (VBOX_SUCCESS(rc))
693 {
694 if (!off)
695 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", Sym.szName);
696 else if (off > 0)
697 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, off);
698 else
699 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, -off);
700 }
701
702 /*
703 * The commands.
704 */
705 if (pDbgcBp)
706 {
707 if (pDbgcBp->cchCmd)
708 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n cmds: '%s'\n",
709 pDbgcBp->szCmd);
710 else
711 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");
712 }
713 else
714 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " [unknown bp]\n");
715
716 return VINF_SUCCESS;
717}
718
719
720/**
721 * The 'bl' command.
722 *
723 * @returns VBox status.
724 * @param pCmd Pointer to the command descriptor (as registered).
725 * @param pCmdHlp Pointer to command helper functions.
726 * @param pVM Pointer to the current VM (if any).
727 * @param paArgs Pointer to (readonly) array of arguments.
728 * @param cArgs Number of arguments in the array.
729 */
730static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
731{
732 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
733
734 /*
735 * Enumerate the breakpoints.
736 */
737 int rc = DBGFR3BpEnum(pVM, dbgcEnumBreakpointsCallback, pDbgc);
738 if (VBOX_FAILURE(rc))
739 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnum failed.\n");
740 return rc;
741}
742
743
744/**
745 * The 'bp' command.
746 *
747 * @returns VBox status.
748 * @param pCmd Pointer to the command descriptor (as registered).
749 * @param pCmdHlp Pointer to command helper functions.
750 * @param pVM Pointer to the current VM (if any).
751 * @param paArgs Pointer to (readonly) array of arguments.
752 * @param cArgs Number of arguments in the array.
753 */
754static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
755{
756 /*
757 * Convert the pointer to a DBGF address.
758 */
759 DBGFADDRESS Address;
760 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
761 if (VBOX_FAILURE(rc))
762 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
763
764 /*
765 * Pick out the optional arguments.
766 */
767 uint64_t iHitTrigger = 0;
768 uint64_t iHitDisable = ~0;
769 const char *pszCmds = NULL;
770 unsigned iArg = 1;
771 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
772 {
773 iHitTrigger = paArgs[iArg].u.u64Number;
774 iArg++;
775 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
776 {
777 iHitDisable = paArgs[iArg].u.u64Number;
778 iArg++;
779 }
780 }
781 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
782 {
783 pszCmds = paArgs[iArg].u.pszString;
784 iArg++;
785 }
786
787 /*
788 * Try set the breakpoint.
789 */
790 RTUINT iBp;
791 rc = DBGFR3BpSet(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
792 if (VBOX_SUCCESS(rc))
793 {
794 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
795 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
796 if (VBOX_SUCCESS(rc))
797 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
798 if (rc == VERR_DBGC_BP_EXISTS)
799 {
800 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
801 if (VBOX_SUCCESS(rc))
802 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
803 }
804 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
805 AssertRC(rc2);
806 }
807 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
808}
809
810
811/**
812 * The 'br' command.
813 *
814 * @returns VBox status.
815 * @param pCmd Pointer to the command descriptor (as registered).
816 * @param pCmdHlp Pointer to command helper functions.
817 * @param pVM Pointer to the current VM (if any).
818 * @param paArgs Pointer to (readonly) array of arguments.
819 * @param cArgs Number of arguments in the array.
820 */
821static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
822{
823 /*
824 * Convert the pointer to a DBGF address.
825 */
826 DBGFADDRESS Address;
827 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
828 if (VBOX_FAILURE(rc))
829 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
830
831 /*
832 * Pick out the optional arguments.
833 */
834 uint64_t iHitTrigger = 0;
835 uint64_t iHitDisable = ~0;
836 const char *pszCmds = NULL;
837 unsigned iArg = 1;
838 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
839 {
840 iHitTrigger = paArgs[iArg].u.u64Number;
841 iArg++;
842 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
843 {
844 iHitDisable = paArgs[iArg].u.u64Number;
845 iArg++;
846 }
847 }
848 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
849 {
850 pszCmds = paArgs[iArg].u.pszString;
851 iArg++;
852 }
853
854 /*
855 * Try set the breakpoint.
856 */
857 RTUINT iBp;
858 rc = DBGFR3BpSetREM(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
859 if (VBOX_SUCCESS(rc))
860 {
861 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
862 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
863 if (VBOX_SUCCESS(rc))
864 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
865 if (rc == VERR_DBGC_BP_EXISTS)
866 {
867 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
868 if (VBOX_SUCCESS(rc))
869 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
870 }
871 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
872 AssertRC(rc2);
873 }
874 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
875}
876
877
878/**
879 * The 'u' command.
880 *
881 * @returns VBox status.
882 * @param pCmd Pointer to the command descriptor (as registered).
883 * @param pCmdHlp Pointer to command helper functions.
884 * @param pVM Pointer to the current VM (if any).
885 * @param paArgs Pointer to (readonly) array of arguments.
886 * @param cArgs Number of arguments in the array.
887 */
888static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
889{
890 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
891
892 /*
893 * Validate input.
894 */
895 if ( cArgs > 1
896 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
897 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
898 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
899 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
900 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
901 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
902
903 /*
904 * Find address.
905 */
906 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS;
907 if (!cArgs)
908 {
909 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
910 {
911 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR;
912 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);
913 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM);
914 if (pDbgc->fRegCtxGuest)
915 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST;
916 else
917 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER;
918 }
919 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE;
920 }
921 else
922 pDbgc->DisasmPos = paArgs[0];
923
924 /*
925 * Range.
926 */
927 switch (pDbgc->DisasmPos.enmRangeType)
928 {
929 case DBGCVAR_RANGE_NONE:
930 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
931 pDbgc->DisasmPos.u64Range = 10;
932 break;
933
934 case DBGCVAR_RANGE_ELEMENTS:
935 if (pDbgc->DisasmPos.u64Range > 2048)
936 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
937 break;
938
939 case DBGCVAR_RANGE_BYTES:
940 if (pDbgc->DisasmPos.u64Range > 65536)
941 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
942 break;
943
944 default:
945 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType);
946 }
947
948 /*
949 * Convert physical and host addresses to guest addresses.
950 */
951 int rc;
952 switch (pDbgc->DisasmPos.enmType)
953 {
954 case DBGCVAR_TYPE_GC_FLAT:
955 case DBGCVAR_TYPE_GC_FAR:
956 break;
957 case DBGCVAR_TYPE_GC_PHYS:
958 case DBGCVAR_TYPE_HC_FLAT:
959 case DBGCVAR_TYPE_HC_PHYS:
960 case DBGCVAR_TYPE_HC_FAR:
961 {
962 DBGCVAR VarTmp;
963 rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos);
964 if (VBOX_FAILURE(rc))
965 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Vrc .\n", &pDbgc->DisasmPos, rc);
966 pDbgc->DisasmPos = VarTmp;
967 break;
968 }
969 default: AssertFailed(); break;
970 }
971
972 /*
973 * Print address.
974 * todo: Change to list near.
975 */
976#if 0
977 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DisasmPos);
978 if (VBOX_FAILURE(rc))
979 return rc;
980#endif
981
982 /*
983 * Do the disassembling.
984 */
985 unsigned cTries = 32;
986 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range;
987 if (iRangeLeft == 0) /* klugde for 'r'. */
988 iRangeLeft = -1;
989 for (;;)
990 {
991 /*
992 * Disassemble the instruction.
993 */
994 char szDis[256];
995 uint32_t cbInstr = 1;
996 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT)
997 rc = DBGFR3DisasInstrEx(pVM, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
998 else
999 rc = DBGFR3DisasInstrEx(pVM, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
1000 if (VBOX_SUCCESS(rc))
1001 {
1002 /* print it */
1003 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]);
1004 if (VBOX_FAILURE(rc))
1005 return rc;
1006 }
1007 else
1008 {
1009 /* bitch. */
1010 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");
1011 if (VBOX_FAILURE(rc))
1012 return rc;
1013 if (cTries-- > 0)
1014 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Too many disassembly failures. Giving up.\n");
1015 cbInstr = 1;
1016 }
1017
1018 /* advance */
1019 if (iRangeLeft < 0) /* 'r' */
1020 break;
1021 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
1022 iRangeLeft--;
1023 else
1024 iRangeLeft -= cbInstr;
1025 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr);
1026 if (VBOX_FAILURE(rc))
1027 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DisasmPos, cbInstr);
1028 if (iRangeLeft <= 0)
1029 break;
1030 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER);
1031 }
1032
1033 NOREF(pCmd); NOREF(pResult);
1034 return 0;
1035}
1036
1037
1038/**
1039 * The 'ls' command.
1040 *
1041 * @returns VBox status.
1042 * @param pCmd Pointer to the command descriptor (as registered).
1043 * @param pCmdHlp Pointer to command helper functions.
1044 * @param pVM Pointer to the current VM (if any).
1045 * @param paArgs Pointer to (readonly) array of arguments.
1046 * @param cArgs Number of arguments in the array.
1047 */
1048static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1049{
1050 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1051
1052 /*
1053 * Validate input.
1054 */
1055 if ( cArgs > 1
1056 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
1057 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
1058 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
1059 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
1060 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
1061 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
1062
1063 /*
1064 * Find address.
1065 */
1066 if (!cArgs)
1067 {
1068 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
1069 {
1070 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR;
1071 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);
1072 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM);
1073 }
1074 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE;
1075 }
1076 else
1077 pDbgc->SourcePos = paArgs[0];
1078
1079 /*
1080 * Ensure the the source address is flat GC.
1081 */
1082 switch (pDbgc->SourcePos.enmType)
1083 {
1084 case DBGCVAR_TYPE_GC_FLAT:
1085 break;
1086 case DBGCVAR_TYPE_GC_PHYS:
1087 case DBGCVAR_TYPE_GC_FAR:
1088 case DBGCVAR_TYPE_HC_FLAT:
1089 case DBGCVAR_TYPE_HC_PHYS:
1090 case DBGCVAR_TYPE_HC_FAR:
1091 {
1092 int rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos);
1093 if (VBOX_FAILURE(rc))
1094 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid address or address type. (rc=%d)\n", rc);
1095 break;
1096 }
1097 default: AssertFailed(); break;
1098 }
1099
1100 /*
1101 * Range.
1102 */
1103 switch (pDbgc->SourcePos.enmRangeType)
1104 {
1105 case DBGCVAR_RANGE_NONE:
1106 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
1107 pDbgc->SourcePos.u64Range = 10;
1108 break;
1109
1110 case DBGCVAR_RANGE_ELEMENTS:
1111 if (pDbgc->SourcePos.u64Range > 2048)
1112 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
1113 break;
1114
1115 case DBGCVAR_RANGE_BYTES:
1116 if (pDbgc->SourcePos.u64Range > 65536)
1117 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
1118 break;
1119
1120 default:
1121 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);
1122 }
1123
1124 /*
1125 * Do the disassembling.
1126 */
1127 bool fFirst = 1;
1128 DBGFLINE LinePrev = { 0, 0, "" };
1129 int iRangeLeft = (int)pDbgc->SourcePos.u64Range;
1130 if (iRangeLeft == 0) /* klugde for 'r'. */
1131 iRangeLeft = -1;
1132 for (;;)
1133 {
1134 /*
1135 * Get line info.
1136 */
1137 DBGFLINE Line;
1138 RTGCINTPTR off;
1139 int rc = DBGFR3LineByAddr(pVM, pDbgc->SourcePos.u.GCFlat, &off, &Line);
1140 if (VBOX_FAILURE(rc))
1141 return VINF_SUCCESS;
1142
1143 unsigned cLines = 0;
1144 if (memcmp(&Line, &LinePrev, sizeof(Line)))
1145 {
1146 /*
1147 * Print filenamename
1148 */
1149 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename))
1150 fFirst = true;
1151 if (fFirst)
1152 {
1153 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "[%s @ %d]\n", Line.szFilename, Line.uLineNo);
1154 if (VBOX_FAILURE(rc))
1155 return rc;
1156 }
1157
1158 /*
1159 * Try open the file and read the line.
1160 */
1161 FILE *phFile = fopen(Line.szFilename, "r");
1162 if (phFile)
1163 {
1164 /* Skip ahead to the desired line. */
1165 char szLine[4096];
1166 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1;
1167 if (cBefore > 7)
1168 cBefore = 0;
1169 unsigned cLeft = Line.uLineNo - cBefore;
1170 while (cLeft > 0)
1171 {
1172 szLine[0] = '\0';
1173 if (!fgets(szLine, sizeof(szLine), phFile))
1174 break;
1175 cLeft--;
1176 }
1177 if (!cLeft)
1178 {
1179 /* print the before lines */
1180 for (;;)
1181 {
1182 size_t cch = strlen(szLine);
1183 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || isspace(szLine[cch - 1])) )
1184 szLine[--cch] = '\0';
1185 if (cBefore-- <= 0)
1186 break;
1187
1188 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine);
1189 szLine[0] = '\0';
1190 fgets(szLine, sizeof(szLine), phFile);
1191 cLines++;
1192 }
1193 /* print the actual line */
1194 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine);
1195 }
1196 fclose(phFile);
1197 if (VBOX_FAILURE(rc))
1198 return rc;
1199 fFirst = false;
1200 }
1201 else
1202 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);
1203
1204 LinePrev = Line;
1205 }
1206
1207
1208 /*
1209 * Advance
1210 */
1211 if (iRangeLeft < 0) /* 'r' */
1212 break;
1213 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
1214 iRangeLeft -= cLines;
1215 else
1216 iRangeLeft -= 1;
1217 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1);
1218 if (VBOX_FAILURE(rc))
1219 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1);
1220 if (iRangeLeft <= 0)
1221 break;
1222 }
1223
1224 NOREF(pCmd); NOREF(pResult);
1225 return 0;
1226}
1227
1228
1229/**
1230 * The 'r' command.
1231 *
1232 * @returns VBox status.
1233 * @param pCmd Pointer to the command descriptor (as registered).
1234 * @param pCmdHlp Pointer to command helper functions.
1235 * @param pVM Pointer to the current VM (if any).
1236 * @param paArgs Pointer to (readonly) array of arguments.
1237 * @param cArgs Number of arguments in the array.
1238 */
1239static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1240{
1241 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1242
1243 if (pDbgc->fRegCtxGuest)
1244 return dbgcCmdRegGuest(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
1245 else
1246 return dbgcCmdRegHyper(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
1247}
1248
1249
1250/**
1251 * Common worker for the dbgcCmdReg*() commands.
1252 *
1253 * @returns VBox status.
1254 * @param pCmd Pointer to the command descriptor (as registered).
1255 * @param pCmdHlp Pointer to command helper functions.
1256 * @param pVM Pointer to the current VM (if any).
1257 * @param paArgs Pointer to (readonly) array of arguments.
1258 * @param cArgs Number of arguments in the array.
1259 * @param pszPrefix The symbol prefix.
1260 */
1261static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult, const char *pszPrefix)
1262{
1263 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1264
1265 /*
1266 * cArgs == 0: Show all
1267 */
1268 if (cArgs == 0)
1269 {
1270 /*
1271 * Get register context.
1272 */
1273 int rc;
1274 PCPUMCTX pCtx;
1275 PCCPUMCTXCORE pCtxCore;
1276 if (!*pszPrefix)
1277 {
1278 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
1279 pCtxCore = CPUMGetGuestCtxCore(pVM);
1280 }
1281 else
1282 {
1283 rc = CPUMQueryHyperCtxPtr(pVM, &pCtx);
1284 pCtxCore = CPUMGetHyperCtxCore(pVM);
1285 }
1286 if (VBOX_FAILURE(rc))
1287 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Getting register context\n");
1288
1289 /*
1290 * Format the flags.
1291 */
1292 static struct
1293 {
1294 const char *pszSet; const char *pszClear; uint32_t fFlag;
1295 } aFlags[] =
1296 {
1297 { "vip",NULL, X86_EFL_VIP },
1298 { "vif",NULL, X86_EFL_VIF },
1299 { "ac", NULL, X86_EFL_AC },
1300 { "vm", NULL, X86_EFL_VM },
1301 { "rf", NULL, X86_EFL_RF },
1302 { "nt", NULL, X86_EFL_NT },
1303 { "ov", "nv", X86_EFL_OF },
1304 { "dn", "up", X86_EFL_DF },
1305 { "ei", "di", X86_EFL_IF },
1306 { "tf", NULL, X86_EFL_TF },
1307 { "ng", "pl", X86_EFL_SF },
1308 { "zr", "nz", X86_EFL_ZF },
1309 { "ac", "na", X86_EFL_AF },
1310 { "po", "pe", X86_EFL_PF },
1311 { "cy", "nc", X86_EFL_CF },
1312 };
1313 char szEFlags[80];
1314 char *psz = szEFlags;
1315 uint32_t efl = pCtxCore->eflags.u32;
1316 for (unsigned i = 0; i < ELEMENTS(aFlags); i++)
1317 {
1318 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
1319 if (pszAdd)
1320 {
1321 strcpy(psz, pszAdd);
1322 psz += strlen(pszAdd);
1323 *psz++ = ' ';
1324 }
1325 }
1326 psz[-1] = '\0';
1327
1328
1329 /*
1330 * Format the registers.
1331 */
1332 if (pDbgc->fRegTerse)
1333 {
1334 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1335 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
1336 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
1337 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",
1338 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
1339 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,
1340 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
1341 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);
1342 }
1343 else
1344 {
1345 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1346 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
1347 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
1348 "%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"
1349 "%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"
1350 "%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"
1351 "%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"
1352 "%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"
1353 "%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"
1354 "%sgdtr=%08x:%04x %sidtr=%08x:%04x %seflags=%08x\n"
1355 "%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"
1356 "%str ={%04x base=%08x limit=%08x flags=%08x}\n"
1357 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
1358 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"
1359 ,
1360 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
1361 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
1362 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0, pszPrefix, pCtx->dr1,
1363 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2, pszPrefix, pCtx->dr3,
1364 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4, pszPrefix, pCtx->dr5,
1365 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6, pszPrefix, pCtx->dr7,
1366 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,
1367 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
1368 pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,
1369 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
1370 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
1371 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
1372 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);
1373 }
1374
1375 /*
1376 * Disassemble one instruction at cs:eip.
1377 */
1378 return pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pCtx->cs, pCtx->eip);
1379 }
1380
1381 /*
1382 * cArgs == 1: Show the register.
1383 * cArgs == 2: Modify the register.
1384 */
1385 if ( cArgs == 1
1386 || cArgs == 2)
1387 {
1388 /* locate the register symbol. */
1389 const char *pszReg = paArgs[0].u.pszString;
1390 if ( *pszPrefix
1391 && pszReg[0] != *pszPrefix)
1392 {
1393 /* prepend the prefix. */
1394 char *psz = (char *)alloca(strlen(pszReg) + 2);
1395 psz[0] = *pszPrefix;
1396 strcpy(psz + 1, paArgs[0].u.pszString);
1397 pszReg = psz;
1398 }
1399 PCDBGCSYM pSym = dbgcLookupRegisterSymbol(pDbgc, pszReg);
1400 if (!pSym)
1401 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);
1402
1403 /* show the register */
1404 if (cArgs == 1)
1405 {
1406 DBGCVAR Var;
1407 memset(&Var, 0, sizeof(Var));
1408 int rc = pSym->pfnGet(pSym, pCmdHlp, DBGCVAR_TYPE_NUMBER, &Var);
1409 if (VBOX_FAILURE(rc))
1410 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed getting value for register '%s'.\n", pszReg);
1411 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s=%Dv\n", pszReg, &Var);
1412 }
1413
1414 /* change the register */
1415 int rc = pSym->pfnSet(pSym, pCmdHlp, &paArgs[1]);
1416 if (VBOX_FAILURE(rc))
1417 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed setting value for register '%s'.\n", pszReg);
1418 return VINF_SUCCESS;
1419 }
1420
1421
1422 NOREF(pCmd); NOREF(paArgs); NOREF(pResult);
1423 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Huh? cArgs=%d Expected 0, 1 or 2!\n", cArgs);
1424}
1425
1426
1427/**
1428 * The 'rg' command.
1429 *
1430 * @returns VBox status.
1431 * @param pCmd Pointer to the command descriptor (as registered).
1432 * @param pCmdHlp Pointer to command helper functions.
1433 * @param pVM Pointer to the current VM (if any).
1434 * @param paArgs Pointer to (readonly) array of arguments.
1435 * @param cArgs Number of arguments in the array.
1436 */
1437static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1438{
1439 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, "");
1440}
1441
1442
1443/**
1444 * The 'rh' command.
1445 *
1446 * @returns VBox status.
1447 * @param pCmd Pointer to the command descriptor (as registered).
1448 * @param pCmdHlp Pointer to command helper functions.
1449 * @param pVM Pointer to the current VM (if any).
1450 * @param paArgs Pointer to (readonly) array of arguments.
1451 * @param cArgs Number of arguments in the array.
1452 */
1453static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1454{
1455 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, ".");
1456}
1457
1458
1459/**
1460 * The 'rt' command.
1461 *
1462 * @returns VBox status.
1463 * @param pCmd Pointer to the command descriptor (as registered).
1464 * @param pCmdHlp Pointer to command helper functions.
1465 * @param pVM Pointer to the current VM (if any).
1466 * @param paArgs Pointer to (readonly) array of arguments.
1467 * @param cArgs Number of arguments in the array.
1468 */
1469static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1470{
1471 NOREF(pCmd); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1472
1473 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1474 pDbgc->fRegTerse = !pDbgc->fRegTerse;
1475 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");
1476}
1477
1478
1479/**
1480 * The 't' command.
1481 *
1482 * @returns VBox status.
1483 * @param pCmd Pointer to the command descriptor (as registered).
1484 * @param pCmdHlp Pointer to command helper functions.
1485 * @param pVM Pointer to the current VM (if any).
1486 * @param paArgs Pointer to (readonly) array of arguments.
1487 * @param cArgs Number of arguments in the array.
1488 */
1489static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1490{
1491 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1492
1493 int rc = DBGFR3Step(pVM);
1494 if (VBOX_SUCCESS(rc))
1495 pDbgc->fReady = false;
1496 else
1497 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);
1498
1499 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1500 return rc;
1501}
1502
1503
1504/**
1505 * The 'k', 'kg' and 'kh' commands.
1506 *
1507 * @returns VBox status.
1508 * @param pCmd Pointer to the command descriptor (as registered).
1509 * @param pCmdHlp Pointer to command helper functions.
1510 * @param pVM Pointer to the current VM (if any).
1511 * @param paArgs Pointer to (readonly) array of arguments.
1512 * @param cArgs Number of arguments in the array.
1513 */
1514static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1515{
1516 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1517
1518 /*
1519 * Figure which context we're called for.
1520 */
1521 bool fGuest = pCmd->pszCmd[1] == 'g'
1522 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest);
1523
1524
1525 DBGFSTACKFRAME Frame;
1526 memset(&Frame, 0, sizeof(Frame));
1527 int rc;
1528 if (fGuest)
1529 rc = DBGFR3StackWalkBeginGuest(pVM, &Frame);
1530 else
1531 rc = DBGFR3StackWalkBeginHyper(pVM, &Frame);
1532 if (VBOX_FAILURE(rc))
1533 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to begin stack walk, rc=%Vrc\n", rc);
1534
1535 /*
1536 * Print header.
1537 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol
1538 */
1539 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
1540 if (VBOX_FAILURE(rc))
1541 return rc;
1542 do
1543 {
1544 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1545 (uint32_t)Frame.AddrFrame.off,
1546 (uint32_t)Frame.AddrReturnFrame.off,
1547 (uint32_t)Frame.AddrReturnPC.Sel,
1548 (uint32_t)Frame.AddrReturnPC.off,
1549 Frame.Args.au32[0],
1550 Frame.Args.au32[1],
1551 Frame.Args.au32[2],
1552 Frame.Args.au32[3]);
1553 if (VBOX_FAILURE(rc))
1554 return rc;
1555 if (!Frame.pSymPC)
1556 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);
1557 else
1558 {
1559 RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */
1560 if (offDisp > 0)
1561 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);
1562 else if (offDisp < 0)
1563 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);
1564 else
1565 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s", Frame.pSymPC->szName);
1566 }
1567 if (VBOX_SUCCESS(rc) && Frame.pLinePC)
1568 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);
1569 if (VBOX_SUCCESS(rc))
1570 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
1571 if (VBOX_FAILURE(rc))
1572 return rc;
1573
1574 /* next */
1575 rc = DBGFR3StackWalkNext(pVM, &Frame);
1576 } while (VBOX_SUCCESS(rc));
1577
1578 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1579 return VINF_SUCCESS;
1580}
1581
1582
1583static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP /*pCmdHlp*/, PCX86DESC64 /*pDesc*/, unsigned /*iEntry*/, bool /* fHyper */, bool * /*fDblEntry*/)
1584{
1585 /* GUEST64 */
1586 return VINF_SUCCESS;
1587}
1588
1589
1590/**
1591 * Wroker function that displays one descriptor entry (GDT, LDT, IDT).
1592 *
1593 * @returns pfnPrintf status code.
1594 * @param pCmdHlp The DBGC command helpers.
1595 * @param pDesc The descriptor to display.
1596 * @param iEntry The descriptor entry number.
1597 * @param fHyper Whether the selector belongs to the hypervisor or not.
1598 */
1599static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper)
1600{
1601 int rc;
1602
1603 const char *pszHyper = fHyper ? " HYPER" : "";
1604 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";
1605 if (pDesc->Gen.u1DescType)
1606 {
1607 static const char * const s_apszTypes[] =
1608 {
1609 "DataRO", /* 0 Read-Only */
1610 "DataRO", /* 1 Read-Only - Accessed */
1611 "DataRW", /* 2 Read/Write */
1612 "DataRW", /* 3 Read/Write - Accessed */
1613 "DownRO", /* 4 Expand-down, Read-Only */
1614 "DownRO", /* 5 Expand-down, Read-Only - Accessed */
1615 "DownRW", /* 6 Expand-down, Read/Write */
1616 "DownRO", /* 7 Expand-down, Read/Write - Accessed */
1617 "CodeEO", /* 8 Execute-Only */
1618 "CodeEO", /* 9 Execute-Only - Accessed */
1619 "CodeER", /* A Execute/Readable */
1620 "CodeER", /* B Execute/Readable - Accessed */
1621 "ConfE0", /* C Conforming, Execute-Only */
1622 "ConfE0", /* D Conforming, Execute-Only - Accessed */
1623 "ConfER", /* E Conforming, Execute/Readable */
1624 "ConfER" /* F Conforming, Execute/Readable - Accessed */
1625 };
1626 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";
1627 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
1628 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1629 uint32_t u32Base = pDesc->Gen.u16BaseLow
1630 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
1631 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
1632 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
1633 if (pDesc->Gen.u1Granularity)
1634 cbLimit <<= PAGE_SHIFT;
1635
1636 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",
1637 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1638 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,
1639 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved, pszHyper);
1640 }
1641 else
1642 {
1643 static const char * const s_apszTypes[] =
1644 {
1645 "Ill-0 ", /* 0 0000 Reserved (Illegal) */
1646 "Tss16A", /* 1 0001 Available 16-bit TSS */
1647 "LDT ", /* 2 0010 LDT */
1648 "Tss16B", /* 3 0011 Busy 16-bit TSS */
1649 "Call16", /* 4 0100 16-bit Call Gate */
1650 "TaskG ", /* 5 0101 Task Gate */
1651 "Int16 ", /* 6 0110 16-bit Interrupt Gate */
1652 "Trap16", /* 7 0111 16-bit Trap Gate */
1653 "Ill-8 ", /* 8 1000 Reserved (Illegal) */
1654 "Tss32A", /* 9 1001 Available 32-bit TSS */
1655 "Ill-A ", /* A 1010 Reserved (Illegal) */
1656 "Tss32B", /* B 1011 Busy 32-bit TSS */
1657 "Call32", /* C 1100 32-bit Call Gate */
1658 "Ill-D ", /* D 1101 Reserved (Illegal) */
1659 "Int32 ", /* E 1110 32-bit Interrupt Gate */
1660 "Trap32" /* F 1111 32-bit Trap Gate */
1661 };
1662 switch (pDesc->Gen.u4Type)
1663 {
1664 /* raw */
1665 case X86_SEL_TYPE_SYS_UNDEFINED:
1666 case X86_SEL_TYPE_SYS_UNDEFINED2:
1667 case X86_SEL_TYPE_SYS_UNDEFINED4:
1668 case X86_SEL_TYPE_SYS_UNDEFINED3:
1669 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs DPL=%d %s%s\n",
1670 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,
1671 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1672 break;
1673
1674 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
1675 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
1676 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
1677 case X86_SEL_TYPE_SYS_386_TSS_BUSY:
1678 case X86_SEL_TYPE_SYS_LDT:
1679 {
1680 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
1681 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";
1682 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";
1683 uint32_t u32Base = pDesc->Gen.u16BaseLow
1684 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
1685 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
1686 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
1687 if (pDesc->Gen.u1Granularity)
1688 cbLimit <<= PAGE_SHIFT;
1689
1690 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",
1691 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
1692 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig,
1693 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved | (pDesc->Gen.u1DefBig << 1),
1694 pszHyper);
1695 break;
1696 }
1697
1698 case X86_SEL_TYPE_SYS_TASK_GATE:
1699 {
1700 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s TSS=%04x DPL=%d %s%s\n",
1701 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1],
1702 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1703 break;
1704 }
1705
1706 case X86_SEL_TYPE_SYS_286_CALL_GATE:
1707 case X86_SEL_TYPE_SYS_386_CALL_GATE:
1708 {
1709 unsigned cParams = pDesc->au8[0] & 0x1f;
1710 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";
1711 RTSEL sel = pDesc->au16[1];
1712 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
1713 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n",
1714 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
1715 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);
1716 break;
1717 }
1718
1719 case X86_SEL_TYPE_SYS_286_INT_GATE:
1720 case X86_SEL_TYPE_SYS_386_INT_GATE:
1721 case X86_SEL_TYPE_SYS_286_TRAP_GATE:
1722 case X86_SEL_TYPE_SYS_386_TRAP_GATE:
1723 {
1724 RTSEL sel = pDesc->au16[1];
1725 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
1726 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n",
1727 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
1728 pDesc->Gen.u2Dpl, pszPresent, pszHyper);
1729 break;
1730 }
1731
1732 /* impossible, just it's necessary to keep gcc happy. */
1733 default:
1734 return VINF_SUCCESS;
1735 }
1736 }
1737 return rc;
1738}
1739
1740
1741/**
1742 * The 'dg', 'dga', 'dl' and 'dla' commands.
1743 *
1744 * @returns VBox status.
1745 * @param pCmd Pointer to the command descriptor (as registered).
1746 * @param pCmdHlp Pointer to command helper functions.
1747 * @param pVM Pointer to the current VM (if any).
1748 * @param paArgs Pointer to (readonly) array of arguments.
1749 * @param cArgs Number of arguments in the array.
1750 */
1751static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1752{
1753 /*
1754 * Validate input.
1755 */
1756 if (!pVM)
1757 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
1758
1759 /*
1760 * Get the CPU mode, check which command variation this is
1761 * and fix a default parameter if needed.
1762 */
1763 CPUMMODE enmMode = CPUMGetGuestMode(pVM);
1764 bool fGdt = pCmd->pszCmd[1] == 'g';
1765 bool fAll = pCmd->pszCmd[2] == 'a';
1766
1767 DBGCVAR Var;
1768 if (!cArgs)
1769 {
1770 cArgs = 1;
1771 paArgs = &Var;
1772 Var.enmType = DBGCVAR_TYPE_NUMBER;
1773 Var.u.u64Number = fGdt ? 0 : 4;
1774 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
1775 Var.u64Range = 1024;
1776 }
1777
1778 /*
1779 * Process the arguments.
1780 */
1781 for (unsigned i = 0; i < cArgs; i++)
1782 {
1783 /*
1784 * Retrive the selector value from the argument.
1785 * The parser may confuse pointers and numbers if more than one
1786 * argument is given, that that into account.
1787 */
1788 /* check that what've got makes sense as we don't trust the parser yet. */
1789 if ( paArgs[i].enmType != DBGCVAR_TYPE_NUMBER
1790 && !DBGCVAR_ISPOINTER(paArgs[i].enmType))
1791 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number or pointer type but %d.\n", i, paArgs[i].enmType);
1792 uint64_t u64;
1793 unsigned cSels = 1;
1794 switch (paArgs[i].enmType)
1795 {
1796 case DBGCVAR_TYPE_NUMBER:
1797 u64 = paArgs[i].u.u64Number;
1798 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE)
1799 cSels = RT_MIN(paArgs[i].u64Range, 1024);
1800 break;
1801 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break;
1802 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break;
1803 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break;
1804 case DBGCVAR_TYPE_HC_FAR: u64 = paArgs[i].u.HCFar.sel; break;
1805 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break;
1806 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break;
1807 default: u64 = _64K; break;
1808 }
1809 if (u64 < _64K)
1810 {
1811 unsigned Sel = (RTSEL)u64;
1812
1813 /*
1814 * Dump the specified range.
1815 */
1816 bool fSingle = cSels == 1;
1817 while ( cSels-- > 0
1818 && Sel < _64K)
1819 {
1820 SELMSELINFO SelInfo;
1821 int rc = SELMR3GetSelectorInfo(pVM, Sel, &SelInfo);
1822 if (RT_SUCCESS(rc))
1823 {
1824 if (SelInfo.fRealMode)
1825 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x RealM Bas=%04x Lim=%04x\n",
1826 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit);
1827 else if (fAll || fSingle || SelInfo.Raw.Gen.u1Present)
1828 {
1829 if (enmMode == CPUMMODE_PROTECTED)
1830 rc = dbgcCmdDumpDTWorker32(pCmdHlp, (PX86DESC)&SelInfo.Raw, Sel, SelInfo.fHyper);
1831 else
1832 {
1833 bool fDblSkip = false;
1834 rc = dbgcCmdDumpDTWorker64(pCmdHlp, (PX86DESC64)&SelInfo.Raw, Sel, SelInfo.fHyper, &fDblSkip);
1835 if (fDblSkip)
1836 Sel += 4;
1837 }
1838 }
1839 }
1840 else
1841 {
1842 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %Vrc\n", Sel, rc);
1843 if (!fAll)
1844 return rc;
1845 }
1846 if (RT_FAILURE(rc))
1847 return rc;
1848
1849 /* next */
1850 Sel += 4;
1851 }
1852 }
1853 else
1854 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds\n", u64);
1855 }
1856
1857 NOREF(pResult);
1858 return VINF_SUCCESS;
1859}
1860
1861
1862/**
1863 * The 'di' and 'dia' commands.
1864 *
1865 * @returns VBox status.
1866 * @param pCmd Pointer to the command descriptor (as registered).
1867 * @param pCmdHlp Pointer to command helper functions.
1868 * @param pVM Pointer to the current VM (if any).
1869 * @param paArgs Pointer to (readonly) array of arguments.
1870 * @param cArgs Number of arguments in the array.
1871 */
1872static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1873{
1874 /*
1875 * Validate input.
1876 */
1877 if (!pVM)
1878 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
1879
1880 /*
1881 * Establish some stuff like the current IDTR and CPU mode,
1882 * and fix a default parameter.
1883 */
1884 uint16_t cbLimit;
1885 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVM, &cbLimit);
1886 CPUMMODE enmMode = CPUMGetGuestMode(pVM);
1887 unsigned cbEntry;
1888 switch (enmMode)
1889 {
1890 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break;
1891 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break;
1892 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break;
1893 default:
1894 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid CPU mode %d.\n", enmMode);
1895 }
1896
1897 bool fAll = pCmd->pszCmd[2] == 'a';
1898 DBGCVAR Var;
1899 if (!cArgs)
1900 {
1901 cArgs = 1;
1902 paArgs = &Var;
1903 Var.enmType = DBGCVAR_TYPE_NUMBER;
1904 Var.u.u64Number = 0;
1905 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
1906 Var.u64Range = 256;
1907 }
1908
1909 /*
1910 * Process the arguments.
1911 */
1912 for (unsigned i = 0; i < cArgs; i++)
1913 {
1914 /* check that what've got makes sense as we don't trust the parser yet. */
1915 if (paArgs[i].enmType != DBGCVAR_TYPE_NUMBER)
1916 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number type but %d.\n", i, paArgs[i].enmType);
1917 if (paArgs[i].u.u64Number < 256)
1918 {
1919 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number;
1920 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE
1921 ? paArgs[i].u64Range
1922 : 1;
1923 bool fSingle = cInts == 1;
1924 while ( cInts-- > 0
1925 && iInt < 256)
1926 {
1927 /*
1928 * Try read it.
1929 */
1930 union
1931 {
1932 RTFAR16 Real;
1933 X86DESC Prot;
1934 X86DESC64 Long;
1935 } u;
1936 if (iInt * cbEntry + (cbEntry - 1) > cbLimit)
1937 {
1938 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x not within the IDT\n", (unsigned)iInt);
1939 if (!fAll && !fSingle)
1940 return VINF_SUCCESS;
1941 }
1942 DBGCVAR AddrVar;
1943 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT;
1944 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry;
1945 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE;
1946 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &u, cbEntry, &AddrVar, NULL);
1947 if (VBOX_FAILURE(rc))
1948 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt);
1949
1950 /*
1951 * Display it.
1952 */
1953 switch (enmMode)
1954 {
1955 case CPUMMODE_REAL:
1956 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %RTfp16\n", (unsigned)iInt, u.Real);
1957 /** @todo resolve 16:16 IDTE to a symbol */
1958 break;
1959 case CPUMMODE_PROTECTED:
1960 if (fAll || fSingle || u.Prot.Gen.u1Present)
1961 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false);
1962 break;
1963 case CPUMMODE_LONG:
1964 if (fAll || fSingle || u.Long.Gen.u1Present)
1965 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL);
1966 break;
1967 default: break; /* to shut up gcc */
1968 }
1969 if (RT_FAILURE(rc))
1970 return rc;
1971
1972 /* next */
1973 iInt++;
1974 }
1975 }
1976 else
1977 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number);
1978 }
1979
1980 NOREF(pResult);
1981 return VINF_SUCCESS;
1982}
1983
1984
1985/**
1986 * The 'da', 'dq', 'dd', 'dw' and 'db' commands.
1987 *
1988 * @returns VBox status.
1989 * @param pCmd Pointer to the command descriptor (as registered).
1990 * @param pCmdHlp Pointer to command helper functions.
1991 * @param pVM Pointer to the current VM (if any).
1992 * @param paArgs Pointer to (readonly) array of arguments.
1993 * @param cArgs Number of arguments in the array.
1994 */
1995static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1996{
1997 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1998
1999 /*
2000 * Validate input.
2001 */
2002 if ( cArgs > 1
2003 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2004 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2005 if (!pVM)
2006 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2007
2008 /*
2009 * Figure out the element size.
2010 */
2011 unsigned cbElement;
2012 bool fAscii = false;
2013 switch (pCmd->pszCmd[1])
2014 {
2015 default:
2016 case 'b': cbElement = 1; break;
2017 case 'w': cbElement = 2; break;
2018 case 'd': cbElement = 4; break;
2019 case 'q': cbElement = 8; break;
2020 case 'a':
2021 cbElement = 1;
2022 fAscii = true;
2023 break;
2024 case '\0':
2025 fAscii = !!(pDbgc->cbDumpElement & 0x80000000);
2026 cbElement = pDbgc->cbDumpElement & 0x7fffffff;
2027 if (!cbElement)
2028 cbElement = 1;
2029 break;
2030 }
2031
2032 /*
2033 * Find address.
2034 */
2035 if (!cArgs)
2036 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE;
2037 else
2038 pDbgc->DumpPos = paArgs[0];
2039
2040 /*
2041 * Range.
2042 */
2043 switch (pDbgc->DumpPos.enmRangeType)
2044 {
2045 case DBGCVAR_RANGE_NONE:
2046 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
2047 pDbgc->DumpPos.u64Range = 0x60;
2048 break;
2049
2050 case DBGCVAR_RANGE_ELEMENTS:
2051 if (pDbgc->DumpPos.u64Range > 2048)
2052 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");
2053 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
2054 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range;
2055 break;
2056
2057 case DBGCVAR_RANGE_BYTES:
2058 if (pDbgc->DumpPos.u64Range > 65536)
2059 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
2060 break;
2061
2062 default:
2063 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);
2064 }
2065
2066 /*
2067 * Do the dumping.
2068 */
2069 pDbgc->cbDumpElement = cbElement | (fAscii << 31);
2070 int cbLeft = (int)pDbgc->DumpPos.u64Range;
2071 uint8_t u8Prev = '\0';
2072 for (;;)
2073 {
2074 /*
2075 * Read memory.
2076 */
2077 char achBuffer[16];
2078 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft);
2079 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft);
2080 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &achBuffer, cbReq, &pDbgc->DumpPos, &cb);
2081 if (VBOX_FAILURE(rc))
2082 {
2083 if (u8Prev && u8Prev != '\n')
2084 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2085 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos);
2086 }
2087
2088 /*
2089 * Display it.
2090 */
2091 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb);
2092 if (!fAscii)
2093 {
2094 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:", &pDbgc->DumpPos);
2095 unsigned i;
2096 for (i = 0; i < cb; i += cbElement)
2097 {
2098 const char *pszSpace = " ";
2099 if (cbElement <= 2 && i == 8 && !fAscii)
2100 pszSpace = "-";
2101 switch (cbElement)
2102 {
2103 case 1: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break;
2104 case 2: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break;
2105 case 4: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break;
2106 case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;
2107 }
2108 }
2109
2110 /* chars column */
2111 if (pDbgc->cbDumpElement == 1)
2112 {
2113 while (i++ < sizeof(achBuffer))
2114 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");
2115 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");
2116 for (i = 0; i < cb; i += cbElement)
2117 {
2118 uint8_t u8 = *(uint8_t *)&achBuffer[i];
2119 if (isprint(u8) && u8 < 127 && u8 >= 32)
2120 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
2121 else
2122 pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");
2123 }
2124 }
2125 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2126 }
2127 else
2128 {
2129 /*
2130 * We print up to the first zero and stop there.
2131 * Only printables + '\t' and '\n' are printed.
2132 */
2133 if (!u8Prev)
2134 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DumpPos);
2135 uint8_t u8 = '\0';
2136 unsigned i;
2137 for (i = 0; i < cb; i++)
2138 {
2139 u8Prev = u8;
2140 u8 = *(uint8_t *)&achBuffer[i];
2141 if ( u8 < 127
2142 && ( (isprint(u8) && u8 >= 32)
2143 || u8 == '\t'
2144 || u8 == '\n'))
2145 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
2146 else if (!u8)
2147 break;
2148 else
2149 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\\x%x", u8);
2150 }
2151 if (u8 == '\0')
2152 cb = cbLeft = i + 1;
2153 if (cbLeft - cb <= 0 && u8Prev != '\n')
2154 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
2155 }
2156
2157 /*
2158 * Advance
2159 */
2160 cbLeft -= (int)cb;
2161 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb);
2162 if (VBOX_FAILURE(rc))
2163 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb);
2164 if (cbLeft <= 0)
2165 break;
2166 }
2167
2168 NOREF(pCmd); NOREF(pResult);
2169 return VINF_SUCCESS;
2170}
2171
2172
2173/**
2174 * Best guess at which paging mode currently applies to the guest
2175 * paging structures.
2176 *
2177 * This have to come up with a decent answer even when the guest
2178 * is in non-paged protected mode or real mode.
2179 *
2180 * @returns cr3.
2181 * @param pDbgc The DBGC instance.
2182 * @param pfPAE Where to store the page address extension indicator.
2183 * @param pfLME Where to store the long mode enabled indicator.
2184 * @param pfPSE Where to store the page size extension indicator.
2185 * @param pfPGE Where to store the page global enabled indicator.
2186 * @param pfNXE Where to store the no-execution enabled inidicator.
2187 */
2188static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
2189{
2190 RTGCUINTREG cr4 = CPUMGetGuestCR4(pDbgc->pVM);
2191 *pfPSE = !!(cr4 & X86_CR4_PSE);
2192 *pfPGE = !!(cr4 & X86_CR4_PGE);
2193 *pfPAE = !!(cr4 & X86_CR4_PAE);
2194 *pfLME = CPUMGetGuestMode(pDbgc->pVM) == CPUMMODE_LONG;
2195 *pfNXE = false; /* GUEST64 GUESTNX */
2196 return CPUMGetGuestCR3(pDbgc->pVM);
2197}
2198
2199
2200/**
2201 * Determin the shadow paging mode.
2202 *
2203 * @returns cr3.
2204 * @param pDbgc The DBGC instance.
2205 * @param pfPAE Where to store the page address extension indicator.
2206 * @param pfLME Where to store the long mode enabled indicator.
2207 * @param pfPSE Where to store the page size extension indicator.
2208 * @param pfPGE Where to store the page global enabled indicator.
2209 * @param pfNXE Where to store the no-execution enabled inidicator.
2210 */
2211static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
2212{
2213 *pfPSE = true;
2214 *pfPGE = false;
2215 switch (PGMGetShadowMode(pDbgc->pVM))
2216 {
2217 default:
2218 case PGMMODE_32_BIT:
2219 *pfPAE = *pfLME = *pfNXE = false;
2220 break;
2221 case PGMMODE_PAE:
2222 *pfLME = *pfNXE = false;
2223 *pfPAE = true;
2224 break;
2225 case PGMMODE_PAE_NX:
2226 *pfLME = false;
2227 *pfPAE = *pfNXE = true;
2228 break;
2229 case PGMMODE_AMD64:
2230 *pfNXE = false;
2231 *pfPAE = *pfLME = true;
2232 break;
2233 case PGMMODE_AMD64_NX:
2234 *pfPAE = *pfLME = *pfNXE = true;
2235 break;
2236 }
2237 return PGMGetHyperCR3(pDbgc->pVM);
2238}
2239
2240
2241/**
2242 * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands.
2243 *
2244 * @returns VBox status.
2245 * @param pCmd Pointer to the command descriptor (as registered).
2246 * @param pCmdHlp Pointer to command helper functions.
2247 * @param pVM Pointer to the current VM (if any).
2248 * @param paArgs Pointer to (readonly) array of arguments.
2249 * @param cArgs Number of arguments in the array.
2250 */
2251static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2252{
2253 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2254
2255 /*
2256 * Validate input.
2257 */
2258 if ( cArgs > 1
2259 || (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
2260 || (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2261 )
2262 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2263 if (!pVM)
2264 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2265
2266 /*
2267 * Guest or shadow page directories? Get the paging parameters.
2268 */
2269 bool fGuest = pCmd->pszCmd[3] != 'h';
2270 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
2271 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
2272 ? pDbgc->fRegCtxGuest
2273 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
2274
2275 bool fPAE, fLME, fPSE, fPGE, fNXE;
2276 uint64_t cr3 = fGuest
2277 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
2278 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
2279 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
2280
2281 /*
2282 * Setup default arugment if none was specified.
2283 * Fix address / index confusion.
2284 */
2285 DBGCVAR VarDefault;
2286 if (!cArgs)
2287 {
2288 if (pCmd->pszCmd[3] == 'a')
2289 {
2290 if (fLME || fPAE)
2291 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");
2292 if (fGuest)
2293 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3);
2294 else
2295 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3);
2296 }
2297 else
2298 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0);
2299 paArgs = &VarDefault;
2300 cArgs = 1;
2301 }
2302 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)
2303 {
2304 Assert(pCmd->pszCmd[3] != 'a');
2305 VarDefault = paArgs[0];
2306 if (VarDefault.u.u64Number <= 1024)
2307 {
2308 if (fPAE)
2309 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n");
2310 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry)
2311 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1);
2312 VarDefault.u.u64Number <<= X86_PD_SHIFT;
2313 }
2314 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT;
2315 paArgs = &VarDefault;
2316 }
2317
2318 /*
2319 * Locate the PDE to start displaying at.
2320 *
2321 * The 'dpda' command takes the address of a PDE, while the others are guest
2322 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple
2323 * while the others require us to do all the tedious walking thru the paging
2324 * hierarchy to find the intended PDE.
2325 */
2326 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */
2327 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */
2328 DBGCVAR VarPDEAddr; /* The address of the current PDE. */
2329 unsigned cEntries; /* The number of entries to display. */
2330 unsigned cEntriesMax; /* The max number of entries to display. */
2331 int rc;
2332 if (pCmd->pszCmd[3] == 'a')
2333 {
2334 VarPDEAddr = paArgs[0];
2335 switch (VarPDEAddr.enmRangeType)
2336 {
2337 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break;
2338 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break;
2339 default: cEntries = 10; break;
2340 }
2341 cEntriesMax = PAGE_SIZE / cbEntry;
2342 }
2343 else
2344 {
2345 /*
2346 * Determin the range.
2347 */
2348 switch (paArgs[0].enmRangeType)
2349 {
2350 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
2351 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;
2352 default: cEntries = 10; break;
2353 }
2354
2355 /*
2356 * Normalize the input address, it must be a flat GC address.
2357 */
2358 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
2359 if (VBOX_FAILURE(rc))
2360 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
2361 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
2362 {
2363 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
2364 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
2365 }
2366 if (fPAE)
2367 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1);
2368 else
2369 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1);
2370
2371 /*
2372 * Do the paging walk until we get to the page directory.
2373 */
2374 DBGCVAR VarCur;
2375 if (fGuest)
2376 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
2377 else
2378 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
2379 if (fLME)
2380 {
2381 /* Page Map Level 4 Lookup. */
2382 /* Check if it's a valid address first? */
2383 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
2384 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
2385 X86PML4E Pml4e;
2386 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
2387 if (VBOX_FAILURE(rc))
2388 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
2389 if (!Pml4e.n.u1Present)
2390 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
2391
2392 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
2393 Assert(fPAE);
2394 }
2395 if (fPAE)
2396 {
2397 /* Page directory pointer table. */
2398 X86PDPE Pdpe;
2399 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe);
2400 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
2401 if (VBOX_FAILURE(rc))
2402 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
2403 if (!Pdpe.n.u1Present)
2404 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
2405
2406 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
2407 VarPDEAddr = VarCur;
2408 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
2409 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE);
2410 }
2411 else
2412 {
2413 /* 32-bit legacy - CR3 == page directory. */
2414 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK;
2415 VarPDEAddr = VarCur;
2416 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE);
2417 }
2418 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
2419 iEntry /= cbEntry;
2420 }
2421
2422 /* adjust cEntries */
2423 cEntries = RT_MAX(1, cEntries);
2424 cEntries = RT_MIN(cEntries, cEntriesMax);
2425
2426 /*
2427 * The display loop.
2428 */
2429 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n",
2430 &VarPDEAddr, iEntry);
2431 do
2432 {
2433 /*
2434 * Read.
2435 */
2436 X86PDEPAE Pde;
2437 Pde.u = 0;
2438 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL);
2439 if (VBOX_FAILURE(rc))
2440 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr);
2441
2442 /*
2443 * Display.
2444 */
2445 if (iEntry != ~0U)
2446 {
2447 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
2448 iEntry++;
2449 }
2450 if (fPSE && Pde.b.u1Size)
2451 DBGCCmdHlpPrintf(pCmdHlp,
2452 fPAE
2453 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
2454 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
2455 Pde.u,
2456 Pde.u & X86_PDE_PAE_PG_MASK,
2457 Pde.b.u1Present ? "p " : "np",
2458 Pde.b.u1Write ? "w" : "r",
2459 Pde.b.u1User ? "u" : "s",
2460 Pde.b.u1Accessed ? "a " : "na",
2461 Pde.b.u1Dirty ? "d " : "nd",
2462 Pde.b.u3Available,
2463 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ",
2464 Pde.b.u1WriteThru ? "pwt" : " ",
2465 Pde.b.u1CacheDisable ? "pcd" : " ",
2466 Pde.b.u1PAT ? "pat" : "",
2467 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");
2468 else
2469 DBGCCmdHlpPrintf(pCmdHlp,
2470 fPAE
2471 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s"
2472 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s",
2473 Pde.u,
2474 Pde.u & X86_PDE_PAE_PG_MASK,
2475 Pde.n.u1Present ? "p " : "np",
2476 Pde.n.u1Write ? "w" : "r",
2477 Pde.n.u1User ? "u" : "s",
2478 Pde.n.u1Accessed ? "a " : "na",
2479 Pde.u & RT_BIT(6) ? "6 " : " ",
2480 Pde.n.u3Available,
2481 Pde.u & RT_BIT(8) ? "8" : " ",
2482 Pde.n.u1WriteThru ? "pwt" : " ",
2483 Pde.n.u1CacheDisable ? "pcd" : " ",
2484 Pde.u & RT_BIT(7) ? "7" : "",
2485 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");
2486 if (Pde.u & UINT64_C(0x7fff000000000000))
2487 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000)));
2488 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
2489 if (VBOX_FAILURE(rc))
2490 return rc;
2491
2492 /*
2493 * Advance.
2494 */
2495 VarPDEAddr.u.u64Number += cbEntry;
2496 if (iEntry != ~0U)
2497 VarGCPtr.u.GCFlat += 1 << (fPAE ? X86_PD_PAE_SHIFT : X86_PD_SHIFT);
2498 } while (cEntries-- > 0);
2499
2500 NOREF(pResult);
2501 return VINF_SUCCESS;
2502}
2503
2504
2505/**
2506 * The 'dpdb' command.
2507 *
2508 * @returns VBox status.
2509 * @param pCmd Pointer to the command descriptor (as registered).
2510 * @param pCmdHlp Pointer to command helper functions.
2511 * @param pVM Pointer to the current VM (if any).
2512 * @param paArgs Pointer to (readonly) array of arguments.
2513 * @param cArgs Number of arguments in the array.
2514 */
2515static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2516{
2517 if (!pVM)
2518 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2519 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
2520 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
2521 if (VBOX_FAILURE(rc1))
2522 return rc1;
2523 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
2524 return rc2;
2525}
2526
2527
2528/**
2529 * The 'dpg*' commands.
2530 *
2531 * @returns VBox status.
2532 * @param pCmd Pointer to the command descriptor (as registered).
2533 * @param pCmdHlp Pointer to command helper functions.
2534 * @param pVM Pointer to the current VM (if any).
2535 * @param paArgs Pointer to (readonly) array of arguments.
2536 * @param cArgs Number of arguments in the array.
2537 */
2538static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2539{
2540 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2541
2542 /*
2543 * Validate input.
2544 */
2545 if ( cArgs != 1
2546 || (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
2547 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
2548 )
2549 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
2550 if (!pVM)
2551 return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n");
2552
2553 /*
2554 * Guest or shadow page tables? Get the paging parameters.
2555 */
2556 bool fGuest = pCmd->pszCmd[3] != 'h';
2557 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
2558 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
2559 ? pDbgc->fRegCtxGuest
2560 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
2561
2562 bool fPAE, fLME, fPSE, fPGE, fNXE;
2563 uint64_t cr3 = fGuest
2564 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
2565 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
2566 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
2567
2568 /*
2569 * Locate the PTE to start displaying at.
2570 *
2571 * The 'dpta' command takes the address of a PTE, while the others are guest
2572 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple
2573 * while the others require us to do all the tedious walking thru the paging
2574 * hierarchy to find the intended PTE.
2575 */
2576 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */
2577 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */
2578 DBGCVAR VarPTEAddr; /* The address of the current PTE. */
2579 unsigned cEntries; /* The number of entries to display. */
2580 unsigned cEntriesMax; /* The max number of entries to display. */
2581 int rc;
2582 if (pCmd->pszCmd[3] == 'a')
2583 {
2584 VarPTEAddr = paArgs[0];
2585 switch (VarPTEAddr.enmRangeType)
2586 {
2587 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break;
2588 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break;
2589 default: cEntries = 10; break;
2590 }
2591 cEntriesMax = PAGE_SIZE / cbEntry;
2592 }
2593 else
2594 {
2595 /*
2596 * Determin the range.
2597 */
2598 switch (paArgs[0].enmRangeType)
2599 {
2600 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
2601 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;
2602 default: cEntries = 10; break;
2603 }
2604
2605 /*
2606 * Normalize the input address, it must be a flat GC address.
2607 */
2608 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
2609 if (VBOX_FAILURE(rc))
2610 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
2611 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
2612 {
2613 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
2614 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
2615 }
2616 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;
2617
2618 /*
2619 * Do the paging walk until we get to the page table.
2620 */
2621 DBGCVAR VarCur;
2622 if (fGuest)
2623 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
2624 else
2625 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
2626 if (fLME)
2627 {
2628 /* Page Map Level 4 Lookup. */
2629 /* Check if it's a valid address first? */
2630 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
2631 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
2632 X86PML4E Pml4e;
2633 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
2634 if (VBOX_FAILURE(rc))
2635 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
2636 if (!Pml4e.n.u1Present)
2637 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
2638
2639 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
2640 Assert(fPAE);
2641 }
2642 if (fPAE)
2643 {
2644 /* Page directory pointer table. */
2645 X86PDPE Pdpe;
2646 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe);
2647 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
2648 if (VBOX_FAILURE(rc))
2649 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
2650 if (!Pdpe.n.u1Present)
2651 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
2652
2653 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
2654
2655 /* Page directory (PAE). */
2656 X86PDEPAE Pde;
2657 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);
2658 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
2659 if (VBOX_FAILURE(rc))
2660 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
2661 if (!Pde.n.u1Present)
2662 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
2663 if (fPSE && Pde.n.u1Size)
2664 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
2665
2666 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
2667 VarPTEAddr = VarCur;
2668 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;
2669 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);
2670 }
2671 else
2672 {
2673 /* Page directory (legacy). */
2674 X86PDE Pde;
2675 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);
2676 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
2677 if (VBOX_FAILURE(rc))
2678 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
2679 if (!Pde.n.u1Present)
2680 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
2681 if (fPSE && Pde.n.u1Size)
2682 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
2683
2684 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;
2685 VarPTEAddr = VarCur;
2686 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;
2687 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);
2688 }
2689 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
2690 iEntry /= cbEntry;
2691 }
2692
2693 /* adjust cEntries */
2694 cEntries = RT_MAX(1, cEntries);
2695 cEntries = RT_MIN(cEntries, cEntriesMax);
2696
2697 /*
2698 * The display loop.
2699 */
2700 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",
2701 &VarPTEAddr, &VarGCPtr, iEntry);
2702 do
2703 {
2704 /*
2705 * Read.
2706 */
2707 X86PTEPAE Pte;
2708 Pte.u = 0;
2709 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL);
2710 if (VBOX_FAILURE(rc))
2711 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);
2712
2713 /*
2714 * Display.
2715 */
2716 if (iEntry != ~0U)
2717 {
2718 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
2719 iEntry++;
2720 }
2721 DBGCCmdHlpPrintf(pCmdHlp,
2722 fPAE
2723 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
2724 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
2725 Pte.u,
2726 Pte.u & X86_PTE_PAE_PG_MASK,
2727 Pte.n.u1Present ? "p " : "np",
2728 Pte.n.u1Write ? "w" : "r",
2729 Pte.n.u1User ? "u" : "s",
2730 Pte.n.u1Accessed ? "a " : "na",
2731 Pte.n.u1Dirty ? "d " : "nd",
2732 Pte.n.u3Available,
2733 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ",
2734 Pte.n.u1WriteThru ? "pwt" : " ",
2735 Pte.n.u1CacheDisable ? "pcd" : " ",
2736 Pte.n.u1PAT ? "pat" : " ",
2737 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "
2738 );
2739 if (Pte.u & UINT64_C(0x7fff000000000000))
2740 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));
2741 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
2742 if (VBOX_FAILURE(rc))
2743 return rc;
2744
2745 /*
2746 * Advance.
2747 */
2748 VarPTEAddr.u.u64Number += cbEntry;
2749 if (iEntry != ~0U)
2750 VarGCPtr.u.GCFlat += PAGE_SIZE;
2751 } while (cEntries-- > 0);
2752
2753 NOREF(pResult);
2754 return VINF_SUCCESS;
2755}
2756
2757
2758/**
2759 * The 'dptb' command.
2760 *
2761 * @returns VBox status.
2762 * @param pCmd Pointer to the command descriptor (as registered).
2763 * @param pCmdHlp Pointer to command helper functions.
2764 * @param pVM Pointer to the current VM (if any).
2765 * @param paArgs Pointer to (readonly) array of arguments.
2766 * @param cArgs Number of arguments in the array.
2767 */
2768static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2769{
2770 if (!pVM)
2771 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2772 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
2773 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
2774 if (VBOX_FAILURE(rc1))
2775 return rc1;
2776 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
2777 return rc2;
2778}
2779
2780
2781/**
2782 * The 'dt' command.
2783 *
2784 * @returns VBox status.
2785 * @param pCmd Pointer to the command descriptor (as registered).
2786 * @param pCmdHlp Pointer to command helper functions.
2787 * @param pVM Pointer to the current VM (if any).
2788 * @param paArgs Pointer to (readonly) array of arguments.
2789 * @param cArgs Number of arguments in the array.
2790 */
2791static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM /*pVM*/, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
2792{
2793 /*
2794 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.
2795 */
2796
2797 /** @todo */
2798 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dt is not implemented yet, feel free to do it. \n");
2799}
2800
2801
2802/**
2803 * The 'm' command.
2804 *
2805 * @returns VBox status.
2806 * @param pCmd Pointer to the command descriptor (as registered).
2807 * @param pCmdHlp Pointer to command helper functions.
2808 * @param pVM Pointer to the current VM (if any).
2809 * @param paArgs Pointer to (readonly) array of arguments.
2810 * @param cArgs Number of arguments in the array.
2811 */
2812static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2813{
2814 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Address: %DV\n", &paArgs[0]);
2815 if (!pVM)
2816 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
2817 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
2818 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
2819 int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
2820 int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
2821 if (VBOX_FAILURE(rc1))
2822 return rc1;
2823 if (VBOX_FAILURE(rc2))
2824 return rc2;
2825 if (VBOX_FAILURE(rc3))
2826 return rc3;
2827 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
2828 return rc4;
2829}
2830
2831
2832/**
2833 * Converts one or more variables into a byte buffer for a
2834 * given unit size.
2835 *
2836 * @returns VBox status codes:
2837 * @retval VERR_TOO_MUCH_DATA if the buffer is too small, bitched.
2838 * @retval VERR_INTERNAL_ERROR on bad variable type, bitched.
2839 * @retval VINF_SUCCESS on success.
2840 *
2841 * @param pvBuf The buffer to convert into.
2842 * @param pcbBuf The buffer size on input. The size of the result on output.
2843 * @param cbUnit The unit size to apply when converting.
2844 * The high bit is used to indicate unicode string.
2845 * @param paVars The array of variables to convert.
2846 * @param cVars The number of variables.
2847 */
2848int dbgcVarsToBytes(PDBGCCMDHLP pCmdHlp, void *pvBuf, uint32_t *pcbBuf, size_t cbUnit, PCDBGCVAR paVars, unsigned cVars)
2849{
2850 union
2851 {
2852 uint8_t *pu8;
2853 uint16_t *pu16;
2854 uint32_t *pu32;
2855 uint64_t *pu64;
2856 } u, uEnd;
2857 u.pu8 = (uint8_t *)pvBuf;
2858 uEnd.pu8 = u.pu8 + *pcbBuf;
2859
2860 unsigned i;
2861 for (i = 0; i < cVars && u.pu8 < uEnd.pu8; i++)
2862 {
2863 switch (paVars[i].enmType)
2864 {
2865 case DBGCVAR_TYPE_GC_FAR:
2866 case DBGCVAR_TYPE_HC_FAR:
2867 case DBGCVAR_TYPE_GC_FLAT:
2868 case DBGCVAR_TYPE_GC_PHYS:
2869 case DBGCVAR_TYPE_HC_FLAT:
2870 case DBGCVAR_TYPE_HC_PHYS:
2871 case DBGCVAR_TYPE_NUMBER:
2872 {
2873 uint64_t u64 = paVars[i].u.u64Number;
2874 switch (cbUnit & 0x1f)
2875 {
2876 case 1:
2877 do
2878 {
2879 *u.pu8++ = u64;
2880 u64 >>= 8;
2881 } while (u64);
2882 break;
2883 case 2:
2884 do
2885 {
2886 *u.pu16++ = u64;
2887 u64 >>= 16;
2888 } while (u64);
2889 break;
2890 case 4:
2891 *u.pu32++ = u64;
2892 u64 >>= 32;
2893 if (u64)
2894 *u.pu32++ = u64;
2895 break;
2896 case 8:
2897 *u.pu64++ = u64;
2898 break;
2899 }
2900 break;
2901 }
2902
2903 case DBGCVAR_TYPE_STRING:
2904 case DBGCVAR_TYPE_SYMBOL:
2905 {
2906 const char *psz = paVars[i].u.pszString;
2907 size_t cbString = strlen(psz);
2908 if (cbUnit & RT_BIT_32(31))
2909 {
2910 /* Explode char to unit. */
2911 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8) * (cbUnit & 0x1f))
2912 {
2913 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
2914 return VERR_TOO_MUCH_DATA;
2915 }
2916 while (*psz)
2917 {
2918 switch (cbUnit & 0x1f)
2919 {
2920 case 1: *u.pu8++ = *psz; break;
2921 case 2: *u.pu16++ = *psz; break;
2922 case 4: *u.pu32++ = *psz; break;
2923 case 8: *u.pu64++ = *psz; break;
2924 }
2925 psz++;
2926 }
2927 }
2928 else
2929 {
2930 /* Raw copy with zero padding if the size isn't aligned. */
2931 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8))
2932 {
2933 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
2934 return VERR_TOO_MUCH_DATA;
2935 }
2936
2937 size_t cbCopy = cbString & ~(cbUnit - 1);
2938 memcpy(u.pu8, psz, cbCopy);
2939 u.pu8 += cbCopy;
2940 psz += cbCopy;
2941
2942 size_t cbReminder = cbString & (cbUnit - 1);
2943 if (cbReminder)
2944 {
2945 memcpy(u.pu8, psz, cbString & (cbUnit - 1));
2946 memset(u.pu8 + cbReminder, 0, cbUnit - cbReminder);
2947 u.pu8 += cbUnit;
2948 }
2949 }
2950 break;
2951 }
2952
2953 default:
2954 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
2955 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INTERNAL_ERROR,
2956 "i=%d enmType=%d\n", i, paVars[i].enmType);
2957 return VERR_INTERNAL_ERROR;
2958 }
2959 }
2960 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
2961 if (i != cVars)
2962 {
2963 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
2964 return VERR_TOO_MUCH_DATA;
2965 }
2966 return VINF_SUCCESS;
2967}
2968
2969
2970/**
2971 * Executes the search.
2972 *
2973 * @returns VBox status code.
2974 * @param pCmdHlp The command helpers.
2975 * @param pVM The VM handle.
2976 * @param pAddress The address to start searching from. (undefined on output)
2977 * @param cbRange The address range to search. Must not wrap.
2978 * @param pabBytes The byte pattern to search for.
2979 * @param cbBytes The size of the pattern.
2980 * @param cbUnit The search unit.
2981 * @param cMaxHits The max number of hits.
2982 * @param pResult Where to store the result if it's a function invocation.
2983 */
2984static int dbgcCmdWorkerSearchMemDoIt(PDBGCCMDHLP pCmdHlp, PVM pVM, PDBGFADDRESS pAddress, RTGCUINTPTR cbRange,
2985 const uint8_t *pabBytes, uint32_t cbBytes,
2986 uint32_t cbUnit, uint64_t cMaxHits, PDBGCVAR pResult)
2987{
2988 /*
2989 * Do the search.
2990 */
2991 uint64_t cHits = 0;
2992 for (;;)
2993 {
2994 /* search */
2995 DBGFADDRESS HitAddress;
2996 int rc = DBGFR3MemScan(pVM, pAddress, cbRange, pabBytes, cbBytes, &HitAddress);
2997 if (RT_FAILURE(rc))
2998 {
2999 if (rc != VERR_DBGF_MEM_NOT_FOUND)
3000 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3MemScan\n");
3001
3002 /* update the current address so we can save it (later). */
3003 pAddress->off += cbRange;
3004 pAddress->FlatPtr += cbRange;
3005 cbRange = 0;
3006 break;
3007 }
3008
3009 /* report result */
3010 DBGCVAR VarCur;
3011 dbgcVarInit(&VarCur);
3012 dbgcVarSetDbgfAddr(&VarCur, &HitAddress);
3013 if (!pResult)
3014 pCmdHlp->pfnExec(pCmdHlp, "db %DV LB 10", &VarCur);
3015 else
3016 dbgcVarSetDbgfAddr(pResult, &HitAddress);
3017
3018 /* advance */
3019 cbRange -= HitAddress.FlatPtr - pAddress->FlatPtr;
3020 *pAddress = HitAddress;
3021 pAddress->FlatPtr += cbBytes;
3022 pAddress->off += cbBytes;
3023 if (cbRange <= cbBytes)
3024 {
3025 cbRange = 0;
3026 break;
3027 }
3028 cbRange -= cbBytes;
3029
3030 if (++cHits >= cMaxHits)
3031 {
3032 /// @todo save the search.
3033 break;
3034 }
3035 }
3036
3037 /*
3038 * Save the search so we can resume it...
3039 */
3040 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3041 if (pDbgc->abSearch != pabBytes)
3042 {
3043 memcpy(pDbgc->abSearch, pabBytes, cbBytes);
3044 pDbgc->cbSearch = cbBytes;
3045 pDbgc->cbSearchUnit = cbUnit;
3046 }
3047 pDbgc->cMaxSearchHits = cMaxHits;
3048 pDbgc->SearchAddr = *pAddress;
3049 pDbgc->cbSearchRange = cbRange;
3050
3051 return cHits ? VINF_SUCCESS : VERR_DBGC_COMMAND_FAILED;
3052}
3053
3054
3055/**
3056 * Resumes the previous search.
3057 *
3058 * @returns VBox status code.
3059 * @param pCmdHlp Pointer to the command helper functions.
3060 * @param pVM Pointer to the current VM (if any).
3061 * @param pResult Where to store the result of a function invocation.
3062 */
3063static int dbgcCmdWorkerSearchMemResume(PDBGCCMDHLP pCmdHlp, PVM pVM, PDBGCVAR pResult)
3064{
3065 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3066
3067 /*
3068 * Make sure there is a previous command.
3069 */
3070 if (!pDbgc->cbSearch)
3071 {
3072 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Error: No previous search\n");
3073 return VERR_DBGC_COMMAND_FAILED;
3074 }
3075
3076 /*
3077 * Make range and address adjustments.
3078 */
3079 DBGFADDRESS Address = pDbgc->SearchAddr;
3080 if (Address.FlatPtr == ~(RTGCUINTPTR)0)
3081 {
3082 Address.FlatPtr -= Address.off;
3083 Address.off = 0;
3084 }
3085
3086 RTGCUINTPTR cbRange = pDbgc->cbSearchRange;
3087 if (!cbRange)
3088 cbRange = ~(RTGCUINTPTR)0;
3089 if (Address.FlatPtr + cbRange < pDbgc->SearchAddr.FlatPtr)
3090 cbRange = ~(RTGCUINTPTR)0 - pDbgc->SearchAddr.FlatPtr + !!pDbgc->SearchAddr.FlatPtr;
3091
3092 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pVM, &Address, cbRange, pDbgc->abSearch, pDbgc->cbSearch,
3093 pDbgc->cbSearchUnit, pDbgc->cMaxSearchHits, pResult);
3094}
3095
3096
3097/**
3098 * Search memory, worker for the 's' and 's?' functions.
3099 *
3100 * @returns VBox status.
3101 * @param pCmdHlp Pointer to the command helper functions.
3102 * @param pVM Pointer to the current VM (if any).
3103 * @param pAddress Where to start searching. If no range, search till end of address space.
3104 * @param cMaxHits The maximum number of hits.
3105 * @param chType The search type.
3106 * @param paPatArgs The pattern variable array.
3107 * @param cPatArgs Number of pattern variables.
3108 * @param pResult Where to store the result of a function invocation.
3109 */
3110static int dbgcCmdWorkerSearchMem(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pAddress, uint64_t cMaxHits, char chType,
3111 PCDBGCVAR paPatArgs, unsigned cPatArgs, PDBGCVAR pResult)
3112{
3113 dbgcVarSetGCFlat(pResult, 0);
3114
3115 /*
3116 * Convert the search pattern into bytes and DBGFR3MemScan can deal with.
3117 */
3118 uint32_t cbUnit;
3119 switch (chType)
3120 {
3121 case 'a':
3122 case 'b': cbUnit = 1; break;
3123 case 'u': cbUnit = 2 | RT_BIT_32(31); break;
3124 case 'w': cbUnit = 2; break;
3125 case 'd': cbUnit = 4; break;
3126 case 'q': cbUnit = 8; break;
3127 default:
3128 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "chType=%c\n", chType);
3129 }
3130 uint8_t abBytes[RT_SIZEOFMEMB(DBGC, abSearch)];
3131 uint32_t cbBytes = sizeof(abBytes);
3132 int rc = dbgcVarsToBytes(pCmdHlp, abBytes, &cbBytes, cbUnit, paPatArgs, cPatArgs);
3133 if (RT_FAILURE(rc))
3134 return VERR_DBGC_COMMAND_FAILED;
3135
3136 /*
3137 * Make DBGF address and fix the range.
3138 */
3139 DBGFADDRESS Address;
3140 rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pAddress, &Address);
3141 if (RT_FAILURE(rc))
3142 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", pAddress);
3143
3144 RTGCUINTPTR cbRange;
3145 switch (pAddress->enmRangeType)
3146 {
3147 case DBGCVAR_RANGE_BYTES:
3148 cbRange = pAddress->u64Range;
3149 if (cbRange != pAddress->u64Range)
3150 cbRange = ~(RTGCUINTPTR)0;
3151 break;
3152
3153 case DBGCVAR_RANGE_ELEMENTS:
3154 cbRange = (RTGCUINTPTR)(pAddress->u64Range * cbUnit);
3155 if ( cbRange != pAddress->u64Range * cbUnit
3156 || cbRange < pAddress->u64Range)
3157 cbRange = ~(RTGCUINTPTR)0;
3158 break;
3159
3160 default:
3161 cbRange = ~(RTGCUINTPTR)0;
3162 break;
3163 }
3164 if (Address.FlatPtr + cbRange < Address.FlatPtr)
3165 cbRange = ~(RTGCUINTPTR)0 - Address.FlatPtr + !!Address.FlatPtr;
3166
3167 /*
3168 * Ok, do it.
3169 */
3170 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pVM, &Address, cbRange, abBytes, cbBytes, cbUnit, cMaxHits, pResult);
3171}
3172
3173
3174/**
3175 * The 's' command.
3176 *
3177 * @returns VBox status.
3178 * @param pCmd Pointer to the command descriptor (as registered).
3179 * @param pCmdHlp Pointer to command helper functions.
3180 * @param pVM Pointer to the current VM (if any).
3181 * @param paArgs Pointer to (readonly) array of arguments.
3182 * @param cArgs Number of arguments in the array.
3183 */
3184static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3185{
3186 /* check that the parser did what it's supposed to do. */
3187 //if ( cArgs <= 2
3188 // && paArgs[0].enmType != DBGCVAR_TYPE_STRING)
3189 // return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
3190
3191 /*
3192 * Repeate previous search?
3193 */
3194 if (cArgs == 0)
3195 return dbgcCmdWorkerSearchMemResume(pCmdHlp, pVM, pResult);
3196
3197 /*
3198 * Parse arguments.
3199 */
3200
3201 return -1;
3202}
3203
3204
3205/**
3206 * The 's?' command.
3207 *
3208 * @returns VBox status.
3209 * @param pCmd Pointer to the command descriptor (as registered).
3210 * @param pCmdHlp Pointer to command helper functions.
3211 * @param pVM Pointer to the current VM (if any).
3212 * @param paArgs Pointer to (readonly) array of arguments.
3213 * @param cArgs Number of arguments in the array.
3214 */
3215static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3216{
3217 /* check that the parser did what it's supposed to do. */
3218 if ( cArgs < 2
3219 || !DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
3220 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
3221 return dbgcCmdWorkerSearchMem(pCmdHlp, pVM, &paArgs[0], pResult ? 1 : 25, pCmd->pszCmd[1], paArgs + 1, cArgs - 1, pResult);
3222}
3223
3224
3225/**
3226 * List near symbol.
3227 *
3228 * @returns VBox status code.
3229 * @param pCmdHlp Pointer to command helper functions.
3230 * @param pVM Pointer to the current VM (if any).
3231 * @param pArg Pointer to the address or symbol to lookup.
3232 */
3233static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)
3234{
3235 dbgcVarSetGCFlat(pResult, 0);
3236
3237 DBGFSYMBOL Symbol;
3238 int rc;
3239 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)
3240 {
3241 /*
3242 * Lookup the symbol address.
3243 */
3244 rc = DBGFR3SymbolByName(pVM, pArg->u.pszString, &Symbol);
3245 if (VBOX_FAILURE(rc))
3246 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByName(, %s,)\n", pArg->u.pszString);
3247
3248 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */
3249 dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);
3250 }
3251 else
3252 {
3253 /*
3254 * Convert it to a flat GC address and lookup that address.
3255 */
3256 DBGCVAR AddrVar;
3257 rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);
3258 if (VBOX_FAILURE(rc))
3259 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);
3260
3261 dbgcVarSetVar(pResult, &AddrVar);
3262
3263 RTGCINTPTR offDisp = 0;
3264 rc = DBGFR3SymbolByAddr(pVM, AddrVar.u.GCFlat, &offDisp, &Symbol);
3265 if (VBOX_FAILURE(rc))
3266 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByAddr(, %VGv,,)\n", AddrVar.u.GCFlat);
3267
3268 if (!offDisp)
3269 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);
3270 else if (offDisp > 0)
3271 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);
3272 else
3273 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);
3274 if ((RTGCINTPTR)Symbol.cb > -offDisp)
3275 {
3276 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);
3277 dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);
3278 }
3279 else
3280 {
3281 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
3282 dbgcVarSetNoRange(pResult);
3283 }
3284 }
3285
3286 return rc;
3287}
3288
3289
3290/**
3291 * The 'ln' (listnear) command.
3292 *
3293 * @returns VBox status.
3294 * @param pCmd Pointer to the command descriptor (as registered).
3295 * @param pCmdHlp Pointer to command helper functions.
3296 * @param pVM Pointer to the current VM (if any).
3297 * @param paArgs Pointer to (readonly) array of arguments.
3298 * @param cArgs Number of arguments in the array.
3299 */
3300static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3301{
3302 dbgcVarSetGCFlat(pResult, 0);
3303 if (!cArgs)
3304 {
3305 /*
3306 * Current cs:eip symbol.
3307 */
3308 DBGCVAR AddrVar;
3309 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(cs:eip)");
3310 if (VBOX_FAILURE(rc))
3311 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");
3312 return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);
3313 }
3314
3315 /*
3316 * Iterate arguments.
3317 */
3318 for (unsigned iArg = 0; iArg < cArgs; iArg++)
3319 {
3320 int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);
3321 if (VBOX_FAILURE(rc))
3322 return rc;
3323 }
3324
3325 NOREF(pCmd); NOREF(pResult);
3326 return VINF_SUCCESS;
3327}
3328
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