VirtualBox

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

Last change on this file since 59209 was 59209, checked in by vboxsync, 9 years ago

DBGC: Mapped out the remaining DBGFEVENTs.

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