VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFDisas.cpp@ 39333

Last change on this file since 39333 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.1 KB
Line 
1/* $Id: DBGFDisas.cpp 38838 2011-09-23 11:21:55Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Disassembler.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DBGF
22#include <VBox/vmm/dbgf.h>
23#include <VBox/vmm/selm.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/cpum.h>
27#include "DBGFInternal.h"
28#include <VBox/dis.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31#include <VBox/vmm/vm.h>
32#include "internal/pgm.h"
33
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37#include <iprt/alloca.h>
38#include <iprt/ctype.h>
39
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44/**
45 * Structure used when disassembling and instructions in DBGF.
46 * This is used so the reader function can get the stuff it needs.
47 */
48typedef struct
49{
50 /** The core structure. */
51 DISCPUSTATE Cpu;
52 /** The VM handle. */
53 PVM pVM;
54 /** The VMCPU handle. */
55 PVMCPU pVCpu;
56 /** The address space for resolving symbol. */
57 RTDBGAS hAs;
58 /** Pointer to the first byte in the segment. */
59 RTGCUINTPTR GCPtrSegBase;
60 /** Pointer to the byte after the end of the segment. (might have wrapped!) */
61 RTGCUINTPTR GCPtrSegEnd;
62 /** The size of the segment minus 1. */
63 RTGCUINTPTR cbSegLimit;
64 /** The guest paging mode. */
65 PGMMODE enmMode;
66 /** Pointer to the current page - R3 Ptr. */
67 void const *pvPageR3;
68 /** Pointer to the current page - GC Ptr. */
69 RTGCPTR pvPageGC;
70 /** Pointer to the next instruction (relative to GCPtrSegBase). */
71 RTGCUINTPTR GCPtrNext;
72 /** The lock information that PGMPhysReleasePageMappingLock needs. */
73 PGMPAGEMAPLOCK PageMapLock;
74 /** Whether the PageMapLock is valid or not. */
75 bool fLocked;
76 /** 64 bits mode or not. */
77 bool f64Bits;
78} DBGFDISASSTATE, *PDBGFDISASSTATE;
79
80
81/*******************************************************************************
82* Internal Functions *
83*******************************************************************************/
84static DECLCALLBACK(int) dbgfR3DisasInstrRead(RTUINTPTR pSrc, uint8_t *pDest, uint32_t size, void *pvUserdata);
85
86
87
88/**
89 * Calls the disassembler with the proper reader functions and such for disa
90 *
91 * @returns VBox status code.
92 * @param pVM VM handle
93 * @param pVCpu VMCPU handle
94 * @param pSelInfo The selector info.
95 * @param enmMode The guest paging mode.
96 * @param fFlags DBGF_DISAS_FLAGS_XXX.
97 * @param GCPtr The GC pointer (selector offset).
98 * @param pState The disas CPU state.
99 */
100static int dbgfR3DisasInstrFirst(PVM pVM, PVMCPU pVCpu, PDBGFSELINFO pSelInfo, PGMMODE enmMode,
101 RTGCPTR GCPtr, uint32_t fFlags, PDBGFDISASSTATE pState)
102{
103 pState->GCPtrSegBase = pSelInfo->GCPtrBase;
104 pState->GCPtrSegEnd = pSelInfo->cbLimit + 1 + (RTGCUINTPTR)pSelInfo->GCPtrBase;
105 pState->cbSegLimit = pSelInfo->cbLimit;
106 pState->enmMode = enmMode;
107 pState->pvPageGC = 0;
108 pState->pvPageR3 = NULL;
109 pState->hAs = pSelInfo->fFlags & DBGFSELINFO_FLAGS_HYPER /** @todo Deal more explicitly with RC in DBGFR3Disas*. */
110 ? DBGF_AS_RC_AND_GC_GLOBAL
111 : DBGF_AS_GLOBAL;
112 pState->pVM = pVM;
113 pState->pVCpu = pVCpu;
114 pState->fLocked = false;
115 pState->f64Bits = enmMode >= PGMMODE_AMD64 && pSelInfo->u.Raw.Gen.u1Long;
116
117 DISCPUMODE enmCpuMode;
118 switch (fFlags & DBGF_DISAS_FLAGS_MODE_MASK)
119 {
120 default:
121 AssertFailed();
122 case DBGF_DISAS_FLAGS_DEFAULT_MODE:
123 enmCpuMode = pState->f64Bits
124 ? CPUMODE_64BIT
125 : pSelInfo->u.Raw.Gen.u1DefBig
126 ? CPUMODE_32BIT
127 : CPUMODE_16BIT;
128 break;
129 case DBGF_DISAS_FLAGS_16BIT_MODE:
130 case DBGF_DISAS_FLAGS_16BIT_REAL_MODE:
131 enmCpuMode = CPUMODE_16BIT;
132 break;
133 case DBGF_DISAS_FLAGS_32BIT_MODE:
134 enmCpuMode = CPUMODE_32BIT;
135 break;
136 case DBGF_DISAS_FLAGS_64BIT_MODE:
137 enmCpuMode = CPUMODE_64BIT;
138 break;
139 }
140
141 uint32_t cbInstr;
142 int rc = DISCoreOneEx(GCPtr,
143 enmCpuMode,
144 dbgfR3DisasInstrRead,
145 &pState->Cpu,
146 &pState->Cpu,
147 &cbInstr);
148 if (RT_SUCCESS(rc))
149 {
150 pState->GCPtrNext = GCPtr + cbInstr;
151 return VINF_SUCCESS;
152 }
153
154 /* cleanup */
155 if (pState->fLocked)
156 {
157 PGMPhysReleasePageMappingLock(pVM, &pState->PageMapLock);
158 pState->fLocked = false;
159 }
160 return rc;
161}
162
163
164#if 0
165/**
166 * Calls the disassembler for disassembling the next instruction.
167 *
168 * @returns VBox status code.
169 * @param pState The disas CPU state.
170 */
171static int dbgfR3DisasInstrNext(PDBGFDISASSTATE pState)
172{
173 uint32_t cbInstr;
174 int rc = DISInstr(&pState->Cpu, (void *)pState->GCPtrNext, 0, &cbInstr, NULL);
175 if (RT_SUCCESS(rc))
176 {
177 pState->GCPtrNext = GCPtr + cbInstr;
178 return VINF_SUCCESS;
179 }
180 return rc;
181}
182#endif
183
184
185/**
186 * Done with the disassembler state, free associated resources.
187 *
188 * @param pState The disas CPU state ++.
189 */
190static void dbgfR3DisasInstrDone(PDBGFDISASSTATE pState)
191{
192 if (pState->fLocked)
193 {
194 PGMPhysReleasePageMappingLock(pState->pVM, &pState->PageMapLock);
195 pState->fLocked = false;
196 }
197}
198
199
200/**
201 * Instruction reader.
202 *
203 * @returns VBox status code. (Why this is a int32_t and not just an int is also beyond me.)
204 * @param PtrSrc Address to read from.
205 * In our case this is relative to the selector pointed to by the 2nd user argument of uDisCpu.
206 * @param pu8Dst Where to store the bytes.
207 * @param cbRead Number of bytes to read.
208 * @param uDisCpu Pointer to the disassembler cpu state. (Why this is a VBOXHUINTPTR is beyond me...)
209 * In this context it's always pointer to the Core of a DBGFDISASSTATE.
210 */
211static DECLCALLBACK(int) dbgfR3DisasInstrRead(RTUINTPTR PtrSrc, uint8_t *pu8Dst, uint32_t cbRead, void *pvDisCpu)
212{
213 PDBGFDISASSTATE pState = (PDBGFDISASSTATE)pvDisCpu;
214 Assert(cbRead > 0);
215 for (;;)
216 {
217 RTGCUINTPTR GCPtr = PtrSrc + pState->GCPtrSegBase;
218
219 /* Need to update the page translation? */
220 if ( !pState->pvPageR3
221 || (GCPtr >> PAGE_SHIFT) != (pState->pvPageGC >> PAGE_SHIFT))
222 {
223 int rc = VINF_SUCCESS;
224
225 /* translate the address */
226 pState->pvPageGC = GCPtr & PAGE_BASE_GC_MASK;
227 if (MMHyperIsInsideArea(pState->pVM, pState->pvPageGC))
228 {
229 pState->pvPageR3 = MMHyperRCToR3(pState->pVM, (RTRCPTR)pState->pvPageGC);
230 if (!pState->pvPageR3)
231 rc = VERR_INVALID_POINTER;
232 }
233 else
234 {
235 if (pState->fLocked)
236 PGMPhysReleasePageMappingLock(pState->pVM, &pState->PageMapLock);
237
238 if (pState->enmMode <= PGMMODE_PROTECTED)
239 rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, pState->pvPageGC, &pState->pvPageR3, &pState->PageMapLock);
240 else
241 rc = PGMPhysGCPtr2CCPtrReadOnly(pState->pVCpu, pState->pvPageGC, &pState->pvPageR3, &pState->PageMapLock);
242 pState->fLocked = RT_SUCCESS_NP(rc);
243 }
244 if (RT_FAILURE(rc))
245 {
246 pState->pvPageR3 = NULL;
247 return rc;
248 }
249 }
250
251 /* check the segment limit */
252 if (!pState->f64Bits && PtrSrc > pState->cbSegLimit)
253 return VERR_OUT_OF_SELECTOR_BOUNDS;
254
255 /* calc how much we can read */
256 uint32_t cb = PAGE_SIZE - (GCPtr & PAGE_OFFSET_MASK);
257 if (!pState->f64Bits)
258 {
259 RTGCUINTPTR cbSeg = pState->GCPtrSegEnd - GCPtr;
260 if (cb > cbSeg && cbSeg)
261 cb = cbSeg;
262 }
263 if (cb > cbRead)
264 cb = cbRead;
265
266 /* read and advance */
267 memcpy(pu8Dst, (char *)pState->pvPageR3 + (GCPtr & PAGE_OFFSET_MASK), cb);
268 cbRead -= cb;
269 if (!cbRead)
270 return VINF_SUCCESS;
271 pu8Dst += cb;
272 PtrSrc += cb;
273 }
274}
275
276
277/**
278 * @copydoc FNDISGETSYMBOL
279 */
280static DECLCALLBACK(int) dbgfR3DisasGetSymbol(PCDISCPUSTATE pCpu, uint32_t u32Sel, RTUINTPTR uAddress, char *pszBuf, size_t cchBuf, RTINTPTR *poff, void *pvUser)
281{
282 PDBGFDISASSTATE pState = (PDBGFDISASSTATE)pCpu;
283 PCDBGFSELINFO pSelInfo = (PCDBGFSELINFO)pvUser;
284 DBGFADDRESS Addr;
285 RTDBGSYMBOL Sym;
286 RTGCINTPTR off;
287 int rc;
288
289 if ( DIS_FMT_SEL_IS_REG(u32Sel)
290 ? DIS_FMT_SEL_GET_REG(u32Sel) == DIS_SELREG_CS
291 : pSelInfo->Sel == DIS_FMT_SEL_GET_VALUE(u32Sel))
292 {
293 rc = DBGFR3AddrFromSelInfoOff(pState->pVM, &Addr, pSelInfo, uAddress);
294 if (RT_SUCCESS(rc))
295 rc = DBGFR3AsSymbolByAddr(pState->pVM, pState->hAs, &Addr, &off, &Sym, NULL /*phMod*/);
296 }
297 else
298 rc = VERR_SYMBOL_NOT_FOUND; /** @todo implement this */
299 if (RT_SUCCESS(rc))
300 {
301 size_t cchName = strlen(Sym.szName);
302 if (cchName >= cchBuf)
303 cchName = cchBuf - 1;
304 memcpy(pszBuf, Sym.szName, cchName);
305 pszBuf[cchName] = '\0';
306
307 *poff = off;
308 }
309
310 return rc;
311}
312
313
314/**
315 * Disassembles the one instruction according to the specified flags and
316 * address, internal worker executing on the EMT of the specified virtual CPU.
317 *
318 * @returns VBox status code.
319 * @param pVM The VM handle.
320 * @param pVCpu The virtual CPU handle.
321 * @param Sel The code selector. This used to determine the 32/16 bit ness and
322 * calculation of the actual instruction address.
323 * @param pGCPtr Pointer to the variable holding the code address
324 * relative to the base of Sel.
325 * @param fFlags Flags controlling where to start and how to format.
326 * A combination of the DBGF_DISAS_FLAGS_* \#defines.
327 * @param pszOutput Output buffer.
328 * @param cbOutput Size of the output buffer.
329 * @param pcbInstr Where to return the size of the instruction.
330 */
331static DECLCALLBACK(int)
332dbgfR3DisasInstrExOnVCpu(PVM pVM, PVMCPU pVCpu, RTSEL Sel, PRTGCPTR pGCPtr, uint32_t fFlags,
333 char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr)
334{
335 VMCPU_ASSERT_EMT(pVCpu);
336 RTGCPTR GCPtr = *pGCPtr;
337
338 /*
339 * Get the Sel and GCPtr if fFlags requests that.
340 */
341 PCCPUMCTXCORE pCtxCore = NULL;
342 PCPUMSELREGHID pHiddenSel = NULL;
343 int rc;
344 if (fFlags & (DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER))
345 {
346 if (fFlags & DBGF_DISAS_FLAGS_CURRENT_GUEST)
347 pCtxCore = CPUMGetGuestCtxCore(pVCpu);
348 else
349 pCtxCore = CPUMGetHyperCtxCore(pVCpu);
350 Sel = pCtxCore->cs;
351 pHiddenSel = (CPUMSELREGHID *)&pCtxCore->csHid;
352 GCPtr = pCtxCore->rip;
353 }
354
355 /*
356 * Read the selector info - assume no stale selectors and nasty stuff like that.
357 * Since the selector flags in the CPUMCTX structures aren't up to date unless
358 * we recently visited REM, we'll not search for the selector there.
359 */
360 DBGFSELINFO SelInfo;
361 const PGMMODE enmMode = PGMGetGuestMode(pVCpu);
362 bool fRealModeAddress = false;
363
364 if ( pHiddenSel
365 && ( (fFlags & DBGF_DISAS_FLAGS_HID_SEL_REGS_VALID)
366 || CPUMAreHiddenSelRegsValid(pVCpu)))
367 {
368 SelInfo.Sel = Sel;
369 SelInfo.SelGate = 0;
370 SelInfo.GCPtrBase = pHiddenSel->u64Base;
371 SelInfo.cbLimit = pHiddenSel->u32Limit;
372 SelInfo.fFlags = PGMMODE_IS_LONG_MODE(enmMode)
373 ? DBGFSELINFO_FLAGS_LONG_MODE
374 : enmMode != PGMMODE_REAL && (!pCtxCore || !pCtxCore->eflags.Bits.u1VM)
375 ? DBGFSELINFO_FLAGS_PROT_MODE
376 : DBGFSELINFO_FLAGS_REAL_MODE;
377
378 SelInfo.u.Raw.au32[0] = 0;
379 SelInfo.u.Raw.au32[1] = 0;
380 SelInfo.u.Raw.Gen.u16LimitLow = 0xffff;
381 SelInfo.u.Raw.Gen.u4LimitHigh = 0xf;
382 SelInfo.u.Raw.Gen.u1Present = pHiddenSel->Attr.n.u1Present;
383 SelInfo.u.Raw.Gen.u1Granularity = pHiddenSel->Attr.n.u1Granularity;;
384 SelInfo.u.Raw.Gen.u1DefBig = pHiddenSel->Attr.n.u1DefBig;
385 SelInfo.u.Raw.Gen.u1Long = pHiddenSel->Attr.n.u1Long;
386 SelInfo.u.Raw.Gen.u1DescType = pHiddenSel->Attr.n.u1DescType;
387 SelInfo.u.Raw.Gen.u4Type = pHiddenSel->Attr.n.u4Type;
388 fRealModeAddress = !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_REAL_MODE);
389 }
390 else if (Sel == DBGF_SEL_FLAT)
391 {
392 SelInfo.Sel = Sel;
393 SelInfo.SelGate = 0;
394 SelInfo.GCPtrBase = 0;
395 SelInfo.cbLimit = ~0;
396 SelInfo.fFlags = PGMMODE_IS_LONG_MODE(enmMode)
397 ? DBGFSELINFO_FLAGS_LONG_MODE
398 : enmMode != PGMMODE_REAL
399 ? DBGFSELINFO_FLAGS_PROT_MODE
400 : DBGFSELINFO_FLAGS_REAL_MODE;
401 SelInfo.u.Raw.au32[0] = 0;
402 SelInfo.u.Raw.au32[1] = 0;
403 SelInfo.u.Raw.Gen.u16LimitLow = 0xffff;
404 SelInfo.u.Raw.Gen.u4LimitHigh = 0xf;
405
406 if ( (fFlags & DBGF_DISAS_FLAGS_HID_SEL_REGS_VALID)
407 || CPUMAreHiddenSelRegsValid(pVCpu))
408 { /* Assume the current CS defines the execution mode. */
409 pCtxCore = CPUMGetGuestCtxCore(pVCpu);
410 pHiddenSel = (CPUMSELREGHID *)&pCtxCore->csHid;
411
412 SelInfo.u.Raw.Gen.u1Present = pHiddenSel->Attr.n.u1Present;
413 SelInfo.u.Raw.Gen.u1Granularity = pHiddenSel->Attr.n.u1Granularity;;
414 SelInfo.u.Raw.Gen.u1DefBig = pHiddenSel->Attr.n.u1DefBig;
415 SelInfo.u.Raw.Gen.u1Long = pHiddenSel->Attr.n.u1Long;
416 SelInfo.u.Raw.Gen.u1DescType = pHiddenSel->Attr.n.u1DescType;
417 SelInfo.u.Raw.Gen.u4Type = pHiddenSel->Attr.n.u4Type;
418 }
419 else
420 {
421 SelInfo.u.Raw.Gen.u1Present = 1;
422 SelInfo.u.Raw.Gen.u1Granularity = 1;
423 SelInfo.u.Raw.Gen.u1DefBig = 1;
424 SelInfo.u.Raw.Gen.u1DescType = 1;
425 SelInfo.u.Raw.Gen.u4Type = X86_SEL_TYPE_EO;
426 }
427 }
428 else if ( !(fFlags & DBGF_DISAS_FLAGS_CURRENT_HYPER)
429 && ( (pCtxCore && pCtxCore->eflags.Bits.u1VM)
430 || enmMode == PGMMODE_REAL
431 || (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE
432 )
433 )
434 { /* V86 mode or real mode - real mode addressing */
435 SelInfo.Sel = Sel;
436 SelInfo.SelGate = 0;
437 SelInfo.GCPtrBase = Sel * 16;
438 SelInfo.cbLimit = ~0;
439 SelInfo.fFlags = DBGFSELINFO_FLAGS_REAL_MODE;
440 SelInfo.u.Raw.au32[0] = 0;
441 SelInfo.u.Raw.au32[1] = 0;
442 SelInfo.u.Raw.Gen.u16LimitLow = 0xffff;
443 SelInfo.u.Raw.Gen.u4LimitHigh = 0xf;
444 SelInfo.u.Raw.Gen.u1Present = 1;
445 SelInfo.u.Raw.Gen.u1Granularity = 1;
446 SelInfo.u.Raw.Gen.u1DefBig = 0; /* 16 bits */
447 SelInfo.u.Raw.Gen.u1DescType = 1;
448 SelInfo.u.Raw.Gen.u4Type = X86_SEL_TYPE_EO;
449 fRealModeAddress = true;
450 }
451 else
452 {
453 rc = SELMR3GetSelectorInfo(pVM, pVCpu, Sel, &SelInfo);
454 if (RT_FAILURE(rc))
455 {
456 RTStrPrintf(pszOutput, cbOutput, "Sel=%04x -> %Rrc\n", Sel, rc);
457 return rc;
458 }
459 }
460
461 /*
462 * Disassemble it.
463 */
464 DBGFDISASSTATE State;
465 rc = dbgfR3DisasInstrFirst(pVM, pVCpu, &SelInfo, enmMode, GCPtr, fFlags, &State);
466 if (RT_FAILURE(rc))
467 {
468 RTStrPrintf(pszOutput, cbOutput, "Disas -> %Rrc\n", rc);
469 return rc;
470 }
471
472 /*
473 * Format it.
474 */
475 char szBuf[512];
476 DISFormatYasmEx(&State.Cpu, szBuf, sizeof(szBuf),
477 DIS_FMT_FLAGS_RELATIVE_BRANCH,
478 fFlags & DBGF_DISAS_FLAGS_NO_SYMBOLS ? NULL : dbgfR3DisasGetSymbol,
479 &SelInfo);
480
481 /*
482 * Print it to the user specified buffer.
483 */
484 if (fFlags & DBGF_DISAS_FLAGS_NO_BYTES)
485 {
486 if (fFlags & DBGF_DISAS_FLAGS_NO_ADDRESS)
487 RTStrPrintf(pszOutput, cbOutput, "%s", szBuf);
488 else if (fRealModeAddress)
489 RTStrPrintf(pszOutput, cbOutput, "%04x:%04x %s", Sel, (unsigned)GCPtr, szBuf);
490 else if (Sel == DBGF_SEL_FLAT)
491 {
492 if (enmMode >= PGMMODE_AMD64)
493 RTStrPrintf(pszOutput, cbOutput, "%RGv %s", GCPtr, szBuf);
494 else
495 RTStrPrintf(pszOutput, cbOutput, "%08RX32 %s", (uint32_t)GCPtr, szBuf);
496 }
497 else
498 {
499 if (enmMode >= PGMMODE_AMD64)
500 RTStrPrintf(pszOutput, cbOutput, "%04x:%RGv %s", Sel, GCPtr, szBuf);
501 else
502 RTStrPrintf(pszOutput, cbOutput, "%04x:%08RX32 %s", Sel, (uint32_t)GCPtr, szBuf);
503 }
504 }
505 else
506 {
507 uint32_t cbBits = State.Cpu.opsize;
508 uint8_t *pau8Bits = (uint8_t *)alloca(cbBits);
509 rc = dbgfR3DisasInstrRead(GCPtr, pau8Bits, cbBits, &State);
510 AssertRC(rc);
511 if (fFlags & DBGF_DISAS_FLAGS_NO_ADDRESS)
512 RTStrPrintf(pszOutput, cbOutput, "%.*Rhxs%*s %s",
513 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
514 szBuf);
515 else if (fRealModeAddress)
516 RTStrPrintf(pszOutput, cbOutput, "%04x:%04x %.*Rhxs%*s %s",
517 Sel, (unsigned)GCPtr,
518 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
519 szBuf);
520 else if (Sel == DBGF_SEL_FLAT)
521 {
522 if (enmMode >= PGMMODE_AMD64)
523 RTStrPrintf(pszOutput, cbOutput, "%RGv %.*Rhxs%*s %s",
524 GCPtr,
525 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
526 szBuf);
527 else
528 RTStrPrintf(pszOutput, cbOutput, "%08RX32 %.*Rhxs%*s %s",
529 (uint32_t)GCPtr,
530 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
531 szBuf);
532 }
533 else
534 {
535 if (enmMode >= PGMMODE_AMD64)
536 RTStrPrintf(pszOutput, cbOutput, "%04x:%RGv %.*Rhxs%*s %s",
537 Sel, GCPtr,
538 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
539 szBuf);
540 else
541 RTStrPrintf(pszOutput, cbOutput, "%04x:%08RX32 %.*Rhxs%*s %s",
542 Sel, (uint32_t)GCPtr,
543 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
544 szBuf);
545 }
546 }
547
548 if (pcbInstr)
549 *pcbInstr = State.Cpu.opsize;
550
551 dbgfR3DisasInstrDone(&State);
552 return VINF_SUCCESS;
553}
554
555
556/**
557 * Disassembles the one instruction according to the specified flags and address.
558 *
559 * @returns VBox status code.
560 * @param pVM VM handle.
561 * @param idCpu The ID of virtual CPU.
562 * @param Sel The code selector. This used to determine the 32/16 bit ness and
563 * calculation of the actual instruction address.
564 * @param GCPtr The code address relative to the base of Sel.
565 * @param fFlags Flags controlling where to start and how to format.
566 * A combination of the DBGF_DISAS_FLAGS_* \#defines.
567 * @param pszOutput Output buffer. This will always be properly
568 * terminated if @a cbOutput is greater than zero.
569 * @param cbOutput Size of the output buffer.
570 * @param pcbInstr Where to return the size of the instruction.
571 *
572 * @remarks May have to switch to the EMT of the virtual CPU in order to do
573 * address conversion.
574 */
575VMMR3DECL(int) DBGFR3DisasInstrEx(PVM pVM, VMCPUID idCpu, RTSEL Sel, RTGCPTR GCPtr, uint32_t fFlags,
576 char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr)
577{
578 AssertReturn(cbOutput > 0, VERR_INVALID_PARAMETER);
579 *pszOutput = '\0';
580 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
581 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
582 AssertReturn(!(fFlags & ~DBGF_DISAS_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
583 AssertReturn((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) <= DBGF_DISAS_FLAGS_64BIT_MODE, VERR_INVALID_PARAMETER);
584
585 /*
586 * Optimize the common case where we're called on the EMT of idCpu since
587 * we're using this all the time when logging.
588 */
589 int rc;
590 PVMCPU pVCpu = VMMGetCpu(pVM);
591 if ( pVCpu
592 && pVCpu->idCpu == idCpu)
593 rc = dbgfR3DisasInstrExOnVCpu(pVM, pVCpu, Sel, &GCPtr, fFlags, pszOutput, cbOutput, pcbInstr);
594 else
595 rc = VMR3ReqPriorityCallWait(pVM, idCpu, (PFNRT)dbgfR3DisasInstrExOnVCpu, 8,
596 pVM, VMMGetCpuById(pVM, idCpu), Sel, &GCPtr, fFlags, pszOutput, cbOutput, pcbInstr);
597 return rc;
598}
599
600
601/**
602 * Disassembles the current guest context instruction.
603 * All registers and data will be displayed. Addresses will be attempted resolved to symbols.
604 *
605 * @returns VBox status code.
606 * @param pVCpu VMCPU handle.
607 * @param pszOutput Output buffer. This will always be properly
608 * terminated if @a cbOutput is greater than zero.
609 * @param cbOutput Size of the output buffer.
610 */
611VMMR3DECL(int) DBGFR3DisasInstrCurrent(PVMCPU pVCpu, char *pszOutput, uint32_t cbOutput)
612{
613 AssertReturn(cbOutput > 0, VERR_INVALID_PARAMETER);
614 *pszOutput = '\0';
615 AssertReturn(pVCpu, VERR_INVALID_CONTEXT);
616 return DBGFR3DisasInstrEx(pVCpu->pVMR3, pVCpu->idCpu, 0, 0,
617 DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_DEFAULT_MODE,
618 pszOutput, cbOutput, NULL);
619}
620
621
622/**
623 * Disassembles the current guest context instruction and writes it to the log.
624 * All registers and data will be displayed. Addresses will be attempted resolved to symbols.
625 *
626 * @returns VBox status code.
627 * @param pVCpu VMCPU handle.
628 * @param pszPrefix Short prefix string to the disassembly string. (optional)
629 */
630VMMR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVMCPU pVCpu, const char *pszPrefix)
631{
632 char szBuf[256];
633 szBuf[0] = '\0';
634 int rc = DBGFR3DisasInstrCurrent(pVCpu, &szBuf[0], sizeof(szBuf));
635 if (RT_FAILURE(rc))
636 RTStrPrintf(szBuf, sizeof(szBuf), "DBGFR3DisasInstrCurrentLog failed with rc=%Rrc\n", rc);
637 if (pszPrefix && *pszPrefix)
638 RTLogPrintf("%s-CPU%d: %s\n", pszPrefix, pVCpu->idCpu, szBuf);
639 else
640 RTLogPrintf("%s\n", szBuf);
641 return rc;
642}
643
644
645
646/**
647 * Disassembles the specified guest context instruction and writes it to the log.
648 * Addresses will be attempted resolved to symbols.
649 *
650 * @returns VBox status code.
651 * @param pVM VM handle.
652 * @param pVCpu The virtual CPU handle, defaults to CPU 0 if NULL.
653 * @param Sel The code selector. This used to determine the 32/16 bit-ness and
654 * calculation of the actual instruction address.
655 * @param GCPtr The code address relative to the base of Sel.
656 */
657VMMR3DECL(int) DBGFR3DisasInstrLogInternal(PVMCPU pVCpu, RTSEL Sel, RTGCPTR GCPtr)
658{
659 char szBuf[256];
660 int rc = DBGFR3DisasInstrEx(pVCpu->pVMR3, pVCpu->idCpu, Sel, GCPtr, DBGF_DISAS_FLAGS_DEFAULT_MODE,
661 &szBuf[0], sizeof(szBuf), NULL);
662 if (RT_FAILURE(rc))
663 RTStrPrintf(szBuf, sizeof(szBuf), "DBGFR3DisasInstrLog(, %RTsel, %RGv) failed with rc=%Rrc\n", Sel, GCPtr, rc);
664 RTLogPrintf("%s\n", szBuf);
665 return rc;
666}
667
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