VirtualBox

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

Last change on this file since 73460 was 73460, checked in by vboxsync, 6 years ago

IPRT,DBGF,Diggers: Moved DBGFRETURNTYPE and the unwind state structure to IPRT (dbg.h) in prep for debug module interface and more. Added stack unwind assist callback for the OS diggers so they can identify special stack frames and supply more info via the sure-register-value array and frame flags. Identify and decode NT/AMD64 trap frames.

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