VirtualBox

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

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

IPRT,DBGF,Diggers: Moved DBGFRETURNTYPE and the unwind state structure to IPRT (dbg.h) in prep for debug module interface and more. Added stack unwind assist callback for the OS diggers so they can identify special stack frames and supply more info via the sure-register-value array and frame flags. Identify and decode NT/AMD64 trap frames.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 33.0 KB
Line 
1/* $Id: VMMGuruMeditation.cpp 73460 2018-08-02 21:06:59Z 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 bool fDoneImport = false;
314 switch (rcErr)
315 {
316 /*
317 * Hypervisor errors.
318 */
319 case VERR_VMM_RING0_ASSERTION:
320 case VINF_EM_DBG_HYPER_ASSERTION:
321 case VERR_VMM_RING3_CALL_DISABLED:
322 {
323 const char *pszMsg1 = VMMR3GetRZAssertMsg1(pVM);
324 while (pszMsg1 && *pszMsg1 == '\n')
325 pszMsg1++;
326 const char *pszMsg2 = VMMR3GetRZAssertMsg2(pVM);
327 while (pszMsg2 && *pszMsg2 == '\n')
328 pszMsg2++;
329 pHlp->pfnPrintf(pHlp,
330 "%s"
331 "%s",
332 pszMsg1,
333 pszMsg2);
334 if ( !pszMsg2
335 || !*pszMsg2
336 || strchr(pszMsg2, '\0')[-1] != '\n')
337 pHlp->pfnPrintf(pHlp, "\n");
338 }
339 RT_FALL_THRU();
340 case VERR_TRPM_DONT_PANIC:
341 case VERR_TRPM_PANIC:
342 case VINF_EM_RAW_STALE_SELECTOR:
343 case VINF_EM_RAW_IRET_TRAP:
344 case VINF_EM_DBG_HYPER_BREAKPOINT:
345 case VINF_EM_DBG_HYPER_STEPPED:
346 case VINF_EM_TRIPLE_FAULT:
347 case VERR_VMM_HYPER_CR3_MISMATCH:
348 {
349 /*
350 * Active trap? This is only of partial interest when in hardware
351 * assisted virtualization mode, thus the different messages.
352 */
353 uint32_t uEIP = CPUMGetHyperEIP(pVCpu);
354 TRPMEVENT enmType;
355 uint8_t u8TrapNo = 0xce;
356 RTGCUINT uErrorCode = 0xdeadface;
357 RTGCUINTPTR uCR2 = 0xdeadface;
358 uint8_t cbInstr = UINT8_MAX;
359 int rc2 = TRPMQueryTrapAll(pVCpu, &u8TrapNo, &enmType, &uErrorCode, &uCR2, &cbInstr);
360 if (VM_IS_RAW_MODE_ENABLED(pVM))
361 {
362 if (RT_SUCCESS(rc2))
363 pHlp->pfnPrintf(pHlp,
364 "!! TRAP=%02x ERRCD=%RGv CR2=%RGv EIP=%RX32 Type=%d cbInstr=%02x\n",
365 u8TrapNo, uErrorCode, uCR2, uEIP, enmType, cbInstr);
366 else
367 pHlp->pfnPrintf(pHlp,
368 "!! EIP=%RX32 NOTRAP\n",
369 uEIP);
370 }
371 else if (RT_SUCCESS(rc2))
372 pHlp->pfnPrintf(pHlp,
373 "!! ACTIVE TRAP=%02x ERRCD=%RGv CR2=%RGv PC=%RGr Type=%d cbInstr=%02x (Guest!)\n",
374 u8TrapNo, uErrorCode, uCR2, CPUMGetGuestRIP(pVCpu), enmType, cbInstr);
375
376 /*
377 * Dump the relevant hypervisor registers and stack.
378 */
379 if (!VM_IS_RAW_MODE_ENABLED(pVM))
380 {
381 if ( rcErr == VERR_VMM_RING0_ASSERTION /* fInRing3Call has already been cleared here. */
382 || pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call)
383 {
384 /* Dump the jmpbuf. */
385 pHlp->pfnPrintf(pHlp,
386 "!!\n"
387 "!! CallRing3JmpBuf:\n"
388 "!!\n");
389 pHlp->pfnPrintf(pHlp,
390 "SavedEsp=%RHv SavedEbp=%RHv SpResume=%RHv SpCheck=%RHv\n",
391 pVCpu->vmm.s.CallRing3JmpBufR0.SavedEsp,
392 pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp,
393 pVCpu->vmm.s.CallRing3JmpBufR0.SpResume,
394 pVCpu->vmm.s.CallRing3JmpBufR0.SpCheck);
395 pHlp->pfnPrintf(pHlp,
396 "pvSavedStack=%RHv cbSavedStack=%#x fInRing3Call=%RTbool\n",
397 pVCpu->vmm.s.CallRing3JmpBufR0.pvSavedStack,
398 pVCpu->vmm.s.CallRing3JmpBufR0.cbSavedStack,
399 pVCpu->vmm.s.CallRing3JmpBufR0.fInRing3Call);
400 pHlp->pfnPrintf(pHlp,
401 "cbUsedMax=%#x cbUsedAvg=%#x cbUsedTotal=%#llx cUsedTotal=%#llx\n",
402 pVCpu->vmm.s.CallRing3JmpBufR0.cbUsedMax,
403 pVCpu->vmm.s.CallRing3JmpBufR0.cbUsedAvg,
404 pVCpu->vmm.s.CallRing3JmpBufR0.cbUsedTotal,
405 pVCpu->vmm.s.CallRing3JmpBufR0.cUsedTotal);
406
407 /* Dump the resume register frame on the stack. */
408 PRTHCUINTPTR pBP;
409#ifdef VMM_R0_SWITCH_STACK
410 pBP = (PRTHCUINTPTR)&pVCpu->vmm.s.pbEMTStackR3[ pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp
411 - MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3)];
412#else
413 pBP = (PRTHCUINTPTR)&pVCpu->vmm.s.pbEMTStackR3[ pVCpu->vmm.s.CallRing3JmpBufR0.cbSavedStack
414 - pVCpu->vmm.s.CallRing3JmpBufR0.SpCheck
415 + pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp];
416#endif
417#if HC_ARCH_BITS == 32
418 pHlp->pfnPrintf(pHlp,
419 "eax=volatile ebx=%08x ecx=volatile edx=volatile esi=%08x edi=%08x\n"
420 "eip=%08x esp=%08x ebp=%08x efl=%08x\n"
421 ,
422 pBP[-3], pBP[-2], pBP[-1],
423 pBP[1], pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp - 8, pBP[0], pBP[-4]);
424#else
425# ifdef RT_OS_WINDOWS
426 pHlp->pfnPrintf(pHlp,
427 "rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
428 "rsi=%016RX64 rdi=%016RX64 r8=volatile r9=volatile \n"
429 "r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
430 "r14=%016RX64 r15=%016RX64\n"
431 "rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rfl=%08RX64\n"
432 ,
433 pBP[-7],
434 pBP[-6], pBP[-5],
435 pBP[-4], pBP[-3],
436 pBP[-2], pBP[-1],
437 pBP[1], pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp - 16, pBP[0], pBP[-8]);
438# else
439 pHlp->pfnPrintf(pHlp,
440 "rax=volatile rbx=%016RX64 rcx=volatile rdx=volatile\n"
441 "rsi=volatile rdi=volatile r8=volatile r9=volatile \n"
442 "r10=volatile r11=volatile r12=%016RX64 r13=%016RX64\n"
443 "r14=%016RX64 r15=%016RX64\n"
444 "rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rflags=%08RX64\n"
445 ,
446 pBP[-5],
447 pBP[-4], pBP[-3],
448 pBP[-2], pBP[-1],
449 pBP[1], pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp - 16, pBP[0], pBP[-6]);
450# endif
451#endif
452
453 /* Callstack. */
454 DBGFADDRESS pc;
455 pc.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
456#if HC_ARCH_BITS == 64
457 pc.FlatPtr = pc.off = pVCpu->vmm.s.CallRing3JmpBufR0.rip;
458#else
459 pc.FlatPtr = pc.off = pVCpu->vmm.s.CallRing3JmpBufR0.eip;
460#endif
461 pc.Sel = DBGF_SEL_FLAT;
462
463 DBGFADDRESS ebp;
464 ebp.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
465 ebp.FlatPtr = ebp.off = pVCpu->vmm.s.CallRing3JmpBufR0.SavedEbp;
466 ebp.Sel = DBGF_SEL_FLAT;
467
468 DBGFADDRESS esp;
469 esp.fFlags = DBGFADDRESS_FLAGS_RING0 | DBGFADDRESS_FLAGS_VALID;
470 esp.Sel = DBGF_SEL_FLAT;
471 esp.FlatPtr = esp.off = pVCpu->vmm.s.CallRing3JmpBufR0.SavedEsp;
472
473 PCDBGFSTACKFRAME pFirstFrame;
474 rc2 = DBGFR3StackWalkBeginEx(pVM->pUVM, pVCpu->idCpu, DBGFCODETYPE_RING0, &ebp, &esp, &pc,
475 RTDBGRETURNTYPE_INVALID, &pFirstFrame);
476 if (RT_SUCCESS(rc2))
477 {
478 pHlp->pfnPrintf(pHlp,
479 "!!\n"
480 "!! Call Stack:\n"
481 "!!\n");
482#if HC_ARCH_BITS == 32
483 pHlp->pfnPrintf(pHlp, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
484#else
485 pHlp->pfnPrintf(pHlp, "RBP Ret RBP Ret RIP RIP Symbol [line]\n");
486#endif
487 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
488 pFrame;
489 pFrame = DBGFR3StackWalkNext(pFrame))
490 {
491#if HC_ARCH_BITS == 32
492 pHlp->pfnPrintf(pHlp,
493 "%RHv %RHv %04RX32:%RHv %RHv %RHv %RHv %RHv",
494 (RTHCUINTPTR)pFrame->AddrFrame.off,
495 (RTHCUINTPTR)pFrame->AddrReturnFrame.off,
496 (RTHCUINTPTR)pFrame->AddrReturnPC.Sel,
497 (RTHCUINTPTR)pFrame->AddrReturnPC.off,
498 pFrame->Args.au32[0],
499 pFrame->Args.au32[1],
500 pFrame->Args.au32[2],
501 pFrame->Args.au32[3]);
502 pHlp->pfnPrintf(pHlp, " %RTsel:%08RHv", pFrame->AddrPC.Sel, pFrame->AddrPC.off);
503#else
504 pHlp->pfnPrintf(pHlp,
505 "%RHv %RHv %RHv %RHv",
506 (RTHCUINTPTR)pFrame->AddrFrame.off,
507 (RTHCUINTPTR)pFrame->AddrReturnFrame.off,
508 (RTHCUINTPTR)pFrame->AddrReturnPC.off,
509 (RTHCUINTPTR)pFrame->AddrPC.off);
510#endif
511 if (pFrame->pSymPC)
512 {
513 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value;
514 if (offDisp > 0)
515 pHlp->pfnPrintf(pHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
516 else if (offDisp < 0)
517 pHlp->pfnPrintf(pHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
518 else
519 pHlp->pfnPrintf(pHlp, " %s", pFrame->pSymPC->szName);
520 }
521 if (pFrame->pLinePC)
522 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
523 pHlp->pfnPrintf(pHlp, "\n");
524 }
525 DBGFR3StackWalkEnd(pFirstFrame);
526 }
527
528 /* Symbols on the stack. */
529#ifdef VMM_R0_SWITCH_STACK
530 uint32_t const iLast = VMM_STACK_SIZE / sizeof(uintptr_t);
531 uint32_t iAddr = (uint32_t)( pVCpu->vmm.s.CallRing3JmpBufR0.SavedEsp
532 - MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3)) / sizeof(uintptr_t);
533 if (iAddr > iLast)
534 iAddr = 0;
535#else
536 uint32_t const iLast = RT_MIN(pVCpu->vmm.s.CallRing3JmpBufR0.cbSavedStack, VMM_STACK_SIZE)
537 / sizeof(uintptr_t);
538 uint32_t iAddr = 0;
539#endif
540 pHlp->pfnPrintf(pHlp,
541 "!!\n"
542 "!! Addresses on the stack (iAddr=%#x, iLast=%#x)\n"
543 "!!\n",
544 iAddr, iLast);
545 uintptr_t const *paAddr = (uintptr_t const *)pVCpu->vmm.s.pbEMTStackR3;
546 while (iAddr < iLast)
547 {
548 uintptr_t const uAddr = paAddr[iAddr];
549 if (uAddr > X86_PAGE_SIZE)
550 {
551 DBGFADDRESS Addr;
552 DBGFR3AddrFromFlat(pVM->pUVM, &Addr, uAddr);
553 RTGCINTPTR offDisp = 0;
554 PRTDBGSYMBOL pSym = DBGFR3AsSymbolByAddrA(pVM->pUVM, DBGF_AS_R0, &Addr,
555 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL | RTDBGSYMADDR_FLAGS_SKIP_ABS_IN_DEFERRED,
556 &offDisp, NULL);
557 RTGCINTPTR offLineDisp;
558 PRTDBGLINE pLine = DBGFR3AsLineByAddrA(pVM->pUVM, DBGF_AS_R0, &Addr, &offLineDisp, NULL);
559 if (pLine || pSym)
560 {
561 pHlp->pfnPrintf(pHlp, "%#06x: %p =>", iAddr * sizeof(uintptr_t), uAddr);
562 if (pSym)
563 pHlp->pfnPrintf(pHlp, " %s + %#x", pSym->szName, (intptr_t)offDisp);
564 if (pLine)
565 pHlp->pfnPrintf(pHlp, " [%s:%u + %#x]\n", pLine->szFilename, pLine->uLineNo, offLineDisp);
566 else
567 pHlp->pfnPrintf(pHlp, "\n");
568 RTDbgSymbolFree(pSym);
569 RTDbgLineFree(pLine);
570 }
571 }
572 iAddr++;
573 }
574
575 /* raw stack */
576 Hlp.fRecSummary = false;
577 pHlp->pfnPrintf(pHlp,
578 "!!\n"
579 "!! Raw stack (mind the direction).\n"
580 "!! pbEMTStackR0=%RHv pbEMTStackBottomR0=%RHv VMM_STACK_SIZE=%#x\n"
581 "!! pbEmtStackR3=%p\n"
582 "!!\n"
583 "%.*Rhxd\n",
584 MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3),
585 MMHyperCCToR0(pVM, pVCpu->vmm.s.pbEMTStackR3) + VMM_STACK_SIZE,
586 VMM_STACK_SIZE,
587 pVCpu->vmm.s.pbEMTStackR3,
588 VMM_STACK_SIZE, pVCpu->vmm.s.pbEMTStackR3);
589 }
590 else
591 {
592 pHlp->pfnPrintf(pHlp,
593 "!! Skipping ring-0 registers and stack, rcErr=%Rrc\n", rcErr);
594 }
595 }
596 else
597 {
598 /*
599 * Try figure out where eip is.
600 */
601 /* core code? */
602 if (uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC < pVM->vmm.s.cbCoreCode)
603 pHlp->pfnPrintf(pHlp,
604 "!! EIP is in CoreCode, offset %#x\n",
605 uEIP - (RTGCUINTPTR)pVM->vmm.s.pvCoreCodeRC);
606 else
607 { /* ask PDM */ /** @todo ask DBGFR3Sym later? */
608 char szModName[64];
609 RTRCPTR RCPtrMod;
610 char szNearSym1[260];
611 RTRCPTR RCPtrNearSym1;
612 char szNearSym2[260];
613 RTRCPTR RCPtrNearSym2;
614 int rc = PDMR3LdrQueryRCModFromPC(pVM, uEIP,
615 &szModName[0], sizeof(szModName), &RCPtrMod,
616 &szNearSym1[0], sizeof(szNearSym1), &RCPtrNearSym1,
617 &szNearSym2[0], sizeof(szNearSym2), &RCPtrNearSym2);
618 if (RT_SUCCESS(rc))
619 pHlp->pfnPrintf(pHlp,
620 "!! EIP in %s (%RRv) at rva %x near symbols:\n"
621 "!! %RRv rva %RRv off %08x %s\n"
622 "!! %RRv rva %RRv off -%08x %s\n",
623 szModName, RCPtrMod, (unsigned)(uEIP - RCPtrMod),
624 RCPtrNearSym1, RCPtrNearSym1 - RCPtrMod, (unsigned)(uEIP - RCPtrNearSym1), szNearSym1,
625 RCPtrNearSym2, RCPtrNearSym2 - RCPtrMod, (unsigned)(RCPtrNearSym2 - uEIP), szNearSym2);
626 else
627 pHlp->pfnPrintf(pHlp,
628 "!! EIP is not in any code known to VMM!\n");
629 }
630
631 /* Disassemble the instruction. */
632 char szInstr[256];
633 rc2 = DBGFR3DisasInstrEx(pVM->pUVM, pVCpu->idCpu, 0, 0,
634 DBGF_DISAS_FLAGS_CURRENT_HYPER | DBGF_DISAS_FLAGS_DEFAULT_MODE,
635 &szInstr[0], sizeof(szInstr), NULL);
636 if (RT_SUCCESS(rc2))
637 pHlp->pfnPrintf(pHlp,
638 "!! %s\n", szInstr);
639
640 /* Dump the hypervisor cpu state. */
641 pHlp->pfnPrintf(pHlp,
642 "!!\n"
643 "!!\n"
644 "!!\n");
645 rc2 = DBGFR3Info(pVM->pUVM, "cpumhyper", "verbose", pHlp);
646 fDoneHyper = true;
647
648 /* Callstack. */
649 PCDBGFSTACKFRAME pFirstFrame;
650 rc2 = DBGFR3StackWalkBegin(pVM->pUVM, pVCpu->idCpu, DBGFCODETYPE_HYPER, &pFirstFrame);
651 if (RT_SUCCESS(rc2))
652 {
653 pHlp->pfnPrintf(pHlp,
654 "!!\n"
655 "!! Call Stack:\n"
656 "!!\n"
657 "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP Symbol [line]\n");
658 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
659 pFrame;
660 pFrame = DBGFR3StackWalkNext(pFrame))
661 {
662 pHlp->pfnPrintf(pHlp,
663 "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
664 (uint32_t)pFrame->AddrFrame.off,
665 (uint32_t)pFrame->AddrReturnFrame.off,
666 (uint32_t)pFrame->AddrReturnPC.Sel,
667 (uint32_t)pFrame->AddrReturnPC.off,
668 pFrame->Args.au32[0],
669 pFrame->Args.au32[1],
670 pFrame->Args.au32[2],
671 pFrame->Args.au32[3]);
672 pHlp->pfnPrintf(pHlp, " %RTsel:%08RGv", pFrame->AddrPC.Sel, pFrame->AddrPC.off);
673 if (pFrame->pSymPC)
674 {
675 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value;
676 if (offDisp > 0)
677 pHlp->pfnPrintf(pHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
678 else if (offDisp < 0)
679 pHlp->pfnPrintf(pHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
680 else
681 pHlp->pfnPrintf(pHlp, " %s", pFrame->pSymPC->szName);
682 }
683 if (pFrame->pLinePC)
684 pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
685 pHlp->pfnPrintf(pHlp, "\n");
686 }
687 DBGFR3StackWalkEnd(pFirstFrame);
688 }
689
690 /* raw stack */
691 Hlp.fRecSummary = false;
692 pHlp->pfnPrintf(pHlp,
693 "!!\n"
694 "!! Raw stack (mind the direction). pbEMTStackRC=%RRv pbEMTStackBottomRC=%RRv\n"
695 "!!\n"
696 "%.*Rhxd\n",
697 pVCpu->vmm.s.pbEMTStackRC, pVCpu->vmm.s.pbEMTStackBottomRC,
698 VMM_STACK_SIZE, pVCpu->vmm.s.pbEMTStackR3);
699 } /* !HMIsEnabled */
700 break;
701 }
702
703 case VERR_IEM_INSTR_NOT_IMPLEMENTED:
704 case VERR_IEM_ASPECT_NOT_IMPLEMENTED:
705 case VERR_PATM_IPE_TRAP_IN_PATCH_CODE:
706 case VERR_EM_GUEST_CPU_HANG:
707 {
708 CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_ABSOLUTELY_ALL);
709 fDoneImport = true;
710
711 DBGFR3Info(pVM->pUVM, "cpumguest", NULL, pHlp);
712 DBGFR3Info(pVM->pUVM, "cpumguestinstr", NULL, pHlp);
713 DBGFR3Info(pVM->pUVM, "cpumguesthwvirt", NULL, pHlp);
714 break;
715 }
716
717 default:
718 {
719 break;
720 }
721
722 } /* switch (rcErr) */
723 Hlp.fRecSummary = false;
724
725
726 /*
727 * Generic info dumper loop.
728 */
729 if (!fDoneImport)
730 CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_ABSOLUTELY_ALL);
731 static struct
732 {
733 const char *pszInfo;
734 const char *pszArgs;
735 } const aInfo[] =
736 {
737 { "mappings", NULL },
738 { "hma", NULL },
739 { "cpumguest", "verbose" },
740 { "cpumguesthwvirt", "verbose" },
741 { "cpumguestinstr", "verbose" },
742 { "cpumhyper", "verbose" },
743 { "cpumhost", "verbose" },
744 { "mode", "all" },
745 { "cpuid", "verbose" },
746 { "handlers", "phys virt hyper stats" },
747 { "timers", NULL },
748 { "activetimers", NULL },
749 };
750 for (unsigned i = 0; i < RT_ELEMENTS(aInfo); i++)
751 {
752 if (fDoneHyper && !strcmp(aInfo[i].pszInfo, "cpumhyper"))
753 continue;
754 pHlp->pfnPrintf(pHlp,
755 "!!\n"
756 "!! {%s, %s}\n"
757 "!!\n",
758 aInfo[i].pszInfo, aInfo[i].pszArgs);
759 DBGFR3Info(pVM->pUVM, aInfo[i].pszInfo, aInfo[i].pszArgs, pHlp);
760 }
761
762 /* All other info items */
763 DBGFR3InfoMulti(pVM,
764 "*",
765 "mappings|hma|cpum|cpumguest|cpumguesthwvirt|cpumguestinstr|cpumhyper|cpumhost|mode|cpuid"
766 "|pgmpd|pgmcr3|timers|activetimers|handlers|help|exithistory",
767 "!!\n"
768 "!! {%s}\n"
769 "!!\n",
770 pHlp);
771
772
773 /* done */
774 pHlp->pfnPrintf(pHlp,
775 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
776
777
778 /*
779 * Repeat the summary to stderr so we don't have to scroll half a mile up.
780 */
781 vmmR3FatalDumpInfoHlpFlushStdErr(&Hlp);
782 if (Hlp.szSummary[0])
783 RTStrmPrintf(g_pStdErr,
784 "%s"
785 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
786 Hlp.szSummary);
787
788 /*
789 * Delete the output instance (flushing and restoring of flags).
790 */
791 vmmR3FatalDumpInfoHlpDelete(&Hlp);
792}
793
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette