VirtualBox

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

Last change on this file since 72557 was 72557, checked in by vboxsync, 7 years ago

EM,NEM,HM: Started on generic exit history, only hooked up to NEM/win. bugref:9044 [adjustments]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1/* $Id: EMR3Dbg.cpp 72557 2018-06-14 21:32:49Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor / Manager, Debugger Related Bits.
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_EM
23#include <VBox/vmm/em.h>
24#include <VBox/vmm/hm.h>
25#include <VBox/vmm/nem.h>
26#include <VBox/dbg.h>
27#include "EMInternal.h"
28#include <VBox/vmm/vm.h>
29#include <iprt/string.h>
30#include <iprt/ctype.h>
31
32
33/** @callback_method_impl{FNDBGCCMD,
34 * Implements the '.alliem' command. }
35 */
36static DECLCALLBACK(int) enmR3DbgCmdAllIem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
37{
38 int rc;
39 bool f;
40
41 if (cArgs == 0)
42 {
43 rc = EMR3QueryExecutionPolicy(pUVM, EMEXECPOLICY_IEM_ALL, &f);
44 if (RT_FAILURE(rc))
45 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "EMR3QueryExecutionPolicy(,EMEXECPOLICY_IEM_ALL,");
46 DBGCCmdHlpPrintf(pCmdHlp, f ? "alliem: enabled\n" : "alliem: disabled\n");
47 }
48 else
49 {
50 rc = DBGCCmdHlpVarToBool(pCmdHlp, &paArgs[0], &f);
51 if (RT_FAILURE(rc))
52 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToBool");
53 rc = EMR3SetExecutionPolicy(pUVM, EMEXECPOLICY_IEM_ALL, f);
54 if (RT_FAILURE(rc))
55 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "EMR3SetExecutionPolicy(,EMEXECPOLICY_IEM_ALL,%RTbool)", f);
56 }
57 return VINF_SUCCESS;
58}
59
60
61/** Describes a optional boolean argument. */
62static DBGCVARDESC const g_BoolArg = { 0, 1, DBGCVAR_CAT_ANY, 0, "boolean", "Boolean value." };
63
64/** Commands. */
65static DBGCCMD const g_aCmds[] =
66{
67 {
68 "alliem", 0, 1, &g_BoolArg, 1, 0, enmR3DbgCmdAllIem, "[boolean]",
69 "Enables or disabled executing ALL code in IEM, if no arguments are given it displays the current status."
70 },
71};
72
73VMM_INT_DECL(const char *) EMR3GetExitTypeName(uint32_t uExitType)
74{
75 switch ((EMEXITTYPE)uExitType)
76 {
77 case EMEXITTYPE_INVALID: return "invalid";
78 case EMEXITTYPE_IO_PORT_READ: return "I/O port read";
79 case EMEXITTYPE_IO_PORT_WRITE: return "I/O port write";
80 case EMEXITTYPE_IO_PORT_STR_READ: return "I/O port string read";
81 case EMEXITTYPE_IO_PORT_STR_WRITE: return "I/O port string write";
82 case EMEXITTYPE_MMIO_READ: return "MMIO read";
83 case EMEXITTYPE_MMIO_WRITE: return "MMIO write";
84 case EMEXITTYPE_MSR_READ: return "MSR read";
85 case EMEXITTYPE_MSR_WRITE: return "MSR write";
86 case EMEXITTYPE_CPUID: return "CPUID";
87 }
88 return NULL;
89}
90
91/**
92 * Translates flags+type into an exit name.
93 *
94 * @returns Exit name.
95 * @param uFlagsAndType The exit to name.
96 * @param pszFallback Buffer for formatting a numeric fallback.
97 * @param cbFallback Size of fallback buffer.
98 */
99static const char *emR3HistoryGetExitName(uint32_t uFlagsAndType, char *pszFallback, size_t cbFallback)
100{
101 const char *pszExitName;
102 switch (uFlagsAndType & EMEXIT_F_KIND_MASK)
103 {
104 case EMEXIT_F_KIND_EM:
105 pszExitName = EMR3GetExitTypeName(uFlagsAndType & EMEXIT_F_TYPE_MASK);
106 break;
107
108 case EMEXIT_F_KIND_VMX:
109 pszExitName = HMR3GetVmxExitName( uFlagsAndType & EMEXIT_F_TYPE_MASK);
110 break;
111
112 case EMEXIT_F_KIND_SVM:
113 pszExitName = HMR3GetSvmExitName( uFlagsAndType & EMEXIT_F_TYPE_MASK);
114 break;
115
116 case EMEXIT_F_KIND_NEM:
117 pszExitName = NEMR3GetExitName( uFlagsAndType & EMEXIT_F_TYPE_MASK);
118 break;
119
120 case EMEXIT_F_KIND_XCPT:
121 switch (uFlagsAndType & EMEXIT_F_TYPE_MASK)
122 {
123 case X86_XCPT_DE: return "Xcpt #DE";
124 case X86_XCPT_DB: return "Xcpt #DB";
125 case X86_XCPT_NMI: return "Xcpt #NMI";
126 case X86_XCPT_BP: return "Xcpt #BP";
127 case X86_XCPT_OF: return "Xcpt #OF";
128 case X86_XCPT_BR: return "Xcpt #BR";
129 case X86_XCPT_UD: return "Xcpt #UD";
130 case X86_XCPT_NM: return "Xcpt #NM";
131 case X86_XCPT_DF: return "Xcpt #DF";
132 case X86_XCPT_CO_SEG_OVERRUN: return "Xcpt #CO_SEG_OVERRUN";
133 case X86_XCPT_TS: return "Xcpt #TS";
134 case X86_XCPT_NP: return "Xcpt #NP";
135 case X86_XCPT_SS: return "Xcpt #SS";
136 case X86_XCPT_GP: return "Xcpt #GP";
137 case X86_XCPT_PF: return "Xcpt #PF";
138 case X86_XCPT_MF: return "Xcpt #MF";
139 case X86_XCPT_AC: return "Xcpt #AC";
140 case X86_XCPT_MC: return "Xcpt #MC";
141 case X86_XCPT_XF: return "Xcpt #XF";
142 case X86_XCPT_VE: return "Xcpt #VE";
143 case X86_XCPT_SX: return "Xcpt #SX";
144 default:
145 pszExitName = NULL;
146 break;
147 }
148 break;
149
150 default:
151 AssertFailed();
152 pszExitName = NULL;
153 break;
154 }
155 if (pszExitName)
156 return pszExitName;
157 RTStrPrintf(pszFallback, cbFallback, "%#06x", uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_TYPE_MASK));
158 return pszFallback;
159}
160
161
162/**
163 * Displays the VM-exit history.
164 *
165 * @param pVM The cross context VM structure.
166 * @param pHlp The info helper functions.
167 * @param pszArgs Arguments, ignored.
168 */
169static DECLCALLBACK(void) emR3InfoExitHistory(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
170{
171 NOREF(pszArgs);
172
173 /*
174 * Figure out target cpu and parse arguments.
175 */
176 PVMCPU pVCpu = VMMGetCpu(pVM);
177 if (!pVCpu)
178 pVCpu = &pVM->aCpus[0];
179 bool fReverse = true;
180 uint32_t cLeft = RT_ELEMENTS(pVCpu->em.s.aExitHistory);
181
182 while (pszArgs && *pszArgs)
183 {
184 pszArgs = RTStrStripL(pszArgs);
185 if (!*pszArgs)
186 break;
187 if (RT_C_IS_DIGIT(*pszArgs))
188 {
189 /* The number to dump. */
190 uint32_t uValue = cLeft;
191 RTStrToUInt32Ex(pszArgs, (char **)&pszArgs, 0, &uValue);
192 if (uValue > 0)
193 cLeft = RT_MIN(uValue, RT_ELEMENTS(pVCpu->em.s.aExitHistory));
194 }
195 else if (RTStrCmp(pszArgs, "reverse") == 0)
196 {
197 pszArgs += 7;
198 fReverse = true;
199 }
200 else if (RTStrCmp(pszArgs, "ascending") == 0)
201 {
202 pszArgs += 9;
203 fReverse = false;
204 }
205 else if (RTStrCmp(pszArgs, "asc") == 0)
206 {
207 pszArgs += 3;
208 fReverse = false;
209 }
210 else
211 {
212 const char *pszStart = pszArgs;
213 while (*pszArgs && !RT_C_IS_SPACE(*pszArgs))
214 pszArgs++;
215 pHlp->pfnPrintf(pHlp, "Unknown option: %.*s\n", pszArgs - pszStart, pszArgs);
216 }
217 }
218
219 /*
220 * Do the job.
221 */
222 uint64_t idx = pVCpu->em.s.iNextExit;
223 if (idx == 0)
224 pHlp->pfnPrintf(pHlp, "CPU[%u]: VM-exit history: empty\n", pVCpu->idCpu);
225 else
226 {
227 /*
228 * Print header.
229 */
230 pHlp->pfnPrintf(pHlp,
231 "CPU[%u]: VM-exit history:\n"
232 " Exit No.: TSC timestamp / delta Flat RIP Exit Name\n"
233 , pVCpu->idCpu);
234
235 /*
236 * Adjust bounds if ascending order.
237 */
238 if (!fReverse)
239 {
240 if (idx > cLeft)
241 idx -= cLeft;
242 else
243 {
244 cLeft = idx;
245 idx = 0;
246 }
247 }
248
249 /*
250 * Print the entries.
251 */
252 uint64_t uPrevTimestamp = 0;
253 do
254 {
255 if (fReverse)
256 idx -= 1;
257 PCEMEXITENTRY const pEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)idx & 0xff];
258
259 /* Get the exit name. */
260 char szExitName[16];
261 const char *pszExitName = emR3HistoryGetExitName(pEntry->uFlagsAndType, szExitName, sizeof(szExitName));
262
263 /* Calc delta (negative if reverse order, positive ascending). */
264 int64_t offDelta = uPrevTimestamp != 0 && pEntry->uTimestamp != 0 ? pEntry->uTimestamp - uPrevTimestamp : 0;
265 uPrevTimestamp = pEntry->uTimestamp;
266
267 /* Do the printing. */
268 if (pEntry->idxSlot == UINT32_MAX)
269 pHlp->pfnPrintf(pHlp, " %10RU64: %#018RX64/%+-9RI64 %016RX64 %#06x %s\n",
270 idx, pEntry->uTimestamp, offDelta, pEntry->uFlatPC, pEntry->uFlagsAndType, pszExitName);
271 else
272 {
273 /** @todo more on this later */
274 pHlp->pfnPrintf(pHlp, " %10RU64: %#018RX64/%+-9RI64 %016RX64 %#06x %s slot=%#x\n",
275 idx, pEntry->uTimestamp, offDelta, pEntry->uFlatPC, pEntry->uFlagsAndType, pszExitName,
276 pEntry->idxSlot);
277 }
278
279 /* Advance if ascending. */
280 if (!fReverse)
281 idx += 1;
282 } while (--cLeft > 0 && idx > 0);
283 }
284}
285
286
287int emR3InitDbg(PVM pVM)
288{
289 /*
290 * Register info dumpers.
291 */
292 int rc = DBGFR3InfoRegisterInternalEx(pVM, "exits", "Dumps the VM-exit history.",
293 emR3InfoExitHistory, DBGFINFO_FLAGS_ALL_EMTS);
294 AssertLogRelRCReturn(rc, rc);
295
296#ifdef VBOX_WITH_DEBUGGER
297 /*
298 * Register debugger commands.
299 */
300 rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
301 AssertLogRelRCReturn(rc, rc);
302#endif
303
304 return VINF_SUCCESS;
305}
306
Note: See TracBrowser for help on using the repository browser.

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