/**
 * Sets the new recompile supervisor code flag.
 *
 * @returns COM status code
 * @param   aEnable new recompile supervisor code flag
 */
STDMETHODIMP MachineDebugger::COMSETTER(RecompileSupervisor)(BOOL aEnable)
{
    LogFlowThisFunc(("enable=%d\n", aEnable));

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
        if (queueSettings())
            mRecompileSupervisorQueued = aEnable; // queue the request
        else
        {
            Console::SafeVMPtr ptrVM(mParent);
            hrc = ptrVM.rc();
            if (SUCCEEDED(hrc))
            {
                int vrc = EMR3SetExecutionPolicy(ptrVM.raw(), EMEXECPOLICY_RECOMPILE_RING0, RT_BOOL(aEnable));
                if (RT_FAILURE(vrc))
                    hrc = setError(VBOX_E_VM_ERROR, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc);
            }
        }
    }
    return hrc;
}
STDMETHODIMP MachineDebugger::DumpGuestCore(IN_BSTR a_bstrFilename, IN_BSTR a_bstrCompression)
{
    CheckComArgStrNotEmptyOrNull(a_bstrFilename);
    Utf8Str strFilename(a_bstrFilename);
    if (a_bstrCompression && *a_bstrCompression)
        return setError(E_INVALIDARG, tr("The compression parameter must be empty"));

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
        {
            int vrc = DBGFR3CoreWrite(ptrVM, strFilename.c_str(), false /*fReplaceFile*/);
            if (RT_SUCCESS(vrc))
                hrc = S_OK;
            else
                hrc = setError(E_FAIL, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
        }
    }

    return hrc;
}
/**
 * Sets the new code scanner enabled flag.
 *
 * @returns COM status code
 * @param   aEnable new code scanner enabled flag
 */
HRESULT MachineDebugger::setCSAMEnabled(BOOL aCSAMEnabled)
{
    LogFlowThisFunc(("enable=%d\n", aCSAMEnabled));

#ifdef VBOX_WITH_RAW_MODE
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (i_queueSettings())
    {
        // queue the request
        mCsamEnabledQueued = aCSAMEnabled;
        return S_OK;
    }

    Console::SafeVMPtr ptrVM(mParent);
    if (FAILED(ptrVM.rc()))
        return ptrVM.rc();

    int vrc = CSAMR3SetScanningEnabled(ptrVM.rawUVM(), aCSAMEnabled != FALSE);
    if (RT_FAILURE(vrc))
        return setError(VBOX_E_VM_ERROR, tr("CSAMR3SetScanningEnabled returned %Rrc"), vrc);

#else  /* !VBOX_WITH_RAW_MODE */
    if (aCSAMEnabled)
        return setError(VBOX_E_VM_ERROR, tr("CASM not present"), VERR_NOT_SUPPORTED);
#endif /* !VBOX_WITH_RAW_MODE */
    return S_OK;
}
HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
{
    LogFlowThisFunc(("\n"));
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
    {
        /*
         * Do the job and try convert the name.
         */
        char szVersion[256];
        int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
        if (RT_SUCCESS(vrc))
        {
            try
            {
                Bstr bstrVersion(szVersion);
                aOSVersion = Utf8Str(bstrVersion);
            }
            catch (std::bad_alloc)
            {
                hrc = E_OUTOFMEMORY;
            }
        }
        else
            hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
    }
    return hrc;
}
/**
 * Enables or disables logging.
 *
 * @returns COM status code
 * @param   aLogEnabled    The new code log state.
 */
HRESULT MachineDebugger::setLogEnabled(BOOL aLogEnabled)
{
    LogFlowThisFunc(("aLogEnabled=%d\n", aLogEnabled));

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (i_queueSettings())
    {
        // queue the request
        mLogEnabledQueued = aLogEnabled;
        return S_OK;
    }

    Console::SafeVMPtr ptrVM(mParent);
    if (FAILED(ptrVM.rc())) return ptrVM.rc();

#ifdef LOG_ENABLED
    int vrc = DBGFR3LogModifyFlags(ptrVM.rawUVM(), aLogEnabled ? "enabled" : "disabled");
    if (RT_FAILURE(vrc))
    {
        /** @todo handle error code. */
    }
#endif

    return S_OK;
}
/**
 * Returns the current virtual time rate.
 *
 * @returns COM status code.
 * @param   aPct     Where to store the rate.
 */
