VirtualBox

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

Last change on this file since 4403 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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