VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/EMR3Dbg.cpp@ 107044

Last change on this file since 107044 was 106895, checked in by vboxsync, 3 weeks ago

VMM/EM: Build fix for when the debugger is disabled. VBP-1447

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/* $Id: EMR3Dbg.cpp 106895 2024-11-08 15:54:03Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor / Manager, Debugger Related Bits.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_EM
33#include <VBox/vmm/em.h>
34#include <VBox/vmm/hm.h>
35#include <VBox/vmm/iem.h>
36#include <VBox/vmm/nem.h>
37#include <VBox/dbg.h>
38#include "EMInternal.h"
39#include <VBox/vmm/vm.h>
40#include <iprt/string.h>
41#include <iprt/ctype.h>
42
43
44#ifdef VBOX_WITH_DEBUGGER
45
46/**
47 * Common worker for the '.alliem' and '.iemrecompiled' commands.
48 */
49static int emR3DbgCmdSetPolicyCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs,
50 EMEXECPOLICY enmPolicy, const char *pszPolicy)
51{
52 int rc;
53 bool f;
54
55 if (cArgs == 0)
56 {
57 rc = EMR3QueryExecutionPolicy(pUVM, enmPolicy, &f);
58 if (RT_FAILURE(rc))
59 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "EMR3QueryExecutionPolicy(,%s,", pszPolicy);
60 DBGCCmdHlpPrintf(pCmdHlp, f ? "%s: enabled\n" : "%s: disabled\n", pszPolicy);
61 }
62 else
63 {
64 rc = DBGCCmdHlpVarToBool(pCmdHlp, &paArgs[0], &f);
65 if (RT_FAILURE(rc))
66 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToBool");
67 rc = EMR3SetExecutionPolicy(pUVM, enmPolicy, f);
68 if (RT_FAILURE(rc))
69 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "EMR3SetExecutionPolicy(,%s,%RTbool)", pszPolicy, f);
70 }
71 return VINF_SUCCESS;
72}
73
74
75/** @callback_method_impl{FNDBGCCMD,
76 * Implements the '.alliem' command. }
77 */
78static DECLCALLBACK(int) emR3DbgCmdAllIem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
79{
80 return emR3DbgCmdSetPolicyCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, EMEXECPOLICY_IEM_ALL, "EMEXECPOLICY_IEM_ALL");
81}
82
83
84/** @callback_method_impl{FNDBGCCMD,
85 * Implements the '.iemrecompiled' command. }
86 */
87static DECLCALLBACK(int) emR3DbgCmdIemRecompiled(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
88{
89 return emR3DbgCmdSetPolicyCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, EMEXECPOLICY_IEM_RECOMPILED, "EMEXECPOLICY_IEM_RECOMPILED");
90}
91
92
93/** Describes a optional boolean argument. */
94static DBGCVARDESC const g_BoolArg = { 0, 1, DBGCVAR_CAT_ANY, 0, "boolean", "Boolean value." };
95
96/** Commands. */
97static DBGCCMD const g_aCmds[] =
98{
99 {
100 "alliem", 0, 1, &g_BoolArg, 1, 0, emR3DbgCmdAllIem, "[boolean]",
101 "Enables or disables executing ALL code in IEM, if no arguments are given it displays the current status."
102 },
103 {
104 "iemrecompiled", 0, 1, &g_BoolArg, 1, 0, emR3DbgCmdIemRecompiled, "[boolean]",
105 "Enables or disables recompiled ALL-in-IEM execution, if no arguments are given it displays the current status."
106 },
107};
108
109#endif /* VBOX_WITH_DEBUGGER */
110
111
112/**
113 * Translates EMEXITTYPE into a name.
114 *
115 * @returns Pointer to read-only name, NULL if unknown type.
116 * @param enmExitType The exit type to name.
117 */
118VMM_INT_DECL(const char *) EMR3GetExitTypeName(EMEXITTYPE enmExitType)
119{
120 switch (enmExitType)
121 {
122 case EMEXITTYPE_INVALID: return "invalid";
123 case EMEXITTYPE_IO_PORT_READ: return "I/O port read";
124 case EMEXITTYPE_IO_PORT_WRITE: return "I/O port write";
125 case EMEXITTYPE_IO_PORT_STR_READ: return "I/O port string read";
126 case EMEXITTYPE_IO_PORT_STR_WRITE: return "I/O port string write";
127 case EMEXITTYPE_MMIO: return "MMIO access";
128 case EMEXITTYPE_MMIO_READ: return "MMIO read";
129 case EMEXITTYPE_MMIO_WRITE: return "MMIO write";
130 case EMEXITTYPE_MSR_READ: return "MSR read";
131 case EMEXITTYPE_MSR_WRITE: return "MSR write";
132 case EMEXITTYPE_CPUID: return "CPUID";
133 case EMEXITTYPE_RDTSC: return "RDTSC";
134 case EMEXITTYPE_MOV_CRX: return "MOV CRx";
135 case EMEXITTYPE_MOV_DRX: return "MOV DRx";
136 case EMEXITTYPE_VMREAD: return "VMREAD";
137 case EMEXITTYPE_VMWRITE: return "VMWRITE";
138
139 /* Raw-mode only: */
140 case EMEXITTYPE_INVLPG: return "INVLPG";
141 case EMEXITTYPE_LLDT: return "LLDT";
142 case EMEXITTYPE_RDPMC: return "RDPMC";
143 case EMEXITTYPE_CLTS: return "CLTS";
144 case EMEXITTYPE_STI: return "STI";
145 case EMEXITTYPE_INT: return "INT";
146 case EMEXITTYPE_SYSCALL: return "SYSCALL";
147 case EMEXITTYPE_SYSENTER: return "SYSENTER";
148 case EMEXITTYPE_HLT: return "HLT";
149 }
150 return NULL;
151}
152
153
154/**
155 * Translates flags+type into an exit name.
156 *
157 * @returns Exit name.
158 * @param uFlagsAndType The exit to name.
159 * @param pszFallback Buffer for formatting a numeric fallback.
160 * @param cbFallback Size of fallback buffer.
161 */
162static const char *emR3HistoryGetExitName(uint32_t uFlagsAndType, char *pszFallback, size_t cbFallback)
163{
164 const char *pszExitName;
165 switch (uFlagsAndType & EMEXIT_F_KIND_MASK)
166 {
167 case EMEXIT_F_KIND_EM:
168 pszExitName = EMR3GetExitTypeName((EMEXITTYPE)(uFlagsAndType & EMEXIT_F_TYPE_MASK));
169 break;
170
171#if !defined(VBOX_VMM_TARGET_ARMV8)
172 case EMEXIT_F_KIND_VMX:
173 pszExitName = HMGetVmxExitName(uFlagsAndType & EMEXIT_F_TYPE_MASK);
174 break;
175
176 case EMEXIT_F_KIND_SVM:
177 pszExitName = HMGetSvmExitName(uFlagsAndType & EMEXIT_F_TYPE_MASK);
178 break;
179#endif
180
181 case EMEXIT_F_KIND_NEM:
182 pszExitName = NEMR3GetExitName(uFlagsAndType & EMEXIT_F_TYPE_MASK);
183 break;
184
185 case EMEXIT_F_KIND_IEM:
186 pszExitName = IEMR3GetExitName(uFlagsAndType & EMEXIT_F_TYPE_MASK);
187 break;
188
189 case EMEXIT_F_KIND_XCPT:
190#if defined(VBOX_VMM_TARGET_ARMV8)
191 pszExitName = NULL;
192 AssertReleaseFailed();
193#else
194 switch (uFlagsAndType & EMEXIT_F_TYPE_MASK)
195 {
196 case X86_XCPT_DE: return "Xcpt #DE";
197 case X86_XCPT_DB: return "Xcpt #DB";
198 case X86_XCPT_NMI: return "Xcpt #NMI";
199 case X86_XCPT_BP: return "Xcpt #BP";
200 case X86_XCPT_OF: return "Xcpt #OF";
201 case X86_XCPT_BR: return "Xcpt #BR";
202 case X86_XCPT_UD: return "Xcpt #UD";
203 case X86_XCPT_NM: return "Xcpt #NM";
204 case X86_XCPT_DF: return "Xcpt #DF";
205 case X86_XCPT_CO_SEG_OVERRUN: return "Xcpt #CO_SEG_OVERRUN";
206 case X86_XCPT_TS: return "Xcpt #TS";
207 case X86_XCPT_NP: return "Xcpt #NP";
208 case X86_XCPT_SS: return "Xcpt #SS";
209 case X86_XCPT_GP: return "Xcpt #GP";
210 case X86_XCPT_PF: return "Xcpt #PF";
211 case X86_XCPT_MF: return "Xcpt #MF";
212 case X86_XCPT_AC: return "Xcpt #AC";
213 case X86_XCPT_MC: return "Xcpt #MC";
214 case X86_XCPT_XF: return "Xcpt #XF";
215 case X86_XCPT_VE: return "Xcpt #VE";
216 case X86_XCPT_CP: return "Xcpt #CP";
217 case X86_XCPT_VC: return "Xcpt #VC";
218 case X86_XCPT_SX: return "Xcpt #SX";
219
220 case X86_XCPT_DF | EMEXIT_F_XCPT_ERRCD: return "Xcpt #DF ErrCd as PC";
221 case X86_XCPT_TS | EMEXIT_F_XCPT_ERRCD: return "Xcpt #TS ErrCd as PC";
222 case X86_XCPT_NP | EMEXIT_F_XCPT_ERRCD: return "Xcpt #NP ErrCd as PC";
223 case X86_XCPT_SS | EMEXIT_F_XCPT_ERRCD: return "Xcpt #SS ErrCd as PC";
224 case X86_XCPT_GP | EMEXIT_F_XCPT_ERRCD: return "Xcpt #GF ErrCd as PC";
225 case X86_XCPT_PF | EMEXIT_F_XCPT_ERRCD: return "Xcpt #PF ErrCd as PC";
226 case X86_XCPT_AC | EMEXIT_F_XCPT_ERRCD: return "Xcpt #AC ErrCd as PC";
227
228 case X86_XCPT_PF | EMEXIT_F_XCPT_CR2: return "Xcpt #PF CR2 as PC";
229
230 default:
231 pszExitName = NULL;
232 break;
233 }
234#endif
235 break;
236
237 default:
238 AssertFailed();
239 pszExitName = NULL;
240 break;
241 }
242 if (pszExitName)
243 return pszExitName;
244 RTStrPrintf(pszFallback, cbFallback, "%#06x", uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_TYPE_MASK));
245 return pszFallback;
246}
247
248
249/**
250 * Displays the VM-exit history.
251 *
252 * @param pVM The cross context VM structure.
253 * @param pHlp The info helper functions.
254 * @param pszArgs Arguments, ignored.
255 */
256static DECLCALLBACK(void) emR3InfoExitHistory(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
257{
258 NOREF(pszArgs);
259
260 /*
261 * Figure out target cpu and parse arguments.
262 */
263 PVMCPU pVCpu = VMMGetCpu(pVM);
264 if (!pVCpu)
265 pVCpu = pVM->apCpusR3[0];
266 bool fReverse = true;
267 uint32_t cLeft = RT_ELEMENTS(pVCpu->em.s.aExitHistory);
268
269 while (pszArgs && *pszArgs)
270 {
271 pszArgs = RTStrStripL(pszArgs);
272 if (!*pszArgs)
273 break;
274 if (RT_C_IS_DIGIT(*pszArgs))
275 {
276 /* The number to dump. */
277 uint32_t uValue = cLeft;
278 RTStrToUInt32Ex(pszArgs, (char **)&pszArgs, 0, &uValue);
279 if (uValue > 0)
280 cLeft = RT_MIN(uValue, RT_ELEMENTS(pVCpu->em.s.aExitHistory));
281 }
282 else if (RTStrCmp(pszArgs, "reverse") == 0)
283 {
284 pszArgs += 7;
285 fReverse = true;
286 }
287 else if (RTStrCmp(pszArgs, "ascending") == 0)
288 {
289 pszArgs += 9;
290 fReverse = false;
291 }
292 else if (RTStrCmp(pszArgs, "asc") == 0)
293 {
294 pszArgs += 3;
295 fReverse = false;
296 }
297 else
298 {
299 const char *pszStart = pszArgs;
300 while (*pszArgs && !RT_C_IS_SPACE(*pszArgs))
301 pszArgs++;
302 pHlp->pfnPrintf(pHlp, "Unknown option: %.*s\n", pszArgs - pszStart, pszArgs);
303 }
304 }
305
306 /*
307 * Do the job.
308 */
309 uint64_t idx = pVCpu->em.s.iNextExit;
310 if (idx == 0)
311 pHlp->pfnPrintf(pHlp, "CPU[%u]: VM-exit history: empty\n", pVCpu->idCpu);
312 else
313 {
314 /*
315 * Print header.
316 */
317 pHlp->pfnPrintf(pHlp,
318 "CPU[%u]: VM-exit history:\n"
319 " Exit No.: TSC timestamp / delta RIP (Flat/*) Exit Name\n"
320 , pVCpu->idCpu);
321
322 /*
323 * Adjust bounds if ascending order.
324 */
325 if (!fReverse)
326 {
327 if (idx > cLeft)
328 idx -= cLeft;
329 else
330 {
331 cLeft = idx;
332 idx = 0;
333 }
334 }
335
336 /*
337 * Print the entries.
338 */
339 uint64_t uPrevTimestamp = 0;
340 do
341 {
342 if (fReverse)
343 idx -= 1;
344 PCEMEXITENTRY const pEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)idx & 0xff];
345
346 /* Get the exit name. */
347 char szExitName[16];
348 const char *pszExitName = emR3HistoryGetExitName(pEntry->uFlagsAndType, szExitName, sizeof(szExitName));
349
350 /* Calc delta (negative if reverse order, positive ascending). */
351 int64_t offDelta = uPrevTimestamp != 0 && pEntry->uTimestamp != 0 ? pEntry->uTimestamp - uPrevTimestamp : 0;
352 uPrevTimestamp = pEntry->uTimestamp;
353
354 char szPC[32];
355 if (!(pEntry->uFlagsAndType & (EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)))
356 RTStrPrintf(szPC, sizeof(szPC), "%016RX64 ", pEntry->uFlatPC);
357 else if (pEntry->uFlagsAndType & EMEXIT_F_UNFLATTENED_PC)
358 RTStrPrintf(szPC, sizeof(szPC), "%016RX64*", pEntry->uFlatPC);
359 else
360 RTStrPrintf(szPC, sizeof(szPC), "%04x:%08RX32* ", (uint32_t)(pEntry->uFlatPC >> 32), (uint32_t)pEntry->uFlatPC);
361
362 /* Do the printing. */
363 if (pEntry->idxSlot == UINT32_MAX)
364 pHlp->pfnPrintf(pHlp, " %10RU64: %#018RX64/%+-9RI64 %s %#07x %s\n",
365 idx, pEntry->uTimestamp, offDelta, szPC, pEntry->uFlagsAndType, pszExitName);
366 else
367 {
368 /** @todo more on this later */
369 pHlp->pfnPrintf(pHlp, " %10RU64: %#018RX64/%+-9RI64 %s %#07x %s slot=%#x\n",
370 idx, pEntry->uTimestamp, offDelta, szPC, pEntry->uFlagsAndType, pszExitName, pEntry->idxSlot);
371 }
372
373 /* Advance if ascending. */
374 if (!fReverse)
375 idx += 1;
376 } while (--cLeft > 0 && idx > 0);
377 }
378}
379
380
381int emR3InitDbg(PVM pVM)
382{
383 /*
384 * Register info dumpers.
385 */
386 const char *pszExitsDesc = "Dumps the VM-exit history. Arguments: Number of entries; 'asc', 'ascending' or 'reverse'.";
387 int rc = DBGFR3InfoRegisterInternalEx(pVM, "exits", pszExitsDesc, emR3InfoExitHistory, DBGFINFO_FLAGS_ALL_EMTS);
388 AssertLogRelRCReturn(rc, rc);
389 rc = DBGFR3InfoRegisterInternalEx(pVM, "exithistory", pszExitsDesc, emR3InfoExitHistory, DBGFINFO_FLAGS_ALL_EMTS);
390 AssertLogRelRCReturn(rc, rc);
391
392#ifdef VBOX_WITH_DEBUGGER
393 /*
394 * Register debugger commands.
395 */
396 rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
397 AssertLogRelRCReturn(rc, rc);
398#endif
399
400 return VINF_SUCCESS;
401}
402
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