VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMGuruMeditation.cpp@ 30037

Last change on this file since 30037 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.0 KB
Line 
1/* $Id: VMMGuruMeditation.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * VMM - The Virtual Machine Monitor, Guru Meditation Code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_VMM
22#include <VBox/vmm.h>
23#include <VBox/pdmapi.h>
24#include <VBox/pdmcritsect.h>
25#include <VBox/trpm.h>
26#include <VBox/dbgf.h>
27#include "VMMInternal.h"
28#include <VBox/vm.h>
29#include <VBox/mm.h>
30#include <VBox/iom.h>
31#include <VBox/em.h>
32
33#include <VBox/err.h>
34#include <VBox/param.h>
35#include <VBox/version.h>
36#include <VBox/hwaccm.h>
37#include <iprt/assert.h>
38#include <iprt/time.h>
39#include <iprt/stream.h>
40#include <iprt/string.h>
41#include <iprt/stdarg.h>
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/**
48 * Structure to pass to DBGFR3Info() and for doing all other
49 * output during fatal dump.
50 */
51typedef struct VMMR3FATALDUMPINFOHLP
52{
53 /** The helper core. */
54 DBGFINFOHLP Core;
55 /** The release logger instance. */
56 PRTLOGGER pRelLogger;
57 /** The saved release logger flags. */
58 RTUINT fRelLoggerFlags;
59 /** The logger instance. */
60 PRTLOGGER pLogger;
61 /** The saved logger flags. */
62 RTUINT fLoggerFlags;
63 /** The saved logger destination flags. */
64 RTUINT fLoggerDestFlags;
65 /** Whether to output to stderr or not. */
66 bool fStdErr;
67} VMMR3FATALDUMPINFOHLP, *PVMMR3FATALDUMPINFOHLP;
68/** Pointer to a VMMR3FATALDUMPINFOHLP structure. */
69typedef const VMMR3FATALDUMPINFOHLP *PCVMMR3FATALDUMPINFOHLP;
70
71
72/**
73 * Print formatted string.
74 *
75 * @param pHlp Pointer to this structure.
76 * @param pszFormat The format string.
77 * @param ... Arguments.
78 */
79static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
80{
81 va_list args;
82 va_start(args, pszFormat);
83 pHlp->pfnPrintfV(pHlp, pszFormat, args);
84 va_end(args);
85}
86
87
88/**
89 * Print formatted string.
90 *
91 * @param pHlp Pointer to this structure.
92 * @param pszFormat The format string.
93 * @param args Argument list.
94 */
95static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
96{
97 PCVMMR3FATALDUMPINFOHLP pMyHlp = (PCVMMR3FATALDUMPINFOHLP)pHlp;
98
99 if (pMyHlp->pRelLogger)
100 {
101 va_list args2;
102 va_copy(args2, args);
103 RTLogLoggerV(pMyHlp->pRelLogger, pszFormat, args2);
104 va_end(args2);
105 }
106 if (pMyHlp->pLogger)
107 {
108 va_list args2;
109 va_copy(args2, args);
110 RTLogLoggerV(pMyHlp->pLogger, pszFormat, args);
111 va_end(args2);
112 }
113 if (pMyHlp->fStdErr)
114 {
115 va_list args2;
116 va_copy(args2, args);
117 RTStrmPrintfV(g_pStdErr, pszFormat, args);
118 va_end(args2);
119 }
120}
121
122
123/**
124 * Initializes the fatal dump output helper.
125 *
126 * @param pHlp The structure to initialize.
127 */
128static void vmmR3FatalDumpInfoHlpInit(PVMMR3FATALDUMPINFOHLP pHlp)
129{
130 memset(pHlp, 0, sizeof(*pHlp));
131
132 pHlp->Core.pfnPrintf = vmmR3FatalDumpInfoHlp_pfnPrintf;
133 pHlp->Core.pfnPrintfV = vmmR3FatalDumpInfoHlp_pfnPrintfV;
134
135 /*
136 * The loggers.
137 */
138 pHlp->pRelLogger = RTLogRelDefaultInstance();
139#ifndef LOG_ENABLED
140 if (!pHlp->pRelLogger)
141#endif
142 pHlp->pLogger = RTLogDefaultInstance();
143
144 if (pHlp->pRelLogger)
145 {
146 pHlp->fRelLoggerFlags = pHlp->pRelLogger->fFlags;
147 pHlp->pRelLogger->fFlags &= ~(RTLOGFLAGS_BUFFERED | RTLOGFLAGS_DISABLED);
148 }
149
150 if (pHlp->pLogger)
151 {
152 pHlp->fLoggerFlags = pHlp->pLogger->fFlags;
153 pHlp->fLoggerDestFlags = pHlp->pLogger->fDestFlags;
154 pHlp->pLogger->fFlags &= ~(RTLOGFLAGS_BUFFERED | RTLOGFLAGS_DISABLED);
155#ifndef DEBUG_sandervl
156 pHlp->pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
157#endif
158 }
159
160 /*
161 * Check if we need write to stderr.
162 */
163#ifdef DEBUG_sandervl
164 pHlp->fStdErr = false; /* takes too long to display here */
165#else
166 pHlp->fStdErr = (!pHlp->pRelLogger || !(pHlp->pRelLogger->fDestFlags & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)))
167 && (!pHlp->pLogger || !(pHlp->pLogger->fDestFlags & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)));
168#endif
169}
170
171
172/**
173 * Deletes the fatal dump output helper.
174 *
175 * @param pHlp The structure to delete.
176 */
177static void vmmR3FatalDumpInfoHlpDelete(PVMMR3FATALDUMPINFOHLP pHlp)
178{
179 if (pHlp->pRelLogger)
180 {
181 RTLogFlush(pHlp->pRelLogger);
182 pHlp->pRelLogger->fFlags = pHlp->fRelLoggerFlags;
183 }
184
185 if (pHlp->pLogger)
186 {
187 RTLogFlush(pHlp->pLogger);
188 pHlp->pLogger->fFlags = pHlp->fLoggerFlags;
189 pHlp->pLogger->fDestFlags = pHlp->fLoggerDestFlags;
190 }
191}
192
193
194/**
195 * Dumps the VM state on a fatal error.
196 *
197 * @param pVM VM Handle.
198 * @param pVCpu VMCPU Handle.
199 * @param rcErr VBox status code.
200 */
201VMMR3DECL(void) VMMR3FatalDump(PVM pVM, PVMCPU pVCpu, int rcErr)
202{
203 /*
204 * Create our output helper and sync it with the log settings.
205 * This helper will be used for all the output.
206 */
207 VMMR3FATALDUMPINFOHLP Hlp;
208 PCDBGFINFOHLP pHlp = &Hlp.Core;
209 vmmR3FatalDumpInfoHlpInit(&Hlp);
210
211 /* Release owned locks to make sure other VCPUs can continue in case they were waiting for one. */
212#if 1
213 PDMR3CritSectLeaveAll(pVM);
214#else
215 MMR3ReleaseOwnedLocks(pVM);
216 PGMR3ReleaseOwnedLocks(pVM);
217 PDMR3ReleaseOwnedLocks(pVM);
218 IOMR3ReleaseOwnedLocks(pVM);
219 EMR3ReleaseOwnedLocks(pVM);
220#endif
221
222 /*
223 * Header.
224 */
225 pHlp->pfnPrintf(pHlp,
226 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
227 "!!\n"
228 "!! Guru Meditation %d (%Rrc)\n"
229 "!!\n",
230 rcErr, rcErr);
231
232 /*
233 * Continue according to context.
234 */
235 bool fDoneHyper = false;
236 switch (rcErr)
237 {
238 /*
239 * Hypervisor errors.
240 */
241 case VERR_VMM_RING0_ASSERTION:
242 case VINF_EM_DBG_HYPER_ASSERTION:
243 case VERR_VMM_RING3_CALL_DISABLED:
244 {
245 const char *pszMsg1 = VMMR3GetRZAssertMsg1(pVM);
246 while (pszMsg1 && *pszMsg1 == '\n')
247 pszMsg1++;
248 const char *pszMsg2 = VMMR3GetRZAssertMsg2(pVM);
249 while (pszMsg2 && *pszMsg2 == '\n')
250 pszMsg2++;
251 pHlp->pfnPrintf(pHlp,
252 "%s"
253 "%s",
254 pszMsg1,
255 pszMsg2);
256 if ( !pszMsg2
257 || !*pszMsg2
258 || strchr(pszMsg2, '\0')[-1] != '\n')
259 pHlp->pfnPrintf(pHlp, "\n");
260 pHlp->pfnPrintf(pHlp, "!!\n");
261 /* fall thru */
262 }
263 case VERR_TRPM_DONT_PANIC:
264 case VERR_TRPM_PANIC:
265 case VINF_EM_RAW_STALE_SELECTOR:
266 case VINF_EM_RAW_IRET_TRAP:
267 case VINF_EM_DBG_HYPER_BREAKPOINT:
268 case VINF_EM_DBG_HYPER_STEPPED:
269 case VERR_VMM_HYPER_CR3_MISMATCH:
270 {
271 /*
272 * Active trap? This is only of partial interest when in hardware
273 * assisted virtualization mode, thus the different messages.
274 */
275 uint32_t uEIP = CPUMGetHyperEIP(pVCpu);
276 TRPMEVENT enmType;
277 uint8_t u8TrapNo = 0xce;
278 RTGCUINT uErrorCode = 0xdeadface;
279 RTGCUINTPTR uCR2 = 0xdeadface;
280 int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2);
281 if (!HWACCMIsEnabled(pVM))
282 {
283 if (RT_SUCCESS(rc2))
284 pHlp->pfnPrintf(pHlp,
285 "!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d\n",
286 u8TrapNo, uErrorCode, uCR2, uEIP, enmType);
287 else
288 pHlp->pfnPrintf(pHlp,
289 "!! EIP=%RX32 NOTRAP\n",
290 uEIP);
291 }
292 else if (RT_SUCCESS(rc2))
293 pHlp->pfnPrintf(pHlp,
294 "!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d (Guest!)\n",
295 u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVCpu), enmType);
296
297 /*
298 * The hypervisor dump is not relevant when we're in VT-x/AMD-V mode.
299 */
300 if (HWACCMIsEnabled(pVM))
301 {
302 pHlp->pfnPrintf(pHlp, "\n");
303#if defined(RT_OS_WINDOWS) && HC_ARCH_BITS == 32
304 /* Callstack. */
305 PCDBGFSTACKFRAME pFirstFrame;
306 DBGFADDRESS eip, ebp, esp;
307
308 eip.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
309#if HC_ARCH_BITS == 64
310 eip.FlatPtr = eip.off = pVCpu->vmm.s.CallRing3JmpBufR0.rip;
311#else
312 eip.FlatPtr = eip.off = pVCpu->vmm.s.CallRing3JmpBufR0.eip;
313#endif
314 eip.Sel = DBGF_SEL_FLAT;
315 ebp.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
316 ebp.FlatPtr = ebp.off = pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp;
317 ebp.Sel = DBGF_SEL_FLAT;
318 esp.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
319 esp.Sel = DBGF_SEL_FLAT;
320 esp.FlatPtr = esp.off = pVCpu->vmm.s.CallRing3JmpBufR0.SavedEsp;
321
322 rc2 = DBGFR3StackWalkBeginEx(pVM, pVCpu->idCpu, DBGFCODETYPE_RING0, &ebp, &esp, &eip,
323 DBGFRETURNTYPE_INVALID, &pFirstFrame);
324 if (RT_SUCCESS(rc2))
325 {
326 pHlp->pfnPrintf(pHlp,
327 "!!\n"
328 "!! Call Stack:\n"
329 "!!\n"
330 "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
331 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
332 pFrame;
333 pFrame = DBGFR3StackWalkNext(pFrame))
334 {
335 pHlp->pfnPrintf(pHlp,
336 "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
337 (uint32_t)pFrame->AddrFrame.off,
338 (uint32_t)pFrame->AddrReturnFrame.off,
339 (uint32_t)pFrame->AddrReturnPC.Sel,
340 (uint32_t)pFrame->AddrReturnPC.off,
341 pFrame->Args.au32[0],
342 pFrame->Args.au32[1],
343 pFrame->Args.au32[2],
344 pFrame->Args.au32[3]);
345 pHlp->pfnPrintf(pHlp, " %RTsel:%08RGv", pFrame->AddrPC.Sel, pFrame->AddrPC.off);
346 if (pFrame->pSymPC)
347 {
348 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value;
349 if (offDisp > 0)
350 pHlp->pfnPrintf(pHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
351 else if (offDisp < 0)
352 pHlp->pfnPrintf(pHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
353 else
354 pHlp->pfnPrintf(pHlp, " %s", pFrame->pSymPC->szName);
355 }
356 if (pFrame->pLinePC)
357 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
358 pHlp->pfnPrintf(pHlp, "\n");
359 }
360 DBGFR3StackWalkEnd(pFirstFrame);
361 }
362#endif /* defined(RT_OS_WINDOWS) && HC_ARCH_BITS == 32 */
363 }
364 else
365 {
366 /*
367 * Try figure out where eip is.
368 */
369 /* core code? */
370 if (uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC < pVM->vmm.s.cbCoreCode)
371 pHlp->pfnPrintf(pHlp,
372 "!! EIP is in CoreCode, offset %#x\n",
373 uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC);
374 else
375 { /* ask PDM */ /** @todo ask DBGFR3Sym later? */
376 char szModName[64];
377 RTRCPTR RCPtrMod;
378 char szNearSym1[260];
379 RTRCPTR RCPtrNearSym1;
380 char szNearSym2[260];
381 RTRCPTR RCPtrNearSym2;
382 int rc = PDMR3LdrQueryRCModFromPC(pVM, uEIP,
383 &szModName[0], sizeof(szModName), &RCPtrMod,
384 &szNearSym1[0], sizeof(szNearSym1), &RCPtrNearSym1,
385 &szNearSym2[0], sizeof(szNearSym2), &RCPtrNearSym2);
386 if (RT_SUCCESS(rc))
387 pHlp->pfnPrintf(pHlp,
388 "!! EIP in %s (%RRv) at rva %x near symbols:\n"
389 "!! %RRv rva %RRv off %08x %s\n"
390 "!! %RRv rva %RRv off -%08x %s\n",
391 szModName, RCPtrMod, (unsigned)(uEIP - RCPtrMod),
392 RCPtrNearSym1, RCPtrNearSym1 - RCPtrMod, (unsigned)(uEIP - RCPtrNearSym1), szNearSym1,
393 RCPtrNearSym2, RCPtrNearSym2 - RCPtrMod, (unsigned)(RCPtrNearSym2 - uEIP), szNearSym2);
394 else
395 pHlp->pfnPrintf(pHlp,
396 "!! EIP is not in any code known to VMM!\n");
397 }
398
399 /* Disassemble the instruction. */
400 char szInstr[256];
401 rc2 = DBGFR3DisasInstrEx(pVM, pVCpu->idCpu, 0, 0, DBGF_DISAS_FLAGS_CURRENT_HYPER, &szInstr[0], sizeof(szInstr), NULL);
402 if (RT_SUCCESS(rc2))
403 pHlp->pfnPrintf(pHlp,
404 "!! %s\n", szInstr);
405
406 /* Dump the hypervisor cpu state. */
407 pHlp->pfnPrintf(pHlp,
408 "!!\n"
409 "!!\n"
410 "!!\n");
411 rc2 = DBGFR3Info(pVM, "cpumhyper", "verbose", pHlp);
412 fDoneHyper = true;
413
414 /* Callstack. */
415 PCDBGFSTACKFRAME pFirstFrame;
416 rc2 = DBGFR3StackWalkBegin(pVM, pVCpu->idCpu, DBGFCODETYPE_HYPER, &pFirstFrame);
417 if (RT_SUCCESS(rc2))
418 {
419 pHlp->pfnPrintf(pHlp,
420 "!!\n"
421 "!! Call Stack:\n"
422 "!!\n"
423 "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
424 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
425 pFrame;
426 pFrame = DBGFR3StackWalkNext(pFrame))
427 {
428 pHlp->pfnPrintf(pHlp,
429 "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
430 (uint32_t)pFrame->AddrFrame.off,
431 (uint32_t)pFrame->AddrReturnFrame.off,
432 (uint32_t)pFrame->AddrReturnPC.Sel,
433 (uint32_t)pFrame->AddrReturnPC.off,
434 pFrame->Args.au32[0],
435 pFrame->Args.au32[1],
436 pFrame->Args.au32[2],
437 pFrame->Args.au32[3]);
438 pHlp->pfnPrintf(pHlp, " %RTsel:%08RGv", pFrame->AddrPC.Sel, pFrame->AddrPC.off);
439 if (pFrame->pSymPC)
440 {
441 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value;
442 if (offDisp > 0)
443 pHlp->pfnPrintf(pHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
444 else if (offDisp < 0)
445 pHlp->pfnPrintf(pHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
446 else
447 pHlp->pfnPrintf(pHlp, " %s", pFrame->pSymPC->szName);
448 }
449 if (pFrame->pLinePC)
450 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
451 pHlp->pfnPrintf(pHlp, "\n");
452 }
453 DBGFR3StackWalkEnd(pFirstFrame);
454 }
455
456 /* raw stack */
457 pHlp->pfnPrintf(pHlp,
458 "!!\n"
459 "!! Raw stack (mind the direction). pbEMTStackRC=%RRv pbEMTStackBottomRC=%RRv\n"
460 "!!\n"
461 "%.*Rhxd\n",
462 pVCpu->vmm.s.pbEMTStackRC, pVCpu->vmm.s.pbEMTStackBottomRC,
463 VMM_STACK_SIZE, pVCpu->vmm.s.pbEMTStackR3);
464 } /* !HWACCMIsEnabled */
465 break;
466 }
467
468 default:
469 {
470 break;
471 }
472
473 } /* switch (rcErr) */
474
475
476 /*
477 * Generic info dumper loop.
478 */
479 static struct
480 {
481 const char *pszInfo;
482 const char *pszArgs;
483 } const aInfo[] =
484 {
485 { "mappings", NULL },
486 { "hma", NULL },
487 { "cpumguest", "verbose" },
488 { "cpumguestinstr", "verbose" },
489 { "cpumhyper", "verbose" },
490 { "cpumhost", "verbose" },
491 { "mode", "all" },
492 { "cpuid", "verbose" },
493 { "gdt", NULL },
494 { "ldt", NULL },
495 //{ "tss", NULL },
496 { "ioport", NULL },
497 { "mmio", NULL },
498 { "phys", NULL },
499 //{ "pgmpd", NULL }, - doesn't always work at init time...
500 { "timers", NULL },
501 { "activetimers", NULL },
502 { "handlers", "phys virt hyper stats" },
503 { "cfgm", NULL },
504 };
505 for (unsigned i = 0; i < RT_ELEMENTS(aInfo); i++)
506 {
507 if (fDoneHyper && !strcmp(aInfo[i].pszInfo, "cpumhyper"))
508 continue;
509 pHlp->pfnPrintf(pHlp,
510 "!!\n"
511 "!! {%s, %s}\n"
512 "!!\n",
513 aInfo[i].pszInfo, aInfo[i].pszArgs);
514 DBGFR3Info(pVM, aInfo[i].pszInfo, aInfo[i].pszArgs, pHlp);
515 }
516
517 /* done */
518 pHlp->pfnPrintf(pHlp,
519 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
520
521
522 /*
523 * Delete the output instance (flushing and restoring of flags).
524 */
525 vmmR3FatalDumpInfoHlpDelete(&Hlp);
526
527 /*
528 * Reset the ring-0 long jump buffer and stack.
529 */
530 /** @todo reset the R0 for the calling virtual cpu. We'll assert (luckily) in
531 * PGMPhys.cpp otherwise. */
532}
533
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use