VirtualBox

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

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

include cpum.h.

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