VirtualBox

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

Last change on this file since 6290 was 6058, checked in by vboxsync, 17 years ago

fixed a couple of mixups in the eflags representation.

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