VirtualBox

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

Last change on this file since 5906 was 5874, checked in by vboxsync, 17 years ago

rearranged checks to drastically improve the chance of flat addresses working when debugging RM code

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