VMMGuruMeditation.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @file
* VMM - The Virtual Machine Monitor, Guru Meditation Code.
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_VMM
#include "VMMInternal.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Structure to pass to DBGFR3Info() and for doing all other
* output during fatal dump.
*/
typedef struct VMMR3FATALDUMPINFOHLP
{
/** The helper core. */
/** The release logger instance. */
/** The saved release logger flags. */
/** The logger instance. */
/** The saved logger flags. */
/** The saved logger destination flags. */
/** Whether to output to stderr or not. */
bool fStdErr;
/** Whether we're still recording the summary or not. */
bool fRecSummary;
/** Buffer for the summary. */
/** The current summary offset. */
/** Pointer to a VMMR3FATALDUMPINFOHLP structure. */
typedef const VMMR3FATALDUMPINFOHLP *PCVMMR3FATALDUMPINFOHLP;
/**
* Print formatted string.
*
* @param pHlp Pointer to this structure.
* @param pszFormat The format string.
* @param ... Arguments.
*/
static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
{
}
/**
* Print formatted string.
*
* @param pHlp Pointer to this structure.
* @param pszFormat The format string.
* @param args Argument list.
*/
static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
{
if (pMyHlp->pRelLogger)
{
}
{
}
{
}
if (pMyHlp->fRecSummary)
{
if (cchLeft > 1)
{
}
}
}
/**
* Initializes the fatal dump output helper.
*
* @param pHlp The structure to initialize.
*/
{
/*
* The loggers.
*/
#ifdef LOG_ENABLED
#else
if (pHlp->pRelLogger)
else
#endif
if (pHlp->pRelLogger)
{
}
{
#ifndef DEBUG_sandervl
#endif
}
/*
* Check if we need write to stderr.
*/
pHlp->fStdErr = (!pHlp->pRelLogger || !(pHlp->pRelLogger->fDestFlags & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)))
#ifdef DEBUG_sandervl
#endif
/*
* Init the summary recording.
*/
pHlp->fRecSummary = true;
pHlp->offSummary = 0;
}
/**
* Deletes the fatal dump output helper.
*
* @param pHlp The structure to delete.
*/
{
if (pHlp->pRelLogger)
{
}
{
}
}
/**
* Dumps the VM state on a fatal error.
*
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param rcErr VBox status code.
*/
{
/*
* Create our output helper and sync it with the log settings.
* This helper will be used for all the output.
*/
/* Release owned locks to make sure other VCPUs can continue in case they were waiting for one. */
/*
* Header.
*/
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"!!\n"
"!! Guru Meditation %d (%Rrc)\n"
"!!\n",
/*
* Continue according to context.
*/
bool fDoneHyper = false;
switch (rcErr)
{
/*
* Hypervisor errors.
*/
case VERR_VMM_RING0_ASSERTION:
{
pszMsg1++;
pszMsg2++;
"%s"
"%s",
pszMsg2);
if ( !pszMsg2
|| !*pszMsg2
/* fall thru */
}
case VERR_TRPM_DONT_PANIC:
case VERR_TRPM_PANIC:
case VINF_EM_RAW_IRET_TRAP:
{
/*
* Active trap? This is only of partial interest when in hardware
* assisted virtualization mode, thus the different messages.
*/
if (!HMIsEnabled(pVM))
{
if (RT_SUCCESS(rc2))
"!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d\n",
else
"!! EIP=%RX32 NOTRAP\n",
uEIP);
}
else if (RT_SUCCESS(rc2))
"!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d (Guest!)\n",
/*
* Dump the relevant hypervisor registers and stack.
*/
if (HMIsEnabled(pVM))
{
{
/* Dump the jmpbuf. */
"!!\n"
"!! CallRing3JmpBuf:\n"
"!!\n");
"SavedEsp=%RHv SavedEbp=%RHv SpResume=%RHv SpCheck=%RHv\n",
"pvSavedStack=%RHv cbSavedStack=%#x fInRing3Call=%RTbool\n",
"cbUsedMax=%#x cbUsedAvg=%#x cbUsedTotal=%#llx cUsedTotal=%#llx\n",
/* Dump the resume register frame on the stack. */
#ifdef VMM_R0_SWITCH_STACK
#else
#endif
#if HC_ARCH_BITS == 32
"eax=volatile ebx=%08x ecx=volatile edx=volatile esi=%08x edi=%08x\n"
"eip=%08x esp=%08x ebp=%08x efl=%08x\n"
,
#else
# ifdef RT_OS_WINDOWS
"rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
"rsi=%016RX64 rdi=%016RX64 r8=volatile r9=volatile \n"
"r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
"r14=%016RX64 r15=%016RX64\n"
"rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rfl=%08RX64\n"
,
pBP[-7],
# else
"rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
"rsi=volatile rdi=volatile r8=volatile r9=volatile \n"
"r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
"r14=%016RX64 r15=%016RX64\n"
"rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rflags=%08RX64\n"
,
pBP[-5],
# endif
#endif
/* Callstack. */
#if HC_ARCH_BITS == 64
#else
#endif
if (RT_SUCCESS(rc2))
{
"!!\n"
"!! Call Stack:\n"
"!!\n");
#if HC_ARCH_BITS == 32
#else
#endif
{
#if HC_ARCH_BITS == 32
"%RHv %RHv %04RX32:%RHv %RHv %RHv %RHv %RHv",
#else
"%RHv %RHv %RHv %RHv",
#endif
{
if (offDisp > 0)
else if (offDisp < 0)
else
}
}
}
/* raw stack */
Hlp.fRecSummary = false;
"!!\n"
"!! Raw stack (mind the direction). \n"
"!! pbEMTStackR0=%RHv pbEMTStackBottomR0=%RHv VMM_STACK_SIZE=%#x\n"
"!! pbEmtStackR3=%p\n"
"!!\n"
"%.*Rhxd\n",
}
else
{
"!! Skipping ring-0 registers and stack, rcErr=%Rrc\n", rcErr);
}
}
else
{
/*
* Try figure out where eip is.
*/
/* core code? */
"!! EIP is in CoreCode, offset %#x\n",
else
{ /* ask PDM */ /** @todo ask DBGFR3Sym later? */
char szModName[64];
char szNearSym1[260];
char szNearSym2[260];
if (RT_SUCCESS(rc))
"!! EIP in %s (%RRv) at rva %x near symbols:\n"
"!! %RRv rva %RRv off %08x %s\n"
"!! %RRv rva %RRv off -%08x %s\n",
else
"!! EIP is not in any code known to VMM!\n");
}
/* Disassemble the instruction. */
char szInstr[256];
if (RT_SUCCESS(rc2))
"!! %s\n", szInstr);
/* Dump the hypervisor cpu state. */
"!!\n"
"!!\n"
"!!\n");
fDoneHyper = true;
/* Callstack. */
if (RT_SUCCESS(rc2))
{
"!!\n"
"!! Call Stack:\n"
"!!\n"
"EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
{
"%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
{
if (offDisp > 0)
else if (offDisp < 0)
else
}
}
}
/* raw stack */
Hlp.fRecSummary = false;
"!!\n"
"!! Raw stack (mind the direction). pbEMTStackRC=%RRv pbEMTStackBottomRC=%RRv\n"
"!!\n"
"%.*Rhxd\n",
} /* !HMIsEnabled */
break;
}
{
break;
}
default:
{
break;
}
} /* switch (rcErr) */
Hlp.fRecSummary = false;
/*
* Generic info dumper loop.
*/
static struct
{
const char *pszInfo;
const char *pszArgs;
} const aInfo[] =
{
{ "mappings", NULL },
{ "hma", NULL },
{ "cpumguest", "verbose" },
{ "cpumguestinstr", "verbose" },
{ "cpumhyper", "verbose" },
{ "cpumhost", "verbose" },
{ "mode", "all" },
{ "cpuid", "verbose" },
{ "handlers", "phys virt hyper stats" },
{ "timers", NULL },
{ "activetimers", NULL },
};
for (unsigned i = 0; i < RT_ELEMENTS(aInfo); i++)
{
continue;
"!!\n"
"!! {%s, %s}\n"
"!!\n",
}
/* All other info items */
"*",
"mappings|hma|cpum|cpumguest|cpumguestinstr|cpumhyper|cpumhost|mode|cpuid"
"|pgmpd|pgmcr3|timers|activetimers|handlers|help",
"!!\n"
"!! {%s}\n"
"!!\n",
pHlp);
/* done */
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
/*
* Repeat the summary to stderr so we don't have to scroll half a mile up.
*/
"%s"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
/*
* Delete the output instance (flushing and restoring of flags).
*/
}