VirtualBox

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

Last change on this file since 93744 was 93554, checked in by vboxsync, 3 years ago

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

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