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