VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/VMMGuruMeditation.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 27.3 KB
Line 
1/* $Id: VMMGuruMeditation.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VMM - The Virtual Machine Monitor, Guru Meditation Code.
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_VMM
33#include <VBox/vmm/vmm.h>
34#include <VBox/vmm/pdmapi.h>
35#include <VBox/vmm/pdmcritsect.h>
36#include <VBox/vmm/trpm.h>
37#include <VBox/vmm/dbgf.h>
38#include "VMMInternal.h"
39#include <VBox/vmm/vm.h>
40#include <VBox/vmm/mm.h>
41#include <VBox/vmm/iom.h>
42#include <VBox/vmm/em.h>
43
44#include <VBox/err.h>
45#include <VBox/param.h>
46#include <VBox/version.h>
47#include <VBox/vmm/hm.h>
48#include <iprt/assert.h>
49#include <iprt/dbg.h>
50#include <iprt/time.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53#include <iprt/stdarg.h>
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/**
60 * Structure to pass to DBGFR3Info() and for doing all other
61 * output during fatal dump.
62 */
63typedef struct VMMR3FATALDUMPINFOHLP
64{
65 /** The helper core. */
66 DBGFINFOHLP Core;
67 /** The release logger instance. */
68 PRTLOGGER pRelLogger;
69 /** The saved release logger flags. */
70 uint32_t fRelLoggerFlags;
71 /** The logger instance. */
72 PRTLOGGER pLogger;
73 /** The saved logger flags. */
74 uint32_t fLoggerFlags;
75 /** The saved logger destination flags. */
76 uint32_t fLoggerDestFlags;
77 /** Whether to output to stderr or not. */
78 bool fStdErr;
79 /** Whether we're still recording the summary or not. */
80 bool fRecSummary;
81 /** Buffer for the summary. */
82 char szSummary[4096 - 2];
83 /** The current summary offset. */
84 size_t offSummary;
85 /** Standard error buffer. */
86 char achStdErrBuf[4096 - 8];
87 /** Standard error buffer offset. */
88 size_t offStdErrBuf;
89} VMMR3FATALDUMPINFOHLP, *PVMMR3FATALDUMPINFOHLP;
90/** Pointer to a VMMR3FATALDUMPINFOHLP structure. */
91typedef const VMMR3FATALDUMPINFOHLP *PCVMMR3FATALDUMPINFOHLP;
92
93
94/**
95 * Flushes the content of achStdErrBuf, setting offStdErrBuf to zero.
96 *
97 * @param pHlp The instance to flush.
98 */
99static void vmmR3FatalDumpInfoHlpFlushStdErr(PVMMR3FATALDUMPINFOHLP pHlp)
100{
101 size_t cch = pHlp->offStdErrBuf;
102 if (cch)
103 {
104 RTStrmWrite(g_pStdErr, pHlp->achStdErrBuf, cch);
105 pHlp->offStdErrBuf = 0;
106 }
107}
108
109/**
110 * @callback_method_impl{FNRTSTROUTPUT, For buffering stderr output.}
111 */
112static DECLCALLBACK(size_t) vmmR3FatalDumpInfoHlp_BufferedStdErrOutput(void *pvArg, const char *pachChars, size_t cbChars)
113{
114 PVMMR3FATALDUMPINFOHLP pHlp = (PVMMR3FATALDUMPINFOHLP)pvArg;
115 if (cbChars)
116 {
117 size_t offBuf = pHlp->offStdErrBuf;
118 if (cbChars < sizeof(pHlp->achStdErrBuf) - offBuf)
119 { /* likely */ }
120 else
121 {
122 vmmR3FatalDumpInfoHlpFlushStdErr(pHlp);
123 if (cbChars < sizeof(pHlp->achStdErrBuf))
124 offBuf = 0;
125 else
126 {
127 RTStrmWrite(g_pStdErr, pachChars, cbChars);
128 return cbChars;
129 }
130 }
131 memcpy(&pHlp->achStdErrBuf[offBuf], pachChars, cbChars);
132 pHlp->offStdErrBuf = offBuf + cbChars;
133 }
134 return cbChars;
135}
136
137
138/**
139 * Print formatted string.
140 *
141 * @param pHlp Pointer to this structure.
142 * @param pszFormat The format string.
143 * @param ... Arguments.
144 */
145static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
146{
147 va_list args;
148 va_start(args, pszFormat);
149 pHlp->pfnPrintfV(pHlp, pszFormat, args);
150 va_end(args);
151}
152
153/**
154 * Print formatted string.
155 *
156 * @param pHlp Pointer to this structure.
157 * @param pszFormat The format string.
158 * @param args Argument list.
159 */
160static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
161{
162 PVMMR3FATALDUMPINFOHLP pMyHlp = (PVMMR3FATALDUMPINFOHLP)pHlp;
163
164 if (pMyHlp->pRelLogger)
165 {
166 va_list args2;
167 va_copy(args2, args);
168 RTLogLoggerV(pMyHlp->pRelLogger, pszFormat, args2);
169 va_end(args2);
170 }
171 if (pMyHlp->pLogger)
172 {
173 va_list args2;
174 va_copy(args2, args);
175 RTLogLoggerV(pMyHlp->pLogger, pszFormat, args);
176 va_end(args2);
177 }
178 if (pMyHlp->fStdErr)
179 {
180 va_list args2;
181 va_copy(args2, args);
182 RTStrFormatV(vmmR3FatalDumpInfoHlp_BufferedStdErrOutput, pMyHlp, NULL, NULL, pszFormat, args2);
183 //RTStrmPrintfV(g_pStdErr, pszFormat, args2);
184 va_end(args2);
185 }
186 if (pMyHlp->fRecSummary)
187 {
188 size_t cchLeft = sizeof(pMyHlp->szSummary) - pMyHlp->offSummary;
189 if (cchLeft > 1)
190 {
191 va_list args2;
192 va_copy(args2, args);
193 size_t cch = RTStrPrintfV(&pMyHlp->szSummary[pMyHlp->offSummary], cchLeft, pszFormat, args);
194 va_end(args2);
195 Assert(cch <= cchLeft);
196 pMyHlp->offSummary += cch;
197 }
198 }
199}
200
201
202/**
203 * Initializes the fatal dump output helper.
204 *
205 * @param pHlp The structure to initialize.
206 */
207static void vmmR3FatalDumpInfoHlpInit(PVMMR3FATALDUMPINFOHLP pHlp)
208{
209 RT_BZERO(pHlp, sizeof(*pHlp));
210
211 pHlp->Core.pfnPrintf = vmmR3FatalDumpInfoHlp_pfnPrintf;
212 pHlp->Core.pfnPrintfV = vmmR3FatalDumpInfoHlp_pfnPrintfV;
213 pHlp->Core.pfnGetOptError = DBGFR3InfoGenericGetOptError;
214
215 /*
216 * The loggers.
217 */
218 pHlp->pRelLogger = RTLogRelGetDefaultInstance();
219#ifdef LOG_ENABLED
220 pHlp->pLogger = RTLogDefaultInstance();
221#else
222 if (pHlp->pRelLogger)
223 pHlp->pLogger = RTLogGetDefaultInstance();
224 else
225 pHlp->pLogger = RTLogDefaultInstance();
226#endif
227
228 if (pHlp->pRelLogger)
229 {
230 pHlp->fRelLoggerFlags = RTLogGetFlags(pHlp->pRelLogger);
231 RTLogChangeFlags(pHlp->pRelLogger, RTLOGFLAGS_BUFFERED, RTLOGFLAGS_DISABLED);
232 }
233
234 if (pHlp->pLogger)
235 {
236 pHlp->fLoggerFlags = RTLogGetFlags(pHlp->pLogger);
237 pHlp->fLoggerDestFlags = RTLogGetDestinations(pHlp->pLogger);
238 RTLogChangeFlags(pHlp->pLogger, RTLOGFLAGS_BUFFERED, RTLOGFLAGS_DISABLED);
239#ifndef DEBUG_sandervl
240 RTLogChangeDestinations(pHlp->pLogger, RTLOGDEST_DEBUGGER, 0);
241#endif
242 }
243
244 /*
245 * Check if we need write to stderr.
246 */
247 pHlp->fStdErr = (!pHlp->pRelLogger || !(RTLogGetDestinations(pHlp->pRelLogger) & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)))
248 && (!pHlp->pLogger || !(RTLogGetDestinations(pHlp->pLogger) & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)));
249#ifdef DEBUG_sandervl
250 pHlp->fStdErr = false; /* takes too long to display here */
251#endif
252 pHlp->offStdErrBuf = 0;
253
254 /*
255 * Init the summary recording.
256 */
257 pHlp->fRecSummary = true;
258 pHlp->offSummary = 0;
259 pHlp->szSummary[0] = '\0';
260}
261
262
263/**
264 * Deletes the fatal dump output helper.
265 *
266 * @param pHlp The structure to delete.
267 */
268static void vmmR3FatalDumpInfoHlpDelete(PVMMR3FATALDUMPINFOHLP pHlp)
269{
270 if (pHlp->pRelLogger)
271 {
272 RTLogFlush(pHlp->pRelLogger);
273 RTLogChangeFlags(pHlp->pRelLogger,
274 pHlp->fRelLoggerFlags & RTLOGFLAGS_DISABLED,
275 pHlp->fRelLoggerFlags & RTLOGFLAGS_BUFFERED);
276 }
277
278 if (pHlp->pLogger)
279 {
280 RTLogFlush(pHlp->pLogger);
281 RTLogChangeFlags(pHlp->pLogger,
282 pHlp->fLoggerFlags & RTLOGFLAGS_DISABLED,
283 pHlp->fLoggerFlags & RTLOGFLAGS_BUFFERED);
284 RTLogChangeDestinations(pHlp->pLogger, 0, pHlp->fLoggerDestFlags & RTLOGDEST_DEBUGGER);
285 }
286
287 if (pHlp->fStdErr)
288 vmmR3FatalDumpInfoHlpFlushStdErr(pHlp);
289}
290
291
292/**
293 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
294 */
295static DECLCALLBACK(VBOXSTRICTRC) vmmR3FatalDumpRendezvousDoneCallback(PVM pVM, PVMCPU pVCpu, void *pvUser)
296{
297 VM_FF_CLEAR(pVM, VM_FF_CHECK_VM_STATE);
298 RT_NOREF(pVCpu, pvUser);
299 return VINF_SUCCESS;
300}
301
302
303/**
304 * Dumps the VM state on a fatal error.
305 *
306 * @param pVM The cross context VM structure.
307 * @param pVCpu The cross context virtual CPU structure.
308 * @param rcErr VBox status code.
309 */
310VMMR3DECL(void) VMMR3FatalDump(PVM pVM, PVMCPU pVCpu, int rcErr)
311{
312 /*
313 * Create our output helper and sync it with the log settings.
314 * This helper will be used for all the output.
315 */
316 VMMR3FATALDUMPINFOHLP Hlp;
317 PCDBGFINFOHLP pHlp = &Hlp.Core;
318 vmmR3FatalDumpInfoHlpInit(&Hlp);
319
320 /* Release owned locks to make sure other VCPUs can continue in case they were waiting for one. */
321 PDMR3CritSectLeaveAll(pVM);
322
323 /*
324 * Header.
325 */
326 pHlp->pfnPrintf(pHlp,
327 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
328 "!!\n"
329 "!! VCPU%u: Guru Meditation %d (%Rrc)\n"
330 "!!\n",
331 pVCpu->idCpu, rcErr, rcErr);
332
333 /*
334 * Continue according to context.
335 */
336 bool fDoneHyper = false;
337 bool fDoneImport = false;
338 switch (rcErr)
339 {
340 /*
341 * Hypervisor errors.
342 */
343 case VERR_VMM_RING0_ASSERTION:
344 case VINF_EM_DBG_HYPER_ASSERTION:
345 case VERR_VMM_RING3_CALL_DISABLED:
346 case VERR_VMM_WRONG_HM_VMCPU_STATE:
347 case VERR_VMM_CONTEXT_HOOK_STILL_ENABLED:
348 {
349 const char *pszMsg1 = VMMR3GetRZAssertMsg1(pVM);
350 while (pszMsg1 && *pszMsg1 == '\n')
351 pszMsg1++;
352 const char *pszMsg2 = VMMR3GetRZAssertMsg2(pVM);
353 while (pszMsg2 && *pszMsg2 == '\n')
354 pszMsg2++;
355 pHlp->pfnPrintf(pHlp,
356 "%s"
357 "%s",
358 pszMsg1,
359 pszMsg2);
360 if ( !pszMsg2
361 || !*pszMsg2
362 || strchr(pszMsg2, '\0')[-1] != '\n')
363 pHlp->pfnPrintf(pHlp, "\n");
364 }
365 RT_FALL_THRU();
366 case VERR_TRPM_DONT_PANIC:
367 case VERR_TRPM_PANIC:
368 case VINF_EM_RAW_STALE_SELECTOR:
369 case VINF_EM_RAW_IRET_TRAP:
370 case VINF_EM_DBG_HYPER_BREAKPOINT:
371 case VINF_EM_DBG_HYPER_STEPPED:
372 case VINF_EM_TRIPLE_FAULT:
373 case VERR_VMM_HYPER_CR3_MISMATCH:
374 case VERR_VMM_LONG_JMP_ERROR:
375 {
376#if defined(VBOX_VMM_TARGET_ARMV8)
377 AssertReleaseFailed();
378#else
379 /*
380 * Active trap? This is only of partial interest when in hardware
381 * assisted virtualization mode, thus the different messages.
382 */
383 TRPMEVENT enmType;
384 uint8_t u8TrapNo = 0xce;
385 uint32_t uErrorCode = 0xdeadface;
386 RTGCUINTPTR uCR2 = 0xdeadface;
387 uint8_t cbInstr = UINT8_MAX;
388 bool fIcebp = false;
389 int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2, &cbInstr, &fIcebp);
390 if (RT_SUCCESS(rc2))
391 pHlp->pfnPrintf(pHlp,
392 "!! ACTIVE TRAP=%02x ERRCD=%RX32 CR2=%RGv PC=%RGr Type=%d cbInstr=%02x fIcebp=%RTbool (Guest!)\n",
393 u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVCpu), enmType, cbInstr, fIcebp);
394
395 /*
396 * Dump the relevant hypervisor registers and stack.
397 */
398 if (rcErr == VERR_VMM_RING0_ASSERTION)
399 {
400 /* Dump the jmpbuf. */
401 pHlp->pfnPrintf(pHlp,
402 "!!\n"
403 "!! AssertJmpBuf:\n"
404 "!!\n");
405 pHlp->pfnPrintf(pHlp,
406 "UnwindSp=%RHv UnwindRetSp=%RHv UnwindBp=%RHv UnwindPc=%RHv\n",
407 pVCpu->vmm.s.AssertJmpBuf.UnwindSp,
408 pVCpu->vmm.s.AssertJmpBuf.UnwindRetSp,
409 pVCpu->vmm.s.AssertJmpBuf.UnwindBp,
410 pVCpu->vmm.s.AssertJmpBuf.UnwindPc);
411 pHlp->pfnPrintf(pHlp,
412 "UnwindRetPcValue=%RHv UnwindRetPcLocation=%RHv\n",
413 pVCpu->vmm.s.AssertJmpBuf.UnwindRetPcValue,
414 pVCpu->vmm.s.AssertJmpBuf.UnwindRetPcLocation);
415 pHlp->pfnPrintf(pHlp,
416 "pfn=%RHv pvUser1=%RHv pvUser2=%RHv\n",
417 pVCpu->vmm.s.AssertJmpBuf.pfn,
418 pVCpu->vmm.s.AssertJmpBuf.pvUser1,
419 pVCpu->vmm.s.AssertJmpBuf.pvUser2);
420
421 /* Dump the resume register frame on the stack. */
422 PRTHCUINTPTR const pBP = (PRTHCUINTPTR)&pVCpu->vmm.s.abAssertStack[ pVCpu->vmm.s.AssertJmpBuf.UnwindBp
423 - pVCpu->vmm.s.AssertJmpBuf.UnwindSp];
424#if HC_ARCH_BITS == 32
425 pHlp->pfnPrintf(pHlp,
426 "eax=volatile ebx=%08x ecx=volatile edx=volatile esi=%08x edi=%08x\n"
427 "eip=%08x esp=%08x ebp=%08x efl=%08x\n"
428 ,
429 pBP[-3], pBP[-2], pBP[-1],
430 pBP[1], pVCpu->vmm.s.AssertJmpBuf.SavedEbp - 8, pBP[0], pBP[-4]);
431#else
432# ifdef RT_OS_WINDOWS
433 pHlp->pfnPrintf(pHlp,
434 "rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
435 "rsi=%016RX64 rdi=%016RX64 r8=volatile r9=volatile \n"
436 "r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
437 "r14=%016RX64 r15=%016RX64\n"
438 "rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rfl=%08RX64\n"
439 ,
440 pBP[-7],
441 pBP[-6], pBP[-5],
442 pBP[-4], pBP[-3],
443 pBP[-2], pBP[-1],
444 pBP[1], pVCpu->vmm.s.AssertJmpBuf.UnwindRetSp, pBP[0], pBP[-8]);
445# else
446 pHlp->pfnPrintf(pHlp,
447 "rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
448 "rsi=volatile rdi=volatile r8=volatile r9=volatile \n"
449 "r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
450 "r14=%016RX64 r15=%016RX64\n"
451 "rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rflags=%08RX64\n"
452 ,
453 pBP[-5],
454 pBP[-4], pBP[-3],
455 pBP[-2], pBP[-1],
456 pBP[1], pVCpu->vmm.s.AssertJmpBuf.UnwindRetSp, pBP[0], pBP[-6]);
457# endif
458#endif
459
460 /* Callstack. */
461 DBGFADDRESS AddrPc, AddrBp, AddrSp;
462 PCDBGFSTACKFRAME pFirstFrame;
463 rc2 = DBGFR3StackWalkBeginEx(pVM->pUVM, pVCpu->idCpu, DBGFCODETYPE_RING0,
464 DBGFR3AddrFromHostR0(&AddrBp, pVCpu->vmm.s.AssertJmpBuf.UnwindBp),
465 DBGFR3AddrFromHostR0(&AddrSp, pVCpu->vmm.s.AssertJmpBuf.UnwindSp),
466 DBGFR3AddrFromHostR0(&AddrPc, pVCpu->vmm.s.AssertJmpBuf.UnwindPc),
467 RTDBGRETURNTYPE_INVALID, &pFirstFrame);
468 if (RT_SUCCESS(rc2))
469 {
470 pHlp->pfnPrintf(pHlp,
471 "!!\n"
472 "!! Call Stack:\n"
473 "!!\n");
474#if HC_ARCH_BITS == 32
475 pHlp->pfnPrintf(pHlp, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
476#else
477 pHlp->pfnPrintf(pHlp, "RBP Ret RBP Ret RIP RIP Symbol [line]\n");
478#endif
479 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
480 pFrame;
481 pFrame = DBGFR3StackWalkNext(pFrame))
482 {
483#if HC_ARCH_BITS == 32
484 pHlp->pfnPrintf(pHlp,
485 "%RHv %RHv %04RX32:%RHv %RHv %RHv %RHv %RHv",
486 (RTHCUINTPTR)pFrame->AddrFrame.off,
487 (RTHCUINTPTR)pFrame->AddrReturnFrame.off,
488 (RTHCUINTPTR)pFrame->AddrReturnPC.Sel,
489 (RTHCUINTPTR)pFrame->AddrReturnPC.off,
490 pFrame->Args.au32[0],
491 pFrame->Args.au32[1],
492 pFrame->Args.au32[2],
493 pFrame->Args.au32[3]);
494 pHlp->pfnPrintf(pHlp, " %RTsel:%08RHv", pFrame->AddrPC.Sel, pFrame->AddrPC.off);
495#else
496 pHlp->pfnPrintf(pHlp,
497 "%RHv %RHv %RHv %RHv",
498 (RTHCUINTPTR)pFrame->AddrFrame.off,
499 (RTHCUINTPTR)pFrame->AddrReturnFrame.off,
500 (RTHCUINTPTR)pFrame->AddrReturnPC.off,
501 (RTHCUINTPTR)pFrame->AddrPC.off);
502#endif
503 if (pFrame->pSymPC)
504 {
505 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value;
506 if (offDisp > 0)
507 pHlp->pfnPrintf(pHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
508 else if (offDisp < 0)
509 pHlp->pfnPrintf(pHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
510 else
511 pHlp->pfnPrintf(pHlp, " %s", pFrame->pSymPC->szName);
512 }
513 if (pFrame->pLinePC)
514 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
515 pHlp->pfnPrintf(pHlp, "\n");
516 for (uint32_t iReg = 0; iReg < pFrame->cSureRegs; iReg++)
517 {
518 const char *pszName = pFrame->paSureRegs[iReg].pszName;
519 if (!pszName)
520 pszName = DBGFR3RegCpuName(pVM->pUVM, pFrame->paSureRegs[iReg].enmReg,
521 pFrame->paSureRegs[iReg].enmType);
522 char szValue[1024];
523 szValue[0] = '\0';
524 DBGFR3RegFormatValue(szValue, sizeof(szValue), &pFrame->paSureRegs[iReg].Value,
525 pFrame->paSureRegs[iReg].enmType, false);
526 pHlp->pfnPrintf(pHlp, " %-3s=%s\n", pszName, szValue);
527 }
528 }
529 DBGFR3StackWalkEnd(pFirstFrame);
530 }
531
532 /* Symbols on the stack. */
533 uint32_t const cbRawStack = RT_MIN(pVCpu->vmm.s.AssertJmpBuf.cbStackValid, sizeof(pVCpu->vmm.s.abAssertStack));
534 uintptr_t const * const pauAddr = (uintptr_t const *)&pVCpu->vmm.s.abAssertStack[0];
535 uint32_t const iEnd = cbRawStack / sizeof(uintptr_t);
536 uint32_t iAddr = 0;
537 pHlp->pfnPrintf(pHlp,
538 "!!\n"
539 "!! Addresses on the stack (iAddr=%#x, iEnd=%#x)\n"
540 "!!\n",
541 iAddr, iEnd);
542 while (iAddr < iEnd)
543 {
544 uintptr_t const uAddr = pauAddr[iAddr];
545 if (uAddr > X86_PAGE_SIZE)
546 {
547 DBGFADDRESS Addr;
548 DBGFR3AddrFromFlat(pVM->pUVM, &Addr, uAddr);
549 RTGCINTPTR offDisp = 0;
550 RTGCINTPTR offLineDisp = 0;
551 PRTDBGSYMBOL pSym = DBGFR3AsSymbolByAddrA(pVM->pUVM, DBGF_AS_R0, &Addr,
552 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL
553 | RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED,
554 &offDisp, NULL);
555 PRTDBGLINE pLine = DBGFR3AsLineByAddrA(pVM->pUVM, DBGF_AS_R0, &Addr, &offLineDisp, NULL);
556 if (pLine || pSym)
557 {
558 pHlp->pfnPrintf(pHlp, "%#06x: %p =>", iAddr * sizeof(uintptr_t), uAddr);
559 if (pSym)
560 pHlp->pfnPrintf(pHlp, " %s + %#x", pSym->szName, (intptr_t)offDisp);
561 if (pLine)
562 pHlp->pfnPrintf(pHlp, " [%s:%u + %#x]\n", pLine->szFilename, pLine->uLineNo, offLineDisp);
563 else
564 pHlp->pfnPrintf(pHlp, "\n");
565 RTDbgSymbolFree(pSym);
566 RTDbgLineFree(pLine);
567 }
568 }
569 iAddr++;
570 }
571
572 /* raw stack */
573 Hlp.fRecSummary = false;
574 pHlp->pfnPrintf(pHlp,
575 "!!\n"
576 "!! Raw stack (mind the direction).\n"
577 "!! pbEMTStackR0=%RHv cbRawStack=%#x\n"
578 "!! pbEmtStackR3=%p\n"
579 "!!\n"
580 "%.*Rhxd\n",
581 pVCpu->vmm.s.AssertJmpBuf.UnwindSp, cbRawStack,
582 &pVCpu->vmm.s.abAssertStack[0],
583 cbRawStack, &pVCpu->vmm.s.abAssertStack[0]);
584 }
585 else
586 {
587 pHlp->pfnPrintf(pHlp,
588 "!! Skipping ring-0 registers and stack, rcErr=%Rrc\n", rcErr);
589 }
590#endif /* !VBOX_VMM_TARGET_ARMV8 */
591 break;
592 }
593
594 case VERR_IEM_INSTR_NOT_IMPLEMENTED:
595 case VERR_IEM_ASPECT_NOT_IMPLEMENTED:
596 case VERR_PATM_IPE_TRAP_IN_PATCH_CODE:
597 case VERR_EM_GUEST_CPU_HANG:
598 {
599 CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_ABSOLUTELY_ALL);
600 fDoneImport = true;
601
602 DBGFR3Info(pVM->pUVM, "cpumguest", NULL, pHlp);
603 DBGFR3Info(pVM->pUVM, "cpumguestinstr", NULL, pHlp);
604 DBGFR3Info(pVM->pUVM, "cpumguesthwvirt", NULL, pHlp);
605 break;
606 }
607
608 /*
609 * For some problems (e.g. VERR_INVALID_STATE in VMMR0.cpp), there could be
610 * additional details in the assertion messages.
611 */
612 default:
613 {
614 const char *pszMsg1 = VMMR3GetRZAssertMsg1(pVM);
615 while (pszMsg1 && *pszMsg1 == '\n')
616 pszMsg1++;
617 if (pszMsg1 && *pszMsg1 != '\0')
618 pHlp->pfnPrintf(pHlp, "AssertMsg1: %s\n", pszMsg1);
619
620 const char *pszMsg2 = VMMR3GetRZAssertMsg2(pVM);
621 while (pszMsg2 && *pszMsg2 == '\n')
622 pszMsg2++;
623 if (pszMsg2 && *pszMsg2 != '\0')
624 pHlp->pfnPrintf(pHlp, "AssertMsg2: %s\n", pszMsg2);
625 break;
626 }
627
628 } /* switch (rcErr) */
629 Hlp.fRecSummary = false;
630
631
632 /*
633 * Generic info dumper loop.
634 */
635 if (!fDoneImport)
636 CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_ABSOLUTELY_ALL);
637 static struct
638 {
639 const char *pszInfo;
640 const char *pszArgs;
641 } const aInfo[] =
642 {
643 { "mappings", NULL },
644 { "hma", NULL },
645 { "cpumguest", "verbose" },
646 { "cpumguesthwvirt", "verbose" },
647 { "cpumguestinstr", "verbose" },
648 { "cpumhyper", "verbose" },
649 { "cpumhost", "verbose" },
650 { "mode", "all" },
651 { "cpuid", "verbose" },
652 { "handlers", "phys virt hyper stats" },
653 { "timers", NULL },
654 { "activetimers", NULL },
655 };
656 for (unsigned i = 0; i < RT_ELEMENTS(aInfo); i++)
657 {
658 if (fDoneHyper && !strcmp(aInfo[i].pszInfo, "cpumhyper"))
659 continue;
660 pHlp->pfnPrintf(pHlp,
661 "!!\n"
662 "!! {%s, %s}\n"
663 "!!\n",
664 aInfo[i].pszInfo, aInfo[i].pszArgs);
665 DBGFR3Info(pVM->pUVM, aInfo[i].pszInfo, aInfo[i].pszArgs, pHlp);
666 }
667
668 /* All other info items */
669 DBGFR3InfoMulti(pVM,
670 "*",
671 "mappings|hma|cpum|cpumguest|cpumguesthwvirt|cpumguestinstr|cpumhyper|cpumhost|mode|cpuid"
672 "|pgmpd|pgmcr3|timers|activetimers|handlers|help|exithistory",
673 "!!\n"
674 "!! {%s}\n"
675 "!!\n",
676 pHlp);
677
678
679 /* done */
680 pHlp->pfnPrintf(pHlp,
681 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
682
683
684 /*
685 * Repeat the summary to stderr so we don't have to scroll half a mile up.
686 */
687 vmmR3FatalDumpInfoHlpFlushStdErr(&Hlp);
688 if (Hlp.szSummary[0])
689 RTStrmPrintf(g_pStdErr,
690 "%s\n"
691 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
692 Hlp.szSummary);
693
694 /*
695 * Delete the output instance (flushing and restoring of flags).
696 */
697 vmmR3FatalDumpInfoHlpDelete(&Hlp);
698
699 /*
700 * Rendezvous with the other EMTs and clear the VM_FF_CHECK_VM_STATE so we can
701 * stop burning CPU cycles.
702 */
703 VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, vmmR3FatalDumpRendezvousDoneCallback, NULL);
704}
705
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