VirtualBox

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

Last change on this file since 106743 was 106743, checked in by vboxsync, 4 weeks ago

VMM/ARM: Make the control flow graph generator work with ARMv8 A64 to some extent, bugref:10393

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