VirtualBox

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

Last change on this file since 46159 was 46159, checked in by vboxsync, 11 years ago

Patch manager support in the disassembler, making the 'u' command in the debugger always show unpatched instruction and annoate those instructions which have patches associated with them (in any state).

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