STDMETHODIMP MachineDebugger::COMSETTER(VirtualTimeRate)(ULONG a_uPct)
{
    if (a_uPct < 2 || a_uPct > 20000)
        return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), a_uPct);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
        if (queueSettings())
            mVirtualTimeRateQueued = a_uPct;
        else
        {
            Console::SafeVMPtr ptrVM(mParent);
            hrc = ptrVM.rc();
            if (SUCCEEDED(hrc))
            {
                int vrc = TMR3SetWarpDrive(ptrVM.raw(), a_uPct);
                if (RT_FAILURE(vrc))
                    hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), a_uPct, vrc);
            }
        }
    }

    return hrc;
}
/**
 * Returns the current virtual time rate.
 *
 * @returns COM status code.
 * @param   a_puPct      Where to store the rate.
 */
HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
        *aVirtualTimeRate = TMR3GetWarpDrive(ptrVM.rawUVM());

    return hrc;
}
/**
 * Get the VM uptime in milliseconds.
 *
 * @returns COM status code
 * @param   aUptime     Where to store the uptime.
 */
HRESULT MachineDebugger::getUptime(LONG64 *aUptime)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
        *aUptime = (int64_t)TMR3TimeVirtGetMilli(ptrVM.rawUVM());

    return hrc;
}
/**
 * Sets the singlestepping flag.
 *
 * @returns COM status code
 * @param   a_fEnable       The new state.
 */
HRESULT MachineDebugger::setSingleStep(BOOL aSingleStep)
{
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
    {
        NOREF(aSingleStep); /** @todo */
        ReturnComNotImplemented();
    }
    return hrc;
}
/**
 * Returns the current unrestricted execution setting.
 *
 * @returns COM status code
 * @param   aEnabled address of result variable
 */
HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtrQuiet ptrVM(mParent);

    if (ptrVM.isOk())
        *aHWVirtExUXEnabled = HMR3IsUXActive(ptrVM.rawUVM());
    else
        *aHWVirtExUXEnabled = false;

    return S_OK;
}
/**
 * Returns the current patch manager enabled flag.
 *
 * @returns COM status code
 * @param   aEnabled address of result variable
 */
