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
4101 /*
4102 * Get the range.
4103 */
4104 PCDBGCVAR pRange = cArgs > 0 ? &paArgs[0] : pDbgc->pLastPos;
4105 RTGCPTR GCPtrFirst = NIL_RTGCPTR;
4106 int rc = DBGCCmdHlpVarToFlatAddr(pCmdHlp, pRange, &GCPtrFirst);
4107 if (RT_FAILURE(rc))
4108 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to convert %DV to a flat address: %Rrc", pRange, rc);
4109
4110 uint64_t cbRange;
4111 rc = DBGCCmdHlpVarGetRange(pCmdHlp, pRange, PAGE_SIZE, PAGE_SIZE * 8, &cbRange);
4112 if (RT_FAILURE(rc))
4113 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to obtain the range of %DV: %Rrc", pRange, rc);
4114
4115 RTGCPTR GCPtrLast = RTGCPTR_MAX - GCPtrFirst;
4116 if (cbRange >= GCPtrLast)
4117 GCPtrLast = RTGCPTR_MAX;
4118 else if (!cbRange)
4119 GCPtrLast = GCPtrFirst;
4120 else
4121 GCPtrLast = GCPtrFirst + cbRange - 1;
4122
4123 /*
4124 * Do we have a CR3?
4125 */
4126 uint64_t cr3 = 0;
4127 if (cArgs > 1)
4128 {
4129 if ((fFlags & (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) == (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW))
4130 return DBGCCmdHlpFail(pCmdHlp, pCmd, "No CR3 or mode arguments when dumping both context, please.");
4131 if (paArgs[1].enmType != DBGCVAR_TYPE_NUMBER)
4132 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The CR3 argument is not a number: %DV", &paArgs[1]);
4133 cr3 = paArgs[1].u.u64Number;
4134 }
4135 else
4136 fFlags |= DBGFPGDMP_FLAGS_CURRENT_CR3;
4137
4138 /*
4139 * Do we have a mode?
4140 */
4141 if (cArgs > 2)
4142 {
4143 if (paArgs[2].enmType != DBGCVAR_TYPE_STRING)
4144 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The mode argument is not a string: %DV", &paArgs[2]);
4145 static const struct MODETOFLAGS
4146 {
4147 const char *pszName;
4148 uint32_t fFlags;
4149 } s_aModeToFlags[] =
4150 {
4151 { "ept", DBGFPGDMP_FLAGS_EPT },
4152 { "legacy", 0 },
4153 { "legacy-np", DBGFPGDMP_FLAGS_NP },
4154 { "pse", DBGFPGDMP_FLAGS_PSE },
4155 { "pse-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_NP },
4156 { "pae", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE },
4157 { "pae-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NP },
4158 { "pae-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE },
4159 { "pae-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP },
4160 { "long", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME },
4161 { "long-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NP },
4162 { "long-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE },
4163 { "long-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP }
4164 };
4165 int i = RT_ELEMENTS(s_aModeToFlags);
4166 while (i-- > 0)
4167 if (!strcmp(s_aModeToFlags[i].pszName, paArgs[2].u.pszString))
4168 {
4169 fFlags |= s_aModeToFlags[i].fFlags;
4170 break;
4171 }
4172 if (i < 0)
4173 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Unknown mode: \"%s\"", paArgs[2].u.pszString);
4174 }
4175 else
4176 fFlags |= DBGFPGDMP_FLAGS_CURRENT_MODE;
4177
4178 /*
4179 * Call the worker.
4180 */
4181 rc = DBGFR3PagingDumpEx(pUVM, pDbgc->idCpu, fFlags, cr3, GCPtrFirst, GCPtrLast, 99 /*cMaxDepth*/,
4182 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
4183 if (RT_FAILURE(rc))
4184 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3PagingDumpEx: %Rrc\n", rc);
4185 return VINF_SUCCESS;
4186}
4187
4188
4189
4190/**
4191 * @callback_method_impl{FNDBGCCMD, The 'dpg*' commands.}
4192 */
4193static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4194{
4195 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4196
4197 /*
4198 * Validate input.
4199 */
4200 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1);
4201 if (pCmd->pszCmd[3] == 'a')
4202 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType));
4203 else
4204 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
4205 || DBGCVAR_ISPOINTER(paArgs[0].enmType));
4206 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4207
4208 /*
4209 * Guest or shadow page tables? Get the paging parameters.
4210 */
4211 bool fGuest = pCmd->pszCmd[3] != 'h';
4212 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
4213 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
4214 ? pDbgc->fRegCtxGuest
4215 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
4216
4217 bool fPAE, fLME, fPSE, fPGE, fNXE;
4218 uint64_t cr3 = fGuest
4219 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
4220 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
4221 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
4222
4223 /*
4224 * Locate the PTE to start displaying at.
4225 *
4226 * The 'dpta' command takes the address of a PTE, while the others are guest
4227 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple
4228 * while the others require us to do all the tedious walking thru the paging
4229 * hierarchy to find the intended PTE.
4230 */
4231 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */
4232 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */
4233 DBGCVAR VarPTEAddr; /* The address of the current PTE. */
4234 unsigned cEntries; /* The number of entries to display. */
4235 unsigned cEntriesMax; /* The max number of entries to display. */
4236 int rc;
4237 if (pCmd->pszCmd[3] == 'a')
4238 {
4239 VarPTEAddr = paArgs[0];
4240 switch (VarPTEAddr.enmRangeType)
4241 {
4242 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break;
4243 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break;
4244 default: cEntries = 10; break;
4245 }
4246 cEntriesMax = PAGE_SIZE / cbEntry;
4247 }
4248 else
4249 {
4250 /*
4251 * Determine the range.
4252 */
4253 switch (paArgs[0].enmRangeType)
4254 {
4255 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
4256 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;
4257 default: cEntries = 10; break;
4258 }
4259
4260 /*
4261 * Normalize the input address, it must be a flat GC address.
4262 */
4263 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
4264 if (RT_FAILURE(rc))
4265 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
4266 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
4267 {
4268 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
4269 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
4270 }
4271 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;
4272
4273 /*
4274 * Do the paging walk until we get to the page table.
4275 */
4276 DBGCVAR VarCur;
4277 if (fGuest)
4278 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
4279 else
4280 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
4281 if (fLME)
4282 {
4283 /* Page Map Level 4 Lookup. */
4284 /* Check if it's a valid address first? */
4285 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
4286 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
4287 X86PML4E Pml4e;
4288 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
4289 if (RT_FAILURE(rc))
4290 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
4291 if (!Pml4e.n.u1Present)
4292 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
4293
4294 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
4295 Assert(fPAE);
4296 }
4297 if (fPAE)
4298 {
4299 /* Page directory pointer table. */
4300 X86PDPE Pdpe;
4301 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe);
4302 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
4303 if (RT_FAILURE(rc))
4304 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
4305 if (!Pdpe.n.u1Present)
4306 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
4307
4308 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
4309
4310 /* Page directory (PAE). */
4311 X86PDEPAE Pde;
4312 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);
4313 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL);
4314 if (RT_FAILURE(rc))
4315 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
4316 if (!Pde.n.u1Present)
4317 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
4318 if (fPSE && Pde.n.u1Size)
4319 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
4320
4321 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
4322 VarPTEAddr = VarCur;
4323 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;
4324 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);
4325 }
4326 else
4327 {
4328 /* Page directory (legacy). */
4329 X86PDE Pde;
4330 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);
4331 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL);
4332 if (RT_FAILURE(rc))
4333 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
4334 if (!Pde.n.u1Present)
4335 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
4336 if (fPSE && Pde.n.u1Size)
4337 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
4338
4339 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;
4340 VarPTEAddr = VarCur;
4341 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;
4342 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);
4343 }
4344 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
4345 }
4346
4347 /* adjust cEntries */
4348 cEntries = RT_MAX(1, cEntries);
4349 cEntries = RT_MIN(cEntries, cEntriesMax);
4350
4351 /*
4352 * The display loop.
4353 */
4354 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",
4355 &VarPTEAddr, &VarGCPtr, iEntry);
4356 do
4357 {
4358 /*
4359 * Read.
4360 */
4361 X86PTEPAE Pte;
4362 Pte.u = 0;
4363 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pte, cbEntry, &VarPTEAddr, NULL);
4364 if (RT_FAILURE(rc))
4365 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);
4366
4367 /*
4368 * Display.
4369 */
4370 if (iEntry != ~0U)
4371 {
4372 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
4373 iEntry++;
4374 }
4375 DBGCCmdHlpPrintf(pCmdHlp,
4376 fPAE
4377 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
4378 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
4379 Pte.u,
4380 Pte.u & X86_PTE_PAE_PG_MASK,
4381 Pte.n.u1Present ? "p " : "np",
4382 Pte.n.u1Write ? "w" : "r",
4383 Pte.n.u1User ? "u" : "s",
4384 Pte.n.u1Accessed ? "a " : "na",
4385 Pte.n.u1Dirty ? "d " : "nd",
4386 Pte.n.u3Available,
4387 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ",
4388 Pte.n.u1WriteThru ? "pwt" : " ",
4389 Pte.n.u1CacheDisable ? "pcd" : " ",
4390 Pte.n.u1PAT ? "pat" : " ",
4391 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "
4392 );
4393 if (Pte.u & UINT64_C(0x7fff000000000000))
4394 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));
4395 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
4396 if (RT_FAILURE(rc))
4397 return rc;
4398
4399 /*
4400 * Advance.
4401 */
4402 VarPTEAddr.u.u64Number += cbEntry;
4403 if (iEntry != ~0U)
4404 VarGCPtr.u.GCFlat += PAGE_SIZE;
4405 } while (cEntries-- > 0);
4406
4407 return VINF_SUCCESS;
4408}
4409
4410
4411/**
4412 * @callback_method_impl{FNDBGCCMD, The 'dptb' command.}
4413 */
4414static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4415{
4416 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4417 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
4418 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
4419 if (RT_FAILURE(rc1))
4420 return rc1;
4421 NOREF(pCmd); NOREF(cArgs);
4422 return rc2;
4423}
4424
4425
4426/**
4427 * @callback_method_impl{FNDBGCCMD, The 'dt' command.}
4428 */
4429static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4430{
4431 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4432 int rc;
4433
4434 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4435 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1);
4436 if (cArgs == 1)
4437 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType != DBGCVAR_TYPE_STRING
4438 && paArgs[0].enmType != DBGCVAR_TYPE_SYMBOL);
4439
4440 /*
4441 * Check if the command indicates the type.
4442 */
4443 enum { kTss16, kTss32, kTss64, kTssToBeDetermined } enmTssType = kTssToBeDetermined;
4444 if (!strcmp(pCmd->pszCmd, "dt16"))
4445 enmTssType = kTss16;
4446 else if (!strcmp(pCmd->pszCmd, "dt32"))
4447 enmTssType = kTss32;
4448 else if (!strcmp(pCmd->pszCmd, "dt64"))
4449 enmTssType = kTss64;
4450
4451 /*
4452 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.
4453 */
4454 uint32_t SelTss = UINT32_MAX;
4455 DBGCVAR VarTssAddr;
4456 if (cArgs == 0)
4457 {
4458 /** @todo consider querying the hidden bits instead (missing API). */
4459 uint16_t SelTR;
4460 rc = DBGFR3RegCpuQueryU16(pUVM, pDbgc->idCpu, DBGFREG_TR, &SelTR);
4461 if (RT_FAILURE(rc))
4462 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query TR, rc=%Rrc\n", rc);
4463 DBGCVAR_INIT_GC_FAR(&VarTssAddr, SelTR, 0);
4464 SelTss = SelTR;
4465 }
4466 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)
4467 {
4468 if (paArgs[0].u.u64Number < 0xffff)
4469 DBGCVAR_INIT_GC_FAR(&VarTssAddr, (RTSEL)paArgs[0].u.u64Number, 0);
4470 else
4471 {
4472 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_ELEMENTS)
4473 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Element count doesn't combine with a TSS address.\n");
4474 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, paArgs[0].u.u64Number);
4475 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_BYTES)
4476 {
4477 VarTssAddr.enmRangeType = paArgs[0].enmRangeType;
4478 VarTssAddr.u64Range = paArgs[0].u64Range;
4479 }
4480 }
4481 }
4482 else
4483 VarTssAddr = paArgs[0];
4484
4485 /*
4486 * Deal with TSS:ign by means of the GDT.
4487 */
4488 if (VarTssAddr.enmType == DBGCVAR_TYPE_GC_FAR)
4489 {
4490 SelTss = VarTssAddr.u.GCFar.sel;
4491 DBGFSELINFO SelInfo;
4492 rc = DBGFR3SelQueryInfo(pUVM, pDbgc->idCpu, VarTssAddr.u.GCFar.sel, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo);
4493 if (RT_FAILURE(rc))
4494 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3SelQueryInfo(,%u,%d,,) -> %Rrc.\n",
4495 pDbgc->idCpu, VarTssAddr.u.GCFar.sel, rc);
4496
4497 if (SelInfo.u.Raw.Gen.u1DescType)
4498 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (!sys)\n", VarTssAddr.u.GCFar.sel);
4499
4500 switch (SelInfo.u.Raw.Gen.u4Type)
4501 {
4502 case X86_SEL_TYPE_SYS_286_TSS_BUSY:
4503 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
4504 if (enmTssType == kTssToBeDetermined)
4505 enmTssType = kTss16;
4506 break;
4507
4508 case X86_SEL_TYPE_SYS_386_TSS_BUSY: /* AMD64 too */
4509 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
4510 if (enmTssType == kTssToBeDetermined)
4511 enmTssType = SelInfo.fFlags & DBGFSELINFO_FLAGS_LONG_MODE ? kTss64 : kTss32;
4512 break;
4513
4514 default:
4515 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (type=%x)\n",
4516 VarTssAddr.u.GCFar.sel, SelInfo.u.Raw.Gen.u4Type);
4517 }
4518
4519 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, SelInfo.GCPtrBase);
4520 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, RT_MAX(SelInfo.cbLimit + 1, SelInfo.cbLimit));
4521 }
4522
4523 /*
4524 * Determine the TSS type if none is currently given.
4525 */
4526 if (enmTssType == kTssToBeDetermined)
4527 {
4528 if ( VarTssAddr.u64Range > 0
4529 && VarTssAddr.u64Range < sizeof(X86TSS32) - 4)
4530 enmTssType = kTss16;
4531 else
4532 {
4533 uint64_t uEfer;
4534 rc = DBGFR3RegCpuQueryU64(pUVM, pDbgc->idCpu, DBGFREG_MSR_K6_EFER, &uEfer);
4535 if ( RT_FAILURE(rc)
4536 || !(uEfer & MSR_K6_EFER_LMA) )
4537 enmTssType = kTss32;
4538 else
4539 enmTssType = kTss64;
4540 }
4541 }
4542
4543 /*
4544 * Figure the min/max sizes.
4545 * ASSUMES max TSS size is 64 KB.
4546 */
4547 uint32_t cbTssMin;
4548 uint32_t cbTssMax;
4549 switch (enmTssType)
4550 {
4551 case kTss16:
4552 cbTssMin = cbTssMax = X86_SEL_TYPE_SYS_286_TSS_LIMIT_MIN + 1;
4553 break;
4554 case kTss32:
4555 cbTssMin = X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1;
4556 cbTssMax = _64K;
4557 break;
4558 case kTss64:
4559 cbTssMin = X86_SEL_TYPE_SYS_386_TSS_LIMIT_MIN + 1;
4560 cbTssMax = _64K;
4561 break;
4562 default:
4563 AssertFailedReturn(VERR_INTERNAL_ERROR);
4564 }
4565 uint32_t cbTss = VarTssAddr.enmRangeType == DBGCVAR_RANGE_BYTES ? (uint32_t)VarTssAddr.u64Range : 0;
4566 if (cbTss == 0)
4567 cbTss = cbTssMin;
4568 else if (cbTss < cbTssMin)
4569 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Minimum TSS size is %u bytes, you specified %llu (%llx) bytes.\n",
4570 cbTssMin, VarTssAddr.u64Range, VarTssAddr.u64Range);
4571 else if (cbTss > cbTssMax)
4572 cbTss = cbTssMax;
4573 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, cbTss);
4574
4575 /*
4576 * Read the TSS into a temporary buffer.
4577 */
4578 uint8_t abBuf[_64K];
4579 size_t cbTssRead;
4580 rc = DBGCCmdHlpMemRead(pCmdHlp, abBuf, cbTss, &VarTssAddr, &cbTssRead);
4581 if (RT_FAILURE(rc))
4582 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read TSS at %Dv: %Rrc\n", &VarTssAddr, rc);
4583 if (cbTssRead < cbTssMin)
4584 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read essential parts of the TSS (read %zu, min %zu).\n",
4585 cbTssRead, cbTssMin);
4586 if (cbTssRead < cbTss)
4587 memset(&abBuf[cbTssRead], 0xff, cbTss - cbTssRead);
4588
4589
4590 /*
4591 * Format the TSS.
4592 */
4593 uint16_t offIoBitmap;
4594 switch (enmTssType)
4595 {
4596 case kTss16:
4597 {
4598 PCX86TSS16 pTss = (PCX86TSS16)&abBuf[0];
4599 if (SelTss != UINT32_MAX)
4600 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS16 at %Dv\n", SelTss, &VarTssAddr);
4601 else
4602 DBGCCmdHlpPrintf(pCmdHlp, "TSS16 at %Dv\n", &VarTssAddr);
4603 DBGCCmdHlpPrintf(pCmdHlp,
4604 "ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x\n"
4605 "ip=%04x sp=%04x bp=%04x\n"
4606 "cs=%04x ss=%04x ds=%04x es=%04x flags=%04x\n"
4607 "ss:sp0=%04x:%04x ss:sp1=%04x:%04x ss:sp2=%04x:%04x\n"
4608 "prev=%04x ldtr=%04x\n"
4609 ,
4610 pTss->ax, pTss->bx, pTss->cx, pTss->dx, pTss->si, pTss->di,
4611 pTss->ip, pTss->sp, pTss->bp,
4612 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->flags,
4613 pTss->ss0, pTss->sp0, pTss->ss1, pTss->sp1, pTss->ss2, pTss->sp2,
4614 pTss->selPrev, pTss->selLdt);
4615 if (pTss->cs != 0)
4616 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%04x L 0", pTss->cs, pTss->ip);
4617 offIoBitmap = 0;
4618 break;
4619 }
4620
4621 case kTss32:
4622 {
4623 PCX86TSS32 pTss = (PCX86TSS32)&abBuf[0];
4624 if (SelTss != UINT32_MAX)
4625 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS32 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin);
4626 else
4627 DBGCCmdHlpPrintf(pCmdHlp, "TSS32 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin);
4628 DBGCCmdHlpPrintf(pCmdHlp,
4629 "eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
4630 "eip=%08x esp=%08x ebp=%08x\n"
4631 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n"
4632 "ss:esp0=%04x:%08x ss:esp1=%04x:%08x ss:esp2=%04x:%08x\n"
4633 "prev=%04x ldtr=%04x cr3=%08x debug=%u iomap=%04x\n"
4634 ,
4635 pTss->eax, pTss->ebx, pTss->ecx, pTss->edx, pTss->esi, pTss->edi,
4636 pTss->eip, pTss->esp, pTss->ebp,
4637 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->fs, pTss->gs, pTss->eflags,
4638 pTss->ss0, pTss->esp0, pTss->ss1, pTss->esp1, pTss->ss2, pTss->esp2,
4639 pTss->selPrev, pTss->selLdt, pTss->cr3, pTss->fDebugTrap, pTss->offIoBitmap);
4640 if (pTss->cs != 0)
4641 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pTss->cs, pTss->eip);
4642 offIoBitmap = pTss->offIoBitmap;
4643 break;
4644 }
4645
4646 case kTss64:
4647 {
4648 PCX86TSS64 pTss = (PCX86TSS64)&abBuf[0];
4649 if (SelTss != UINT32_MAX)
4650 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS64 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin);
4651 else
4652 DBGCCmdHlpPrintf(pCmdHlp, "TSS64 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin);
4653 DBGCCmdHlpPrintf(pCmdHlp,
4654 "rsp0=%016RX64 rsp1=%016RX64 rsp2=%016RX64\n"
4655 "ist1=%016RX64 ist2=%016RX64\n"
4656 "ist3=%016RX64 ist4=%016RX64\n"
4657 "ist5=%016RX64 ist6=%016RX64\n"
4658 "ist7=%016RX64 iomap=%04x\n"
4659 ,
4660 pTss->rsp0, pTss->rsp1, pTss->rsp2,
4661 pTss->ist1, pTss->ist2,
4662 pTss->ist3, pTss->ist4,
4663 pTss->ist5, pTss->ist6,
4664 pTss->ist7, pTss->offIoBitmap);
4665 offIoBitmap = pTss->offIoBitmap;
4666 break;
4667 }
4668
4669 default:
4670 AssertFailedReturn(VERR_INTERNAL_ERROR);
4671 }
4672
4673 /*
4674 * Dump the interrupt redirection bitmap.
4675 */
4676 if (enmTssType != kTss16)
4677 {
4678 if ( offIoBitmap > cbTssMin
4679 && offIoBitmap < cbTss) /** @todo check exactly what the edge cases are here. */
4680 {
4681 if (offIoBitmap - cbTssMin >= 32)
4682 {
4683 DBGCCmdHlpPrintf(pCmdHlp, "Interrupt redirection:\n");
4684 uint8_t const *pbIntRedirBitmap = &abBuf[offIoBitmap - 32];
4685 uint32_t iStart = 0;
4686 bool fPrev = ASMBitTest(pbIntRedirBitmap, 0); /* LE/BE issue */
4687 for (uint32_t i = 0; i < 256; i++)
4688 {
4689 bool fThis = ASMBitTest(pbIntRedirBitmap, i);
4690 if (fThis != fPrev)
4691 {
4692 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, i - 1, fPrev ? "Protected mode" : "Redirected");
4693 fPrev = fThis;
4694 iStart = i;
4695 }
4696 }
4697 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, 255, fPrev ? "Protected mode" : "Redirected");
4698 }
4699 else
4700 DBGCCmdHlpPrintf(pCmdHlp, "Invalid interrupt redirection bitmap size: %u (%#x), expected 32 bytes.\n",
4701 offIoBitmap - cbTssMin, offIoBitmap - cbTssMin);
4702 }
4703 else if (offIoBitmap > 0)
4704 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap (-%#x)\n", cbTssMin - offIoBitmap);
4705 else
4706 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap\n");
4707 }
4708
4709 /*
4710 * Dump the I/O permission bitmap if present. The IOPM cannot start below offset 0x68
4711 * (that applies to both 32-bit and 64-bit TSSs since their size is the same).
4712 * Note that there is always one padding byte that is not technically part of the bitmap
4713 * and "must have all bits set". It's not clear what happens when it doesn't. All ports
4714 * not covered by the bitmap are considered to be not accessible.
4715 */
4716 if (enmTssType != kTss16)
4717 {
4718 if (offIoBitmap < cbTss && offIoBitmap >= 0x68)
4719 {
4720 uint32_t cPorts = RT_MIN((cbTss - offIoBitmap) * 8, _64K);
4721 DBGCVAR VarAddr;
4722 DBGCCmdHlpEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarTssAddr, offIoBitmap);
4723 DBGCCmdHlpPrintf(pCmdHlp, "I/O bitmap at %DV - %#x ports:\n", &VarAddr, cPorts);
4724
4725 uint8_t const *pbIoBitmap = &abBuf[offIoBitmap];
4726 uint32_t iStart = 0;
4727 bool fPrev = ASMBitTest(pbIoBitmap, 0);
4728 uint32_t cLine = 0;
4729 for (uint32_t i = 1; i < _64K; i++)
4730 {
4731 bool fThis = i < cPorts ? ASMBitTest(pbIoBitmap, i) : true;
4732 if (fThis != fPrev)
4733 {
4734 cLine++;
4735 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s%s", iStart, i-1,
4736 fPrev ? "GP" : "OK", (cLine % 6) == 0 ? "\n" : " ");
4737 fPrev = fThis;
4738 iStart = i;
4739 }
4740 }
4741 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s\n", iStart, _64K-1, fPrev ? "GP" : "OK");
4742 }
4743 else if (offIoBitmap > 0)
4744 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap (-%#x)\n", cbTssMin - offIoBitmap);
4745 else
4746 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap\n");
4747 }
4748
4749 return VINF_SUCCESS;
4750}
4751
4752
4753/**
4754 * @callback_method_impl{FNDBGFR3TYPEDUMP, The 'dti' command dumper callback.}
4755 */
4756static DECLCALLBACK(int) dbgcCmdDumpTypeInfoCallback(uint32_t off, const char *pszField, uint32_t iLvl,
4757 const char *pszType, uint32_t fTypeFlags,
4758 uint32_t cElements, void *pvUser)
4759{
4760 PDBGCCMDHLP pCmdHlp = (PDBGCCMDHLP)pvUser;
4761
4762 /* Pad with spaces to match the level. */
4763 for (uint32_t i = 0; i < iLvl; i++)
4764 DBGCCmdHlpPrintf(pCmdHlp, " ");
4765
4766 size_t cbWritten = 0;
4767 DBGCCmdHlpPrintfEx(pCmdHlp, &cbWritten, "+0x%04x %s", off, pszField);
4768 while (cbWritten < 32)
4769 {
4770 /* Fill with spaces to get proper aligning. */
4771 DBGCCmdHlpPrintf(pCmdHlp, " ");
4772 cbWritten++;
4773 }
4774
4775 DBGCCmdHlpPrintf(pCmdHlp, ": ");
4776 if (fTypeFlags & DBGFTYPEREGMEMBER_F_ARRAY)
4777 DBGCCmdHlpPrintf(pCmdHlp, "[%u] ", cElements);
4778 if (fTypeFlags & DBGFTYPEREGMEMBER_F_POINTER)
4779 DBGCCmdHlpPrintf(pCmdHlp, "Ptr ");
4780 DBGCCmdHlpPrintf(pCmdHlp, "%s\n", pszType);
4781
4782 return VINF_SUCCESS;
4783}
4784
4785
4786/**
4787 * @callback_method_impl{FNDBGCCMD, The 'dti' command.}
4788 */
4789static DECLCALLBACK(int) dbgcCmdDumpTypeInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4790{
4791 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4792 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1 || cArgs == 2);
4793 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_STRING);
4794 if (cArgs == 2)
4795 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[1].enmType == DBGCVAR_TYPE_NUMBER);
4796
4797 uint32_t cLvlMax = cArgs == 2 ? (uint32_t)paArgs[1].u.u64Number : UINT32_MAX;
4798 return DBGFR3TypeDumpEx(pUVM, paArgs[0].u.pszString, 0 /* fFlags */, cLvlMax,
4799 dbgcCmdDumpTypeInfoCallback, pCmdHlp);
4800}
4801
4802
4803static void dbgcCmdDumpTypedValCallbackBuiltin(PDBGCCMDHLP pCmdHlp, DBGFTYPEBUILTIN enmType, size_t cbType,
4804 PDBGFTYPEVALBUF pValBuf)
4805{
4806 switch (enmType)
4807 {
4808 case DBGFTYPEBUILTIN_UINT8:
4809 DBGCCmdHlpPrintf(pCmdHlp, "%RU8", pValBuf->u8);
4810 break;
4811 case DBGFTYPEBUILTIN_INT8:
4812 DBGCCmdHlpPrintf(pCmdHlp, "%RI8", pValBuf->i8);
4813 break;
4814 case DBGFTYPEBUILTIN_UINT16:
4815 DBGCCmdHlpPrintf(pCmdHlp, "%RU16", pValBuf->u16);
4816 break;
4817 case DBGFTYPEBUILTIN_INT16:
4818 DBGCCmdHlpPrintf(pCmdHlp, "%RI16", pValBuf->i16);
4819 break;
4820 case DBGFTYPEBUILTIN_UINT32:
4821 DBGCCmdHlpPrintf(pCmdHlp, "%RU32", pValBuf->u32);
4822 break;
4823 case DBGFTYPEBUILTIN_INT32:
4824 DBGCCmdHlpPrintf(pCmdHlp, "%RI32", pValBuf->i32);
4825 break;
4826 case DBGFTYPEBUILTIN_UINT64:
4827 DBGCCmdHlpPrintf(pCmdHlp, "%RU64", pValBuf->u64);
4828 break;
4829 case DBGFTYPEBUILTIN_INT64:
4830 DBGCCmdHlpPrintf(pCmdHlp, "%RI64", pValBuf->i64);
4831 break;
4832 case DBGFTYPEBUILTIN_PTR32:
4833 DBGCCmdHlpPrintf(pCmdHlp, "%RX32", pValBuf->GCPtr);
4834 break;
4835 case DBGFTYPEBUILTIN_PTR64:
4836 DBGCCmdHlpPrintf(pCmdHlp, "%RX64", pValBuf->GCPtr);
4837 break;
4838 case DBGFTYPEBUILTIN_PTR:
4839 if (cbType == sizeof(uint32_t))
4840 DBGCCmdHlpPrintf(pCmdHlp, "%RX32", pValBuf->GCPtr);
4841 else if (cbType == sizeof(uint64_t))
4842 DBGCCmdHlpPrintf(pCmdHlp, "%RX64", pValBuf->GCPtr);
4843 else
4844 DBGCCmdHlpPrintf(pCmdHlp, "<Unsupported pointer width %u>", cbType);
4845 break;
4846 case DBGFTYPEBUILTIN_SIZE:
4847 if (cbType == sizeof(uint32_t))
4848 DBGCCmdHlpPrintf(pCmdHlp, "%RU32", pValBuf->size);
4849 else if (cbType == sizeof(uint64_t))
4850 DBGCCmdHlpPrintf(pCmdHlp, "%RU64", pValBuf->size);
4851 else
4852 DBGCCmdHlpPrintf(pCmdHlp, "<Unsupported size width %u>", cbType);
4853 break;
4854 case DBGFTYPEBUILTIN_FLOAT32:
4855 case DBGFTYPEBUILTIN_FLOAT64:
4856 case DBGFTYPEBUILTIN_COMPOUND:
4857 default:
4858 AssertMsgFailed(("Invalid built-in type: %d\n", enmType));
4859 }
4860}
4861
4862/**
4863 * @callback_method_impl{FNDBGFR3TYPEDUMP, The 'dtv' command dumper callback.}
4864 */
4865static DECLCALLBACK(int) dbgcCmdDumpTypedValCallback(uint32_t off, const char *pszField, uint32_t iLvl,
4866 DBGFTYPEBUILTIN enmType, size_t cbType,
4867 PDBGFTYPEVALBUF pValBuf, uint32_t cValBufs,
4868 void *pvUser)
4869{
4870 PDBGCCMDHLP pCmdHlp = (PDBGCCMDHLP)pvUser;
4871
4872 /* Pad with spaces to match the level. */
4873 for (uint32_t i = 0; i < iLvl; i++)
4874 DBGCCmdHlpPrintf(pCmdHlp, " ");
4875
4876 size_t cbWritten = 0;
4877 DBGCCmdHlpPrintfEx(pCmdHlp, &cbWritten, "+0x%04x %s", off, pszField);
4878 while (cbWritten < 32)
4879 {
4880 /* Fill with spaces to get proper aligning. */
4881 DBGCCmdHlpPrintf(pCmdHlp, " ");
4882 cbWritten++;
4883 }
4884
4885 DBGCCmdHlpPrintf(pCmdHlp, ": ");
4886 if (cValBufs > 1)
4887 DBGCCmdHlpPrintf(pCmdHlp, "[%u] [ ", cValBufs);
4888
4889 for (uint32_t i = 0; i < cValBufs; i++)
4890 {
4891 dbgcCmdDumpTypedValCallbackBuiltin(pCmdHlp, enmType, cbType, pValBuf);
4892 if (i < cValBufs - 1)
4893 DBGCCmdHlpPrintf(pCmdHlp, " , ");
4894 pValBuf++;
4895 }
4896
4897 if (cValBufs > 1)
4898 DBGCCmdHlpPrintf(pCmdHlp, " ]");
4899 DBGCCmdHlpPrintf(pCmdHlp, "\n");
4900
4901 return VINF_SUCCESS;
4902}
4903
4904
4905/**
4906 * @callback_method_impl{FNDBGCCMD, The 'dtv' command.}
4907 */
4908static DECLCALLBACK(int) dbgcCmdDumpTypedVal(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4909{
4910 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4911 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 2 || cArgs == 3);
4912 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_STRING);
4913 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISGCPOINTER(paArgs[1].enmType));
4914 if (cArgs == 3)
4915 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[2].enmType == DBGCVAR_TYPE_NUMBER);
4916
4917 /*
4918 * Make DBGF address and fix the range.
4919 */
4920 DBGFADDRESS Address;
4921 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &Address);
4922 if (RT_FAILURE(rc))
4923 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", &paArgs[1]);
4924
4925 uint32_t cLvlMax = cArgs == 3 ? (uint32_t)paArgs[2].u.u64Number : UINT32_MAX;
4926 return DBGFR3TypeValDumpEx(pUVM, &Address, paArgs[0].u.pszString, 0 /* fFlags */, cLvlMax,
4927 dbgcCmdDumpTypedValCallback, pCmdHlp);
4928}
4929
4930/**
4931 * @callback_method_impl{FNDBGCCMD, The 'm' command.}
4932 */
4933static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
4934{
4935 DBGCCmdHlpPrintf(pCmdHlp, "Address: %DV\n", &paArgs[0]);
4936 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
4937 return dbgcCmdDumpPageHierarchy(pCmd, pCmdHlp, pUVM, paArgs, cArgs);
4938}
4939
4940
4941/**
4942 * Converts one or more variables into a byte buffer for a
4943 * given unit size.
4944 *
4945 * @returns VBox status codes:
4946 * @retval VERR_TOO_MUCH_DATA if the buffer is too small, bitched.
4947 * @retval VERR_INTERNAL_ERROR on bad variable type, bitched.
4948 * @retval VINF_SUCCESS on success.
4949 *
4950 * @param pCmdHlp The command helper callback table.
4951 * @param pvBuf The buffer to convert into.
4952 * @param pcbBuf The buffer size on input. The size of the result on output.
4953 * @param cbUnit The unit size to apply when converting.
4954 * The high bit is used to indicate unicode string.
4955 * @param paVars The array of variables to convert.
4956 * @param cVars The number of variables.
4957 */
4958int dbgcVarsToBytes(PDBGCCMDHLP pCmdHlp, void *pvBuf, uint32_t *pcbBuf, size_t cbUnit, PCDBGCVAR paVars, unsigned cVars)
4959{
4960 union
4961 {
4962 uint8_t *pu8;
4963 uint16_t *pu16;
4964 uint32_t *pu32;
4965 uint64_t *pu64;
4966 } u, uEnd;
4967 u.pu8 = (uint8_t *)pvBuf;
4968 uEnd.pu8 = u.pu8 + *pcbBuf;
4969
4970 unsigned i;
4971 for (i = 0; i < cVars && u.pu8 < uEnd.pu8; i++)
4972 {
4973 switch (paVars[i].enmType)
4974 {
4975 case DBGCVAR_TYPE_GC_FAR:
4976 case DBGCVAR_TYPE_GC_FLAT:
4977 case DBGCVAR_TYPE_GC_PHYS:
4978 case DBGCVAR_TYPE_HC_FLAT:
4979 case DBGCVAR_TYPE_HC_PHYS:
4980 case DBGCVAR_TYPE_NUMBER:
4981 {
4982 uint64_t u64 = paVars[i].u.u64Number;
4983 switch (cbUnit & 0x1f)
4984 {
4985 case 1:
4986 do
4987 {
4988 *u.pu8++ = u64;
4989 u64 >>= 8;
4990 } while (u64);
4991 break;
4992 case 2:
4993 do
4994 {
4995 *u.pu16++ = u64;
4996 u64 >>= 16;
4997 } while (u64);
4998 break;
4999 case 4:
5000 *u.pu32++ = u64;
5001 u64 >>= 32;
5002 if (u64)
5003 *u.pu32++ = u64;
5004 break;
5005 case 8:
5006 *u.pu64++ = u64;
5007 break;
5008 }
5009 break;
5010 }
5011
5012 case DBGCVAR_TYPE_STRING:
5013 case DBGCVAR_TYPE_SYMBOL:
5014 {
5015 const char *psz = paVars[i].u.pszString;
5016 size_t cbString = strlen(psz);
5017 if (cbUnit & RT_BIT_32(31))
5018 {
5019 /* Explode char to unit. */
5020 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8) * (cbUnit & 0x1f))
5021 {
5022 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
5023 return VERR_TOO_MUCH_DATA;
5024 }
5025 while (*psz)
5026 {
5027 switch (cbUnit & 0x1f)
5028 {
5029 case 1: *u.pu8++ = *psz; break;
5030 case 2: *u.pu16++ = *psz; break;
5031 case 4: *u.pu32++ = *psz; break;
5032 case 8: *u.pu64++ = *psz; break;
5033 }
5034 psz++;
5035 }
5036 }
5037 else
5038 {
5039 /* Raw copy with zero padding if the size isn't aligned. */
5040 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8))
5041 {
5042 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
5043 return VERR_TOO_MUCH_DATA;
5044 }
5045
5046 size_t cbCopy = cbString & ~(cbUnit - 1);
5047 memcpy(u.pu8, psz, cbCopy);
5048 u.pu8 += cbCopy;
5049 psz += cbCopy;
5050
5051 size_t cbReminder = cbString & (cbUnit - 1);
5052 if (cbReminder)
5053 {
5054 memcpy(u.pu8, psz, cbString & (cbUnit - 1));
5055 memset(u.pu8 + cbReminder, 0, cbUnit - cbReminder);
5056 u.pu8 += cbUnit;
5057 }
5058 }
5059 break;
5060 }
5061
5062 default:
5063 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
5064 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INTERNAL_ERROR,
5065 "i=%d enmType=%d\n", i, paVars[i].enmType);
5066 return VERR_INTERNAL_ERROR;
5067 }
5068 }
5069 *pcbBuf = u.pu8 - (uint8_t *)pvBuf;
5070 if (i != cVars)
5071 {
5072 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf);
5073 return VERR_TOO_MUCH_DATA;
5074 }
5075 return VINF_SUCCESS;
5076}
5077
5078
5079/**
5080 * @callback_method_impl{FNDBGCCMD, The 'eb'\, 'ew'\, 'ed' and 'eq' commands.}
5081 */
5082static DECLCALLBACK(int) dbgcCmdEditMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5083{
5084 /*
5085 * Validate input.
5086 */
5087 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2);
5088 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType));
5089 for (unsigned iArg = 1; iArg < cArgs; iArg++)
5090 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER);
5091 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
5092
5093 /*
5094 * Figure out the element size.
5095 */
5096 unsigned cbElement;
5097 switch (pCmd->pszCmd[1])
5098 {
5099 default:
5100 case 'b': cbElement = 1; break;
5101 case 'w': cbElement = 2; break;
5102 case 'd': cbElement = 4; break;
5103 case 'q': cbElement = 8; break;
5104 }
5105
5106 /*
5107 * Do setting.
5108 */
5109 DBGCVAR Addr = paArgs[0];
5110 for (unsigned iArg = 1;;)
5111 {
5112 size_t cbWritten;
5113 int rc = pCmdHlp->pfnMemWrite(pCmdHlp, &paArgs[iArg].u, cbElement, &Addr, &cbWritten);
5114 if (RT_FAILURE(rc))
5115 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Writing memory at %DV.\n", &Addr);
5116 if (cbWritten != cbElement)
5117 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Only wrote %u out of %u bytes!\n", cbWritten, cbElement);
5118
5119 /* advance. */
5120 iArg++;
5121 if (iArg >= cArgs)
5122 break;
5123 rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%Dv + %#x", &Addr, cbElement);
5124 if (RT_FAILURE(rc))
5125 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
5126 }
5127
5128 return VINF_SUCCESS;
5129}
5130
5131
5132/**
5133 * Executes the search.
5134 *
5135 * @returns VBox status code.
5136 * @param pCmdHlp The command helpers.
5137 * @param pUVM The user mode VM handle.
5138 * @param pAddress The address to start searching from. (undefined on output)
5139 * @param cbRange The address range to search. Must not wrap.
5140 * @param pabBytes The byte pattern to search for.
5141 * @param cbBytes The size of the pattern.
5142 * @param cbUnit The search unit.
5143 * @param cMaxHits The max number of hits.
5144 * @param pResult Where to store the result if it's a function invocation.
5145 */
5146static int dbgcCmdWorkerSearchMemDoIt(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR cbRange,
5147 const uint8_t *pabBytes, uint32_t cbBytes,
5148 uint32_t cbUnit, uint64_t cMaxHits, PDBGCVAR pResult)
5149{
5150 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5151
5152 /*
5153 * Do the search.
5154 */
5155 uint64_t cHits = 0;
5156 for (;;)
5157 {
5158 /* search */
5159 DBGFADDRESS HitAddress;
5160 int rc = DBGFR3MemScan(pUVM, pDbgc->idCpu, pAddress, cbRange, 1, pabBytes, cbBytes, &HitAddress);
5161 if (RT_FAILURE(rc))
5162 {
5163 if (rc != VERR_DBGF_MEM_NOT_FOUND)
5164 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3MemScan\n");
5165
5166 /* update the current address so we can save it (later). */
5167 pAddress->off += cbRange;
5168 pAddress->FlatPtr += cbRange;
5169 cbRange = 0;
5170 break;
5171 }
5172
5173 /* report result */
5174 DBGCVAR VarCur;
5175 rc = DBGCCmdHlpVarFromDbgfAddr(pCmdHlp, &HitAddress, &VarCur);
5176 if (RT_FAILURE(rc))
5177 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGCCmdHlpVarFromDbgfAddr\n");
5178 if (!pResult)
5179 pCmdHlp->pfnExec(pCmdHlp, "db %DV LB 10", &VarCur);
5180 else
5181 DBGCVAR_ASSIGN(pResult, &VarCur);
5182
5183 /* advance */
5184 cbRange -= HitAddress.FlatPtr - pAddress->FlatPtr;
5185 *pAddress = HitAddress;
5186 pAddress->FlatPtr += cbBytes;
5187 pAddress->off += cbBytes;
5188 if (cbRange <= cbBytes)
5189 {
5190 cbRange = 0;
5191 break;
5192 }
5193 cbRange -= cbBytes;
5194
5195 if (++cHits >= cMaxHits)
5196 {
5197 /// @todo save the search.
5198 break;
5199 }
5200 }
5201
5202 /*
5203 * Save the search so we can resume it...
5204 */
5205 if (pDbgc->abSearch != pabBytes)
5206 {
5207 memcpy(pDbgc->abSearch, pabBytes, cbBytes);
5208 pDbgc->cbSearch = cbBytes;
5209 pDbgc->cbSearchUnit = cbUnit;
5210 }
5211 pDbgc->cMaxSearchHits = cMaxHits;
5212 pDbgc->SearchAddr = *pAddress;
5213 pDbgc->cbSearchRange = cbRange;
5214
5215 return cHits ? VINF_SUCCESS : VERR_DBGC_COMMAND_FAILED;
5216}
5217
5218
5219/**
5220 * Resumes the previous search.
5221 *
5222 * @returns VBox status code.
5223 * @param pCmdHlp Pointer to the command helper functions.
5224 * @param pUVM The user mode VM handle.
5225 * @param pResult Where to store the result of a function invocation.
5226 */
5227static int dbgcCmdWorkerSearchMemResume(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGCVAR pResult)
5228{
5229 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5230
5231 /*
5232 * Make sure there is a previous command.
5233 */
5234 if (!pDbgc->cbSearch)
5235 {
5236 DBGCCmdHlpPrintf(pCmdHlp, "Error: No previous search\n");
5237 return VERR_DBGC_COMMAND_FAILED;
5238 }
5239
5240 /*
5241 * Make range and address adjustments.
5242 */
5243 DBGFADDRESS Address = pDbgc->SearchAddr;
5244 if (Address.FlatPtr == ~(RTGCUINTPTR)0)
5245 {
5246 Address.FlatPtr -= Address.off;
5247 Address.off = 0;
5248 }
5249
5250 RTGCUINTPTR cbRange = pDbgc->cbSearchRange;
5251 if (!cbRange)
5252 cbRange = ~(RTGCUINTPTR)0;
5253 if (Address.FlatPtr + cbRange < pDbgc->SearchAddr.FlatPtr)
5254 cbRange = ~(RTGCUINTPTR)0 - pDbgc->SearchAddr.FlatPtr + !!pDbgc->SearchAddr.FlatPtr;
5255
5256 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, pDbgc->abSearch, pDbgc->cbSearch,
5257 pDbgc->cbSearchUnit, pDbgc->cMaxSearchHits, pResult);
5258}
5259
5260
5261/**
5262 * Search memory, worker for the 's' and 's?' functions.
5263 *
5264 * @returns VBox status code.
5265 * @param pCmdHlp Pointer to the command helper functions.
5266 * @param pUVM The user mode VM handle.
5267 * @param pAddress Where to start searching. If no range, search till end of address space.
5268 * @param cMaxHits The maximum number of hits.
5269 * @param chType The search type.
5270 * @param paPatArgs The pattern variable array.
5271 * @param cPatArgs Number of pattern variables.
5272 * @param pResult Where to store the result of a function invocation.
5273 */
5274static int dbgcCmdWorkerSearchMem(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR pAddress, uint64_t cMaxHits, char chType,
5275 PCDBGCVAR paPatArgs, unsigned cPatArgs, PDBGCVAR pResult)
5276{
5277 if (pResult)
5278 DBGCVAR_INIT_GC_FLAT(pResult, 0);
5279
5280 /*
5281 * Convert the search pattern into bytes and DBGFR3MemScan can deal with.
5282 */
5283 uint32_t cbUnit;
5284 switch (chType)
5285 {
5286 case 'a':
5287 case 'b': cbUnit = 1; break;
5288 case 'u': cbUnit = 2 | RT_BIT_32(31); break;
5289 case 'w': cbUnit = 2; break;
5290 case 'd': cbUnit = 4; break;
5291 case 'q': cbUnit = 8; break;
5292 default:
5293 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "chType=%c\n", chType);
5294 }
5295 uint8_t abBytes[RT_SIZEOFMEMB(DBGC, abSearch)];
5296 uint32_t cbBytes = sizeof(abBytes);
5297 int rc = dbgcVarsToBytes(pCmdHlp, abBytes, &cbBytes, cbUnit, paPatArgs, cPatArgs);
5298 if (RT_FAILURE(rc))
5299 return VERR_DBGC_COMMAND_FAILED;
5300
5301 /*
5302 * Make DBGF address and fix the range.
5303 */
5304 DBGFADDRESS Address;
5305 rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pAddress, &Address);
5306 if (RT_FAILURE(rc))
5307 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", pAddress);
5308
5309 RTGCUINTPTR cbRange;
5310 switch (pAddress->enmRangeType)
5311 {
5312 case DBGCVAR_RANGE_BYTES:
5313 cbRange = pAddress->u64Range;
5314 if (cbRange != pAddress->u64Range)
5315 cbRange = ~(RTGCUINTPTR)0;
5316 break;
5317
5318 case DBGCVAR_RANGE_ELEMENTS:
5319 cbRange = (RTGCUINTPTR)(pAddress->u64Range * cbUnit);
5320 if ( cbRange != pAddress->u64Range * cbUnit
5321 || cbRange < pAddress->u64Range)
5322 cbRange = ~(RTGCUINTPTR)0;
5323 break;
5324
5325 default:
5326 cbRange = ~(RTGCUINTPTR)0;
5327 break;
5328 }
5329 if (Address.FlatPtr + cbRange < Address.FlatPtr)
5330 cbRange = ~(RTGCUINTPTR)0 - Address.FlatPtr + !!Address.FlatPtr;
5331
5332 /*
5333 * Ok, do it.
5334 */
5335 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, abBytes, cbBytes, cbUnit, cMaxHits, pResult);
5336}
5337
5338
5339/**
5340 * @callback_method_impl{FNDBGCCMD, The 's' command.}
5341 */
5342static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5343{
5344 RT_NOREF2(pCmd, paArgs);
5345
5346 /* check that the parser did what it's supposed to do. */
5347 //if ( cArgs <= 2
5348 // && paArgs[0].enmType != DBGCVAR_TYPE_STRING)
5349 // return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
5350
5351 /*
5352 * Repeat previous search?
5353 */
5354 if (cArgs == 0)
5355 return dbgcCmdWorkerSearchMemResume(pCmdHlp, pUVM, NULL);
5356
5357 /*
5358 * Parse arguments.
5359 */
5360
5361 return -1;
5362}
5363
5364
5365/**
5366 * @callback_method_impl{FNDBGCCMD, The 's?' command.}
5367 */
5368static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5369{
5370 /* check that the parser did what it's supposed to do. */
5371 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2 && DBGCVAR_ISGCPOINTER(paArgs[0].enmType));
5372 return dbgcCmdWorkerSearchMem(pCmdHlp, pUVM, &paArgs[0], 25, pCmd->pszCmd[1], paArgs + 1, cArgs - 1, NULL);
5373}
5374
5375
5376/**
5377 * Matching function for interrupts event names.
5378 *
5379 * This parses the interrupt number and length.
5380 *
5381 * @returns True if match, false if not.
5382 * @param pPattern The user specified pattern to match.
5383 * @param pszEvtName The event name.
5384 * @param pCmdHlp Command helpers for warning about malformed stuff.
5385 * @param piFirst Where to return start interrupt number on success.
5386 * @param pcInts Where to return the number of interrupts on success.
5387 */
5388static bool dbgcEventIsMatchingInt(PCDBGCVAR pPattern, const char *pszEvtName, PDBGCCMDHLP pCmdHlp,
5389 uint8_t *piFirst, uint16_t *pcInts)
5390{
5391 /*
5392 * Ignore trailing hex digits when comparing with the event base name.
5393 */
5394 const char *pszPattern = pPattern->u.pszString;
5395 const char *pszEnd = RTStrEnd(pszPattern, RTSTR_MAX);
5396 while ( (uintptr_t)pszEnd > (uintptr_t)pszPattern
5397 && RT_C_IS_XDIGIT(pszEnd[-1]))
5398 pszEnd -= 1;
5399 if (RTStrSimplePatternNMatch(pszPattern, pszEnd - pszPattern, pszEvtName, RTSTR_MAX))
5400 {
5401 /*
5402 * Parse the index and length.
5403 */
5404 if (!*pszEnd)
5405 *piFirst = 0;
5406 else
5407 {
5408 int rc = RTStrToUInt8Full(pszEnd, 16, piFirst);
5409 if (rc != VINF_SUCCESS)
5410 {
5411 if (RT_FAILURE(rc))
5412 *piFirst = 0;
5413 DBGCCmdHlpPrintf(pCmdHlp, "Warning: %Rrc parsing '%s' - interpreting it as %#x\n", rc, pszEnd, *piFirst);
5414 }
5415 }
5416
5417 if (pPattern->enmRangeType == DBGCVAR_RANGE_NONE)
5418 *pcInts = 1;
5419 else
5420 *pcInts = RT_MAX(RT_MIN((uint16_t)pPattern->u64Range, 256 - *piFirst), 1);
5421 return true;
5422 }
5423 return false;
5424}
5425
5426
5427/**
5428 * Updates a DBGC event config.
5429 *
5430 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
5431 * @param ppEvtCfg The event configuration entry to update.
5432 * @param pszCmd The new command. Leave command alone if NULL.
5433 * @param enmEvtState The new event state.
5434 * @param fChangeCmdOnly Whether to only update the command.
5435 */
5436static int dbgcEventUpdate(PDBGCEVTCFG *ppEvtCfg, const char *pszCmd, DBGCEVTSTATE enmEvtState, bool fChangeCmdOnly)
5437{
5438 PDBGCEVTCFG pEvtCfg = *ppEvtCfg;
5439
5440 /*
5441 * If we've got a command string, update the command too.
5442 */
5443 if (pszCmd)
5444 {
5445 size_t cchCmd = strlen(pszCmd);
5446 if ( !cchCmd
5447 && ( !fChangeCmdOnly
5448 ? enmEvtState == kDbgcEvtState_Disabled
5449 : !pEvtCfg || pEvtCfg->enmState == kDbgcEvtState_Disabled))
5450 {
5451 /* NULL entry is fine if no command and disabled. */
5452 RTMemFree(pEvtCfg);
5453 *ppEvtCfg = NULL;
5454 }
5455 else
5456 {
5457 if (!pEvtCfg || pEvtCfg->cchCmd < cchCmd)
5458 {
5459 RTMemFree(pEvtCfg);
5460 *ppEvtCfg = pEvtCfg = (PDBGCEVTCFG)RTMemAlloc(RT_UOFFSETOF_DYN(DBGCEVTCFG, szCmd[cchCmd + 1]));
5461 if (!pEvtCfg)
5462 return VERR_NO_MEMORY;
5463 }
5464 pEvtCfg->enmState = enmEvtState;
5465 pEvtCfg->cchCmd = cchCmd;
5466 memcpy(pEvtCfg->szCmd, pszCmd, cchCmd + 1);
5467 }
5468 }
5469 /*
5470 * Update existing or enable new. If NULL and not enabled, we can keep it that way.
5471 */
5472 else if (pEvtCfg || enmEvtState != kDbgcEvtState_Disabled)
5473 {
5474 if (!pEvtCfg)
5475 {
5476 *ppEvtCfg = pEvtCfg = (PDBGCEVTCFG)RTMemAlloc(sizeof(DBGCEVTCFG));
5477 if (!pEvtCfg)
5478 return VERR_NO_MEMORY;
5479 pEvtCfg->cchCmd = 0;
5480 pEvtCfg->szCmd[0] = '\0';
5481 }
5482 pEvtCfg->enmState = enmEvtState;
5483 }
5484
5485 return VINF_SUCCESS;
5486}
5487
5488
5489/**
5490 * Record one settings change for a plain event.
5491 *
5492 * @returns The new @a cIntCfgs value.
5493 * @param paEventCfgs The event setttings array. Must have DBGFEVENT_END
5494 * entries.
5495 * @param cEventCfgs The current number of entries in @a paEventCfgs.
5496 * @param enmType The event to change the settings for.
5497 * @param enmEvtState The new event state.
5498 * @param iSxEvt Index into the g_aDbgcSxEvents array.
5499 *
5500 * @remarks We use abUnused[0] for the enmEvtState, while abUnused[1] and
5501 * abUnused[2] are used for iSxEvt.
5502 */
5503static uint32_t dbgcEventAddPlainConfig(PDBGFEVENTCONFIG paEventCfgs, uint32_t cEventCfgs, DBGFEVENTTYPE enmType,
5504 DBGCEVTSTATE enmEvtState, uint16_t iSxEvt)
5505{
5506 uint32_t iCfg;
5507 for (iCfg = 0; iCfg < cEventCfgs; iCfg++)
5508 if (paEventCfgs[iCfg].enmType == enmType)
5509 break;
5510 if (iCfg == cEventCfgs)
5511 {
5512 Assert(cEventCfgs < DBGFEVENT_END);
5513 paEventCfgs[iCfg].enmType = enmType;
5514 cEventCfgs++;
5515 }
5516 paEventCfgs[iCfg].fEnabled = enmEvtState > kDbgcEvtState_Disabled;
5517 paEventCfgs[iCfg].abUnused[0] = enmEvtState;
5518 paEventCfgs[iCfg].abUnused[1] = (uint8_t)iSxEvt;
5519 paEventCfgs[iCfg].abUnused[2] = (uint8_t)(iSxEvt >> 8);
5520 return cEventCfgs;
5521}
5522
5523
5524/**
5525 * Record one or more interrupt event config changes.
5526 *
5527 * @returns The new @a cIntCfgs value.
5528 * @param paIntCfgs Interrupt confiruation array. Must have 256 entries.
5529 * @param cIntCfgs The current number of entries in @a paIntCfgs.
5530 * @param iInt The interrupt number to start with.
5531 * @param cInts The number of interrupts to change.
5532 * @param pszName The settings name (hwint/swint).
5533 * @param enmEvtState The new event state.
5534 * @param bIntOp The new DBGF interrupt state.
5535 */
5536static uint32_t dbgcEventAddIntConfig(PDBGFINTERRUPTCONFIG paIntCfgs, uint32_t cIntCfgs, uint8_t iInt, uint16_t cInts,
5537 const char *pszName, DBGCEVTSTATE enmEvtState, uint8_t bIntOp)
5538{
5539 bool const fHwInt = *pszName == 'h';
5540
5541 bIntOp |= (uint8_t)enmEvtState << 4;
5542 uint8_t const bSoftState = !fHwInt ? bIntOp : DBGFINTERRUPTSTATE_DONT_TOUCH;
5543 uint8_t const bHardState = fHwInt ? bIntOp : DBGFINTERRUPTSTATE_DONT_TOUCH;
5544
5545 while (cInts > 0)
5546 {
5547 uint32_t iCfg;
5548 for (iCfg = 0; iCfg < cIntCfgs; iCfg++)
5549 if (paIntCfgs[iCfg].iInterrupt == iInt)
5550 break;
5551 if (iCfg == cIntCfgs)
5552 break;
5553 if (fHwInt)
5554 paIntCfgs[iCfg].enmHardState = bHardState;
5555 else
5556 paIntCfgs[iCfg].enmSoftState = bSoftState;
5557 iInt++;
5558 cInts--;
5559 }
5560
5561 while (cInts > 0)
5562 {
5563 Assert(cIntCfgs < 256);
5564 paIntCfgs[cIntCfgs].iInterrupt = iInt;
5565 paIntCfgs[cIntCfgs].enmHardState = bHardState;
5566 paIntCfgs[cIntCfgs].enmSoftState = bSoftState;
5567 cIntCfgs++;
5568 iInt++;
5569 cInts--;
5570 }
5571
5572 return cIntCfgs;
5573}
5574
5575
5576/**
5577 * Applies event settings changes to DBGC and DBGF.
5578 *
5579 * @returns VBox status code (fully bitched)
5580 * @param pCmdHlp The command helpers.
5581 * @param pUVM The user mode VM handle.
5582 * @param paIntCfgs Interrupt configuration array. We use the upper 4
5583 * bits of the settings for the DBGCEVTSTATE. This
5584 * will be cleared.
5585 * @param cIntCfgs Number of interrupt configuration changes.
5586 * @param paEventCfgs The generic event configuration array. We use the
5587 * abUnused[0] member for the DBGCEVTSTATE, and
5588 * abUnused[2:1] for the g_aDbgcSxEvents index.
5589 * @param cEventCfgs The number of generic event settings changes.
5590 * @param pszCmd The commands to associate with the changed events.
5591 * If this is NULL, don't touch the command.
5592 * @param fChangeCmdOnly Whether to only change the commands (sx-).
5593 */
5594static int dbgcEventApplyChanges(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGFINTERRUPTCONFIG paIntCfgs, uint32_t cIntCfgs,
5595 PCDBGFEVENTCONFIG paEventCfgs, uint32_t cEventCfgs, const char *pszCmd, bool fChangeCmdOnly)
5596{
5597 int rc;
5598
5599 /*
5600 * Apply changes to DBGC. This can only fail with out of memory error.
5601 */
5602 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5603 if (cIntCfgs)
5604 for (uint32_t iCfg = 0; iCfg < cIntCfgs; iCfg++)
5605 {
5606 DBGCEVTSTATE enmEvtState = (DBGCEVTSTATE)(paIntCfgs[iCfg].enmHardState >> 4);
5607 paIntCfgs[iCfg].enmHardState &= 0xf;
5608 if (paIntCfgs[iCfg].enmHardState != DBGFINTERRUPTSTATE_DONT_TOUCH)
5609 {
5610 rc = dbgcEventUpdate(&pDbgc->apHardInts[paIntCfgs[iCfg].iInterrupt], pszCmd, enmEvtState, fChangeCmdOnly);
5611 if (RT_FAILURE(rc))
5612 return rc;
5613 }
5614
5615 enmEvtState = (DBGCEVTSTATE)(paIntCfgs[iCfg].enmSoftState >> 4);
5616 paIntCfgs[iCfg].enmSoftState &= 0xf;
5617 if (paIntCfgs[iCfg].enmSoftState != DBGFINTERRUPTSTATE_DONT_TOUCH)
5618 {
5619 rc = dbgcEventUpdate(&pDbgc->apSoftInts[paIntCfgs[iCfg].iInterrupt], pszCmd, enmEvtState, fChangeCmdOnly);
5620 if (RT_FAILURE(rc))
5621 return rc;
5622 }
5623 }
5624
5625 if (cEventCfgs)
5626 {
5627 for (uint32_t iCfg = 0; iCfg < cEventCfgs; iCfg++)
5628 {
5629 Assert((unsigned)paEventCfgs[iCfg].enmType < RT_ELEMENTS(pDbgc->apEventCfgs));
5630 uint16_t iSxEvt = RT_MAKE_U16(paEventCfgs[iCfg].abUnused[1], paEventCfgs[iCfg].abUnused[2]);
5631 Assert(iSxEvt < RT_ELEMENTS(g_aDbgcSxEvents));
5632 rc = dbgcEventUpdate(&pDbgc->apEventCfgs[iSxEvt], pszCmd, (DBGCEVTSTATE)paEventCfgs[iCfg].abUnused[0], fChangeCmdOnly);
5633 if (RT_FAILURE(rc))
5634 return rc;
5635 }
5636 }
5637
5638 /*
5639 * Apply changes to DBGF.
5640 */
5641 if (!fChangeCmdOnly)
5642 {
5643 if (cIntCfgs)
5644 {
5645 rc = DBGFR3InterruptConfigEx(pUVM, paIntCfgs, cIntCfgs);
5646 if (RT_FAILURE(rc))
5647 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3InterruptConfigEx: %Rrc\n", rc);
5648 }
5649 if (cEventCfgs)
5650 {
5651 rc = DBGFR3EventConfigEx(pUVM, paEventCfgs, cEventCfgs);
5652 if (RT_FAILURE(rc))
5653 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3EventConfigEx: %Rrc\n", rc);
5654 }
5655 }
5656
5657 return VINF_SUCCESS;
5658}
5659
5660
5661/**
5662 * @callback_method_impl{FNDBGCCMD, The 'sx[eni-]' commands.}
5663 */
5664static DECLCALLBACK(int) dbgcCmdEventCtrl(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5665{
5666 /*
5667 * Figure out which command this is.
5668 */
5669 uint8_t bIntOp;
5670 DBGCEVTSTATE enmEvtState;
5671 bool fChangeCmdOnly;
5672 switch (pCmd->pszCmd[2])
5673 {
5674 case 'e': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Enabled; fChangeCmdOnly = false; break;
5675 case 'n': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Notify; fChangeCmdOnly = false; break;
5676 case '-': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Invalid; fChangeCmdOnly = true; break;
5677 case 'i': bIntOp = DBGFINTERRUPTSTATE_DISABLED; enmEvtState = kDbgcEvtState_Disabled; fChangeCmdOnly = false; break;
5678 default:
5679 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "pszCmd=%s\n", pCmd->pszCmd);
5680 }
5681
5682 /*
5683 * Command option.
5684 */
5685 unsigned iArg = 0;
5686 const char *pszCmd = NULL;
5687 if ( cArgs >= iArg + 2
5688 && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING
5689 && paArgs[iArg + 1].enmType == DBGCVAR_TYPE_STRING
5690 && strcmp(paArgs[iArg].u.pszString, "-c") == 0)
5691 {
5692 pszCmd = paArgs[iArg + 1].u.pszString;
5693 iArg += 2;
5694 }
5695 if (fChangeCmdOnly && !pszCmd)
5696 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "The 'sx-' requires the '-c cmd' arguments.\n");
5697
5698 /*
5699 * The remaining arguments are event specifiers to which the operation should be applied.
5700 */
5701 uint32_t cIntCfgs = 0;
5702 DBGFINTERRUPTCONFIG aIntCfgs[256];
5703 uint32_t cEventCfgs = 0;
5704 DBGFEVENTCONFIG aEventCfgs[DBGFEVENT_END];
5705
5706 for (; iArg < cArgs; iArg++)
5707 {
5708 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, paArgs[iArg].enmType == DBGCVAR_TYPE_STRING
5709 || paArgs[iArg].enmType == DBGCVAR_TYPE_SYMBOL);
5710 uint32_t cHits = 0;
5711 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++)
5712 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain)
5713 {
5714 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName)
5715 || ( g_aDbgcSxEvents[iEvt].pszAltNm
5716 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) )
5717 {
5718 cEventCfgs = dbgcEventAddPlainConfig(aEventCfgs, cEventCfgs, g_aDbgcSxEvents[iEvt].enmType,
5719 enmEvtState, iEvt);
5720 cHits++;
5721 }
5722 }
5723 else
5724 {
5725 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt);
5726 uint8_t iInt;
5727 uint16_t cInts;
5728 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts))
5729 {
5730 cIntCfgs = dbgcEventAddIntConfig(aIntCfgs, cIntCfgs, iInt, cInts, g_aDbgcSxEvents[iEvt].pszName,
5731 enmEvtState, bIntOp);
5732 cHits++;
5733 }
5734 }
5735 if (!cHits)
5736 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString);
5737 }
5738
5739 /*
5740 * Apply the changes.
5741 */
5742 return dbgcEventApplyChanges(pCmdHlp, pUVM, aIntCfgs, cIntCfgs, aEventCfgs, cEventCfgs, pszCmd, fChangeCmdOnly);
5743}
5744
5745
5746/**
5747 * @callback_method_impl{FNDBGCCMD, The 'sxr' commands.}
5748 */
5749static DECLCALLBACK(int) dbgcCmdEventCtrlReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5750{
5751 RT_NOREF1(pCmd);
5752 uint32_t cEventCfgs = 0;
5753 DBGFEVENTCONFIG aEventCfgs[DBGFEVENT_END];
5754 uint32_t cIntCfgs = 0;
5755 DBGFINTERRUPTCONFIG aIntCfgs[256];
5756
5757 if (cArgs == 0)
5758 {
5759 /*
5760 * All events.
5761 */
5762 for (uint32_t iInt = 0; iInt < 256; iInt++)
5763 {
5764 aIntCfgs[iInt].iInterrupt = iInt;
5765 aIntCfgs[iInt].enmHardState = DBGFINTERRUPTSTATE_DONT_TOUCH;
5766 aIntCfgs[iInt].enmSoftState = DBGFINTERRUPTSTATE_DONT_TOUCH;
5767 }
5768 cIntCfgs = 256;
5769
5770 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++)
5771 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain)
5772 {
5773 aEventCfgs[cEventCfgs].enmType = g_aDbgcSxEvents[iEvt].enmType;
5774 aEventCfgs[cEventCfgs].fEnabled = g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled;
5775 aEventCfgs[cEventCfgs].abUnused[0] = g_aDbgcSxEvents[iEvt].enmDefault;
5776 aEventCfgs[cEventCfgs].abUnused[1] = (uint8_t)iEvt;
5777 aEventCfgs[cEventCfgs].abUnused[2] = (uint8_t)(iEvt >> 8);
5778 cEventCfgs++;
5779 }
5780 else
5781 {
5782 uint8_t const bState = ( g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled
5783 ? DBGFINTERRUPTSTATE_ENABLED : DBGFINTERRUPTSTATE_DISABLED)
5784 | ((uint8_t)g_aDbgcSxEvents[iEvt].enmDefault << 4);
5785 if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0)
5786 for (uint32_t iInt = 0; iInt < 256; iInt++)
5787 aIntCfgs[iInt].enmHardState = bState;
5788 else
5789 for (uint32_t iInt = 0; iInt < 256; iInt++)
5790 aIntCfgs[iInt].enmSoftState = bState;
5791 }
5792 }
5793 else
5794 {
5795 /*
5796 * Selected events.
5797 */
5798 for (uint32_t iArg = 0; iArg < cArgs; iArg++)
5799 {
5800 unsigned cHits = 0;
5801 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++)
5802 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain)
5803 {
5804 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName)
5805 || ( g_aDbgcSxEvents[iEvt].pszAltNm
5806 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) )
5807 {
5808 cEventCfgs = dbgcEventAddPlainConfig(aEventCfgs, cEventCfgs, g_aDbgcSxEvents[iEvt].enmType,
5809 g_aDbgcSxEvents[iEvt].enmDefault, iEvt);
5810 cHits++;
5811 }
5812 }
5813 else
5814 {
5815 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt);
5816 uint8_t iInt;
5817 uint16_t cInts;
5818 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts))
5819 {
5820 cIntCfgs = dbgcEventAddIntConfig(aIntCfgs, cIntCfgs, iInt, cInts, g_aDbgcSxEvents[iEvt].pszName,
5821 g_aDbgcSxEvents[iEvt].enmDefault,
5822 g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled
5823 ? DBGFINTERRUPTSTATE_ENABLED : DBGFINTERRUPTSTATE_DISABLED);
5824 cHits++;
5825 }
5826 }
5827 if (!cHits)
5828 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString);
5829 }
5830 }
5831
5832 /*
5833 * Apply the reset changes.
5834 */
5835 return dbgcEventApplyChanges(pCmdHlp, pUVM, aIntCfgs, cIntCfgs, aEventCfgs, cEventCfgs, "", false);
5836}
5837
5838
5839/**
5840 * Used during DBGC initialization to configure events with defaults.
5841 *
5842 * @returns VBox status code.
5843 * @param pDbgc The DBGC instance.
5844 */
5845void dbgcEventInit(PDBGC pDbgc)
5846{
5847 if (pDbgc->pUVM)
5848 dbgcCmdEventCtrlReset(NULL, &pDbgc->CmdHlp, pDbgc->pUVM, NULL, 0);
5849}
5850
5851
5852/**
5853 * Used during DBGC termination to disable all events.
5854 *
5855 * @param pDbgc The DBGC instance.
5856 */
5857void dbgcEventTerm(PDBGC pDbgc)
5858{
5859/** @todo need to do more than just reset later. */
5860 if (pDbgc->pUVM && VMR3GetStateU(pDbgc->pUVM) < VMSTATE_DESTROYING)
5861 dbgcCmdEventCtrlReset(NULL, &pDbgc->CmdHlp, pDbgc->pUVM, NULL, 0);
5862}
5863
5864
5865static void dbgcEventDisplay(PDBGCCMDHLP pCmdHlp, const char *pszName, DBGCEVTSTATE enmDefault, PDBGCEVTCFG const *ppEvtCfg)
5866{
5867 RT_NOREF1(enmDefault);
5868 PDBGCEVTCFG pEvtCfg = *ppEvtCfg;
5869
5870 const char *pszState;
5871 switch (pEvtCfg ? pEvtCfg->enmState : kDbgcEvtState_Disabled)
5872 {
5873 case kDbgcEvtState_Disabled: pszState = "ignore"; break;
5874 case kDbgcEvtState_Enabled: pszState = "enabled"; break;
5875 case kDbgcEvtState_Notify: pszState = "notify"; break;
5876 default:
5877 AssertFailed();
5878 pszState = "invalid";
5879 break;
5880 }
5881
5882 if (pEvtCfg && pEvtCfg->cchCmd > 0)
5883 DBGCCmdHlpPrintf(pCmdHlp, "%-22s %-7s \"%s\"\n", pszName, pszState, pEvtCfg->szCmd);
5884 else
5885 DBGCCmdHlpPrintf(pCmdHlp, "%-22s %s\n", pszName, pszState);
5886}
5887
5888
5889static void dbgcEventDisplayRange(PDBGCCMDHLP pCmdHlp, const char *pszBaseNm, DBGCEVTSTATE enmDefault,
5890 PDBGCEVTCFG const *papEvtCfgs, unsigned iCfg, unsigned cCfgs)
5891{
5892 do
5893 {
5894 PCDBGCEVTCFG pFirstCfg = papEvtCfgs[iCfg];
5895 if (pFirstCfg && pFirstCfg->enmState == kDbgcEvtState_Disabled && pFirstCfg->cchCmd == 0)
5896 pFirstCfg = NULL;
5897
5898 unsigned const iFirstCfg = iCfg;
5899 iCfg++;
5900 while (iCfg < cCfgs)
5901 {
5902 PCDBGCEVTCFG pCurCfg = papEvtCfgs[iCfg];
5903 if (pCurCfg && pCurCfg->enmState == kDbgcEvtState_Disabled && pCurCfg->cchCmd == 0)
5904 pCurCfg = NULL;
5905 if (pCurCfg != pFirstCfg)
5906 {
5907 if (!pCurCfg || !pFirstCfg)
5908 break;
5909 if (pCurCfg->enmState != pFirstCfg->enmState)
5910 break;
5911 if (pCurCfg->cchCmd != pFirstCfg->cchCmd)
5912 break;
5913 if (memcmp(pCurCfg->szCmd, pFirstCfg->szCmd, pFirstCfg->cchCmd) != 0)
5914 break;
5915 }
5916 iCfg++;
5917 }
5918
5919 char szName[16];
5920 unsigned cEntries = iCfg - iFirstCfg;
5921 if (cEntries == 1)
5922 RTStrPrintf(szName, sizeof(szName), "%s%02x", pszBaseNm, iFirstCfg);
5923 else
5924 RTStrPrintf(szName, sizeof(szName), "%s%02x L %#x", pszBaseNm, iFirstCfg, cEntries);
5925 dbgcEventDisplay(pCmdHlp, szName, enmDefault, &papEvtCfgs[iFirstCfg]);
5926
5927 cCfgs -= cEntries;
5928 } while (cCfgs > 0);
5929}
5930
5931
5932/**
5933 * @callback_method_impl{FNDBGCCMD, The 'sx' commands.}
5934 */
5935static DECLCALLBACK(int) dbgcCmdEventCtrlList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
5936{
5937 RT_NOREF2(pCmd, pUVM);
5938 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5939
5940 if (cArgs == 0)
5941 {
5942 /*
5943 * All events.
5944 */
5945 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++)
5946 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain)
5947 dbgcEventDisplay(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5948 &pDbgc->apEventCfgs[iEvt]);
5949 else if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0)
5950 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5951 pDbgc->apHardInts, 0, 256);
5952 else
5953 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5954 pDbgc->apSoftInts, 0, 256);
5955 }
5956 else
5957 {
5958 /*
5959 * Selected events.
5960 */
5961 for (uint32_t iArg = 0; iArg < cArgs; iArg++)
5962 {
5963 unsigned cHits = 0;
5964 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++)
5965 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain)
5966 {
5967 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName)
5968 || ( g_aDbgcSxEvents[iEvt].pszAltNm
5969 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) )
5970 {
5971 dbgcEventDisplay(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5972 &pDbgc->apEventCfgs[iEvt]);
5973 cHits++;
5974 }
5975 }
5976 else
5977 {
5978 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt);
5979 uint8_t iInt;
5980 uint16_t cInts;
5981 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts))
5982 {
5983 if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0)
5984 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5985 pDbgc->apHardInts, iInt, cInts);
5986 else
5987 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault,
5988 pDbgc->apSoftInts, iInt, cInts);
5989 cHits++;
5990 }
5991 }
5992 if (cHits == 0)
5993 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString);
5994 }
5995 }
5996
5997 return VINF_SUCCESS;
5998}
5999
6000
6001
6002/**
6003 * List near symbol.
6004 *
6005 * @returns VBox status code.
6006 * @param pCmdHlp Pointer to command helper functions.
6007 * @param pUVM The user mode VM handle.
6008 * @param pArg Pointer to the address or symbol to lookup.
6009 */
6010static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR pArg)
6011{
6012 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6013
6014 RTDBGSYMBOL Symbol;
6015 int rc;
6016 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)
6017 {
6018 /*
6019 * Lookup the symbol address.
6020 */
6021 rc = DBGFR3AsSymbolByName(pUVM, pDbgc->hDbgAs, pArg->u.pszString, &Symbol, NULL);
6022 if (RT_FAILURE(rc))
6023 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsSymbolByName(,,%s,)\n", pArg->u.pszString);
6024
6025 rc = DBGCCmdHlpPrintf(pCmdHlp, "%RTptr %s\n", Symbol.Value, Symbol.szName);
6026 }
6027 else
6028 {
6029 /*
6030 * Convert it to a flat GC address and lookup that address.
6031 */
6032 DBGCVAR AddrVar;
6033 rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);
6034 if (RT_FAILURE(rc))
6035 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);
6036
6037 RTINTPTR offDisp;
6038 DBGFADDRESS Addr;
6039 rc = DBGFR3AsSymbolByAddr(pUVM, pDbgc->hDbgAs, DBGFR3AddrFromFlat(pDbgc->pUVM, &Addr, AddrVar.u.GCFlat),
6040 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL | RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED,
6041 &offDisp, &Symbol, NULL);
6042 if (RT_FAILURE(rc))
6043 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsSymbolByAddr(,,%RGv,,)\n", AddrVar.u.GCFlat);
6044
6045 if (!offDisp)
6046 rc = DBGCCmdHlpPrintf(pCmdHlp, "%DV %s", &AddrVar, Symbol.szName);
6047 else if (offDisp > 0)
6048 rc = DBGCCmdHlpPrintf(pCmdHlp, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);
6049 else
6050 rc = DBGCCmdHlpPrintf(pCmdHlp, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);
6051 if (Symbol.cb > 0)
6052 rc = DBGCCmdHlpPrintf(pCmdHlp, " (LB %RGv)\n", Symbol.cb);
6053 else
6054 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
6055 }
6056
6057 return rc;
6058}
6059
6060
6061/**
6062 * @callback_method_impl{FNDBGCCMD, The 'ln' (listnear) command.}
6063 */
6064static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
6065{
6066 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6067 if (!cArgs)
6068 {
6069 /*
6070 * Current cs:eip symbol.
6071 */
6072 DBGCVAR AddrVar;
6073 const char *pszFmtExpr = pDbgc->fRegCtxGuest ? "%%(cs:eip)" : "%%(.cs:.eip)";
6074 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, pszFmtExpr);
6075 if (RT_FAILURE(rc))
6076 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%s\n", pszFmtExpr + 1);
6077 return dbgcDoListNear(pCmdHlp, pUVM, &AddrVar);
6078 }
6079
6080/** @todo Fix the darn parser, it's resolving symbols specified as arguments before we get in here. */
6081 /*
6082 * Iterate arguments.
6083 */
6084 for (unsigned iArg = 0; iArg < cArgs; iArg++)
6085 {
6086 int rc = dbgcDoListNear(pCmdHlp, pUVM, &paArgs[iArg]);
6087 if (RT_FAILURE(rc))
6088 return rc;
6089 }
6090
6091 NOREF(pCmd);
6092 return VINF_SUCCESS;
6093}
6094
6095
6096/**
6097 * Matches the module patters against a module name.
6098 *
6099 * @returns true if matching, otherwise false.
6100 * @param pszName The module name.
6101 * @param paArgs The module pattern argument list.
6102 * @param cArgs Number of arguments.
6103 */
6104static bool dbgcCmdListModuleMatch(const char *pszName, PCDBGCVAR paArgs, unsigned cArgs)
6105{
6106 for (uint32_t i = 0; i < cArgs; i++)
6107 if (RTStrSimplePatternMatch(paArgs[i].u.pszString, pszName))
6108 return true;
6109 return false;
6110}
6111
6112
6113/**
6114 * @callback_method_impl{FNDBGCCMD, The 'ln' (list near) command.}
6115 */
6116static DECLCALLBACK(int) dbgcCmdListModules(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
6117{
6118 bool const fMappings = pCmd->pszCmd[2] == 'o';
6119 bool const fVerbose = pCmd->pszCmd[strlen(pCmd->pszCmd) - 1] == 'v';
6120 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6121
6122 /*
6123 * Iterate the modules in the current address space and print info about
6124 * those matching the input.
6125 */
6126 RTDBGAS hAsCurAlias = pDbgc->hDbgAs;
6127 for (uint32_t iAs = 0;; iAs++)
6128 {
6129 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, hAsCurAlias);
6130 uint32_t cMods = RTDbgAsModuleCount(hAs);
6131 for (uint32_t iMod = 0; iMod < cMods; iMod++)
6132 {
6133 RTDBGMOD hMod = RTDbgAsModuleByIndex(hAs, iMod);
6134 if (hMod != NIL_RTDBGMOD)
6135 {
6136 bool const fDeferred = RTDbgModIsDeferred(hMod);
6137 bool const fExports = RTDbgModIsExports(hMod);
6138 uint32_t const cSegs = fDeferred ? 1 : RTDbgModSegmentCount(hMod);
6139 const char * const pszName = RTDbgModName(hMod);
6140 const char * const pszImgFile = RTDbgModImageFile(hMod);
6141 const char * const pszImgFileUsed = RTDbgModImageFileUsed(hMod);
6142 const char * const pszDbgFile = RTDbgModDebugFile(hMod);
6143 if ( cArgs == 0
6144 || dbgcCmdListModuleMatch(pszName, paArgs, cArgs))
6145 {
6146 /*
6147 * Find the mapping with the lower address, preferring a full
6148 * image mapping, for the main line.
6149 */
6150 RTDBGASMAPINFO aMappings[128];
6151 uint32_t cMappings = RT_ELEMENTS(aMappings);
6152 int rc = RTDbgAsModuleQueryMapByIndex(hAs, iMod, &aMappings[0], &cMappings, 0 /*fFlags*/);
6153 if (RT_SUCCESS(rc))
6154 {
6155 bool fFull = false;
6156 RTUINTPTR uMin = RTUINTPTR_MAX;
6157 for (uint32_t iMap = 0; iMap < cMappings; iMap++)
6158 if ( aMappings[iMap].Address < uMin
6159 && ( !fFull
6160 || aMappings[iMap].iSeg == NIL_RTDBGSEGIDX))
6161 uMin = aMappings[iMap].Address;
6162 if (!fVerbose || !pszImgFile)
6163 DBGCCmdHlpPrintf(pCmdHlp, "%RGv %04x %s%s\n", (RTGCUINTPTR)uMin, cSegs, pszName,
6164 fExports ? " (exports)" : fDeferred ? " (deferred)" : "");
6165 else
6166 DBGCCmdHlpPrintf(pCmdHlp, "%RGv %04x %-12s %s%s\n", (RTGCUINTPTR)uMin, cSegs, pszName, pszImgFile,
6167 fExports ? " (exports)" : fDeferred ? " (deferred)" : "");
6168 if (fVerbose && pszImgFileUsed)
6169 DBGCCmdHlpPrintf(pCmdHlp, " Local image: %s\n", pszImgFileUsed);
6170 if (fVerbose && pszDbgFile)
6171 DBGCCmdHlpPrintf(pCmdHlp, " Debug file: %s\n", pszDbgFile);
6172
6173 if (fMappings)
6174 {
6175 /* sort by address first - not very efficient. */
6176 for (uint32_t i = 0; i + 1 < cMappings; i++)
6177 for (uint32_t j = i + 1; j < cMappings; j++)
6178 if (aMappings[j].Address < aMappings[i].Address)
6179 {
6180 RTDBGASMAPINFO Tmp = aMappings[j];
6181 aMappings[j] = aMappings[i];
6182 aMappings[i] = Tmp;
6183 }
6184
6185 /* print */
6186 if ( cMappings == 1
6187 && aMappings[0].iSeg == NIL_RTDBGSEGIDX
6188 && !fDeferred)
6189 {
6190 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
6191 {
6192 RTDBGSEGMENT SegInfo;
6193 rc = RTDbgModSegmentByIndex(hMod, iSeg, &SegInfo);
6194 if (RT_SUCCESS(rc))
6195 {
6196 if (SegInfo.uRva != RTUINTPTR_MAX)
6197 DBGCCmdHlpPrintf(pCmdHlp, " %RGv %RGv #%02x %s\n",
6198 (RTGCUINTPTR)(aMappings[0].Address + SegInfo.uRva),
6199 (RTGCUINTPTR)SegInfo.cb, iSeg, SegInfo.szName);
6200 else
6201 DBGCCmdHlpPrintf(pCmdHlp, " %*s %RGv #%02x %s\n",
6202 sizeof(RTGCUINTPTR)*2, "noload",
6203 (RTGCUINTPTR)SegInfo.cb, iSeg, SegInfo.szName);
6204 }
6205 else
6206 DBGCCmdHlpPrintf(pCmdHlp, " Error query segment #%u: %Rrc\n", iSeg, rc);
6207 }
6208 }
6209 else
6210 {
6211 for (uint32_t iMap = 0; iMap < cMappings; iMap++)
6212 if (aMappings[iMap].iSeg == NIL_RTDBGSEGIDX)
6213 DBGCCmdHlpPrintf(pCmdHlp, " %RGv %RGv <everything>\n",
6214 (RTGCUINTPTR)aMappings[iMap].Address,
6215 (RTGCUINTPTR)RTDbgModImageSize(hMod));
6216 else if (!fDeferred)
6217 {
6218 RTDBGSEGMENT SegInfo;
6219 rc = RTDbgModSegmentByIndex(hMod, aMappings[iMap].iSeg, &SegInfo);
6220 if (RT_FAILURE(rc))
6221 {
6222 RT_ZERO(SegInfo);
6223 strcpy(SegInfo.szName, "error");
6224 }
6225 DBGCCmdHlpPrintf(pCmdHlp, " %RGv %RGv #%02x %s\n",
6226 (RTGCUINTPTR)aMappings[iMap].Address,
6227 (RTGCUINTPTR)SegInfo.cb,
6228 aMappings[iMap].iSeg, SegInfo.szName);
6229 }
6230 else
6231 DBGCCmdHlpPrintf(pCmdHlp, " %RGv #%02x\n",
6232 (RTGCUINTPTR)aMappings[iMap].Address, aMappings[iMap].iSeg);
6233 }
6234 }
6235 }
6236 else
6237 DBGCCmdHlpPrintf(pCmdHlp, "%.*s %04x %s (rc=%Rrc)\n",
6238 sizeof(RTGCPTR) * 2, "???????????", cSegs, pszName, rc);
6239 /** @todo missing address space API for enumerating the mappings. */
6240 }
6241 RTDbgModRelease(hMod);
6242 }
6243 }
6244 RTDbgAsRelease(hAs);
6245
6246 /* For DBGF_AS_RC_AND_GC_GLOBAL we're required to do more work. */
6247 if (hAsCurAlias != DBGF_AS_RC_AND_GC_GLOBAL)
6248 break;
6249 AssertBreak(iAs == 0);
6250 hAsCurAlias = DBGF_AS_GLOBAL;
6251 }
6252
6253 NOREF(pCmd);
6254 return VINF_SUCCESS;
6255}
6256
6257
6258
6259/**
6260 * @callback_method_impl{FNDBGCFUNC, Reads a unsigned 8-bit value.}
6261 */
6262static DECLCALLBACK(int) dbgcFuncReadU8(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6263 PDBGCVAR pResult)
6264{
6265 RT_NOREF1(pUVM);
6266 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6267 AssertReturn(DBGCVAR_ISPOINTER(paArgs[0].enmType), VERR_DBGC_PARSE_BUG);
6268 AssertReturn(paArgs[0].enmRangeType == DBGCVAR_RANGE_NONE, VERR_DBGC_PARSE_BUG);
6269
6270 uint8_t b;
6271 int rc = DBGCCmdHlpMemRead(pCmdHlp, &b, sizeof(b), &paArgs[0], NULL);
6272 if (RT_FAILURE(rc))
6273 return rc;
6274 DBGCVAR_INIT_NUMBER(pResult, b);
6275
6276 NOREF(pFunc);
6277 return VINF_SUCCESS;
6278}
6279
6280
6281/**
6282 * @callback_method_impl{FNDBGCFUNC, Reads a unsigned 16-bit value.}
6283 */
6284static DECLCALLBACK(int) dbgcFuncReadU16(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6285 PDBGCVAR pResult)
6286{
6287 RT_NOREF1(pUVM);
6288 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6289 AssertReturn(DBGCVAR_ISPOINTER(paArgs[0].enmType), VERR_DBGC_PARSE_BUG);
6290 AssertReturn(paArgs[0].enmRangeType == DBGCVAR_RANGE_NONE, VERR_DBGC_PARSE_BUG);
6291
6292 uint16_t u16;
6293 int rc = DBGCCmdHlpMemRead(pCmdHlp, &u16, sizeof(u16), &paArgs[0], NULL);
6294 if (RT_FAILURE(rc))
6295 return rc;
6296 DBGCVAR_INIT_NUMBER(pResult, u16);
6297
6298 NOREF(pFunc);
6299 return VINF_SUCCESS;
6300}
6301
6302
6303/**
6304 * @callback_method_impl{FNDBGCFUNC, Reads a unsigned 32-bit value.}
6305 */
6306static DECLCALLBACK(int) dbgcFuncReadU32(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6307 PDBGCVAR pResult)
6308{
6309 RT_NOREF1(pUVM);
6310 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6311 AssertReturn(DBGCVAR_ISPOINTER(paArgs[0].enmType), VERR_DBGC_PARSE_BUG);
6312 AssertReturn(paArgs[0].enmRangeType == DBGCVAR_RANGE_NONE, VERR_DBGC_PARSE_BUG);
6313
6314 uint32_t u32;
6315 int rc = DBGCCmdHlpMemRead(pCmdHlp, &u32, sizeof(u32), &paArgs[0], NULL);
6316 if (RT_FAILURE(rc))
6317 return rc;
6318 DBGCVAR_INIT_NUMBER(pResult, u32);
6319
6320 NOREF(pFunc);
6321 return VINF_SUCCESS;
6322}
6323
6324
6325/**
6326 * @callback_method_impl{FNDBGCFUNC, Reads a unsigned 64-bit value.}
6327 */
6328static DECLCALLBACK(int) dbgcFuncReadU64(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6329 PDBGCVAR pResult)
6330{
6331 RT_NOREF1(pUVM);
6332 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6333 AssertReturn(DBGCVAR_ISPOINTER(paArgs[0].enmType), VERR_DBGC_PARSE_BUG);
6334 AssertReturn(paArgs[0].enmRangeType == DBGCVAR_RANGE_NONE, VERR_DBGC_PARSE_BUG);
6335
6336 uint64_t u64;
6337 int rc = DBGCCmdHlpMemRead(pCmdHlp, &u64, sizeof(u64), &paArgs[0], NULL);
6338 if (RT_FAILURE(rc))
6339 return rc;
6340 DBGCVAR_INIT_NUMBER(pResult, u64);
6341
6342 NOREF(pFunc);
6343 return VINF_SUCCESS;
6344}
6345
6346
6347/**
6348 * @callback_method_impl{FNDBGCFUNC, Reads a unsigned pointer-sized value.}
6349 */
6350static DECLCALLBACK(int) dbgcFuncReadPtr(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6351 PDBGCVAR pResult)
6352{
6353 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6354 AssertReturn(DBGCVAR_ISPOINTER(paArgs[0].enmType), VERR_DBGC_PARSE_BUG);
6355 AssertReturn(paArgs[0].enmRangeType == DBGCVAR_RANGE_NONE, VERR_DBGC_PARSE_BUG);
6356
6357 CPUMMODE enmMode = DBGCCmdHlpGetCpuMode(pCmdHlp);
6358 if (enmMode == CPUMMODE_LONG)
6359 return dbgcFuncReadU64(pFunc, pCmdHlp, pUVM, paArgs, cArgs, pResult);
6360 return dbgcFuncReadU32(pFunc, pCmdHlp, pUVM, paArgs, cArgs, pResult);
6361}
6362
6363
6364/**
6365 * @callback_method_impl{FNDBGCFUNC, The hi(value) function implementation.}
6366 */
6367static DECLCALLBACK(int) dbgcFuncHi(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6368 PDBGCVAR pResult)
6369{
6370 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6371
6372 uint16_t uHi;
6373 switch (paArgs[0].enmType)
6374 {
6375 case DBGCVAR_TYPE_GC_FLAT: uHi = (uint16_t)(paArgs[0].u.GCFlat >> 16); break;
6376 case DBGCVAR_TYPE_GC_FAR: uHi = (uint16_t)paArgs[0].u.GCFar.sel; break;
6377 case DBGCVAR_TYPE_GC_PHYS: uHi = (uint16_t)(paArgs[0].u.GCPhys >> 16); break;
6378 case DBGCVAR_TYPE_HC_FLAT: uHi = (uint16_t)((uintptr_t)paArgs[0].u.pvHCFlat >> 16); break;
6379 case DBGCVAR_TYPE_HC_PHYS: uHi = (uint16_t)(paArgs[0].u.HCPhys >> 16); break;
6380 case DBGCVAR_TYPE_NUMBER: uHi = (uint16_t)(paArgs[0].u.u64Number >> 16); break;
6381 default:
6382 AssertFailedReturn(VERR_DBGC_PARSE_BUG);
6383 }
6384 DBGCVAR_INIT_NUMBER(pResult, uHi);
6385 DBGCVAR_SET_RANGE(pResult, paArgs[0].enmRangeType, paArgs[0].u64Range);
6386
6387 NOREF(pFunc); NOREF(pCmdHlp); NOREF(pUVM);
6388 return VINF_SUCCESS;
6389}
6390
6391
6392/**
6393 * @callback_method_impl{FNDBGCFUNC, The low(value) function implementation.}
6394 */
6395static DECLCALLBACK(int) dbgcFuncLow(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6396 PDBGCVAR pResult)
6397{
6398 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6399
6400 uint16_t uLow;
6401 switch (paArgs[0].enmType)
6402 {
6403 case DBGCVAR_TYPE_GC_FLAT: uLow = (uint16_t)paArgs[0].u.GCFlat; break;
6404 case DBGCVAR_TYPE_GC_FAR: uLow = (uint16_t)paArgs[0].u.GCFar.off; break;
6405 case DBGCVAR_TYPE_GC_PHYS: uLow = (uint16_t)paArgs[0].u.GCPhys; break;
6406 case DBGCVAR_TYPE_HC_FLAT: uLow = (uint16_t)(uintptr_t)paArgs[0].u.pvHCFlat; break;
6407 case DBGCVAR_TYPE_HC_PHYS: uLow = (uint16_t)paArgs[0].u.HCPhys; break;
6408 case DBGCVAR_TYPE_NUMBER: uLow = (uint16_t)paArgs[0].u.u64Number; break;
6409 default:
6410 AssertFailedReturn(VERR_DBGC_PARSE_BUG);
6411 }
6412 DBGCVAR_INIT_NUMBER(pResult, uLow);
6413 DBGCVAR_SET_RANGE(pResult, paArgs[0].enmRangeType, paArgs[0].u64Range);
6414
6415 NOREF(pFunc); NOREF(pCmdHlp); NOREF(pUVM);
6416 return VINF_SUCCESS;
6417}
6418
6419
6420/**
6421 * @callback_method_impl{FNDBGCFUNC,The low(value) function implementation.}
6422 */
6423static DECLCALLBACK(int) dbgcFuncNot(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
6424 PDBGCVAR pResult)
6425{
6426 AssertReturn(cArgs == 1, VERR_DBGC_PARSE_BUG);
6427 NOREF(pFunc); NOREF(pCmdHlp); NOREF(pUVM);
6428 return DBGCCmdHlpEval(pCmdHlp, pResult, "!(%Dv)", &paArgs[0]);
6429}
6430
6431
6432/** Generic pointer argument wo/ range. */
6433static const DBGCVARDESC g_aArgPointerWoRange[] =
6434{
6435 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
6436 { 1, 1, DBGCVAR_CAT_POINTER_NO_RANGE, 0, "value", "Address or number." },
6437};
6438
6439/** Generic pointer or number argument. */
6440static const DBGCVARDESC g_aArgPointerNumber[] =
6441{
6442 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
6443 { 1, 1, DBGCVAR_CAT_POINTER_NUMBER, 0, "value", "Address or number." },
6444};
6445
6446
6447
6448/** Function descriptors for the CodeView / WinDbg emulation.
6449 * The emulation isn't attempting to be identical, only somewhat similar.
6450 */
6451const DBGCFUNC g_aFuncsCodeView[] =
6452{
6453 { "by", 1, 1, &g_aArgPointerWoRange[0], RT_ELEMENTS(g_aArgPointerWoRange), 0, dbgcFuncReadU8, "address", "Reads a byte at the given address." },
6454 { "dwo", 1, 1, &g_aArgPointerWoRange[0], RT_ELEMENTS(g_aArgPointerWoRange), 0, dbgcFuncReadU32, "address", "Reads a 32-bit value at the given address." },
6455 { "hi", 1, 1, &g_aArgPointerNumber[0], RT_ELEMENTS(g_aArgPointerNumber), 0, dbgcFuncHi, "value", "Returns the high 16-bit bits of a value." },
6456 { "low", 1, 1, &g_aArgPointerNumber[0], RT_ELEMENTS(g_aArgPointerNumber), 0, dbgcFuncLow, "value", "Returns the low 16-bit bits of a value." },
6457 { "not", 1, 1, &g_aArgPointerNumber[0], RT_ELEMENTS(g_aArgPointerNumber), 0, dbgcFuncNot, "address", "Boolean NOT." },
6458 { "poi", 1, 1, &g_aArgPointerWoRange[0], RT_ELEMENTS(g_aArgPointerWoRange), 0, dbgcFuncReadPtr, "address", "Reads a pointer sized (CS) value at the given address." },
6459 { "qwo", 1, 1, &g_aArgPointerWoRange[0], RT_ELEMENTS(g_aArgPointerWoRange), 0, dbgcFuncReadU64, "address", "Reads a 32-bit value at the given address." },
6460 { "wo", 1, 1, &g_aArgPointerWoRange[0], RT_ELEMENTS(g_aArgPointerWoRange), 0, dbgcFuncReadU16, "address", "Reads a 16-bit value at the given address." },
6461};
6462
6463/** The number of functions in the CodeView/WinDbg emulation. */
6464const uint32_t g_cFuncsCodeView = RT_ELEMENTS(g_aFuncsCodeView);
6465
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette