/** * Checks if the interrupt flag is enabled or not. * * @returns true if it's enabled. * @returns false if it's disabled. * * @param pVM Pointer to the VM. * @param pCtxCore CPU context */ VMM_INT_DECL(bool) PATMAreInterruptsEnabledByCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore) { if (PATMIsEnabled(pVM)) { if (PATMIsPatchGCAddr(pVM, pCtxCore->eip)) return false; } return !!(pCtxCore->eflags.u32 & X86_EFL_IF); }
/** * Returns the current patch manager enabled flag. * * @returns COM status code * @param enabled address of result variable */ STDMETHODIMP MachineDebugger::COMGETTER(PATMEnabled)(BOOL *enabled) { if (!enabled) return E_POINTER; if (gpVM) *enabled = PATMIsEnabled(gpVM); else *enabled = false; return S_OK; }
/** * Checks if the interrupt flag is enabled or not. * * @returns true if it's enabled. * @returns false if it's disabled. * * @param pVM The cross context VM structure. * @param pCtx The guest CPU context. * @todo CPUM should wrap this, EM.cpp shouldn't call us. */ VMM_INT_DECL(bool) PATMAreInterruptsEnabledByCtx(PVM pVM, PCPUMCTX pCtx) { if (PATMIsEnabled(pVM)) { Assert(!HMIsEnabled(pVM)); if (PATMIsPatchGCAddr(pVM, pCtx->eip)) return false; } return !!(pCtx->eflags.u32 & X86_EFL_IF); }
/** * Reads patch code. * * @retval VINF_SUCCESS on success. * @retval VERR_PATCH_NOT_FOUND if the request is entirely outside the patch * code. * * @param pVM The cross context VM structure. * @param GCPtrPatchCode The patch address to start reading at. * @param pvDst Where to return the patch code. * @param cbToRead Number of bytes to read. * @param pcbRead Where to return the actual number of bytes we've * read. Optional. */ VMM_INT_DECL(int) PATMReadPatchCode(PVM pVM, RTGCPTR GCPtrPatchCode, void *pvDst, size_t cbToRead, size_t *pcbRead) { /* Shortcut. */ if (!PATMIsEnabled(pVM)) return VERR_PATCH_NOT_FOUND; Assert(!HMIsEnabled(pVM)); /* * Check patch code and patch helper code. We assume the requested bytes * are not in either. */ RTGCPTR offPatchCode = GCPtrPatchCode - (RTGCPTR32)pVM->patm.s.pPatchMemGC; if (offPatchCode >= pVM->patm.s.cbPatchMem) { offPatchCode = GCPtrPatchCode - (RTGCPTR32)pVM->patm.s.pbPatchHelpersRC; if (offPatchCode >= pVM->patm.s.cbPatchHelpers) return VERR_PATCH_NOT_FOUND; /* * Patch helper memory. */ uint32_t cbMaxRead = pVM->patm.s.cbPatchHelpers - (uint32_t)offPatchCode; if (cbToRead > cbMaxRead) cbToRead = cbMaxRead; #ifdef IN_RC memcpy(pvDst, pVM->patm.s.pbPatchHelpersRC + (uint32_t)offPatchCode, cbToRead); #else memcpy(pvDst, pVM->patm.s.pbPatchHelpersR3 + (uint32_t)offPatchCode, cbToRead); #endif } else { /* * Patch memory. */ uint32_t cbMaxRead = pVM->patm.s.cbPatchMem - (uint32_t)offPatchCode; if (cbToRead > cbMaxRead) cbToRead = cbMaxRead; #ifdef IN_RC memcpy(pvDst, pVM->patm.s.pPatchMemGC + (uint32_t)offPatchCode, cbToRead); #else memcpy(pvDst, pVM->patm.s.pPatchMemHC + (uint32_t)offPatchCode, cbToRead); #endif } if (pcbRead) *pcbRead = cbToRead; return VINF_SUCCESS; }
/** * Returns the current patch manager enabled flag. * * @returns COM status code * @param aEnabled address of result variable */ STDMETHODIMP MachineDebugger::COMGETTER(PATMEnabled) (BOOL *aEnabled) { CheckComArgOutPointerValid(aEnabled); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); Console::SafeVMPtrQuiet pVM (mParent); if (pVM.isOk()) *aEnabled = PATMIsEnabled (pVM.raw()); else *aEnabled = false; return S_OK; }
/** * Load virtualized flags. * * This function is called from CPUMRawEnter(). It doesn't have to update the * IF and IOPL eflags bits, the caller will enforce those to set and 0 respectively. * * @param pVM Pointer to the VM. * @param pCtxCore The cpu context core. * @see pg_raw */ VMM_INT_DECL(void) PATMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore) { bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip); /* * Currently we don't bother to check whether PATM is enabled or not. * For all cases where it isn't, IOPL will be safe and IF will be set. */ register uint32_t efl = pCtxCore->eflags.u32; CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK; AssertMsg((efl & X86_EFL_IF) || PATMShouldUseRawMode(pVM, (RTRCPTR)pCtxCore->eip), ("X86_EFL_IF is clear and PATM is disabled! (eip=%RRv eflags=%08x fPATM=%d pPATMGC=%RRv-%RRv\n", pCtxCore->eip, pCtxCore->eflags.u32, PATMIsEnabled(pVM), pVM->patm.s.pPatchMemGC, pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem)); AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode, ("fPIF=%d eip=%RRv\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip)); efl &= ~PATM_VIRTUAL_FLAGS_MASK; efl |= X86_EFL_IF; pCtxCore->eflags.u32 = efl; #ifdef IN_RING3 #ifdef PATM_EMULATE_SYSENTER PCPUMCTX pCtx; /* Check if the sysenter handler has changed. */ pCtx = CPUMQueryGuestCtxPtr(pVM); if ( pCtx->SysEnter.cs != 0 && pCtx->SysEnter.eip != 0 ) { if (pVM->patm.s.pfnSysEnterGC != (RTRCPTR)pCtx->SysEnter.eip) { pVM->patm.s.pfnSysEnterPatchGC = 0; pVM->patm.s.pfnSysEnterGC = 0; Log2(("PATMRawEnter: installing sysenter patch for %RRv\n", pCtx->SysEnter.eip)); pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip); if (pVM->patm.s.pfnSysEnterPatchGC == 0) { rc = PATMR3InstallPatch(pVM, pCtx->SysEnter.eip, PATMFL_SYSENTER | PATMFL_CODE32); if (rc == VINF_SUCCESS) { pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip); pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip; Assert(pVM->patm.s.pfnSysEnterPatchGC); } } else pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip; } } else { pVM->patm.s.pfnSysEnterPatchGC = 0; pVM->patm.s.pfnSysEnterGC = 0; } #endif #endif }
/** * Checks whether the GC address is part of our patch region * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pAddrGC Guest context address * @internal */ VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR pAddrGC) { return (PATMIsEnabled(pVM) && pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem) ? true : false; }
/** * Check if we must use raw mode (patch code being executed) * * @param pVM Pointer to the VM. * @param pAddrGC Guest context address */ VMM_INT_DECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC) { return ( PATMIsEnabled(pVM) && ((pAddrGC >= (RTRCPTR)pVM->patm.s.pPatchMemGC && pAddrGC < (RTRCPTR)((RTRCUINTPTR)pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem)))) ? true : false; }
/** * Annotates an instruction if patched. * * @param pVM The cross context VM structure. * @param RCPtr The instruction address. * @param cbInstr The instruction length. * @param pszBuf The output buffer. This will be an empty string if the * instruction wasn't patched. If it's patched, it will * hold a symbol-like string describing the patch. * @param cbBuf The size of the output buffer. */ VMMR3_INT_DECL(void) PATMR3DbgAnnotatePatchedInstruction(PVM pVM, RTRCPTR RCPtr, uint8_t cbInstr, char *pszBuf, size_t cbBuf) { /* * Always zero the buffer. */ AssertReturnVoid(cbBuf > 0); *pszBuf = '\0'; /* * Drop out immediately if it cannot be a patched instruction. */ if (!PATMIsEnabled(pVM)) return; if ( RCPtr < pVM->patm.s.pPatchedInstrGCLowest || RCPtr > pVM->patm.s.pPatchedInstrGCHighest) return; /* * Look for a patch record covering any part of the instruction. * * The first query results in a patched less or equal to RCPtr. While the * second results in one that's greater than RCPtr. */ PPATMPATCHREC pPatchRec; pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, RCPtr, false /*fFromAbove*/); if ( !pPatchRec || RCPtr - pPatchRec->patch.pPrivInstrGC > pPatchRec->patch.cbPrivInstr) { pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, RCPtr, true /*fFromAbove*/); if ( !pPatchRec || (RTRCPTR)(RCPtr + cbInstr) < pPatchRec->patch.pPrivInstrGC ) return; } /* * Lazy bird uses the symbol name generation code for describing the patch. */ size_t off = patmR3DbgDescribePatchAsSymbol(pPatchRec, pszBuf, cbBuf); if (off + 1 < cbBuf) { const char *pszState; switch (pPatchRec->patch.uState) { case PATCH_REFUSED: pszState = "Refused"; break; case PATCH_DISABLED: pszState = "Disabled"; break; case PATCH_ENABLED: pszState = "Enabled"; break; case PATCH_UNUSABLE: pszState = "Unusable"; break; case PATCH_DIRTY: pszState = "Dirty"; break; case PATCH_DISABLE_PENDING: pszState = "DisablePending"; break; default: pszState = "State???"; AssertFailed(); break; } if (pPatchRec->patch.cbPatchBlockSize > 0) off += RTStrPrintf(&pszBuf[off], cbBuf - off, " - %s (%u b) - %#x LB %#x", pszState, pPatchRec->patch.cbPatchJump, pPatchRec->patch.pPatchBlockOffset + pVM->patm.s.pPatchMemGC, pPatchRec->patch.cbPatchBlockSize); else off += RTStrPrintf(&pszBuf[off], cbBuf - off, " - %s (%u b)", pszState, pPatchRec->patch.cbPatchJump); } }
/** * Checks whether the GC address is part of our patch region. * * @returns VBox status code. * @param pVM The cross context VM structure. * @param uGCAddr Guest context address. * @internal */ VMMDECL(bool) PATMIsPatchGCAddrExclHelpers(PVM pVM, RTRCUINTPTR uGCAddr) { return PATMIsEnabled(pVM) && uGCAddr - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem; }
/** * Checks whether the GC address is part of our patch or helper regions. * * @returns VBox status code. * @param pVM The cross context VM structure. * @param uGCAddr Guest context address. * @internal */ VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR uGCAddr) { return PATMIsEnabled(pVM) && ( uGCAddr - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem || uGCAddr - (RTRCUINTPTR)pVM->patm.s.pbPatchHelpersRC < pVM->patm.s.cbPatchHelpers); }
/** * Check if we must use raw mode (patch code being executed) * * @param pVM The cross context VM structure. * @param pAddrGC Guest context address */ VMM_INT_DECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC) { return PATMIsEnabled(pVM) && ( (RTRCUINTPTR)pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem || (RTRCUINTPTR)pAddrGC - (RTRCUINTPTR)pVM->patm.s.pbPatchHelpersRC < pVM->patm.s.cbPatchHelpers); }