VirtualBox

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

Last change on this file since 20088 was 19797, checked in by vboxsync, 16 years ago

Release all taken locks in VMMR3FatalDump instead.

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