VirtualBox

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

Last change on this file since 13762 was 13714, checked in by vboxsync, 16 years ago

VMM: More renaming and cleanup, caught another R3/R0 pointer - the ring-0 logger.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.0 KB
Line 
1/* $Id: VMMGuruMeditation.cpp 13714 2008-10-31 14:01:43Z 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
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 rcErr VBox status code.
199 */
200VMMR3DECL(void) VMMR3FatalDump(PVM pVM, int rcErr)
201{
202 /*
203 * Create our output helper and sync it with the log settings.
204 * This helper will be used for all the output.
205 */
206 VMMR3FATALDUMPINFOHLP Hlp;
207 PCDBGFINFOHLP pHlp = &Hlp.Core;
208 vmmR3FatalDumpInfoHlpInit(&Hlp);
209
210 /*
211 * Header.
212 */
213 pHlp->pfnPrintf(pHlp,
214 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
215 "!!\n"
216 "!! Guru Meditation %d (%Vrc)\n"
217 "!!\n",
218 rcErr, rcErr);
219
220 /*
221 * Continue according to context.
222 */
223 bool fDoneHyper = false;
224 switch (rcErr)
225 {
226 /*
227 * Hypervisor errors.
228 */
229 case VERR_VMM_RING0_ASSERTION:
230 case VINF_EM_DBG_HYPER_ASSERTION:
231 {
232 bool fIsRing0 = rcErr == VERR_VMM_RING0_ASSERTION;
233 const char *pszMsg1 = fIsRing0 ? pVM->vmm.s.szRing0AssertMsg1 : VMMR3GetGCAssertMsg1(pVM);
234 while (pszMsg1 && *pszMsg1 == '\n')
235 pszMsg1++;
236 const char *pszMsg2 = fIsRing0 ? pVM->vmm.s.szRing0AssertMsg2 : VMMR3GetGCAssertMsg2(pVM);
237 while (pszMsg2 && *pszMsg2 == '\n')
238 pszMsg2++;
239 pHlp->pfnPrintf(pHlp,
240 "%s"
241 "%s",
242 pszMsg1,
243 pszMsg2);
244 if ( !pszMsg2
245 || !*pszMsg2
246 || strchr(pszMsg2, '\0')[-1] != '\n')
247 pHlp->pfnPrintf(pHlp, "\n");
248 pHlp->pfnPrintf(pHlp, "!!\n");
249 /* fall thru */
250 }
251 case VERR_TRPM_DONT_PANIC:
252 case VERR_TRPM_PANIC:
253 case VINF_EM_RAW_STALE_SELECTOR:
254 case VINF_EM_RAW_IRET_TRAP:
255 case VINF_EM_DBG_HYPER_BREAKPOINT:
256 case VINF_EM_DBG_HYPER_STEPPED:
257 {
258 /*
259 * Active trap? This is only of partial interest when in hardware
260 * assisted virtualization mode, thus the different messages.
261 */
262 uint32_t uEIP = CPUMGetHyperEIP(pVM);
263 TRPMEVENT enmType;
264 uint8_t u8TrapNo = 0xce;
265 RTGCUINT uErrorCode = 0xdeadface;
266 RTGCUINTPTR uCR2 = 0xdeadface;
267 int rc2 = TRPMQueryTrapAll(pVM, &u8TrapNo, &enmType, &uErrorCode, &uCR2);
268 if (!HWACCMR3IsActive(pVM))
269 {
270 if (RT_SUCCESS(rc2))
271 pHlp->pfnPrintf(pHlp,
272 "!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d\n",
273 u8TrapNo, uErrorCode, uCR2, uEIP, enmType);
274 else
275 pHlp->pfnPrintf(pHlp,
276 "!! EIP=%RX32 NOTRAP\n",
277 uEIP);
278 }
279 else if (RT_SUCCESS(rc2))
280 pHlp->pfnPrintf(pHlp,
281 "!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d (Guest!)\n",
282 u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVM), enmType);
283
284 /*
285 * The hypervisor dump is not relevant when we're in VT-x/AMD-V mode.
286 */
287 if (HWACCMR3IsActive(pVM))
288 pHlp->pfnPrintf(pHlp, "\n");
289 else
290 {
291 /*
292 * Try figure out where eip is.
293 */
294 /* core code? */
295 if (uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC < pVM->vmm.s.cbCoreCode)
296 pHlp->pfnPrintf(pHlp,
297 "!! EIP is in CoreCode, offset %#x\n",
298 uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC);
299 else
300 { /* ask PDM */ /** @todo ask DBGFR3Sym later? */
301 char szModName[64];
302 RTRCPTR RCPtrMod;
303 char szNearSym1[260];
304 RTRCPTR RCPtrNearSym1;
305 char szNearSym2[260];
306 RTRCPTR RCPtrNearSym2;
307 int rc = PDMR3LdrQueryRCModFromPC(pVM, uEIP,
308 &szModName[0], sizeof(szModName), &RCPtrMod,
309 &szNearSym1[0], sizeof(szNearSym1), &RCPtrNearSym1,
310 &szNearSym2[0], sizeof(szNearSym2), &RCPtrNearSym2);
311 if (VBOX_SUCCESS(rc))
312 pHlp->pfnPrintf(pHlp,
313 "!! EIP in %s (%RRv) at rva %x near symbols:\n"
314 "!! %RRv rva %RRv off %08x %s\n"
315 "!! %RRv rva %RRv off -%08x %s\n",
316 szModName, RCPtrMod, (unsigned)(uEIP - RCPtrMod),
317 RCPtrNearSym1, RCPtrNearSym1 - RCPtrMod, (unsigned)(uEIP - RCPtrNearSym1), szNearSym1,
318 RCPtrNearSym2, RCPtrNearSym2 - RCPtrMod, (unsigned)(RCPtrNearSym2 - uEIP), szNearSym2);
319 else
320 pHlp->pfnPrintf(pHlp,
321 "!! EIP is not in any code known to VMM!\n");
322 }
323
324 /* Disassemble the instruction. */
325 char szInstr[256];
326 rc2 = DBGFR3DisasInstrEx(pVM, 0, 0, DBGF_DISAS_FLAGS_CURRENT_HYPER, &szInstr[0], sizeof(szInstr), NULL);
327 if (VBOX_SUCCESS(rc2))
328 pHlp->pfnPrintf(pHlp,
329 "!! %s\n", szInstr);
330
331 /* Dump the hypervisor cpu state. */
332 pHlp->pfnPrintf(pHlp,
333 "!!\n"
334 "!!\n"
335 "!!\n");
336 rc2 = DBGFR3Info(pVM, "cpumhyper", "verbose", pHlp);
337 fDoneHyper = true;
338
339 /* Callstack. */
340 DBGFSTACKFRAME Frame = {0};
341 rc2 = DBGFR3StackWalkBeginHyper(pVM, &Frame);
342 if (VBOX_SUCCESS(rc2))
343 {
344 pHlp->pfnPrintf(pHlp,
345 "!!\n"
346 "!! Call Stack:\n"
347 "!!\n"
348 "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
349 do
350 {
351 pHlp->pfnPrintf(pHlp,
352 "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
353 (uint32_t)Frame.AddrFrame.off,
354 (uint32_t)Frame.AddrReturnFrame.off,
355 (uint32_t)Frame.AddrReturnPC.Sel,
356 (uint32_t)Frame.AddrReturnPC.off,
357 Frame.Args.au32[0],
358 Frame.Args.au32[1],
359 Frame.Args.au32[2],
360 Frame.Args.au32[3]);
361 pHlp->pfnPrintf(pHlp, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);
362 if (Frame.pSymPC)
363 {
364 RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value;
365 if (offDisp > 0)
366 pHlp->pfnPrintf(pHlp, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);
367 else if (offDisp < 0)
368 pHlp->pfnPrintf(pHlp, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);
369 else
370 pHlp->pfnPrintf(pHlp, " %s", Frame.pSymPC->szName);
371 }
372 if (Frame.pLinePC)
373 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);
374 pHlp->pfnPrintf(pHlp, "\n");
375
376 /* next */
377 rc2 = DBGFR3StackWalkNext(pVM, &Frame);
378 } while (VBOX_SUCCESS(rc2));
379 DBGFR3StackWalkEnd(pVM, &Frame);
380 }
381
382 /* raw stack */
383 pHlp->pfnPrintf(pHlp,
384 "!!\n"
385 "!! Raw stack (mind the direction).\n"
386 "!!\n"
387 "%.*Vhxd\n",
388 VMM_STACK_SIZE, pVM->vmm.s.pbEMTStackR3);
389 } /* !HWACCMR3IsActive */
390 break;
391 }
392
393 default:
394 {
395 break;
396 }
397
398 } /* switch (rcErr) */
399
400
401 /*
402 * Generic info dumper loop.
403 */
404 static struct
405 {
406 const char *pszInfo;
407 const char *pszArgs;
408 } const aInfo[] =
409 {
410 { "mappings", NULL },
411 { "hma", NULL },
412 { "cpumguest", "verbose" },
413 { "cpumguestinstr", "verbose" },
414 { "cpumhyper", "verbose" },
415 { "cpumhost", "verbose" },
416 { "mode", "all" },
417 { "cpuid", "verbose" },
418 { "gdt", NULL },
419 { "ldt", NULL },
420 //{ "tss", NULL },
421 { "ioport", NULL },
422 { "mmio", NULL },
423 { "phys", NULL },
424 //{ "pgmpd", NULL }, - doesn't always work at init time...
425 { "timers", NULL },
426 { "activetimers", NULL },
427 { "handlers", "phys virt hyper stats" },
428 { "cfgm", NULL },
429 };
430 for (unsigned i = 0; i < RT_ELEMENTS(aInfo); i++)
431 {
432 if (fDoneHyper && !strcmp(aInfo[i].pszInfo, "cpumhyper"))
433 continue;
434 pHlp->pfnPrintf(pHlp,
435 "!!\n"
436 "!! {%s, %s}\n"
437 "!!\n",
438 aInfo[i].pszInfo, aInfo[i].pszArgs);
439 DBGFR3Info(pVM, aInfo[i].pszInfo, aInfo[i].pszArgs, pHlp);
440 }
441
442 /* done */
443 pHlp->pfnPrintf(pHlp,
444 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
445
446
447 /*
448 * Delete the output instance (flushing and restoring of flags).
449 */
450 vmmR3FatalDumpInfoHlpDelete(&Hlp);
451}
452
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use