HRESULT MachineDebugger::getPATMEnabled(BOOL *aPATMEnabled)
{
#ifdef VBOX_WITH_RAW_MODE
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtrQuiet ptrVM(mParent);
    if (ptrVM.isOk())
        *aPATMEnabled = PATMR3IsEnabled(ptrVM.rawUVM());
    else
#endif
        *aPATMEnabled = false;

    return S_OK;
}
HRESULT Guest::internalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
                                     ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon,
                                     ULONG *aMemShared, ULONG *aMemCache, ULONG *aPageTotal,
                                     ULONG *aMemAllocTotal, ULONG *aMemFreeTotal,
                                     ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    *aCpuUser    = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
    *aCpuKernel  = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
    *aCpuIdle    = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
    *aMemTotal   = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K);     /* page (4K) -> 1KB units */
    *aMemFree    = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K);       /* page (4K) -> 1KB units */
    *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
    *aMemCache   = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K);     /* page (4K) -> 1KB units */
    *aPageTotal  = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K);   /* page (4K) -> 1KB units */

    /* Play safe or smth? */
    *aMemAllocTotal   = 0;
    *aMemFreeTotal    = 0;
    *aMemBalloonTotal = 0;
    *aMemSharedTotal  = 0;
    *aMemShared       = 0;

    /* MUST release all locks before calling any PGM statistics queries,
     * as they are executed by EMT and that might deadlock us by VMM device
     * activity which waits for the Guest object lock. */
    alock.release();
    Console::SafeVMPtr ptrVM(mParent);
    if (!ptrVM.isOk())
        return E_FAIL;

    uint64_t cbFreeTotal, cbAllocTotal, cbBalloonedTotal, cbSharedTotal;
    int rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal);
    AssertRCReturn(rc, E_FAIL);

    *aMemAllocTotal   = (ULONG)(cbAllocTotal / _1K);  /* bytes -> KB */
    *aMemFreeTotal    = (ULONG)(cbFreeTotal / _1K);
    *aMemBalloonTotal = (ULONG)(cbBalloonedTotal / _1K);
    *aMemSharedTotal  = (ULONG)(cbSharedTotal / _1K);

    /* Query the missing per-VM memory statistics. */
    uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbSharedMem, cbZeroMemIgn;
    rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn);
    AssertRCReturn(rc, E_FAIL);
    *aMemShared = (ULONG)(cbSharedMem / _1K);

    return S_OK;
}
HRESULT MachineDebugger::logStringProps(PRTLOGGER pLogger, PFNLOGGETSTR pfnLogGetStr,
                                        const char *pszLogGetStr, BSTR *a_pbstrSettings)
{
    /* Make sure the VM is powered up. */
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (FAILED(hrc))
        return hrc;

    /* Make sure we've got a logger. */
    if (!pLogger)
    {
        Bstr bstrEmpty;
        bstrEmpty.cloneTo(a_pbstrSettings);
        return S_OK;
    }

    /* Do the job. */
    size_t cbBuf = _1K;
    for (;;)
    {
        char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
        AssertReturn(pszBuf, E_OUTOFMEMORY);

        int rc = pfnLogGetStr(pLogger, pszBuf, cbBuf);
        if (RT_SUCCESS(rc))
        {
            try
            {
                Bstr bstrRet(pszBuf);
                bstrRet.detachTo(a_pbstrSettings);
                hrc = S_OK;
            }
            catch (std::bad_alloc)
            {
                hrc = E_OUTOFMEMORY;
            }
            RTMemTmpFree(pszBuf);
            return hrc;
        }
        RTMemTmpFree(pszBuf);
        AssertReturn(rc == VERR_BUFFER_OVERFLOW, setError(VBOX_E_IPRT_ERROR, tr("%s returned %Rrc"), pszLogGetStr, rc));

        /* try again with a bigger buffer. */
        cbBuf *= 2;
        AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
    }
}
/**
 * Sets the singlestepping flag.
 *
 * @returns COM status code
 * @param   a_fEnable       The new state.
 */
STDMETHODIMP MachineDebugger::COMSETTER(SingleStep)(BOOL a_fEnable)
{
    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
        {
            /** @todo */
            ReturnComNotImplemented();
        }
    }
    return hrc;
}
/**
 * Returns the current PAE flag.
 *
 * @returns COM status code
 * @param   aEnabled address of result variable
 */
HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtrQuiet ptrVM(mParent);

    if (ptrVM.isOk())
    {
        uint32_t cr4;
        int rc = DBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/,  DBGFREG_CR4, &cr4); AssertRC(rc);
        *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
    }
    else
        *aPAEEnabled = false;

    return S_OK;
}
/**
 * Hack for getting the user mode VM handle (UVM).
 *
 * This is only temporary (promise) while prototyping the debugger.
 *
 * @returns COM status code
 * @param   aVM         Where to store the vm handle. Since there is no
 *                      uintptr_t in COM, we're using the max integer.
 *                      (No, ULONG is not pointer sized!)
 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
 * @remarks Prior to 4.3 this returned PVM.
 */
HRESULT MachineDebugger::getVM(LONG64 *aVM)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
    {
        VMR3RetainUVM(ptrVM.rawUVM());
        *aVM = (intptr_t)ptrVM.rawUVM();
    }

    /*
     * Note! ptrVM protection provided by SafeVMPtr is no long effective
     *       after we return from this method.
     */
    return hrc;
}
/**
 * Returns the current virtual time rate.
 *
 * @returns COM status code.
 * @param   a_puPct      Where to store the rate.
 */
