VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/MachineDebuggerImpl.cpp

Last change on this file was 103085, checked in by vboxsync, 4 months ago

Main,FE/VBoxManage,FE/VirtualBox,ValidationKit: Allow setting the primary VM execution engine to make it easier to force particular engine for testing, bugref:10583

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.8 KB
RevLine 
[14627]1/* $Id: MachineDebuggerImpl.cpp 103085 2024-01-26 16:17:43Z vboxsync $ */
[1]2/** @file
[44373]3 * VBox IMachineDebugger COM class implementation (VBoxC).
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]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
[1]26 */
27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[67914]32#define LOG_GROUP LOG_GROUP_MAIN_MACHINEDEBUGGER
33#include "LoggingNew.h"
34
[1]35#include "MachineDebuggerImpl.h"
[15762]36
37#include "Global.h"
[1]38#include "ConsoleImpl.h"
[89696]39#include "ProgressImpl.h"
[25860]40
41#include "AutoCaller.h"
[1]42
[93444]43#include <VBox/vmm/vmmr3vtable.h>
[35346]44#include <VBox/vmm/em.h>
[44340]45#include <VBox/vmm/uvm.h>
[35346]46#include <VBox/vmm/tm.h>
[43387]47#include <VBox/vmm/hm.h>
[1]48#include <VBox/err.h>
[30681]49#include <iprt/cpp/utils.h>
[1]50
51
52// constructor / destructor
[14627]53/////////////////////////////////////////////////////////////////////////////
[1]54
[27607]55MachineDebugger::MachineDebugger()
56 : mParent(NULL)
57{
58}
[14627]59
[27607]60MachineDebugger::~MachineDebugger()
61{
62}
63
[1]64HRESULT MachineDebugger::FinalConstruct()
65{
[21878]66 unconst(mParent) = NULL;
[35638]67 return BaseFinalConstruct();
[1]68}
69
70void MachineDebugger::FinalRelease()
71{
[14627]72 uninit();
[35638]73 BaseFinalRelease();
[1]74}
75
[14627]76// public initializer/uninitializer for internal purposes only
77/////////////////////////////////////////////////////////////////////////////
[1]78
79/**
80 * Initializes the machine debugger object.
81 *
82 * @returns COM result indicator
[14627]83 * @param aParent handle of our parent object
[1]84 */
[62598]85HRESULT MachineDebugger::init(Console *aParent)
[1]86{
[21878]87 LogFlowThisFunc(("aParent=%p\n", aParent));
[1]88
[26235]89 ComAssertRet(aParent, E_INVALIDARG);
[1]90
[14627]91 /* Enclose the state transition NotReady->InInit->Ready */
[21878]92 AutoInitSpan autoInitSpan(this);
93 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[1]94
[21878]95 unconst(mParent) = aParent;
[14627]96
[46423]97 for (unsigned i = 0; i < RT_ELEMENTS(maiQueuedEmExecPolicyParams); i++)
98 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
[63147]99 mSingleStepQueued = -1;
100 mLogEnabledQueued = -1;
101 mVirtualTimeRateQueued = UINT32_MAX;
[14627]102 mFlushMode = false;
103
[89696]104 m_hSampleReport = NULL;
105
[14627]106 /* Confirm a successful initialization */
107 autoInitSpan.setSucceeded();
108
[1]109 return S_OK;
110}
111
112/**
113 * Uninitializes the instance and sets the ready flag to FALSE.
114 * Called either from FinalRelease() or by the parent when it gets destroyed.
115 */
116void MachineDebugger::uninit()
117{
[21878]118 LogFlowThisFunc(("\n"));
[1]119
[14627]120 /* Enclose the state transition Ready->InUninit->NotReady */
[21878]121 AutoUninitSpan autoUninitSpan(this);
[14627]122 if (autoUninitSpan.uninitDone())
123 return;
[1]124
[27607]125 unconst(mParent) = NULL;
[14627]126 mFlushMode = false;
[1]127}
128
[89696]129/**
130 * @callback_method_impl{FNDBGFPROGRESS}
131 */
132/*static*/ DECLCALLBACK(int) MachineDebugger::i_dbgfProgressCallback(void *pvUser, unsigned uPercentage)
133{
134 MachineDebugger *pThis = (MachineDebugger *)pvUser;
135
136 int vrc = pThis->m_Progress->i_iprtProgressCallback(uPercentage, static_cast<Progress *>(pThis->m_Progress));
137 if ( RT_SUCCESS(vrc)
138 && uPercentage == 100)
139 {
[93444]140 PCVMMR3VTABLE const pVMM = pThis->mParent->i_getVMMVTable();
141 AssertPtrReturn(pVMM, VERR_INTERNAL_ERROR_3);
142
143 vrc = pVMM->pfnDBGFR3SampleReportDumpToFile(pThis->m_hSampleReport, pThis->m_strFilename.c_str());
144 pVMM->pfnDBGFR3SampleReportRelease(pThis->m_hSampleReport);
[89696]145 pThis->m_hSampleReport = NULL;
146 if (RT_SUCCESS(vrc))
147 pThis->m_Progress->i_notifyComplete(S_OK);
148 else
149 {
150 HRESULT hrc = pThis->setError(VBOX_E_IPRT_ERROR,
151 tr("Writing the sample report to '%s' failed with %Rrc"),
152 pThis->m_strFilename.c_str(), vrc);
153 pThis->m_Progress->i_notifyComplete(hrc);
154 }
155 pThis->m_Progress.setNull();
156 }
157 else if (vrc == VERR_CANCELLED)
158 vrc = VERR_DBGF_CANCELLED;
159
160 return vrc;
161}
162
[14627]163// IMachineDebugger properties
164/////////////////////////////////////////////////////////////////////////////
165
[1]166/**
167 * Returns the current singlestepping flag.
168 *
169 * @returns COM status code
[65120]170 * @param aSingleStep Where to store the result.
[1]171 */
[51092]172HRESULT MachineDebugger::getSingleStep(BOOL *aSingleStep)
[1]173{
[51092]174 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
175 Console::SafeVMPtr ptrVM(mParent);
[98262]176 HRESULT hrc = ptrVM.hrc();
[39712]177 if (SUCCEEDED(hrc))
178 {
[63244]179 RT_NOREF(aSingleStep); /** @todo */
[51092]180 ReturnComNotImplemented();
[39712]181 }
182 return hrc;
[1]183}
184
185/**
186 * Sets the singlestepping flag.
187 *
188 * @returns COM status code
[65103]189 * @param aSingleStep The new state.
[1]190 */
[51092]191HRESULT MachineDebugger::setSingleStep(BOOL aSingleStep)
[1]192{
[51092]193 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
194 Console::SafeVMPtr ptrVM(mParent);
[98262]195 HRESULT hrc = ptrVM.hrc();
[39712]196 if (SUCCEEDED(hrc))
197 {
[63244]198 NOREF(aSingleStep); /** @todo */
[51092]199 ReturnComNotImplemented();
[39712]200 }
201 return hrc;
[1]202}
203
204/**
[46423]205 * Internal worker for getting an EM executable policy setting.
[1]206 *
[46423]207 * @returns COM status code.
208 * @param enmPolicy Which EM policy.
209 * @param pfEnforced Where to return the policy setting.
[1]210 */
[51092]211HRESULT MachineDebugger::i_getEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL *pfEnforced)
[1]212{
[46423]213 CheckComArgOutPointerValid(pfEnforced);
[1]214
[21878]215 AutoCaller autoCaller(this);
[98262]216 HRESULT hrc = autoCaller.hrc();
[46423]217 if (SUCCEEDED(hrc))
218 {
219 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[51092]220 if (i_queueSettings())
[46423]221 *pfEnforced = maiQueuedEmExecPolicyParams[enmPolicy] == 1;
222 else
223 {
224 bool fEnforced = false;
225 Console::SafeVMPtrQuiet ptrVM(mParent);
[98262]226 hrc = ptrVM.hrc();
[46423]227 if (SUCCEEDED(hrc))
[93444]228 ptrVM.vtable()->pfnEMR3QueryExecutionPolicy(ptrVM.rawUVM(), enmPolicy, &fEnforced);
[46423]229 *pfEnforced = fEnforced;
230 }
231 }
232 return hrc;
[1]233}
234
235/**
[46423]236 * Internal worker for setting an EM executable policy.
[1]237 *
[46423]238 * @returns COM status code.
239 * @param enmPolicy Which policy to change.
240 * @param fEnforce Whether to enforce the policy or not.
[1]241 */
[51092]242HRESULT MachineDebugger::i_setEmExecPolicyProperty(EMEXECPOLICY enmPolicy, BOOL fEnforce)
[1]243{
[21878]244 AutoCaller autoCaller(this);
[98262]245 HRESULT hrc = autoCaller.hrc();
[38324]246 if (SUCCEEDED(hrc))
[1]247 {
[46423]248 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[51092]249 if (i_queueSettings())
[46423]250 maiQueuedEmExecPolicyParams[enmPolicy] = fEnforce ? 1 : 0;
[38324]251 else
252 {
[46423]253 Console::SafeVMPtrQuiet ptrVM(mParent);
[98262]254 hrc = ptrVM.hrc();
[38324]255 if (SUCCEEDED(hrc))
256 {
[93444]257 int vrc = ptrVM.vtable()->pfnEMR3SetExecutionPolicy(ptrVM.rawUVM(), enmPolicy, fEnforce != FALSE);
[38324]258 if (RT_FAILURE(vrc))
[73003]259 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("EMR3SetExecutionPolicy failed with %Rrc"), vrc);
[38324]260 }
261 }
[1]262 }
[38324]263 return hrc;
[1]264}
265
266/**
[46423]267 * Returns the current execute-all-in-IEM setting.
268 *
269 * @returns COM status code
[65103]270 * @param aExecuteAllInIEM Address of result variable.
[46423]271 */
[51092]272HRESULT MachineDebugger::getExecuteAllInIEM(BOOL *aExecuteAllInIEM)
[46423]273{
[51092]274 return i_getEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
[1]275}
276
277/**
[46423]278 * Changes the execute-all-in-IEM setting.
279 *
280 * @returns COM status code
[65103]281 * @param aExecuteAllInIEM New setting.
[46423]282 */
[51092]283HRESULT MachineDebugger::setExecuteAllInIEM(BOOL aExecuteAllInIEM)
[46423]284{
[51092]285 LogFlowThisFunc(("enable=%d\n", aExecuteAllInIEM));
286 return i_setEmExecPolicyProperty(EMEXECPOLICY_IEM_ALL, aExecuteAllInIEM);
[46423]287}
288
289/**
[1]290 * Returns the log enabled / disabled status.
291 *
292 * @returns COM status code
[58132]293 * @param aLogEnabled address of result variable
[1]294 */
[51092]295HRESULT MachineDebugger::getLogEnabled(BOOL *aLogEnabled)
[1]296{
[9242]297#ifdef LOG_ENABLED
[25310]298 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[14627]299
300 const PRTLOGGER pLogInstance = RTLogDefaultInstance();
[90693]301 *aLogEnabled = pLogInstance && !(RTLogGetFlags(pLogInstance) & RTLOGFLAGS_DISABLED);
[9242]302#else
[51092]303 *aLogEnabled = false;
[9242]304#endif
[14627]305
[1]306 return S_OK;
307}
308
309/**
310 * Enables or disables logging.
311 *
312 * @returns COM status code
[58132]313 * @param aLogEnabled The new code log state.
[1]314 */
[51092]315HRESULT MachineDebugger::setLogEnabled(BOOL aLogEnabled)
[1]316{
[51092]317 LogFlowThisFunc(("aLogEnabled=%d\n", aLogEnabled));
[1]318
[25310]319 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[14627]320
[51092]321 if (i_queueSettings())
[1]322 {
[14627]323 // queue the request
[51092]324 mLogEnabledQueued = aLogEnabled;
[14627]325 return S_OK;
[1]326 }
327
[44373]328 Console::SafeVMPtr ptrVM(mParent);
[98262]329 if (FAILED(ptrVM.hrc())) return ptrVM.hrc();
[1]330
[9242]331#ifdef LOG_ENABLED
[93444]332 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyFlags(ptrVM.rawUVM(), aLogEnabled ? "enabled" : "disabled");
[21878]333 if (RT_FAILURE(vrc))
[1]334 {
335 /** @todo handle error code. */
336 }
[9242]337#endif
[14627]338
[1]339 return S_OK;
340}
341
[51092]342HRESULT MachineDebugger::i_logStringProps(PRTLOGGER pLogger, PFNLOGGETSTR pfnLogGetStr,
[56567]343 const char *pszLogGetStr, Utf8Str *pstrSettings)
[35250]344{
[39668]345 /* Make sure the VM is powered up. */
346 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
347 Console::SafeVMPtr ptrVM(mParent);
[98262]348 HRESULT hrc = ptrVM.hrc();
[39668]349 if (FAILED(hrc))
350 return hrc;
351
352 /* Make sure we've got a logger. */
353 if (!pLogger)
354 {
[56567]355 *pstrSettings = "";
[39668]356 return S_OK;
357 }
358
359 /* Do the job. */
360 size_t cbBuf = _1K;
361 for (;;)
362 {
363 char *pszBuf = (char *)RTMemTmpAlloc(cbBuf);
364 AssertReturn(pszBuf, E_OUTOFMEMORY);
[56567]365 int vrc = pstrSettings->reserveNoThrow(cbBuf);
366 if (RT_SUCCESS(vrc))
[39668]367 {
[56567]368 vrc = pfnLogGetStr(pLogger, pstrSettings->mutableRaw(), cbBuf);
369 if (RT_SUCCESS(vrc))
[39668]370 {
[56567]371 pstrSettings->jolt();
372 return S_OK;
[39668]373 }
[56567]374 *pstrSettings = "";
[73003]375 AssertReturn(vrc == VERR_BUFFER_OVERFLOW,
376 setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("%s returned %Rrc"), pszLogGetStr, vrc));
[39668]377 }
[56567]378 else
379 return E_OUTOFMEMORY;
[39668]380
381 /* try again with a bigger buffer. */
382 cbBuf *= 2;
383 AssertReturn(cbBuf <= _256K, setError(E_FAIL, tr("%s returns too much data"), pszLogGetStr));
384 }
[35250]385}
386
[51092]387HRESULT MachineDebugger::getLogDbgFlags(com::Utf8Str &aLogDbgFlags)
[35250]388{
[90692]389 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryFlags, "RTLogQueryFlags", &aLogDbgFlags);
[35250]390}
391
[51092]392HRESULT MachineDebugger::getLogDbgGroups(com::Utf8Str &aLogDbgGroups)
[35250]393{
[90692]394 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryGroupSettings, "RTLogQueryGroupSettings", &aLogDbgGroups);
[35250]395}
396
[51092]397HRESULT MachineDebugger::getLogDbgDestinations(com::Utf8Str &aLogDbgDestinations)
[39668]398{
[90692]399 return i_logStringProps(RTLogGetDefaultInstance(), RTLogQueryDestinations, "RTLogQueryDestinations", &aLogDbgDestinations);
[39668]400}
401
[51092]402HRESULT MachineDebugger::getLogRelFlags(com::Utf8Str &aLogRelFlags)
[39668]403{
[90692]404 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryFlags, "RTLogQueryFlags", &aLogRelFlags);
[39668]405}
406
[51092]407HRESULT MachineDebugger::getLogRelGroups(com::Utf8Str &aLogRelGroups)
[39668]408{
[90692]409 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryGroupSettings, "RTLogQueryGroupSettings", &aLogRelGroups);
[39668]410}
411
[51092]412HRESULT MachineDebugger::getLogRelDestinations(com::Utf8Str &aLogRelDestinations)
[39668]413{
[90692]414 return i_logStringProps(RTLogRelGetDefaultInstance(), RTLogQueryDestinations, "RTLogQueryDestinations", &aLogRelDestinations);
[39668]415}
416
[1]417/**
[72328]418 * Return the main execution engine of the VM.
419 *
420 * @returns COM status code
421 * @param apenmEngine Address of the result variable.
422 */
423HRESULT MachineDebugger::getExecutionEngine(VMExecutionEngine_T *apenmEngine)
424{
425 *apenmEngine = VMExecutionEngine_NotSet;
426
427 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
428 Console::SafeVMPtrQuiet ptrVM(mParent);
429 if (ptrVM.isOk())
430 {
431 uint8_t bEngine = UINT8_MAX;
[94951]432 int vrc = ptrVM.vtable()->pfnEMR3QueryMainExecutionEngine(ptrVM.rawUVM(), &bEngine);
433 if (RT_SUCCESS(vrc))
[72328]434 switch (bEngine)
435 {
436 case VM_EXEC_ENGINE_NOT_SET: *apenmEngine = VMExecutionEngine_NotSet; break;
437 case VM_EXEC_ENGINE_HW_VIRT: *apenmEngine = VMExecutionEngine_HwVirt; break;
438 case VM_EXEC_ENGINE_NATIVE_API: *apenmEngine = VMExecutionEngine_NativeApi; break;
[103085]439 case VM_EXEC_ENGINE_IEM:
440 {
441 bool fForced = false;
442 vrc = ptrVM.vtable()->pfnEMR3QueryExecutionPolicy(ptrVM.rawUVM(), EMEXECPOLICY_IEM_RECOMPILED, &fForced);
443 if (RT_SUCCESS(vrc) && fForced)
444 *apenmEngine = VMExecutionEngine_Recompiler;
445 else
446 *apenmEngine = VMExecutionEngine_Interpreter;
447 break;
448 }
[72328]449 default: AssertMsgFailed(("bEngine=%d\n", bEngine));
450 }
451 }
452
453 return S_OK;
454}
455
456/**
[10695]457 * Returns the current nested paging flag.
458 *
459 * @returns COM status code
[65120]460 * @param aHWVirtExNestedPagingEnabled address of result variable
[10695]461 */
[51092]462HRESULT MachineDebugger::getHWVirtExNestedPagingEnabled(BOOL *aHWVirtExNestedPagingEnabled)
[10695]463{
[25310]464 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[14627]465
[44373]466 Console::SafeVMPtrQuiet ptrVM(mParent);
467 if (ptrVM.isOk())
[93444]468 *aHWVirtExNestedPagingEnabled = ptrVM.vtable()->pfnHMR3IsNestedPagingActive(ptrVM.rawUVM());
[10695]469 else
[51092]470 *aHWVirtExNestedPagingEnabled = false;
[14627]471
[10695]472 return S_OK;
473}
474
475/**
[13221]476 * Returns the current VPID flag.
477 *
478 * @returns COM status code
[65120]479 * @param aHWVirtExVPIDEnabled address of result variable
[13221]480 */
[51092]481HRESULT MachineDebugger::getHWVirtExVPIDEnabled(BOOL *aHWVirtExVPIDEnabled)
[13221]482{
[25310]483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[14627]484
[44373]485 Console::SafeVMPtrQuiet ptrVM(mParent);
486 if (ptrVM.isOk())
[93444]487 *aHWVirtExVPIDEnabled = ptrVM.vtable()->pfnHMR3IsVpidActive(ptrVM.rawUVM());
[13221]488 else
[51092]489 *aHWVirtExVPIDEnabled = false;
[14627]490
[13221]491 return S_OK;
492}
493
[45971]494/**
495 * Returns the current unrestricted execution setting.
496 *
497 * @returns COM status code
[65103]498 * @param aHWVirtExUXEnabled address of result variable
[45971]499 */
[51092]500HRESULT MachineDebugger::getHWVirtExUXEnabled(BOOL *aHWVirtExUXEnabled)
[45971]501{
502 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
503
504 Console::SafeVMPtrQuiet ptrVM(mParent);
505 if (ptrVM.isOk())
[93444]506 *aHWVirtExUXEnabled = ptrVM.vtable()->pfnHMR3IsUXActive(ptrVM.rawUVM());
[45971]507 else
[51092]508 *aHWVirtExUXEnabled = false;
[45971]509
510 return S_OK;
511}
512
[51092]513HRESULT MachineDebugger::getOSName(com::Utf8Str &aOSName)
[35250]514{
[35306]515 LogFlowThisFunc(("\n"));
[51092]516 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[93444]517
[51092]518 Console::SafeVMPtr ptrVM(mParent);
[98262]519 HRESULT hrc = ptrVM.hrc();
[35306]520 if (SUCCEEDED(hrc))
521 {
[51092]522 /*
523 * Do the job and try convert the name.
524 */
525 char szName[64];
[93444]526 int vrc = ptrVM.vtable()->pfnDBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), szName, sizeof(szName), NULL, 0);
[51092]527 if (RT_SUCCESS(vrc))
[93444]528 hrc = aOSName.assignEx(szName);
[51092]529 else
[73003]530 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
[35306]531 }
532 return hrc;
[35250]533}
534
[51092]535HRESULT MachineDebugger::getOSVersion(com::Utf8Str &aOSVersion)
[35250]536{
[35306]537 LogFlowThisFunc(("\n"));
[51092]538 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[93444]539
[51092]540 Console::SafeVMPtr ptrVM(mParent);
[98262]541 HRESULT hrc = ptrVM.hrc();
[35306]542 if (SUCCEEDED(hrc))
543 {
[51092]544 /*
545 * Do the job and try convert the name.
546 */
547 char szVersion[256];
[93444]548 int vrc = ptrVM.vtable()->pfnDBGFR3OSQueryNameAndVersion(ptrVM.rawUVM(), NULL, 0, szVersion, sizeof(szVersion));
[51092]549 if (RT_SUCCESS(vrc))
[93444]550 hrc = aOSVersion.assignEx(szVersion);
[51092]551 else
[73003]552 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSQueryNameAndVersion failed with %Rrc"), vrc);
[35306]553 }
554 return hrc;
[35250]555}
556
[13221]557/**
[7990]558 * Returns the current PAE flag.
559 *
560 * @returns COM status code
[65103]561 * @param aPAEEnabled address of result variable.
[7990]562 */
[51092]563HRESULT MachineDebugger::getPAEEnabled(BOOL *aPAEEnabled)
[7990]564{
[25310]565 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[14627]566
[44347]567 Console::SafeVMPtrQuiet ptrVM(mParent);
568 if (ptrVM.isOk())
[7990]569 {
[44347]570 uint32_t cr4;
[94951]571 int vrc = ptrVM.vtable()->pfnDBGFR3RegCpuQueryU32(ptrVM.rawUVM(), 0 /*idCpu*/, DBGFREG_CR4, &cr4); AssertRC(vrc);
[51092]572 *aPAEEnabled = RT_BOOL(cr4 & X86_CR4_PAE);
[7990]573 }
574 else
[51092]575 *aPAEEnabled = false;
[14627]576
[7990]577 return S_OK;
578}
579
580/**
[444]581 * Returns the current virtual time rate.
[5190]582 *
[444]583 * @returns COM status code.
[65103]584 * @param aVirtualTimeRate Where to store the rate.
[444]585 */
[51092]586HRESULT MachineDebugger::getVirtualTimeRate(ULONG *aVirtualTimeRate)
[444]587{
[51092]588 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[444]589
[51092]590 Console::SafeVMPtr ptrVM(mParent);
[98262]591 HRESULT hrc = ptrVM.hrc();
[39712]592 if (SUCCEEDED(hrc))
[93444]593 *aVirtualTimeRate = ptrVM.vtable()->pfnTMR3GetWarpDrive(ptrVM.rawUVM());
[444]594
[39712]595 return hrc;
[444]596}
597
598/**
[65103]599 * Set the virtual time rate.
[5190]600 *
[444]601 * @returns COM status code.
[65103]602 * @param aVirtualTimeRate The new rate.
[444]603 */
[51092]604HRESULT MachineDebugger::setVirtualTimeRate(ULONG aVirtualTimeRate)
[444]605{
[51092]606 HRESULT hrc = S_OK;
[444]607
[51092]608 if (aVirtualTimeRate < 2 || aVirtualTimeRate > 20000)
609 return setError(E_INVALIDARG, tr("%u is out of range [2..20000]"), aVirtualTimeRate);
610
611 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
612 if (i_queueSettings())
613 mVirtualTimeRateQueued = aVirtualTimeRate;
614 else
[444]615 {
[51092]616 Console::SafeVMPtr ptrVM(mParent);
[98262]617 hrc = ptrVM.hrc();
[51092]618 if (SUCCEEDED(hrc))
[39712]619 {
[93444]620 int vrc = ptrVM.vtable()->pfnTMR3SetWarpDrive(ptrVM.rawUVM(), aVirtualTimeRate);
[51092]621 if (RT_FAILURE(vrc))
[98278]622 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("TMR3SetWarpDrive(, %u) failed with vrc=%Rrc"), aVirtualTimeRate, vrc);
[39712]623 }
[444]624 }
625
[39712]626 return hrc;
[444]627}
628
629/**
[62598]630 * Get the VM uptime in milliseconds.
631 *
632 * @returns COM status code
633 * @param aUptime Where to store the uptime.
634 */
635HRESULT MachineDebugger::getUptime(LONG64 *aUptime)
636{
637 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
638
639 Console::SafeVMPtr ptrVM(mParent);
[98262]640 HRESULT hrc = ptrVM.hrc();
[62598]641 if (SUCCEEDED(hrc))
[93444]642 *aUptime = (int64_t)ptrVM.vtable()->pfnTMR3TimeVirtGetMilli(ptrVM.rawUVM());
[62598]643
644 return hrc;
645}
646
[14627]647// IMachineDebugger methods
648/////////////////////////////////////////////////////////////////////////////
649
[51092]650HRESULT MachineDebugger::dumpGuestCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
[35242]651{
[51092]652 if (aCompression.length())
[35242]653 return setError(E_INVALIDARG, tr("The compression parameter must be empty"));
654
[51092]655 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
656 Console::SafeVMPtr ptrVM(mParent);
[98262]657 HRESULT hrc = ptrVM.hrc();
[35242]658 if (SUCCEEDED(hrc))
659 {
[93444]660 int vrc = ptrVM.vtable()->pfnDBGFR3CoreWrite(ptrVM.rawUVM(), aFilename.c_str(), false /*fReplaceFile*/);
[51092]661 if (RT_SUCCESS(vrc))
662 hrc = S_OK;
663 else
[73003]664 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3CoreWrite failed with %Rrc"), vrc);
[35242]665 }
666
667 return hrc;
668}
669
[51092]670HRESULT MachineDebugger::dumpHostProcessCore(const com::Utf8Str &aFilename, const com::Utf8Str &aCompression)
[35242]671{
[63244]672 RT_NOREF(aFilename, aCompression);
[35242]673 ReturnComNotImplemented();
674}
675
[35306]676/**
677 * Debug info string buffer formatter.
678 */
679typedef struct MACHINEDEBUGGERINOFHLP
680{
681 /** The core info helper structure. */
682 DBGFINFOHLP Core;
683 /** Pointer to the buffer. */
684 char *pszBuf;
685 /** The size of the buffer. */
686 size_t cbBuf;
687 /** The offset into the buffer */
688 size_t offBuf;
689 /** Indicates an out-of-memory condition. */
690 bool fOutOfMemory;
691} MACHINEDEBUGGERINOFHLP;
692/** Pointer to a Debug info string buffer formatter. */
693typedef MACHINEDEBUGGERINOFHLP *PMACHINEDEBUGGERINOFHLP;
694
695
696/**
697 * @callback_method_impl{FNRTSTROUTPUT}
698 */
699static DECLCALLBACK(size_t) MachineDebuggerInfoOutput(void *pvArg, const char *pachChars, size_t cbChars)
700{
701 PMACHINEDEBUGGERINOFHLP pHlp = (PMACHINEDEBUGGERINOFHLP)pvArg;
702
703 /*
704 * Grow the buffer if required.
705 */
706 size_t const cbRequired = cbChars + pHlp->offBuf + 1;
707 if (cbRequired > pHlp->cbBuf)
708 {
709 if (RT_UNLIKELY(pHlp->fOutOfMemory))
710 return 0;
711
712 size_t cbBufNew = pHlp->cbBuf * 2;
713 if (cbRequired > cbBufNew)
714 cbBufNew = RT_ALIGN_Z(cbRequired, 256);
715 void *pvBufNew = RTMemRealloc(pHlp->pszBuf, cbBufNew);
716 if (RT_UNLIKELY(!pvBufNew))
717 {
718 pHlp->fOutOfMemory = true;
719 RTMemFree(pHlp->pszBuf);
720 pHlp->pszBuf = NULL;
721 pHlp->cbBuf = 0;
722 pHlp->offBuf = 0;
723 return 0;
724 }
725
726 pHlp->pszBuf = (char *)pvBufNew;
727 pHlp->cbBuf = cbBufNew;
728 }
729
730 /*
731 * Copy the bytes into the buffer and terminate it.
732 */
[65550]733 if (cbChars)
734 {
735 memcpy(&pHlp->pszBuf[pHlp->offBuf], pachChars, cbChars);
736 pHlp->offBuf += cbChars;
737 }
[35306]738 pHlp->pszBuf[pHlp->offBuf] = '\0';
739 Assert(pHlp->offBuf < pHlp->cbBuf);
740 return cbChars;
741}
742
743/**
[58132]744 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV}
[35306]745 */
[65088]746static DECLCALLBACK(void) MachineDebuggerInfoPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
[35306]747{
[65088]748 RTStrFormatV(MachineDebuggerInfoOutput, (void *)pHlp, NULL, NULL, pszFormat, args);
[35306]749}
750
751/**
[58132]752 * @interface_method_impl{DBGFINFOHLP,pfnPrintf}
[35306]753 */
754static DECLCALLBACK(void) MachineDebuggerInfoPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
755{
756 va_list va;
757 va_start(va, pszFormat);
758 MachineDebuggerInfoPrintfV(pHlp, pszFormat, va);
759 va_end(va);
760}
761
762/**
763 * Initializes the debug info string buffer formatter
764 *
[93445]765 * @param pHlp The help structure to init.
766 * @param pVMM The VMM vtable.
[35306]767 */
[93444]768static void MachineDebuggerInfoInit(PMACHINEDEBUGGERINOFHLP pHlp, PCVMMR3VTABLE pVMM)
[35306]769{
[80156]770 pHlp->Core.pfnPrintf = MachineDebuggerInfoPrintf;
771 pHlp->Core.pfnPrintfV = MachineDebuggerInfoPrintfV;
[93444]772 pHlp->Core.pfnGetOptError = pVMM->pfnDBGFR3InfoGenericGetOptError;
[80156]773 pHlp->pszBuf = NULL;
774 pHlp->cbBuf = 0;
775 pHlp->offBuf = 0;
776 pHlp->fOutOfMemory = false;
[35306]777}
778
779/**
780 * Deletes the debug info string buffer formatter.
781 * @param pHlp The helper structure to delete.
782 */
783static void MachineDebuggerInfoDelete(PMACHINEDEBUGGERINOFHLP pHlp)
784{
785 RTMemFree(pHlp->pszBuf);
786 pHlp->pszBuf = NULL;
787}
788
[51092]789HRESULT MachineDebugger::info(const com::Utf8Str &aName, const com::Utf8Str &aArgs, com::Utf8Str &aInfo)
[35242]790{
[35306]791 LogFlowThisFunc(("\n"));
792
793 /*
794 * Do the autocaller and lock bits.
795 */
796 AutoCaller autoCaller(this);
[98262]797 HRESULT hrc = autoCaller.hrc();
[35306]798 if (SUCCEEDED(hrc))
799 {
800 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
801 Console::SafeVMPtr ptrVM(mParent);
[98262]802 hrc = ptrVM.hrc();
[35306]803 if (SUCCEEDED(hrc))
804 {
805 /*
806 * Create a helper and call DBGFR3Info.
807 */
808 MACHINEDEBUGGERINOFHLP Hlp;
[93444]809 MachineDebuggerInfoInit(&Hlp, ptrVM.vtable());
810 int vrc = ptrVM.vtable()->pfnDBGFR3Info(ptrVM.rawUVM(), aName.c_str(), aArgs.c_str(), &Hlp.Core);
[35306]811 if (RT_SUCCESS(vrc))
812 {
813 if (!Hlp.fOutOfMemory)
[93444]814 hrc = aInfo.assignEx(Hlp.pszBuf);
[35306]815 else
816 hrc = E_OUTOFMEMORY;
817 }
818 else
[73003]819 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3Info failed with %Rrc"), vrc);
[35306]820 MachineDebuggerInfoDelete(&Hlp);
821 }
822 }
823 return hrc;
[35242]824}
825
[51092]826HRESULT MachineDebugger::injectNMI()
[35242]827{
828 LogFlowThisFunc(("\n"));
829
[51092]830 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
831 Console::SafeVMPtr ptrVM(mParent);
[98262]832 HRESULT hrc = ptrVM.hrc();
[35242]833 if (SUCCEEDED(hrc))
834 {
[93444]835 int vrc = ptrVM.vtable()->pfnDBGFR3InjectNMI(ptrVM.rawUVM(), 0);
[51092]836 if (RT_SUCCESS(vrc))
837 hrc = S_OK;
838 else
[73003]839 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3InjectNMI failed with %Rrc"), vrc);
[35242]840 }
841 return hrc;
842}
843
[51092]844HRESULT MachineDebugger::modifyLogFlags(const com::Utf8Str &aSettings)
[35250]845{
[51092]846 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
847 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
848 Console::SafeVMPtr ptrVM(mParent);
[98262]849 HRESULT hrc = ptrVM.hrc();
[39650]850 if (SUCCEEDED(hrc))
851 {
[93444]852 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyFlags(ptrVM.rawUVM(), aSettings.c_str());
[51092]853 if (RT_SUCCESS(vrc))
854 hrc = S_OK;
855 else
[73003]856 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyFlags failed with %Rrc"), vrc);
[39650]857 }
858 return hrc;
[35250]859}
860
[51092]861HRESULT MachineDebugger::modifyLogGroups(const com::Utf8Str &aSettings)
[35250]862{
[51092]863 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
864 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
865 Console::SafeVMPtr ptrVM(mParent);
[98262]866 HRESULT hrc = ptrVM.hrc();
[39650]867 if (SUCCEEDED(hrc))
868 {
[93444]869 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyGroups(ptrVM.rawUVM(), aSettings.c_str());
[51092]870 if (RT_SUCCESS(vrc))
871 hrc = S_OK;
872 else
[73003]873 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyGroups failed with %Rrc"), vrc);
[39650]874 }
875 return hrc;
[35250]876}
877
[51092]878HRESULT MachineDebugger::modifyLogDestinations(const com::Utf8Str &aSettings)
[35250]879{
[51092]880 LogFlowThisFunc(("aSettings=%s\n", aSettings.c_str()));
881 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
882 Console::SafeVMPtr ptrVM(mParent);
[98262]883 HRESULT hrc = ptrVM.hrc();
[39650]884 if (SUCCEEDED(hrc))
885 {
[93444]886 int vrc = ptrVM.vtable()->pfnDBGFR3LogModifyDestinations(ptrVM.rawUVM(), aSettings.c_str());
[51092]887 if (RT_SUCCESS(vrc))
888 hrc = S_OK;
889 else
[73003]890 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3LogModifyDestinations failed with %Rrc"), vrc);
[39650]891 }
892 return hrc;
[35250]893}
894
[51092]895HRESULT MachineDebugger::readPhysicalMemory(LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
[35242]896{
[63244]897 RT_NOREF(aAddress, aSize, aBytes);
[35242]898 ReturnComNotImplemented();
899}
900
[51092]901HRESULT MachineDebugger::writePhysicalMemory(LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
[35242]902{
[63244]903 RT_NOREF(aAddress, aSize, aBytes);
[35242]904 ReturnComNotImplemented();
905}
906
[51092]907HRESULT MachineDebugger::readVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, std::vector<BYTE> &aBytes)
[35242]908{
[63244]909 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
[35242]910 ReturnComNotImplemented();
911}
912
[51092]913HRESULT MachineDebugger::writeVirtualMemory(ULONG aCpuId, LONG64 aAddress, ULONG aSize, const std::vector<BYTE> &aBytes)
[35242]914{
[63244]915 RT_NOREF(aCpuId, aAddress, aSize, aBytes);
[35242]916 ReturnComNotImplemented();
917}
918
[55883]919HRESULT MachineDebugger::loadPlugIn(const com::Utf8Str &aName, com::Utf8Str &aPlugInName)
920{
921 /*
922 * Lock the debugger and get the VM pointer
923 */
924 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
925 Console::SafeVMPtr ptrVM(mParent);
[98262]926 HRESULT hrc = ptrVM.hrc();
[55883]927 if (SUCCEEDED(hrc))
928 {
929 /*
930 * Do the job and try convert the name.
931 */
932 if (aName.equals("all"))
933 {
[93444]934 ptrVM.vtable()->pfnDBGFR3PlugInLoadAll(ptrVM.rawUVM());
935 hrc = aPlugInName.assignEx("all");
[55883]936 }
937 else
938 {
939 RTERRINFOSTATIC ErrInfo;
940 char szName[80];
[93444]941 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInLoad(ptrVM.rawUVM(), aName.c_str(), szName, sizeof(szName), RTErrInfoInitStatic(&ErrInfo));
[55883]942 if (RT_SUCCESS(vrc))
[93444]943 hrc = aPlugInName.assignEx(szName);
[55883]944 else
945 hrc = setErrorVrc(vrc, "%s", ErrInfo.szMsg);
946 }
947 }
948 return hrc;
949
950}
951
952HRESULT MachineDebugger::unloadPlugIn(const com::Utf8Str &aName)
953{
954 /*
955 * Lock the debugger and get the VM pointer
956 */
957 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
958 Console::SafeVMPtr ptrVM(mParent);
[98262]959 HRESULT hrc = ptrVM.hrc();
[55883]960 if (SUCCEEDED(hrc))
961 {
962 /*
963 * Do the job and try convert the name.
964 */
965 if (aName.equals("all"))
966 {
[93444]967 ptrVM.vtable()->pfnDBGFR3PlugInUnloadAll(ptrVM.rawUVM());
[55883]968 hrc = S_OK;
969 }
970 else
971 {
[93444]972 int vrc = ptrVM.vtable()->pfnDBGFR3PlugInUnload(ptrVM.rawUVM(), aName.c_str());
[55883]973 if (RT_SUCCESS(vrc))
974 hrc = S_OK;
975 else if (vrc == VERR_NOT_FOUND)
[91503]976 hrc = setErrorBoth(E_FAIL, vrc, tr("Plug-in '%s' was not found"), aName.c_str());
[55883]977 else
[91503]978 hrc = setErrorVrc(vrc, tr("Error unloading '%s': %Rrc"), aName.c_str(), vrc);
[55883]979 }
980 }
981 return hrc;
982
983}
984
[51092]985HRESULT MachineDebugger::detectOS(com::Utf8Str &aOs)
[35250]986{
[35306]987 LogFlowThisFunc(("\n"));
988
989 /*
[55883]990 * Lock the debugger and get the VM pointer
[35306]991 */
[51092]992 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
993 Console::SafeVMPtr ptrVM(mParent);
[98262]994 HRESULT hrc = ptrVM.hrc();
[35306]995 if (SUCCEEDED(hrc))
996 {
[51092]997 /*
[55883]998 * Do the job.
[51092]999 */
1000 char szName[64];
[93444]1001 int vrc = ptrVM.vtable()->pfnDBGFR3OSDetect(ptrVM.rawUVM(), szName, sizeof(szName));
[51092]1002 if (RT_SUCCESS(vrc) && vrc != VINF_DBGF_OS_NOT_DETCTED)
[93444]1003 hrc = aOs.assignEx(szName);
[51092]1004 else
[73003]1005 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("DBGFR3OSDetect failed with %Rrc"), vrc);
[35306]1006 }
1007 return hrc;
[35250]1008}
1009
[55885]1010HRESULT MachineDebugger::queryOSKernelLog(ULONG aMaxMessages, com::Utf8Str &aDmesg)
1011{
1012 /*
1013 * Lock the debugger and get the VM pointer
1014 */
1015 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1016 Console::SafeVMPtr ptrVM(mParent);
[98262]1017 HRESULT hrc = ptrVM.hrc();
[55885]1018 if (SUCCEEDED(hrc))
1019 {
[93444]1020 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)ptrVM.vtable()->pfnDBGFR3OSQueryInterface(ptrVM.rawUVM(), DBGFOSINTERFACE_DMESG);
[55885]1021 if (pDmesg)
1022 {
1023 size_t cbActual;
1024 size_t cbBuf = _512K;
1025 int vrc = aDmesg.reserveNoThrow(cbBuf);
1026 if (RT_SUCCESS(vrc))
1027 {
1028 uint32_t cMessages = aMaxMessages == 0 ? UINT32_MAX : aMaxMessages;
[93470]1029 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), ptrVM.vtable(), 0 /*fFlags*/, cMessages,
[55885]1030 aDmesg.mutableRaw(), cbBuf, &cbActual);
1031
1032 uint32_t cTries = 10;
1033 while (vrc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1034 {
1035 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
[55996]1036 vrc = aDmesg.reserveNoThrow(cbBuf);
[55885]1037 if (RT_SUCCESS(vrc))
[93470]1038 vrc = pDmesg->pfnQueryKernelLog(pDmesg, ptrVM.rawUVM(), ptrVM.vtable(), 0 /*fFlags*/, cMessages,
[55885]1039 aDmesg.mutableRaw(), cbBuf, &cbActual);
1040 }
1041 if (RT_SUCCESS(vrc))
1042 aDmesg.jolt();
1043 else if (vrc == VERR_BUFFER_OVERFLOW)
[91503]1044 hrc = setError(E_FAIL, tr("Too much log available, must use the maxMessages parameter to restrict."));
[55885]1045 else
1046 hrc = setErrorVrc(vrc);
1047 }
1048 else
1049 hrc = setErrorBoth(E_OUTOFMEMORY, vrc);
1050 }
1051 else
[91503]1052 hrc = setError(E_FAIL, tr("The dmesg interface isn't implemented by guest OS digger, or detectOS() has not been called."));
[55885]1053 }
1054 return hrc;
1055}
1056
[51092]1057HRESULT MachineDebugger::getRegister(ULONG aCpuId, const com::Utf8Str &aName, com::Utf8Str &aValue)
[35242]1058{
[35502]1059 /*
1060 * The prologue.
1061 */
1062 LogFlowThisFunc(("\n"));
[51092]1063 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1064 Console::SafeVMPtr ptrVM(mParent);
[98262]1065 HRESULT hrc = ptrVM.hrc();
[35502]1066 if (SUCCEEDED(hrc))
1067 {
[51092]1068 /*
1069 * Real work.
1070 */
1071 DBGFREGVAL Value;
1072 DBGFREGVALTYPE enmType;
[93444]1073 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQuery(ptrVM.rawUVM(), aCpuId, aName.c_str(), &Value, &enmType);
[51092]1074 if (RT_SUCCESS(vrc))
[35502]1075 {
[93444]1076 char szHex[160];
1077 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &Value, enmType, true /*fSpecial*/);
1078 if (cch > 0)
1079 hrc = aValue.assignEx(szHex);
1080 else
1081 hrc = E_UNEXPECTED;
[35502]1082 }
[51092]1083 else if (vrc == VERR_DBGF_REGISTER_NOT_FOUND)
[73003]1084 hrc = setErrorBoth(E_FAIL, vrc, tr("Register '%s' was not found"), aName.c_str());
[51092]1085 else if (vrc == VERR_INVALID_CPU_ID)
[73003]1086 hrc = setErrorBoth(E_FAIL, vrc, tr("Invalid CPU ID: %u"), aCpuId);
[51092]1087 else
[73003]1088 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
[98278]1089 tr("DBGFR3RegNmQuery failed with vrc=%Rrc querying register '%s' with default cpu set to %u"),
[73003]1090 vrc, aName.c_str(), aCpuId);
[35502]1091 }
1092
1093 return hrc;
[35242]1094}
1095
[51092]1096HRESULT MachineDebugger::getRegisters(ULONG aCpuId, std::vector<com::Utf8Str> &aNames, std::vector<com::Utf8Str> &aValues)
[35242]1097{
[63244]1098 RT_NOREF(aCpuId); /** @todo fix missing aCpuId usage! */
1099
[35312]1100 /*
1101 * The prologue.
1102 */
1103 LogFlowThisFunc(("\n"));
[51092]1104 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1105 Console::SafeVMPtr ptrVM(mParent);
[98262]1106 HRESULT hrc = ptrVM.hrc();
[35312]1107 if (SUCCEEDED(hrc))
1108 {
[51092]1109 /*
1110 * Real work.
1111 */
1112 size_t cRegs;
[93444]1113 int vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAllCount(ptrVM.rawUVM(), &cRegs);
[51092]1114 if (RT_SUCCESS(vrc))
[35312]1115 {
[51092]1116 PDBGFREGENTRYNM paRegs = (PDBGFREGENTRYNM)RTMemAllocZ(sizeof(paRegs[0]) * cRegs);
1117 if (paRegs)
[35312]1118 {
[93444]1119 vrc = ptrVM.vtable()->pfnDBGFR3RegNmQueryAll(ptrVM.rawUVM(), paRegs, cRegs);
[51092]1120 if (RT_SUCCESS(vrc))
[35312]1121 {
[51092]1122 try
[35312]1123 {
[55702]1124 aValues.resize(cRegs);
1125 aNames.resize(cRegs);
[102092]1126 uint32_t iDst = 0;
1127 for (uint32_t iSrc = 0; iSrc < cRegs; iSrc++)
1128 if (paRegs[iSrc].pszName) /* skip padding entries */
1129 {
1130 char szHex[160];
1131 szHex[159] = szHex[0] = '\0';
1132 ssize_t cch = ptrVM.vtable()->pfnDBGFR3RegFormatValue(szHex, sizeof(szHex), &paRegs[iSrc].Val,
1133 paRegs[iSrc].enmType, true /*fSpecial*/);
1134 Assert(cch > 0); NOREF(cch);
1135 aNames[iDst] = paRegs[iSrc].pszName;
1136 aValues[iDst] = szHex;
1137 iDst++;
1138 }
1139
1140 /* If we skipped padding entries, resize the return arrays to the actual return size. */
1141 if (iDst < cRegs)
[35550]1142 {
[102092]1143 aValues.resize(iDst);
1144 aNames.resize(iDst);
[35550]1145 }
[35312]1146 }
[73505]1147 catch (std::bad_alloc &)
[51092]1148 {
1149 hrc = E_OUTOFMEMORY;
1150 }
[35312]1151 }
[35550]1152 else
[73003]1153 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAll failed with %Rrc"), vrc);
[51092]1154
1155 RTMemFree(paRegs);
[35312]1156 }
1157 else
[51092]1158 hrc = E_OUTOFMEMORY;
[35312]1159 }
[51092]1160 else
[73003]1161 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3RegNmQueryAllCount failed with %Rrc"), vrc);
[35312]1162 }
1163 return hrc;
[35242]1164}
1165
[51092]1166HRESULT MachineDebugger::setRegister(ULONG aCpuId, const com::Utf8Str &aName, const com::Utf8Str &aValue)
[35242]1167{
[63244]1168 RT_NOREF(aCpuId, aName, aValue);
[35242]1169 ReturnComNotImplemented();
1170}
1171
[51092]1172HRESULT MachineDebugger::setRegisters(ULONG aCpuId, const std::vector<com::Utf8Str> &aNames,
1173 const std::vector<com::Utf8Str> &aValues)
[35242]1174{
[63244]1175 RT_NOREF(aCpuId, aNames, aValues);
[35242]1176 ReturnComNotImplemented();
1177}
1178
[51092]1179HRESULT MachineDebugger::dumpGuestStack(ULONG aCpuId, com::Utf8Str &aStack)
[35250]1180{
[61561]1181 /*
1182 * The prologue.
1183 */
1184 LogFlowThisFunc(("\n"));
1185 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1186 Console::SafeVMPtr ptrVM(mParent);
[98262]1187 HRESULT hrc = ptrVM.hrc();
[61561]1188 if (SUCCEEDED(hrc))
1189 {
[61935]1190 /*
1191 * There is currently a problem with the windows diggers and SMP, where
1192 * guest driver memory is being read from CPU zero in order to ensure that
1193 * we've got a consisten virtual memory view. If one of the other CPUs
1194 * initiates a rendezvous while we're unwinding the stack and trying to
1195 * read guest driver memory, we will deadlock.
1196 *
1197 * So, check the VM state and maybe suspend the VM before we continue.
1198 */
1199 int vrc = VINF_SUCCESS;
1200 bool fPaused = false;
1201 if (aCpuId != 0)
1202 {
[93444]1203 VMSTATE enmVmState = ptrVM.vtable()->pfnVMR3GetStateU(ptrVM.rawUVM());
[61935]1204 if ( enmVmState == VMSTATE_RUNNING
[80074]1205 || enmVmState == VMSTATE_RUNNING_LS)
[61935]1206 {
1207 alock.release();
[93444]1208 vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), VMSUSPENDREASON_USER);
[61935]1209 alock.acquire();
1210 fPaused = RT_SUCCESS(vrc);
1211 }
1212 }
[61561]1213 if (RT_SUCCESS(vrc))
1214 {
[61786]1215 PCDBGFSTACKFRAME pFirstFrame;
[93444]1216 vrc = ptrVM.vtable()->pfnDBGFR3StackWalkBegin(ptrVM.rawUVM(), aCpuId, DBGFCODETYPE_GUEST, &pFirstFrame);
[61786]1217 if (RT_SUCCESS(vrc))
[61561]1218 {
[61786]1219 /*
1220 * Print header.
1221 */
1222 try
[61561]1223 {
[61786]1224 uint32_t fBitFlags = 0;
1225 for (PCDBGFSTACKFRAME pFrame = pFirstFrame;
1226 pFrame;
[93444]1227 pFrame = ptrVM.vtable()->pfnDBGFR3StackWalkNext(pFrame))
[61561]1228 {
[61786]1229 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT);
1230 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT)
1231 {
1232 if (fCurBitFlags != fBitFlags)
1233 aStack.append("SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
[93444]1234 aStack.appendPrintf("%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1235 pFrame->AddrFrame.Sel,
1236 (uint16_t)pFrame->AddrFrame.off,
1237 pFrame->AddrReturnFrame.Sel,
1238 (uint16_t)pFrame->AddrReturnFrame.off,
1239 (uint32_t)pFrame->AddrReturnPC.Sel,
1240 (uint32_t)pFrame->AddrReturnPC.off,
1241 pFrame->Args.au32[0],
1242 pFrame->Args.au32[1],
1243 pFrame->Args.au32[2],
1244 pFrame->Args.au32[3]);
[61786]1245 }
1246 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT)
1247 {
1248 if (fCurBitFlags != fBitFlags)
1249 aStack.append("EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
[93444]1250 aStack.appendPrintf("%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
1251 (uint32_t)pFrame->AddrFrame.off,
1252 (uint32_t)pFrame->AddrReturnFrame.off,
1253 (uint32_t)pFrame->AddrReturnPC.Sel,
1254 (uint32_t)pFrame->AddrReturnPC.off,
1255 pFrame->Args.au32[0],
1256 pFrame->Args.au32[1],
1257 pFrame->Args.au32[2],
1258 pFrame->Args.au32[3]);
[61786]1259 }
1260 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT)
1261 {
1262 if (fCurBitFlags != fBitFlags)
1263 aStack.append("RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n");
[93444]1264 aStack.appendPrintf("%016RX64 %04RX16:%016RX64 %016RX64",
1265 (uint64_t)pFrame->AddrFrame.off,
1266 pFrame->AddrReturnFrame.Sel,
1267 (uint64_t)pFrame->AddrReturnFrame.off,
1268 (uint64_t)pFrame->AddrReturnPC.off);
[61786]1269 }
[61561]1270
[61786]1271 if (!pFrame->pSymPC)
[93444]1272 aStack.appendPrintf(fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT
1273 ? " %RTsel:%016RGv"
1274 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT
1275 ? " %RTsel:%08RGv"
1276 : " %RTsel:%04RGv"
1277 , pFrame->AddrPC.Sel, pFrame->AddrPC.off);
[61561]1278 else
[61786]1279 {
1280 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */
1281 if (offDisp > 0)
[93444]1282 aStack.appendPrintf(" %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp);
[61786]1283 else if (offDisp < 0)
[93444]1284 aStack.appendPrintf(" %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp);
[61786]1285 else
[93444]1286 aStack.appendPrintf(" %s", pFrame->pSymPC->szName);
[61786]1287 }
1288 if (pFrame->pLinePC)
[93444]1289 aStack.appendPrintf(" [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo);
1290 aStack.append("\n");
[61786]1291
1292 fBitFlags = fCurBitFlags;
[61561]1293 }
[61786]1294 }
[73505]1295 catch (std::bad_alloc &)
[61786]1296 {
1297 hrc = E_OUTOFMEMORY;
1298 }
[61561]1299
[93444]1300 ptrVM.vtable()->pfnDBGFR3StackWalkEnd(pFirstFrame);
[61561]1301 }
[61786]1302 else
[73003]1303 hrc = setErrorBoth(E_FAIL, vrc, tr("DBGFR3StackWalkBegin failed with %Rrc"), vrc);
[61561]1304
[61935]1305 /*
1306 * Resume the VM if we suspended it.
1307 */
1308 if (fPaused)
1309 {
1310 alock.release();
[93444]1311 ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_USER);
[61935]1312 }
[61561]1313 }
1314 else
[73003]1315 hrc = setErrorBoth(E_FAIL, vrc, tr("Suspending the VM failed with %Rrc\n"), vrc);
[61561]1316 }
1317
1318 return hrc;
[35250]1319}
1320
[14627]1321/**
1322 * Resets VM statistics.
1323 *
1324 * @returns COM status code.
1325 * @param aPattern The selection pattern. A bit similar to filename globbing.
1326 */
[51092]1327HRESULT MachineDebugger::resetStats(const com::Utf8Str &aPattern)
[14627]1328{
[44347]1329 Console::SafeVMPtrQuiet ptrVM(mParent);
1330 if (!ptrVM.isOk())
[91503]1331 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
[14627]1332
[93444]1333 ptrVM.vtable()->pfnSTAMR3Reset(ptrVM.rawUVM(), aPattern.c_str());
[15827]1334
[14627]1335 return S_OK;
1336}
1337
1338/**
1339 * Dumps VM statistics to the log.
1340 *
1341 * @returns COM status code.
1342 * @param aPattern The selection pattern. A bit similar to filename globbing.
1343 */
[51092]1344HRESULT MachineDebugger::dumpStats(const com::Utf8Str &aPattern)
[14627]1345{
[44347]1346 Console::SafeVMPtrQuiet ptrVM(mParent);
1347 if (!ptrVM.isOk())
[91503]1348 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
[14627]1349
[93444]1350 ptrVM.vtable()->pfnSTAMR3Dump(ptrVM.rawUVM(), aPattern.c_str());
[15827]1351
[14627]1352 return S_OK;
1353}
1354
1355/**
1356 * Get the VM statistics in an XML format.
1357 *
1358 * @returns COM status code.
1359 * @param aPattern The selection pattern. A bit similar to filename globbing.
1360 * @param aWithDescriptions Whether to include the descriptions.
1361 * @param aStats The XML document containing the statistics.
1362 */
[51092]1363HRESULT MachineDebugger::getStats(const com::Utf8Str &aPattern, BOOL aWithDescriptions, com::Utf8Str &aStats)
[14627]1364{
[62598]1365 Console::SafeVMPtrQuiet ptrVM(mParent);
[44347]1366 if (!ptrVM.isOk())
[91503]1367 return setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
[14627]1368
1369 char *pszSnapshot;
[93444]1370 int vrc = ptrVM.vtable()->pfnSTAMR3Snapshot(ptrVM.rawUVM(), aPattern.c_str(), &pszSnapshot, NULL, !!aWithDescriptions);
[21878]1371 if (RT_FAILURE(vrc))
[14627]1372 return vrc == VERR_NO_MEMORY ? E_OUTOFMEMORY : E_FAIL;
1373
1374 /** @todo this is horribly inefficient! And it's kinda difficult to tell whether it failed...
1375 * Must use UTF-8 or ASCII here and completely avoid these two extra copy operations.
1376 * Until that's done, this method is kind of useless for debugger statistics GUI because
1377 * of the amount statistics in a debug build. */
[93444]1378 HRESULT hrc = aStats.assignEx(pszSnapshot);
1379 ptrVM.vtable()->pfnSTAMR3SnapshotFree(ptrVM.rawUVM(), pszSnapshot);
[14627]1380
[93444]1381 return hrc;
[14627]1382}
1383
1384
[80114]1385/** Wrapper around TMR3GetCpuLoadPercents. */
1386HRESULT MachineDebugger::getCPULoad(ULONG aCpuId, ULONG *aPctExecuting, ULONG *aPctHalted, ULONG *aPctOther, LONG64 *aMsInterval)
1387{
1388 HRESULT hrc;
1389 Console::SafeVMPtrQuiet ptrVM(mParent);
1390 if (ptrVM.isOk())
1391 {
1392 uint8_t uPctExecuting = 0;
1393 uint8_t uPctHalted = 0;
1394 uint8_t uPctOther = 0;
1395 uint64_t msInterval = 0;
[93444]1396 int vrc = ptrVM.vtable()->pfnTMR3GetCpuLoadPercents(ptrVM.rawUVM(), aCpuId >= UINT32_MAX / 2 ? VMCPUID_ALL : aCpuId,
1397 &msInterval, &uPctExecuting, &uPctHalted, &uPctOther);
[80114]1398 if (RT_SUCCESS(vrc))
1399 {
1400 *aPctExecuting = uPctExecuting;
1401 *aPctHalted = uPctHalted;
1402 *aPctOther = uPctOther;
1403 *aMsInterval = msInterval;
1404 hrc = S_OK;
1405 }
1406 else
1407 hrc = setErrorVrc(vrc);
1408 }
1409 else
[91503]1410 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("Machine is not running"));
[80114]1411 return hrc;
1412}
1413
1414
[89696]1415HRESULT MachineDebugger::takeGuestSample(const com::Utf8Str &aFilename, ULONG aUsInterval, LONG64 aUsSampleTime, ComPtr<IProgress> &pProgress)
1416{
1417 /*
1418 * The prologue.
1419 */
1420 LogFlowThisFunc(("\n"));
1421 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1422 Console::SafeVMPtr ptrVM(mParent);
[98262]1423 HRESULT hrc = ptrVM.hrc();
[89696]1424 if (SUCCEEDED(hrc))
1425 {
1426 if (!m_hSampleReport)
1427 {
1428 m_strFilename = aFilename;
1429
[93444]1430 int vrc = ptrVM.vtable()->pfnDBGFR3SampleReportCreate(ptrVM.rawUVM(), aUsInterval,
1431 DBGF_SAMPLE_REPORT_F_STACK_REVERSE, &m_hSampleReport);
[89696]1432 if (RT_SUCCESS(vrc))
1433 {
1434 hrc = m_Progress.createObject();
1435 if (SUCCEEDED(hrc))
1436 {
1437 hrc = m_Progress->init(static_cast<IMachineDebugger*>(this),
1438 tr("Creating guest sample report..."),
1439 TRUE /* aCancelable */);
1440 if (SUCCEEDED(hrc))
1441 {
[93444]1442 vrc = ptrVM.vtable()->pfnDBGFR3SampleReportStart(m_hSampleReport, aUsSampleTime, i_dbgfProgressCallback,
1443 static_cast<MachineDebugger*>(this));
[89696]1444 if (RT_SUCCESS(vrc))
1445 hrc = m_Progress.queryInterfaceTo(pProgress.asOutParam());
1446 else
1447 hrc = setErrorVrc(vrc);
1448 }
1449 }
1450
1451 if (FAILED(hrc))
1452 {
[93444]1453 ptrVM.vtable()->pfnDBGFR3SampleReportRelease(m_hSampleReport);
[89696]1454 m_hSampleReport = NULL;
1455 }
1456 }
1457 else
1458 hrc = setErrorVrc(vrc);
1459 }
1460 else
[91503]1461 hrc = setError(VBOX_E_INVALID_VM_STATE, tr("A sample report is already in progress"));
[89696]1462 }
1463
1464 return hrc;
1465}
1466
[93460]1467/**
1468 * Hack for getting the user mode VM handle (UVM) and VMM function table.
1469 *
1470 * @returns COM status code
[93485]1471 * @param aMagicVersion The VMMR3VTABLE_MAGIC_VERSION value of the
1472 * caller so we can check that the function table
1473 * is compatible. (Otherwise, the caller can't
1474 * safely release the UVM reference.)
[93460]1475 * @param aUVM Where to store the vm handle. Since there is no
1476 * uintptr_t in COM, we're using the max integer. (No,
1477 * ULONG is not pointer sized!)
1478 * @param aVMMFunctionTable Where to store the vm handle.
1479 *
1480 * @remarks The returned handle must be passed to VMR3ReleaseUVM()!
1481 */
1482HRESULT MachineDebugger::getUVMAndVMMFunctionTable(LONG64 aMagicVersion, LONG64 *aVMMFunctionTable, LONG64 *aUVM)
1483{
1484 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[89696]1485
[93460]1486 /*
1487 * Make sure it is a local call.
1488 */
1489 RTTHREAD hThread = RTThreadSelf();
1490 if (hThread != NIL_RTTHREAD)
1491 {
1492 const char *pszName = RTThreadGetName(hThread);
1493 if ( !RTStrStartsWith(pszName, "ALIEN-") /* COM worker threads are aliens */
1494 && !RTStrStartsWith(pszName, "nspr-") /* XPCOM worker threads are nspr-X */ )
1495 {
1496 /*
1497 * Use safe VM pointer to get both the UVM and VMM function table.
1498 */
1499 Console::SafeVMPtr ptrVM(mParent);
[98262]1500 HRESULT hrc = ptrVM.hrc();
[93460]1501 if (SUCCEEDED(hrc))
1502 {
1503 if (VMMR3VTABLE_IS_COMPATIBLE_EX(ptrVM.vtable()->uMagicVersion, (uint64_t)aMagicVersion))
1504 {
1505 ptrVM.vtable()->pfnVMR3RetainUVM(ptrVM.rawUVM());
1506 *aUVM = (intptr_t)ptrVM.rawUVM();
1507 *aVMMFunctionTable = (intptr_t)ptrVM.vtable();
1508 hrc = S_OK;
1509 }
1510 else
1511 hrc = setError(E_FAIL, tr("Incompatible VMM function table: %RX64 vs %RX64 (caller)"),
1512 ptrVM.vtable()->uMagicVersion, (uint64_t)aMagicVersion);
1513 }
1514 return hrc;
1515 }
1516 }
1517
1518 return setError(E_ACCESSDENIED, tr("The method getUVMAndVMMFunctionTable is only for local calls"));
1519}
1520
1521
1522
[14627]1523// public methods only for internal purposes
1524/////////////////////////////////////////////////////////////////////////////
1525
[51092]1526void MachineDebugger::i_flushQueuedSettings()
[1]1527{
[14627]1528 mFlushMode = true;
[63147]1529 if (mSingleStepQueued != -1)
[1]1530 {
[39712]1531 COMSETTER(SingleStep)(mSingleStepQueued);
[63147]1532 mSingleStepQueued = -1;
[1]1533 }
[46423]1534 for (unsigned i = 0; i < EMEXECPOLICY_END; i++)
1535 if (maiQueuedEmExecPolicyParams[i] != UINT8_MAX)
1536 {
[51092]1537 i_setEmExecPolicyProperty((EMEXECPOLICY)i, RT_BOOL(maiQueuedEmExecPolicyParams[i]));
[46423]1538 maiQueuedEmExecPolicyParams[i] = UINT8_MAX;
1539 }
[63147]1540 if (mLogEnabledQueued != -1)
[1]1541 {
[39712]1542 COMSETTER(LogEnabled)(mLogEnabledQueued);
[63147]1543 mLogEnabledQueued = -1;
[1]1544 }
[63147]1545 if (mVirtualTimeRateQueued != UINT32_MAX)
[444]1546 {
[39712]1547 COMSETTER(VirtualTimeRate)(mVirtualTimeRateQueued);
[63147]1548 mVirtualTimeRateQueued = UINT32_MAX;
[444]1549 }
[14627]1550 mFlushMode = false;
[1]1551}
1552
1553// private methods
[14627]1554/////////////////////////////////////////////////////////////////////////////
1555
[51092]1556bool MachineDebugger::i_queueSettings() const
[14627]1557{
1558 if (!mFlushMode)
1559 {
1560 // check if the machine is running
1561 MachineState_T machineState;
[39712]1562 mParent->COMGETTER(State)(&machineState);
[24301]1563 switch (machineState)
1564 {
[14627]1565 // queue the request
[24301]1566 default:
1567 return true;
1568
1569 case MachineState_Running:
1570 case MachineState_Paused:
1571 case MachineState_Stuck:
1572 case MachineState_LiveSnapshotting:
1573 case MachineState_Teleporting:
1574 break;
1575 }
[14627]1576 }
1577 return false;
1578}
[14772]1579/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use