VirtualBox

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

Last change on this file since 72544 was 72384, checked in by vboxsync, 7 years ago

VMM/Guru: Speed up stderr output by explicit buffering. Makes a big difference on Windows. :) [fix]

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