VirtualBox

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

Last change on this file since 45841 was 45753, checked in by vboxsync, 12 years ago

Don't call MMHyperIsInsideArea if we're using HM to execute code, it will return bogus results!

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