VirtualBox

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

Last change on this file since 102468 was 99900, checked in by vboxsync, 19 months ago

VMM/EM: Added .iemrecompiled debugger command. bugref:10369

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