VirtualBox

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

Last change on this file since 31530 was 31530, checked in by vboxsync, 14 years ago

Debugger: Updated the file headers.

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