VirtualBox

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

Last change on this file since 5730 was 5671, checked in by vboxsync, 17 years ago

some cleanup.

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