STDMETHODIMP MachineDebugger::COMGETTER(VirtualTimeRate)(ULONG *a_puPct)
{
    CheckComArgOutPointerValid(a_puPct);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
            *a_puPct = TMGetWarpDrive(ptrVM.raw());
    }

    return hrc;
}
HRESULT MachineDebugger::i_logStringProps(PRTLOGGER pLogger, PFNLOGGETSTR pfnLogGetStr,
                                          const char *pszLogGetStr, Utf8Str *pstrSettings)
{
    /* Make sure the VM is powered up. */
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (FAILED(hrc))
        return hrc;

    /* Make sure we've got a logger. */
    if (!pLogger)
    {
        *pstrSettings = "";
        return S_OK;
    }

    /* Do the job. */
    size_t cbBuf = _1K;
    for (;;)
    {
        char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
        AssertReturn(pszBuf, E_OUTOFMEMORY);
        int vrc = pstrSettings->reserveNoThrow(cbBuf);
        if (RT_SUCCESS(vrc))
        {
            vrc = pfnLogGetStr(pLogger, pstrSettings->mutableRaw(), cbBuf);
            if (RT_SUCCESS(vrc))
            {
                pstrSettings->jolt();
                return S_OK;
            }
            *pstrSettings = "";
            AssertReturn(vrc == VERR_BUFFER_OVERFLOW, setError(VBOX_E_IPRT_ERROR, tr("%s returned %Rrc"), pszLogGetStr, vrc));
        }
        else
            return E_OUTOFMEMORY;

        /* try again with a bigger buffer. */
        cbBuf *= 2;
        AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
    }
}
HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
{
    if (aCompression.length())
        return setError(E_INVALIDARG, tr("The compression parameter must be empty"));

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    Console::SafeVMPtr ptrVM(mParent);
    HRESULT hrc = ptrVM.rc();
    if (SUCCEEDED(hrc))
    {
        int vrc = DBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
        if (RT_SUCCESS(vrc))
            hrc = S_OK;
        else
            hrc = setError(E_FAIL, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
    }

    return hrc;
}
/**
 * Returns the current singlestepping flag.
 *
 * @returns COM status code
 * @param   a_fEnabled      Where to store the result.
 */
STDMETHODIMP MachineDebugger::COMGETTER(SingleStep)(BOOL *a_fEnabled)
{
    CheckComArgOutPointerValid(a_fEnabled);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
        {
            /** @todo */
            ReturnComNotImplemented();
        }
    }
    return hrc;
}
/**
 * Hack for getting the VM handle.
 *
 * This is only temporary (promise) while prototyping the debugger.
 *
 * @returns COM status code
 * @param   a_u64Vm     Where to store the vm handle. Since there is no
 *                      uintptr_t in COM, we're using the max integer.
 *                      (No, ULONG is not pointer sized!)
 */
STDMETHODIMP MachineDebugger::COMGETTER(VM)(LONG64 *a_u64Vm)
{
    CheckComArgOutPointerValid(a_u64Vm);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
            *a_u64Vm = (intptr_t)ptrVM.raw();

        /*
         * Note! pVM protection provided by SafeVMPtr is no long effective
         *       after we return from this method.
         */
    }

    return hrc;
}
/**
 * Internal worker for getting an EM executable policy setting.
 *
 * @returns COM status code.
 * @param   enmPolicy           Which EM policy.
 * @param   pfEnforced          Where to return the policy setting.
 */
HRESULT MachineDebugger::i_getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced)
{
    CheckComArgOutPointerValid(pfEnforced);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
        if (i_queueSettings())
            *pfEnforced = maiQueuedEmExecPolicyParams[enmPolicy] == 1;
        else
        {
            bool fEnforced = false;
            Console::SafeVMPtrQuiet ptrVM(mParent);
            hrc = ptrVM.rc();
            if (SUCCEEDED(hrc))
                EMR3QueryExecutionPolicy(ptrVM.rawUVM(), enmPolicy, &fEnforced);
            *pfEnforced = fEnforced;
        }
    }
    return hrc;
}
/**
 * Internal worker for setting an EM executable policy.
 *
 * @returns COM status code.
 * @param   enmPolicy           Which policy to change.
 * @param   fEnforce            Whether to enforce the policy or not.
 */
HRESULT MachineDebugger::i_setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce)
{
    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
        if (i_queueSettings())
            maiQueuedEmExecPolicyParams[enmPolicy] = fEnforce ? 1 : 0;
        else
        {
            Console::SafeVMPtrQuiet ptrVM(mParent);
            hrc = ptrVM.rc();
            if (SUCCEEDED(hrc))
            {
                int vrc = EMR3SetExecutionPolicy(ptrVM.rawUVM(), enmPolicy, fEnforce != FALSE);
                if (RT_FAILURE(vrc))
                    hrc = setError(VBOX_E_VM_ERROR, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc);
            }
        }
    }
    return hrc;
}
STDMETHODIMP MachineDebugger::COMGETTER(OSVersion)(BSTR *a_pbstrVersion)
{
    LogFlowThisFunc(("\n"));
    CheckComArgNotNull(a_pbstrVersion);
    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
        {
            /*
             * Do the job and try convert the name.
             */
            char szVersion[256];
            int vrc = DBGFR3OSQueryNameAndVersion(ptrVM.raw(), NULL, 0, szVersion, sizeof(szVersion));
            if (RT_SUCCESS(vrc))
            {
                try
                {
                    Bstr bstrVersion(szVersion);
                    bstrVersion.detachTo(a_pbstrVersion);
                }
                catch (std::bad_alloc)
                {
                    hrc = E_OUTOFMEMORY;
                }
            }
            else
                hrc = setError(VBOX_E_VM_ERROR, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
        }
    }
    return hrc;
}
/**
 * Returns the current virtual time rate.
 *
 * @returns COM status code.
 * @param   aPct     Where to store the rate.
 */
HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
{
    HRESULT hrc = S_OK;

    if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
        return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    if (i_queueSettings())
        mVirtualTimeRateQueued = aVirtualTimeRate;
    else
    {
        Console::SafeVMPtr ptrVM(mParent);
        hrc = ptrVM.rc();
        if (SUCCEEDED(hrc))
        {
            int vrc = TMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
            if (RT_FAILURE(vrc))
                hrc = setError(VBOX_E_VM_ERROR, tr("TMR3SetWarpDrive(, %u) failed with rc=%Rrc"), aVirtualTimeRate, vrc);
        }
    }

    return hrc;
}
Console::teleporterSrcThreadWrapper(RTTHREAD hThread, void *pvUser)
{
    TeleporterStateSrc *pState = (TeleporterStateSrc *)pvUser;

    /*
     * Console::teleporterSrc does the work, we just grab onto the VM handle
     * and do the cleanups afterwards.
     */
    SafeVMPtr ptrVM(pState->mptrConsole);
    HRESULT hrc = ptrVM.rc();

    if (SUCCEEDED(hrc))
        hrc = pState->mptrConsole->teleporterSrc(pState);

    /* Close the connection ASAP on so that the other side can complete. */
    if (pState->mhSocket != NIL_RTSOCKET)
    {
        RTTcpClientClose(pState->mhSocket);
        pState->mhSocket = NIL_RTSOCKET;
    }

    /* Aaarg! setMachineState trashes error info on Windows, so we have to
       complete things here on failure instead of right before cleanup. */
    if (FAILED(hrc))
        pState->mptrProgress->notifyComplete(hrc);

    /* We can no longer be canceled (success), or it doesn't matter any longer (failure). */
    pState->mptrProgress->setCancelCallback(NULL, NULL);

    /*
     * Write lock the console before resetting mptrCancelableProgress and
     * fixing the state.
     */
    AutoWriteLock autoLock(pState->mptrConsole COMMA_LOCKVAL_SRC_POS);
    pState->mptrConsole->mptrCancelableProgress.setNull();

    VMSTATE const        enmVMState      = VMR3GetStateU(pState->mpUVM);
    MachineState_T const enmMachineState = pState->mptrConsole->mMachineState;
    if (SUCCEEDED(hrc))
    {
        /*
         * Automatically shut down the VM on success.
         *
         * Note! We have to release the VM caller object or we'll deadlock in
         *       powerDown.
         */
        AssertLogRelMsg(enmVMState == VMSTATE_SUSPENDED, ("%s\n", VMR3GetStateName(enmVMState)));
        AssertLogRelMsg(enmMachineState == MachineState_TeleportingPausedVM, ("%s\n", Global::stringifyMachineState(enmMachineState)));

        ptrVM.release();

        pState->mptrConsole->mVMIsAlreadyPoweringOff = true; /* (Make sure we stick in the TeleportingPausedVM state.) */
        hrc = pState->mptrConsole->powerDown();
        pState->mptrConsole->mVMIsAlreadyPoweringOff = false;

        pState->mptrProgress->notifyComplete(hrc);
    }
    else
    {
        /*
         * Work the state machinery on failure.
         *
         * If the state is no longer 'Teleporting*', some other operation has
         * canceled us and there is nothing we need to do here.  In all other
         * cases, we've failed one way or another.
         */
        if (   enmMachineState == MachineState_Teleporting
                || enmMachineState == MachineState_TeleportingPausedVM
           )
        {
            if (pState->mfUnlockedMedia)
            {
                ErrorInfoKeeper Oak;
                HRESULT hrc2 = pState->mptrConsole->mControl->LockMedia();
                if (FAILED(hrc2))
                {
                    uint64_t StartMS = RTTimeMilliTS();
                    do
                    {
                        RTThreadSleep(2);
                        hrc2 = pState->mptrConsole->mControl->LockMedia();
                    } while (   FAILED(hrc2)
                                && RTTimeMilliTS() - StartMS < 2000);
                }
                if (SUCCEEDED(hrc2))
                    pState->mfUnlockedMedia = true;
                else
                    LogRel(("FATAL ERROR: Failed to re-take the media locks. hrc2=%Rhrc\n", hrc2));
            }

            switch (enmVMState)
            {
            case VMSTATE_RUNNING:
            case VMSTATE_RUNNING_LS:
            case VMSTATE_DEBUGGING:
            case VMSTATE_DEBUGGING_LS:
            case VMSTATE_POWERING_OFF:
            case VMSTATE_POWERING_OFF_LS:
            case VMSTATE_RESETTING:
            case VMSTATE_RESETTING_LS:
                Assert(!pState->mfSuspendedByUs);
                Assert(!pState->mfUnlockedMedia);
                pState->mptrConsole->setMachineState(MachineState_Running);
                break;

            case VMSTATE_GURU_MEDITATION:
            case VMSTATE_GURU_MEDITATION_LS:
                pState->mptrConsole->setMachineState(MachineState_Stuck);
                break;

            case VMSTATE_FATAL_ERROR:
            case VMSTATE_FATAL_ERROR_LS:
                pState->mptrConsole->setMachineState(MachineState_Paused);
                break;

            default:
                AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState)));
            case VMSTATE_SUSPENDED:
            case VMSTATE_SUSPENDED_LS:
            case VMSTATE_SUSPENDING:
            case VMSTATE_SUSPENDING_LS:
            case VMSTATE_SUSPENDING_EXT_LS:
                if (!pState->mfUnlockedMedia)
                {
                    pState->mptrConsole->setMachineState(MachineState_Paused);
                    if (pState->mfSuspendedByUs)
                    {
                        autoLock.release();
                        int rc = VMR3Resume(VMR3GetVM(pState->mpUVM));
                        AssertLogRelMsgRC(rc, ("VMR3Resume -> %Rrc\n", rc));
                        autoLock.acquire();
                    }
                }
                else
                {
                    /* Faking a guru meditation is the best I can think of doing here... */
                    pState->mptrConsole->setMachineState(MachineState_Stuck);
                }
                break;
            }
        }
    }
    autoLock.release();

    /*
     * Cleanup.
     */
    Assert(pState->mhSocket == NIL_RTSOCKET);
    delete pState;

    return VINF_SUCCESS; /* ignored */
}
void Guest::i_updateStats(uint64_t iTick)
{
    uint64_t cbFreeTotal      = 0;
    uint64_t cbAllocTotal     = 0;
    uint64_t cbBalloonedTotal = 0;
    uint64_t cbSharedTotal    = 0;
    uint64_t cbSharedMem      = 0;
    ULONG    uNetStatRx       = 0;
    ULONG    uNetStatTx       = 0;
    ULONG    aGuestStats[GUESTSTATTYPE_MAX];
    RT_ZERO(aGuestStats);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    ULONG validStats = mVmValidStats;
    /* Check if we have anything to report */
    if (validStats)
    {
        mVmValidStats = pm::VMSTATMASK_NONE;
        memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats));
    }
    alock.release();

    /*
     * Calling SessionMachine may take time as the object resides in VBoxSVC
     * process. This is why we took a snapshot of currently collected stats
     * and released the lock.
     */
    Console::SafeVMPtrQuiet ptrVM(mParent);
    if (ptrVM.isOk())
    {
        int rc;

        /*
         * There is no point in collecting VM shared memory if other memory
         * statistics are not available yet. Or is there?
         */
        if (validStats)
        {
            /* Query the missing per-VM memory statistics. */
            uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbZeroMemIgn;
            rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn);
            if (rc == VINF_SUCCESS)
                validStats |= pm::VMSTATMASK_GUEST_MEMSHARED;
        }

        if (mCollectVMMStats)
        {
            rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal);
            AssertRC(rc);
            if (rc == VINF_SUCCESS)
                validStats |= pm::VMSTATMASK_VMM_ALLOC  | pm::VMSTATMASK_VMM_FREE
                           |  pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED;
        }

        uint64_t uRxPrev = mNetStatRx;
        uint64_t uTxPrev = mNetStatTx;
        mNetStatRx = mNetStatTx = 0;
        rc = STAMR3Enum(ptrVM.rawUVM(), "/Public/Net/*/Bytes*", i_staticEnumStatsCallback, this);
        AssertRC(rc);

        uint64_t uTsNow = RTTimeNanoTS();
        uint64_t cNsPassed = uTsNow - mNetStatLastTs;
        if (cNsPassed >= 1000)
        {
            mNetStatLastTs = uTsNow;

            uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
            uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
            validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX;
            LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, cNsPassed));
        }
        else
        {
            /* Can happen on resume or if we're using a non-monotonic clock
               source for the timer and the time is adjusted. */
            mNetStatRx = uRxPrev;
            mNetStatTx = uTxPrev;
            LogThisFunc(("Net Ts=%llu cNsPassed=%llu - too small interval\n", uTsNow, cNsPassed));
        }
    }

    mParent->i_reportVmStatistics(validStats,
                                  aGuestStats[GUESTSTATTYPE_CPUUSER],
                                  aGuestStats[GUESTSTATTYPE_CPUKERNEL],
                                  aGuestStats[GUESTSTATTYPE_CPUIDLE],
                                  /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K),
                                  (ULONG)(cbSharedMem / _1K), /* bytes -> KB */
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K),
                                  (ULONG)(cbAllocTotal / _1K), /* bytes -> KB */
                                  (ULONG)(cbFreeTotal / _1K),
                                  (ULONG)(cbBalloonedTotal / _1K),
                                  (ULONG)(cbSharedTotal / _1K),
                                  uNetStatRx,
                                  uNetStatTx);
}