VirtualBox

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

Last change on this file since 99377 was 99051, checked in by vboxsync, 21 months ago

VMM: More ARMv8 x86/amd64 separation work, VBoxVMMArm compiles and links now, bugref:10385

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