VirtualBox

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

Last change on this file since 5040 was 5040, checked in by vboxsync, 18 years ago

GC phys/virt to HC virt functions are no longer accessible in our PDM interface.
Rewrote disassembly functions to use the mapping functions.

Code that runs in EMT (like CSAM/PATM) can still use the old conversion functions. Easier to use
and (far) less overhead.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.0 KB
Line 
1/* $Id: DBGFDisas.cpp 5040 2007-09-26 09:03:00Z vboxsync $ */
2/** @file
3 * VMM DBGF - Debugger Facility, Disassembler.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/dbgf.h>
24#include <VBox/selm.h>
25#include <VBox/mm.h>
26#include <VBox/pgm.h>
27#include "DBGFInternal.h"
28#include <VBox/dis.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31
32#include <VBox/log.h>
33#include <iprt/assert.h>
34#include <iprt/string.h>
35#include <iprt/alloca.h>
36#include <iprt/ctype.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static DECLCALLBACK(int) dbgfR3DisasInstrRead(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, void *pvUserdata);
43
44
45/**
46 * Structure used when disassembling and instructions in DBGF.
47 * This is used so the reader function can get the stuff it needs.
48 */
49typedef struct
50{
51 /** The core structure. */
52 DISCPUSTATE Cpu;
53 /** The VM handle. */
54 PVM pVM;
55 /** Pointer to the first byte in the segemnt. */
56 RTGCUINTPTR GCPtrSegBase;
57 /** Pointer to the byte after the end of the segment. (might have wrapped!) */
58 RTGCUINTPTR GCPtrSegEnd;
59 /** The size of the segment minus 1. */
60 RTGCUINTPTR cbSegLimit;
61 /** The guest paging mode. */
62 PGMMODE enmMode;
63 /** Pointer to the current page - HC Ptr. */
64 void *pvPageHC;
65 /** Pointer to the current page - GC Ptr. */
66 RTGCPTR pvPageGC;
67 /** Pointer to the next instruction (relative to GCPtrSegBase). */
68 RTGCUINTPTR GCPtrNext;
69 /** The lock information that PGMPhysReleasePageMappingLock needs. */
70 PGMPAGEMAPLOCK pageMapLock;
71} DBGFDISASSTATE, *PDBGFDISASSTATE;
72
73
74
75/**
76 * Calls the dissassembler with the proper reader functions and such for disa
77 *
78 * @returns VBox status code.
79 * @param pVM VM handle
80 * @param pSelInfo The selector info.
81 * @param enmMode The guest paging mode.
82 * @param GCPtr The GC pointer (selector offset).
83 * @param pState The disas CPU state.
84 */
85static int dbgfR3DisasInstrFirst(PVM pVM, PSELMSELINFO pSelInfo, PGMMODE enmMode, RTGCPTR GCPtr, PDBGFDISASSTATE pState)
86{
87 pState->Cpu.mode = pSelInfo->Raw.Gen.u1DefBig ? CPUMODE_32BIT : CPUMODE_16BIT;
88 pState->Cpu.pfnReadBytes = dbgfR3DisasInstrRead;
89 pState->GCPtrSegBase = pSelInfo->GCPtrBase;
90 pState->GCPtrSegEnd = pSelInfo->cbLimit + 1 + (RTGCUINTPTR)pSelInfo->GCPtrBase;
91 pState->cbSegLimit = pSelInfo->cbLimit;
92 pState->enmMode = enmMode;
93 pState->pvPageGC = 0;
94 pState->pvPageHC = NULL;
95 pState->pVM = pVM;
96 Assert((uintptr_t)GCPtr == GCPtr);
97 uint32_t cbInstr;
98 int rc = DISInstr(&pState->Cpu, GCPtr, 0, &cbInstr, NULL);
99
100 /* Release mapping lock acquired in dbgfR3DisasInstrRead */
101 if (PGMPhysIsPageMappingLockValid(pVM, &pState->pageMapLock))
102 PGMPhysReleasePageMappingLock(pVM, &pState->pageMapLock);
103
104 if (VBOX_SUCCESS(rc))
105 {
106 pState->GCPtrNext = GCPtr + cbInstr;
107 return VINF_SUCCESS;
108 }
109 return rc;
110}
111
112
113#if 0
114/**
115 * Calls the dissassembler for disassembling the next instruction.
116 *
117 * @returns VBox status code.
118 * @param pState The disas CPU state.
119 */
120static int dbgfR3DisasInstrNext(PDBGFDISASSTATE pState)
121{
122 pState->rc = VINF_SUCCESS;
123 uint32_t cbInstr;
124 int rc = DISInstr(&pState->Cpu, (void *)pState->GCPtrNext, 0, &cbInstr, NULL);
125 if (VBOX_SUCCESS(rc))
126 {
127 pState->GCPtrNext = GCPtr + cbInstr;
128 return VINF_SUCCESS;
129 }
130 return rc;
131}
132#endif
133
134
135/**
136 * Instruction reader.
137 *
138 * @returns VBox status code. (Why this is a int32_t and not just an int is also beyond me.)
139 * @param PtrSrc Address to read from.
140 * In our case this is relative to the selector pointed to by the 2nd user argument of uDisCpu.
141 * @param pu8Dst Where to store the bytes.
142 * @param cbRead Number of bytes to read.
143 * @param uDisCpu Pointer to the disassembler cpu state. (Why this is a VBOXHUINTPTR is beyond me...)
144 * In this context it's always pointer to the Core of a DBGFDISASSTATE.
145 */
146static DECLCALLBACK(int) dbgfR3DisasInstrRead(RTHCUINTPTR PtrSrc, uint8_t *pu8Dst, unsigned cbRead, void *pvDisCpu)
147{
148 PDBGFDISASSTATE pState = (PDBGFDISASSTATE)pvDisCpu;
149 Assert(cbRead > 0);
150 for (;;)
151 {
152 RTGCUINTPTR GCPtr = PtrSrc + pState->GCPtrSegBase;
153
154 /* Need to update the page translation? */
155 if ( !pState->pvPageHC
156 || (GCPtr >> PAGE_SHIFT) != (pState->pvPageGC >> PAGE_SHIFT))
157 {
158 int rc = VINF_SUCCESS;
159
160 /* translate the address */
161 pState->pvPageGC = GCPtr & PAGE_BASE_GC_MASK;
162 if (MMHyperIsInsideArea(pState->pVM, pState->pvPageGC))
163 {
164 pState->pvPageHC = MMHyperGC2HC(pState->pVM, pState->pvPageGC);
165 if (!pState->pvPageHC)
166 rc = VERR_INVALID_POINTER;
167 }
168 else
169 {
170 if (PGMPhysIsPageMappingLockValid(pState->pVM, &pState->pageMapLock))
171 PGMPhysReleasePageMappingLock(pState->pVM, &pState->pageMapLock);
172
173 if (pState->enmMode <= PGMMODE_PROTECTED)
174 rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, pState->pvPageGC, &pState->pvPageHC, &pState->pageMapLock);
175 else
176 rc = PGMPhysGCPtr2CCPtrReadOnly(pState->pVM, pState->pvPageGC, &pState->pvPageHC, &pState->pageMapLock);
177 }
178 if (VBOX_FAILURE(rc))
179 {
180 pState->pvPageHC = NULL;
181 return rc;
182 }
183 }
184
185 /* check the segemnt limit */
186 if (PtrSrc > pState->cbSegLimit)
187 return VERR_OUT_OF_SELECTOR_BOUNDS;
188
189 /* calc how much we can read */
190 uint32_t cb = PAGE_SIZE - (GCPtr & PAGE_OFFSET_MASK);
191 RTGCUINTPTR cbSeg = pState->GCPtrSegEnd - GCPtr;
192 if (cb > cbSeg && cbSeg)
193 cb = cbSeg;
194 if (cb > cbRead)
195 cb = cbRead;
196
197 /* read and advance */
198 memcpy(pu8Dst, (char *)pState->pvPageHC + (GCPtr & PAGE_OFFSET_MASK), cb);
199 cbRead -= cb;
200 if (!cbRead)
201 return VINF_SUCCESS;
202 pu8Dst += cb;
203 PtrSrc += cb;
204 }
205}
206
207
208/**
209 * Copy a string and return pointer to the terminator char in the copy.
210 */
211inline char *mystrpcpy(char *pszDst, const char *pszSrc)
212{
213 size_t cch = strlen(pszSrc);
214 memcpy(pszDst, pszSrc, cch + 1);
215 return pszDst + cch;
216}
217
218
219/**
220 * Disassembles the one instruction according to the specified flags and address.
221 *
222 * @returns VBox status code.
223 * @param pVM VM handle.
224 * @param Sel The code selector. This used to determin the 32/16 bit ness and
225 * calculation of the actual instruction address.
226 * @param GCPtr The code address relative to the base of Sel.
227 * @param fFlags Flags controlling where to start and how to format.
228 * A combination of the DBGF_DISAS_FLAGS_* \#defines.
229 * @param pszOutput Output buffer.
230 * @param cchOutput Size of the output buffer.
231 * @param pcbInstr Where to return the size of the instruction.
232 */
233DBGFR3DECL(int) DBGFR3DisasInstrEx(PVM pVM, RTSEL Sel, RTGCPTR GCPtr, unsigned fFlags, char *pszOutput, uint32_t cchOutput, uint32_t *pcbInstr)
234{
235 /*
236 * Get the Sel and GCPtr if fFlags requests that.
237 */
238 PCCPUMCTXCORE pCtxCore = NULL;
239 CPUMSELREGHID *pHiddenSel = NULL;
240 int rc;
241 if (fFlags & (DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER))
242 {
243 if (fFlags & DBGF_DISAS_FLAGS_CURRENT_GUEST)
244 pCtxCore = CPUMGetGuestCtxCore(pVM);
245 else
246 pCtxCore = CPUMGetHyperCtxCore(pVM);
247 Sel = pCtxCore->cs;
248 pHiddenSel = (CPUMSELREGHID *)&pCtxCore->csHid;
249 GCPtr = pCtxCore->eip;
250 }
251
252 /*
253 * Read the selector info - assume no stale selectors and nasty stuff like that.
254 * Since the selector flags in the CPUMCTX structures aren't up to date unless
255 * we recently visited REM, we'll not search for the selector there.
256 */
257 SELMSELINFO SelInfo;
258 const PGMMODE enmMode = PGMGetGuestMode(pVM);
259 bool fRealModeAddress = false;
260
261 if ( pHiddenSel
262 && CPUMAreHiddenSelRegsValid(pVM))
263 {
264 SelInfo.GCPtrBase = pHiddenSel->u32Base;
265 SelInfo.cbLimit = pHiddenSel->u32Limit;
266 SelInfo.fHyper = false;
267 SelInfo.fRealMode = !!(pCtxCore && pCtxCore->eflags.Bits.u1VM || enmMode == PGMMODE_REAL);
268 SelInfo.Raw.au32[0] = 0;
269 SelInfo.Raw.au32[1] = 0;
270 SelInfo.Raw.Gen.u16LimitLow = ~0;
271 SelInfo.Raw.Gen.u4LimitHigh = ~0;
272 SelInfo.Raw.Gen.u1Present = pHiddenSel->Attr.n.u1Present;
273 SelInfo.Raw.Gen.u1Granularity = pHiddenSel->Attr.n.u1Granularity;;
274 SelInfo.Raw.Gen.u1DefBig = pHiddenSel->Attr.n.u1DefBig;
275 SelInfo.Raw.Gen.u1DescType = pHiddenSel->Attr.n.u1DescType;
276 SelInfo.Raw.Gen.u4Type = pHiddenSel->Attr.n.u4Type;
277 fRealModeAddress = SelInfo.fRealMode;
278 }
279 else if ( !(fFlags & DBGF_DISAS_FLAGS_CURRENT_HYPER)
280 && ( (pCtxCore && pCtxCore->eflags.Bits.u1VM)
281 || enmMode == PGMMODE_REAL) )
282 { /* V86 mode or real mode - real mode addressing */
283 SelInfo.GCPtrBase = Sel * 16;
284 SelInfo.cbLimit = ~0;
285 SelInfo.fHyper = false;
286 SelInfo.fRealMode = true;
287 SelInfo.Raw.au32[0] = 0;
288 SelInfo.Raw.au32[1] = 0;
289 SelInfo.Raw.Gen.u16LimitLow = ~0;
290 SelInfo.Raw.Gen.u4LimitHigh = ~0;
291 SelInfo.Raw.Gen.u1Present = 1;
292 SelInfo.Raw.Gen.u1Granularity = 1;
293 SelInfo.Raw.Gen.u1DefBig = 0; /* 16 bits */
294 SelInfo.Raw.Gen.u1DescType = 1;
295 SelInfo.Raw.Gen.u4Type = X86_SEL_TYPE_EO;
296 fRealModeAddress = true;
297 }
298 else if (Sel == DBGF_SEL_FLAT)
299 {
300 SelInfo.GCPtrBase = 0;
301 SelInfo.cbLimit = ~0;
302 SelInfo.fHyper = false;
303 SelInfo.fRealMode = false;
304 SelInfo.Raw.au32[0] = 0;
305 SelInfo.Raw.au32[1] = 0;
306 SelInfo.Raw.Gen.u16LimitLow = ~0;
307 SelInfo.Raw.Gen.u4LimitHigh = ~0;
308 SelInfo.Raw.Gen.u1Present = 1;
309 SelInfo.Raw.Gen.u1Granularity = 1;
310 SelInfo.Raw.Gen.u1DefBig = 1;
311 SelInfo.Raw.Gen.u1DescType = 1;
312 SelInfo.Raw.Gen.u4Type = X86_SEL_TYPE_EO;
313 }
314 else
315 {
316 rc = SELMR3GetSelectorInfo(pVM, Sel, &SelInfo);
317 if (VBOX_FAILURE(rc))
318 {
319 RTStrPrintf(pszOutput, cchOutput, "Sel=%04x -> %Vrc\n", Sel, rc);
320 return rc;
321 }
322 }
323
324 /*
325 * Disassemble it.
326 */
327 DBGFDISASSTATE State;
328 rc = dbgfR3DisasInstrFirst(pVM, &SelInfo, enmMode, GCPtr, &State);
329 if (VBOX_FAILURE(rc))
330 {
331 RTStrPrintf(pszOutput, cchOutput, "Disas -> %Vrc\n", rc);
332 return rc;
333 }
334
335 /*
336 * Format it.
337 */
338 char szBuf[512];
339 char *psz = &szBuf[0];
340
341 /* prefix */
342 if (State.Cpu.prefix & PREFIX_LOCK)
343 psz = (char *)memcpy(psz, "lock ", sizeof("lock ")) + sizeof("lock ") - 1;
344 if (State.Cpu.prefix & PREFIX_REP)
345 psz = (char *)memcpy(psz, "rep(e) ", sizeof("rep(e) ")) + sizeof("rep(e) ") - 1;
346 else if(State.Cpu.prefix & PREFIX_REPNE)
347 psz = (char *)memcpy(psz, "repne ", sizeof("repne ")) + sizeof("repne ") - 1;
348
349 /* the instruction */
350 const char *pszFormat = State.Cpu.pszOpcode;
351 char ch;
352 while ((ch = *pszFormat) && !isspace(ch) && ch != '%')
353 {
354 *psz++ = ch;
355 pszFormat++;
356 }
357 if (isspace(ch))
358 {
359 do *psz++ = ' ';
360#ifdef DEBUG_bird /* Not sure if Sander want's this because of log size */
361 while (psz - szBuf < 8);
362#else
363 while (0);
364#endif
365 while (isspace(*pszFormat))
366 pszFormat++;
367 }
368
369 if (fFlags & DBGF_DISAS_FLAGS_NO_ANNOTATION)
370 pCtxCore = NULL;
371
372 /** @todo implement annotation and symbol lookup! */
373 int iParam = 1;
374 for (;;)
375 {
376 ch = *pszFormat;
377 if (ch == '%')
378 {
379 ch = pszFormat[1];
380 switch (ch)
381 {
382 /*
383 * Relative jump offset.
384 */
385 case 'J':
386 {
387 AssertMsg(iParam == 1, ("Invalid branch parameter nr %d\n", iParam));
388 int32_t i32Disp;
389 if (State.Cpu.param1.flags & USE_IMMEDIATE8_REL)
390 i32Disp = (int32_t)(int8_t)State.Cpu.param1.parval;
391 else if (State.Cpu.param1.flags & USE_IMMEDIATE16_REL)
392 i32Disp = (int32_t)(int16_t)State.Cpu.param1.parval;
393 else if (State.Cpu.param1.flags & USE_IMMEDIATE32_REL)
394 i32Disp = (int32_t)State.Cpu.param1.parval;
395 else
396 {
397 AssertMsgFailed(("Oops!\n"));
398 return VERR_GENERAL_FAILURE;
399 }
400 RTGCUINTPTR GCPtrTarget = (RTGCUINTPTR)GCPtr + State.Cpu.opsize + i32Disp;
401 switch (State.Cpu.opmode)
402 {
403 case CPUMODE_16BIT: GCPtrTarget &= UINT16_MAX; break;
404 case CPUMODE_32BIT: GCPtrTarget &= UINT32_MAX; break;
405 }
406#ifdef DEBUG_bird /* an experiment. */
407 DBGFSYMBOL Sym;
408 RTGCINTPTR off;
409 int rc = DBGFR3SymbolByAddr(pVM, GCPtrTarget + SelInfo.GCPtrBase, &off, &Sym);
410 if ( VBOX_SUCCESS(rc)
411 && Sym.Value - SelInfo.GCPtrBase <= SelInfo.cbLimit
412 && off < _1M * 16 && off > -_1M * 16)
413 {
414 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz, "%s", Sym.szName);
415 if (off > 0)
416 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz, "+%#x", (int)off);
417 else if (off > 0)
418 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz, "-%#x", -(int)off);
419 switch (State.Cpu.opmode)
420 {
421 case CPUMODE_16BIT:
422 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
423 i32Disp >= 0 ? " (%04VGv/+%x)" : " (%04VGv/-%x)",
424 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
425 break;
426 case CPUMODE_32BIT:
427 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
428 i32Disp >= 0 ? " (%08VGv/+%x)" : " (%08VGv/-%x)",
429 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
430 break;
431 default:
432 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
433 i32Disp >= 0 ? " (%VGv/+%x)" : " (%VGv/-%x)",
434 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
435 break;
436 }
437 }
438 else
439#endif /* DEBUG_bird */
440 {
441 switch (State.Cpu.opmode)
442 {
443 case CPUMODE_16BIT:
444 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
445 i32Disp >= 0 ? "%04VGv (+%x)" : "%04VGv (-%x)",
446 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
447 break;
448 case CPUMODE_32BIT:
449 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
450 i32Disp >= 0 ? "%08VGv (+%x)" : "%08VGv (-%x)",
451 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
452 break;
453 default:
454 psz += RTStrPrintf(psz, &szBuf[sizeof(szBuf)] - psz,
455 i32Disp >= 0 ? "%VGv (+%x)" : "%VGv (-%x)",
456 GCPtrTarget, i32Disp >= 0 ? i32Disp : -i32Disp);
457 break;
458 }
459 }
460 break;
461 }
462
463 case 'A': //direct address
464 case 'C': //control register
465 case 'D': //debug register
466 case 'E': //ModRM specifies parameter
467 case 'F': //Eflags register
468 case 'G': //ModRM selects general register
469 case 'I': //Immediate data
470 case 'M': //ModRM may only refer to memory
471 case 'O': //No ModRM byte
472 case 'P': //ModRM byte selects MMX register
473 case 'Q': //ModRM byte selects MMX register or memory address
474 case 'R': //ModRM byte may only refer to a general register
475 case 'S': //ModRM byte selects a segment register
476 case 'T': //ModRM byte selects a test register
477 case 'V': //ModRM byte selects an XMM/SSE register
478 case 'W': //ModRM byte selects an XMM/SSE register or a memory address
479 case 'X': //DS:SI
480 case 'Y': //ES:DI
481 switch (iParam)
482 {
483 case 1: psz = mystrpcpy(psz, State.Cpu.param1.szParam); break;
484 case 2: psz = mystrpcpy(psz, State.Cpu.param2.szParam); break;
485 case 3: psz = mystrpcpy(psz, State.Cpu.param3.szParam); break;
486 }
487 pszFormat += 2;
488 break;
489
490 case 'e': //register based on operand size (e.g. %eAX)
491 if (State.Cpu.opmode == CPUMODE_32BIT)
492 *psz++ = 'E';
493 *psz++ = pszFormat[2];
494 *psz++ = pszFormat[3];
495 pszFormat += 4;
496 break;
497
498 default:
499 AssertMsgFailed(("Oops! ch=%c\n", ch));
500 break;
501 }
502
503 /* Skip to the next parameter in the format string. */
504 pszFormat = strchr(pszFormat, ',');
505 if (!pszFormat)
506 break;
507 pszFormat++;
508 *psz++ = ch = ',';
509 iParam++;
510 }
511 else
512 {
513 /* output char, but check for parameter separator first. */
514 if (ch == ',')
515 iParam++;
516 *psz++ = ch;
517 if (!ch)
518 break;
519 pszFormat++;
520 }
521
522#ifdef DEBUG_bird /* Not sure if Sander want's this because of log size */
523 /* space after commas */
524 if (ch == ',')
525 {
526 while (isspace(*pszFormat))
527 pszFormat++;
528 *psz++ = ' ';
529 }
530#endif
531 } /* foreach char in pszFormat */
532 *psz = '\0';
533
534 /*
535 * Print it to the user specified buffer.
536 */
537 if (fFlags & DBGF_DISAS_FLAGS_NO_BYTES)
538 {
539 if (fFlags & DBGF_DISAS_FLAGS_NO_ADDRESS)
540 RTStrPrintf(pszOutput, cchOutput, "%s", szBuf);
541 else if (fRealModeAddress)
542 RTStrPrintf(pszOutput, cchOutput, "%04x:%04x %s", Sel, (unsigned)GCPtr, szBuf);
543 else if (Sel == DBGF_SEL_FLAT)
544 RTStrPrintf(pszOutput, cchOutput, "%VGv %s", GCPtr, szBuf);
545 else
546 RTStrPrintf(pszOutput, cchOutput, "%04x:%VGv %s", Sel, GCPtr, szBuf);
547 }
548 else
549 {
550 size_t cbBits = State.Cpu.opsize;
551 uint8_t *pau8Bits = (uint8_t *)alloca(cbBits);
552 rc = dbgfR3DisasInstrRead(GCPtr, pau8Bits, cbBits, &State);
553 AssertRC(rc);
554
555 /* Release mapping lock acquired in dbgfR3DisasInstrRead */
556 if (PGMPhysIsPageMappingLockValid(pVM, &State.pageMapLock))
557 PGMPhysReleasePageMappingLock(pVM, &State.pageMapLock);
558
559 if (fFlags & DBGF_DISAS_FLAGS_NO_ADDRESS)
560 RTStrPrintf(pszOutput, cchOutput, "%.*Vhxs%*s %s",
561 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
562 szBuf);
563 else if (fRealModeAddress)
564 RTStrPrintf(pszOutput, cchOutput, "%04x:%04x %.*Vhxs%*s %s",
565 Sel, (unsigned)GCPtr,
566 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
567 szBuf);
568 else if (Sel == DBGF_SEL_FLAT)
569 RTStrPrintf(pszOutput, cchOutput, "%VGv %.*Vhxs%*s %s",
570 GCPtr,
571 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
572 szBuf);
573 else
574 RTStrPrintf(pszOutput, cchOutput, "%04x:%VGv %.*Vhxs%*s %s",
575 Sel, GCPtr,
576 cbBits, pau8Bits, cbBits < 8 ? (8 - cbBits) * 3 : 0, "",
577 szBuf);
578
579 }
580
581 if (pcbInstr)
582 *pcbInstr = State.Cpu.opsize;
583 return VINF_SUCCESS;
584}
585
586
587/**
588 * Disassembles an instruction.
589 * Addresses will be tried resolved to symbols
590 *
591 * @returns VBox status code.
592 * @param pVM VM handle.
593 * @param Sel The code selector. This used to determin the 32/16 bit ness and
594 * calculation of the actual instruction address.
595 * @param GCPtr The code address relative to the base of Sel.
596 * @param pszOutput Output buffer.
597 * @param cchOutput Size of the output buffer.
598 */
599DBGFR3DECL(int) DBGFR3DisasInstr(PVM pVM, RTSEL Sel, RTGCPTR GCPtr, char *pszOutput, uint32_t cchOutput)
600{
601 return DBGFR3DisasInstrEx(pVM, Sel, GCPtr, 0, pszOutput, cchOutput, NULL);
602}
603
604
605/**
606 * Disassembles the current guest context instruction.
607 * All registers and data will be displayed. Addresses will be attempted resolved to symbols.
608 *
609 * @returns VBox status code.
610 * @param pVM VM handle.
611 * @param pszOutput Output buffer.
612 * @param cchOutput Size of the output buffer.
613 */
614DBGFR3DECL(int) DBGFR3DisasInstrCurrent(PVM pVM, char *pszOutput, uint32_t cchOutput)
615{
616 return DBGFR3DisasInstrEx(pVM, 0, 0, DBGF_DISAS_FLAGS_CURRENT_GUEST, pszOutput, cchOutput, NULL);
617}
618
619
620/**
621 * Disassembles the current guest context instruction and writes it to the log.
622 * All registers and data will be displayed. Addresses will be attempted resolved to symbols.
623 *
624 * @returns VBox status code.
625 * @param pVM VM handle.
626 * @param pszPrefix Short prefix string to the dissassembly string. (optional)
627 */
628DBGFR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVM pVM, const char *pszPrefix)
629{
630 char szBuf[256];
631 szBuf[0] = '\0';
632 int rc = DBGFR3DisasInstrCurrent(pVM, &szBuf[0], sizeof(szBuf));
633 if (VBOX_FAILURE(rc))
634 RTStrPrintf(szBuf, sizeof(szBuf), "DBGFR3DisasInstrCurrentLog failed with rc=%Vrc\n", rc);
635 if (pszPrefix && *pszPrefix)
636 RTLogPrintf("%s: %s\n", pszPrefix, szBuf);
637 else
638 RTLogPrintf("%s\n", szBuf);
639 return rc;
640}
641
642
643
644/**
645 * Disassembles the specified guest context instruction and writes it to the log.
646 * Addresses will be attempted resolved to symbols.
647 *
648 * @returns VBox status code.
649 * @param pVM VM handle.
650 * @param Sel The code selector. This used to determin the 32/16 bit-ness and
651 * calculation of the actual instruction address.
652 * @param GCPtr The code address relative to the base of Sel.
653 */
654DBGFR3DECL(int) DBGFR3DisasInstrLogInternal(PVM pVM, RTSEL Sel, RTGCPTR GCPtr)
655{
656 char szBuf[256];
657 szBuf[0] = '\0';
658 int rc = DBGFR3DisasInstr(pVM, Sel, GCPtr, &szBuf[0], sizeof(szBuf));
659 if (VBOX_FAILURE(rc))
660 RTStrPrintf(szBuf, sizeof(szBuf), "DBGFR3DisasInstrLog(, %RTsel, %RGv) failed with rc=%Vrc\n", Sel, GCPtr, rc);
661 RTLogPrintf("%s\n", szBuf);
662 return rc;
663}
664
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