summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2022-09-26 19:29:50 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2022-09-26 19:29:50 +0000
commitb2e4c55d1ca2cbba0f971eb4409c0a81a17546fa (patch)
tree8808f7d1e2cb5d3328de15df2e5d0d49db6cb417 /src
parentcf314082b4c736a8bee3a72826f7bd24297a0839 (diff)
downloadVirtualBox-svn-b2e4c55d1ca2cbba0f971eb4409c0a81a17546fa.tar.gz
Main,FE/VBoxManage: Implement possiblity to configure some of the guest debugging facilities to make it more accessible, bugref:1098
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@96888 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src')
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp80
-rw-r--r--src/VBox/Main/Makefile.kmk1
-rw-r--r--src/VBox/Main/idl/VirtualBox.xidl137
-rw-r--r--src/VBox/Main/include/ConsoleImpl.h1
-rw-r--r--src/VBox/Main/include/GuestDebugControlImpl.h82
-rw-r--r--src/VBox/Main/include/MachineImpl.h7
-rw-r--r--src/VBox/Main/include/SessionImpl.h1
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl.cpp27
-rw-r--r--src/VBox/Main/src-client/ConsoleImpl2.cpp57
-rw-r--r--src/VBox/Main/src-client/SessionImpl.cpp17
-rw-r--r--src/VBox/Main/src-server/GuestDebugControlImpl.cpp457
-rw-r--r--src/VBox/Main/src-server/MachineImpl.cpp60
-rw-r--r--src/VBox/Main/src-server/SnapshotImpl.cpp7
-rw-r--r--src/VBox/Main/xml/Settings.cpp84
14 files changed, 1010 insertions, 8 deletions
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
index 9a694f4c500..3465e1be841 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
@@ -262,6 +262,10 @@ enum
MODIFYVM_TESTING_ENABLED,
MODIFYVM_TESTING_MMIO,
MODIFYVM_TESTING_CFG_DWORD,
+ MODIFYVM_GUEST_DEBUG_PROVIDER,
+ MODIFYVM_GUEST_DEBUG_IO_PROVIDER,
+ MODIFYVM_GUEST_DEBUG_ADDRESS,
+ MODIFYVM_GUEST_DEBUG_PORT,
};
static const RTGETOPTDEF g_aModifyVMOptions[] =
@@ -470,6 +474,10 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
OPT1("--testing-enabled", MODIFYVM_TESTING_ENABLED, RTGETOPT_REQ_BOOL_ONOFF),
OPT1("--testing-mmio", MODIFYVM_TESTING_MMIO, RTGETOPT_REQ_BOOL_ONOFF),
OPT1("--testing-cfg-dword", MODIFYVM_TESTING_CFG_DWORD, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_INDEX),
+ OPT1("--guest-debug-provider", MODIFYVM_GUEST_DEBUG_PROVIDER, RTGETOPT_REQ_STRING),
+ OPT1("--guest-debug-io-provider", MODIFYVM_GUEST_DEBUG_IO_PROVIDER, RTGETOPT_REQ_STRING),
+ OPT1("--guest-debug-address", MODIFYVM_GUEST_DEBUG_ADDRESS, RTGETOPT_REQ_STRING),
+ OPT1("--guest-debug-port", MODIFYVM_GUEST_DEBUG_PORT, RTGETOPT_REQ_UINT32),
};
static void vrdeWarningDeprecatedOption(const char *pszOption)
@@ -3557,6 +3565,78 @@ RTEXITCODE handleModifyVM(HandlerArg *a)
GetOptState.uIndex);
break;
+ case MODIFYVM_GUEST_DEBUG_PROVIDER:
+ {
+ ComPtr<IGuestDebugControl> gstDbgCtrl;
+ CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GuestDebugControl)(gstDbgCtrl.asOutParam()));
+
+ GuestDebugProvider_T enmDebugProvider = GuestDebugProvider_None;
+
+ if (!RTStrICmp(ValueUnion.psz, "none"))
+ enmDebugProvider = GuestDebugProvider_None;
+ else if (!RTStrICmp(ValueUnion.psz, "native"))
+ enmDebugProvider = GuestDebugProvider_Native;
+ else if (!RTStrICmp(ValueUnion.psz, "gdb"))
+ enmDebugProvider = GuestDebugProvider_GDB;
+ else if (!RTStrICmp(ValueUnion.psz, "kd"))
+ enmDebugProvider = GuestDebugProvider_KD;
+ else
+ {
+ errorArgument(ModifyVM::tr("Invalid --guest-debug-provider '%s' (valid: none, native, gdb, kd)"),
+ ValueUnion.psz);
+ hrc = E_FAIL;
+ }
+
+ if (SUCCEEDED(hrc))
+ CHECK_ERROR(gstDbgCtrl, COMSETTER(DebugProvider)(enmDebugProvider));
+ break;
+ }
+
+ case MODIFYVM_GUEST_DEBUG_IO_PROVIDER:
+ {
+ ComPtr<IGuestDebugControl> gstDbgCtrl;
+ CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GuestDebugControl)(gstDbgCtrl.asOutParam()));
+
+ GuestDebugIoProvider_T enmDebugIoProvider = GuestDebugIoProvider_None;
+
+ if (!RTStrICmp(ValueUnion.psz, "none"))
+ enmDebugIoProvider = GuestDebugIoProvider_None;
+ else if (!RTStrICmp(ValueUnion.psz, "tcp"))
+ enmDebugIoProvider = GuestDebugIoProvider_TCP;
+ else if (!RTStrICmp(ValueUnion.psz, "udp"))
+ enmDebugIoProvider = GuestDebugIoProvider_UDP;
+ else if (!RTStrICmp(ValueUnion.psz, "ipc"))
+ enmDebugIoProvider = GuestDebugIoProvider_IPC;
+ else
+ {
+ errorArgument(ModifyVM::tr("Invalid --guest-debug-io-provider '%s' (valid: none, tcp, udp, ipc)"),
+ ValueUnion.psz);
+ hrc = E_FAIL;
+ }
+
+ if (SUCCEEDED(hrc))
+ CHECK_ERROR(gstDbgCtrl, COMSETTER(DebugIoProvider)(enmDebugIoProvider));
+ break;
+ }
+
+ case MODIFYVM_GUEST_DEBUG_ADDRESS:
+ {
+ ComPtr<IGuestDebugControl> gstDbgCtrl;
+ CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GuestDebugControl)(gstDbgCtrl.asOutParam()));
+
+ Bstr bstr(ValueUnion.psz);
+ CHECK_ERROR(gstDbgCtrl, COMSETTER(DebugAddress)(bstr.raw()));
+ break;
+ }
+
+ case MODIFYVM_GUEST_DEBUG_PORT:
+ {
+ ComPtr<IGuestDebugControl> gstDbgCtrl;
+ CHECK_ERROR_BREAK(sessionMachine, COMGETTER(GuestDebugControl)(gstDbgCtrl.asOutParam()));
+ CHECK_ERROR(gstDbgCtrl, COMSETTER(DebugPort)(ValueUnion.u32));
+ break;
+ }
+
default:
errorGetOpt(c, &ValueUnion);
hrc = E_FAIL;
diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk
index 97db8aca265..8677611dc0e 100644
--- a/src/VBox/Main/Makefile.kmk
+++ b/src/VBox/Main/Makefile.kmk
@@ -647,6 +647,7 @@ VBoxSVC_SOURCES = \
$(if $(VBOX_WITH_CLOUD_NET), \
src-server/CloudNetworkImpl.cpp \
,) \
+ src-server/GuestDebugControlImpl.cpp \
src-server/GuestOSTypeImpl.cpp \
src-server/HostDnsService.cpp \
src-server/HostImpl.cpp \
diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl
index 1eb8ebd4223..4449088ffe7 100644
--- a/src/VBox/Main/idl/VirtualBox.xidl
+++ b/src/VBox/Main/idl/VirtualBox.xidl
@@ -6671,7 +6671,7 @@
<interface
name="IMachine" extends="$unknown"
- uuid="9fbd57c7-e1b2-4baa-bbfb-ae831c06f32b"
+ uuid="300763af-5d6b-46e6-aa96-273eac15538a"
wsmap="managed"
rest="managed"
wrap-hint-server-addinterfaces="IInternalMachineControl"
@@ -7448,6 +7448,12 @@
</desc>
</attribute>
+ <attribute name="guestDebugControl" type="IGuestDebugControl" readonly="yes">
+ <desc>
+ Guest debugging configuration.
+ </desc>
+ </attribute>
+
<method name="lockMachine">
<rest name="lock" request="post" path="/vms/{vmid}/actions/"/>
<desc>
@@ -23918,7 +23924,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
<interface
name="IInternalSessionControl" extends="$unknown"
- uuid="a797fb40-7e04-4aa5-88c5-299aa0454577"
+ uuid="5045c372-2e8f-4d9e-ad9d-121ab1661146"
internal="yes"
wsmap="suppress"
>
@@ -24320,6 +24326,22 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
<param name="global" type="boolean" dir="in"/>
</method>
+ <method name="onGuestDebugControlChange">
+ <desc>
+ Triggered when settings of the guest debug settings of the
+ associated virtual machine have changed.
+
+ <result name="VBOX_E_INVALID_VM_STATE">
+ Session state prevents operation.
+ </result>
+ <result name="VBOX_E_INVALID_OBJECT_STATE">
+ Session type prevents operation.
+ </result>
+
+ </desc>
+ <param name="guestDebugControl" type="IGuestDebugControl" dir="in"/>
+ </method>
+
<method name="onUSBDeviceAttach">
<desc>
Triggered when a request to capture a USB device (as a result
@@ -26070,6 +26092,91 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
</interface>
<!--
+ // IGuestDebugControl
+ /////////////////////////////////////////////////////////////////////////
+ -->
+ <enum
+ name="GuestDebugProvider"
+ uuid="acdaddc5-aa0f-4f2e-be1f-a9be2828d24a"
+ >
+ <desc>
+ The enabled guest debug provider. This enumeration represents possible
+ values for the <link to="IGuestDebugControl::debugProvider"/> attribute.
+ </desc>
+ <const name="None" value="0">
+ <desc>Guest debugging is disabled.</desc>
+ </const>
+ <const name="Native" value="1">
+ <desc>The native debugger console is enabled.</desc>
+ </const>
+ <const name="GDB" value="2">
+ <desc>The GDB remote stub is enabled.</desc>
+ </const>
+ <const name="KD" value="3">
+ <desc>The WinDbg/KD remote stub is enabled.</desc>
+ </const>
+ </enum>
+
+ <enum
+ name="GuestDebugIoProvider"
+ uuid="0cf00b1b-2ff7-414c-81c6-6cf410eaec4a"
+ >
+ <desc>
+ The enabled guest debug I/O provider. This enumeration represents possible
+ values for the <link to="IGuestDebugControl::debugIoProvider"/> attribute.
+ </desc>
+ <const name="None" value="0">
+ <desc>No connection available (only useful with
+ <link to="GuestDebugProvider::None"/>).
+ </desc>
+ </const>
+ <const name="TCP" value="1">
+ <desc>The remote stub is available through a TCP connection.</desc>
+ </const>
+ <const name="UDP" value="2">
+ <desc>The remote stub is available through a UDP connection.</desc>
+ </const>
+ <const name="IPC" value="3">
+ <desc>The remote stub is available through a IPC connection,
+ namely a named pipe on Windows or a unix socket on other hosts.</desc>
+ </const>
+ </enum>
+
+ <interface
+ name="IGuestDebugControl" extends="$unknown"
+ uuid="1474bb3a-f096-4cd7-a857-8d8e3cea7331"
+ wsmap="managed"
+ rest="managed"
+ reservedMethods="2" reservedAttributes="2"
+ >
+ <desc>
+ Controls the guest debug settings of one virtual machine.
+ </desc>
+
+ <attribute name="debugProvider" type="GuestDebugProvider">
+ <desc>The currently active debug provider.</desc>
+ </attribute>
+
+ <attribute name="debugIoProvider" type="GuestDebugIoProvider">
+ <desc>The I/O backend for the selected debug provider.</desc>
+ </attribute>
+
+ <attribute name="debugAddress" type="wstring">
+ <desc>
+ The address to connect to or listen on,
+ depending on the type.
+ </desc>
+ </attribute>
+
+ <attribute name="debugPort" type="unsigned long">
+ <desc>
+ The port to listen on or connect to, depending on the selected I/O
+ provider. Might be ignored by some providers.
+ </desc>
+ </attribute>
+ </interface>
+
+ <!--
// IVirtualBoxClient
/////////////////////////////////////////////////////////////////////////
-->
@@ -26133,7 +26240,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
-->
<enum
name="VBoxEventType"
- uuid="05dfb131-4deb-4125-9bcd-96518026b423"
+ uuid="e4c5252d-7d1a-4051-8cfb-5b2d7a73d992"
>
<desc>
@@ -26622,8 +26729,13 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
See <link to="IHostAudioDeviceChangedEvent">IHostAudioDeviceChangedEvent</link>.
</desc>
</const>
+ <const name="OnGuestDebugControlChanged" value="117">
+ <desc>
+ See <link to="IGuestDebugControlChangedEvent">IGuestDebugControlChangedEvent</link>.
+ </desc>
+ </const>
<!-- End event marker -->
- <const name="End" value="117">
+ <const name="End" value="118">
<desc>
Must be last event, used for iterations and structures relying on numerical event values.
</desc>
@@ -28959,6 +29071,23 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
</interface>
+ <interface
+ name="IGuestDebugControlChangedEvent" extends="IEvent"
+ uuid="a3d2799e-d3ad-4f73-91ef-7d839689f6d6"
+ wsmap="managed" autogen="VBoxEvent" id="OnGuestDebugControlChanged"
+ >
+ <desc>
+ Notification when a property of the <link to="IMachine::guestDebugControl">guest debug</link>
+ settings changes. Interested callees should use IGuestDebugControl methods and attributes
+ to find out what has changed.
+ </desc>
+ <attribute name="guestDebugControl" type="IGuestDebugControl" readonly="yes">
+ <desc>
+ Guest debug control object that is subject to change.
+ </desc>
+ </attribute>
+ </interface>
+
<!--
// Auxiliary containers
//////////////////////////////////////////////////////////////////////////
diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h
index ef6ba29f5c7..6a632ef63e5 100644
--- a/src/VBox/Main/include/ConsoleImpl.h
+++ b/src/VBox/Main/include/ConsoleImpl.h
@@ -227,6 +227,7 @@ public:
HRESULT i_onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup);
HRESULT i_onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent);
HRESULT i_onExtraDataChange(const Bstr &aMachineId, const Bstr &aKey, const Bstr &aVal);
+ HRESULT i_onGuestDebugControlChange(IGuestDebugControl *aGuestDebugControl);
HRESULT i_getGuestProperty(const Utf8Str &aName, Utf8Str *aValue, LONG64 *aTimestamp, Utf8Str *aFlags);
HRESULT i_setGuestProperty(const Utf8Str &aName, const Utf8Str &aValue, const Utf8Str &aFlags);
diff --git a/src/VBox/Main/include/GuestDebugControlImpl.h b/src/VBox/Main/include/GuestDebugControlImpl.h
new file mode 100644
index 00000000000..32cdb3bc82e
--- /dev/null
+++ b/src/VBox/Main/include/GuestDebugControlImpl.h
@@ -0,0 +1,82 @@
+/* $Id$ */
+/** @file
+ *
+ * VirtualBox/GuestDebugControl COM class implementation
+ */
+
+/*
+ * Copyright (C) 2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef MAIN_INCLUDED_GuestDebugControlImpl_h
+#define MAIN_INCLUDED_GuestDebugControlImpl_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include "GuestDebugControlWrap.h"
+
+namespace settings
+{
+ struct Debugging;
+}
+
+class ATL_NO_VTABLE GuestDebugControl :
+ public GuestDebugControlWrap
+{
+public:
+
+ DECLARE_COMMON_CLASS_METHODS(GuestDebugControl)
+
+ HRESULT FinalConstruct();
+ void FinalRelease();
+
+ // public initializer/uninitializer for internal purposes only
+ HRESULT init(Machine *aParent);
+ HRESULT init(Machine *aParent, GuestDebugControl *aThat);
+ HRESULT initCopy(Machine *aParent, GuestDebugControl *aThat);
+ void uninit();
+
+ // public internal methods
+ HRESULT i_loadSettings(const settings::Debugging &data);
+ HRESULT i_saveSettings(settings::Debugging &data);
+ void i_rollback();
+ void i_commit();
+ void i_copyFrom(GuestDebugControl *aThat);
+ Machine *i_getMachine() const;
+
+private:
+
+ // wrapped IGuestDebugControl properties
+ HRESULT getDebugProvider(GuestDebugProvider_T *aDebugProvider);
+ HRESULT setDebugProvider(GuestDebugProvider_T aDebugProvider);
+ HRESULT getDebugIoProvider(GuestDebugIoProvider_T *aDebugIoProvider);
+ HRESULT setDebugIoProvider(GuestDebugIoProvider_T aDebugIoProvider);
+ HRESULT getDebugAddress(com::Utf8Str &aAddress);
+ HRESULT setDebugAddress(const com::Utf8Str &aAddress);
+ HRESULT getDebugPort(ULONG *aPort);
+ HRESULT setDebugPort(ULONG aPort);
+
+ struct Data;
+ Data *m;
+};
+
+#endif /* !MAIN_INCLUDED_GuestDebugControlImpl_h */
diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h
index 5999b05421d..778b49502d0 100644
--- a/src/VBox/Main/include/MachineImpl.h
+++ b/src/VBox/Main/include/MachineImpl.h
@@ -51,6 +51,7 @@
#include "BandwidthGroupImpl.h"
#include "TrustedPlatformModuleImpl.h"
#include "NvramStoreImpl.h"
+#include "GuestDebugControlImpl.h"
#ifdef VBOX_WITH_RESOURCE_USAGE_API
# include "Performance.h"
# include "PerformanceImpl.h"
@@ -525,6 +526,7 @@ public:
IsModified_GraphicsAdapter = 0x004000,
IsModified_TrustedPlatformModule = 0x008000,
IsModified_NvramStore = 0x010000,
+ IsModified_GuestDebugControl = 0x020000,
};
/**
@@ -575,6 +577,8 @@ public:
virtual HRESULT i_onStorageDeviceChange(IMediumAttachment * /* mediumAttachment */, BOOL /* remove */,
BOOL /* silent */) { return S_OK; }
virtual HRESULT i_onRecordingChange(BOOL /* aEnable */) { return S_OK; }
+ virtual HRESULT i_onGuestDebugControlChange(IGuestDebugControl * /* guestDebugControl */) { return S_OK; }
+
HRESULT i_saveRegistryEntry(settings::MachineRegistryEntry &data);
@@ -839,6 +843,7 @@ protected:
const ComObjPtr<RecordingSettings> mRecordingSettings;
const ComObjPtr<GraphicsAdapter> mGraphicsAdapter;
const ComObjPtr<BandwidthControl> mBandwidthControl;
+ const ComObjPtr<GuestDebugControl> mGuestDebugControl;
const ComObjPtr<TrustedPlatformModule> mTrustedPlatformModule;
const ComObjPtr<NvramStore> mNvramStore;
@@ -1034,6 +1039,7 @@ private:
HRESULT getStateKeyStore(com::Utf8Str &aKeyStore);
HRESULT getLogKeyId(com::Utf8Str &aKeyId);
HRESULT getLogKeyStore(com::Utf8Str &aKeyStore);
+ HRESULT getGuestDebugControl(ComPtr<IGuestDebugControl> &aGuestDebugControl);
// wrapped IMachine methods
HRESULT lockMachine(const ComPtr<ISession> &aSession,
@@ -1432,6 +1438,7 @@ public:
HRESULT i_onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup);
HRESULT i_onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent);
HRESULT i_onCPUExecutionCapChange(ULONG aCpuExecutionCap);
+ HRESULT i_onGuestDebugControlChange(IGuestDebugControl *guestDebugControl);
bool i_hasMatchingUSBFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs);
diff --git a/src/VBox/Main/include/SessionImpl.h b/src/VBox/Main/include/SessionImpl.h
index e361fbfbd1a..adb8b181795 100644
--- a/src/VBox/Main/include/SessionImpl.h
+++ b/src/VBox/Main/include/SessionImpl.h
@@ -122,6 +122,7 @@ private:
HRESULT onRecordingChange(BOOL aEnable);
HRESULT onUSBControllerChange();
HRESULT onSharedFolderChange(BOOL aGlobal);
+ HRESULT onGuestDebugControlChange(const ComPtr<IGuestDebugControl> &aGuestDebugControl);
HRESULT onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
const ComPtr<IVirtualBoxErrorInfo> &aError,
ULONG aMaskedInterfaces,
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index 28645930cfc..e11131e596b 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -6050,6 +6050,33 @@ HRESULT Console::i_onSharedFolderChange(BOOL aGlobal)
}
/**
+ * Called by IInternalSessionControl::OnGuestDebugControlChange().
+ */
+HRESULT Console::i_onGuestDebugControlChange(IGuestDebugControl *aGuestDebugControl)
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ HRESULT hrc = S_OK;
+
+ /* don't trigger changes if the VM isn't running */
+ SafeVMPtrQuiet ptrVM(this);
+ if (ptrVM.isOk())
+ {
+ /// @todo
+ }
+
+ if (SUCCEEDED(hrc))
+ ::FireGuestDebugControlChangedEvent(mEventSource, aGuestDebugControl);
+
+ LogFlowThisFunc(("Leaving rc=%#x\n", S_OK));
+ return hrc;
+}
+
+
+/**
* Called by IInternalSessionControl::OnUSBDeviceAttach() or locally by
* processRemoteUSBDevices() after IInternalMachineControl::RunUSBDeviceFilters()
* returns TRUE for a given remote USB device.
diff --git a/src/VBox/Main/src-client/ConsoleImpl2.cpp b/src/VBox/Main/src-client/ConsoleImpl2.cpp
index 8026b5908e5..c99c2a30a44 100644
--- a/src/VBox/Main/src-client/ConsoleImpl2.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl2.cpp
@@ -3768,6 +3768,63 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, Au
strFile = strVBoxHome;
strFile.append("dbgc-init");
InsertConfigString(pDbgc, "GlobalInitScript", strFile);
+
+ /*
+ * Configure guest debug settings.
+ */
+ ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
+ GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
+
+ hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
+ hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
+ if (enmGstDbgProvider != GuestDebugProvider_None)
+ {
+ GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
+ hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
+ hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
+ Utf8Str strAddress = bstr;
+ bstr.setNull();
+
+ ULONG ulPort = 0;
+ hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
+
+ PCFGMNODE pDbgSettings;
+ InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
+ InsertConfigString(pDbgSettings, "Address", strAddress);
+ InsertConfigInteger(pDbgSettings, "Port", ulPort);
+
+ switch (enmGstDbgProvider)
+ {
+ case GuestDebugProvider_Native:
+ InsertConfigString(pDbgSettings, "StubType", "Native");
+ break;
+ case GuestDebugProvider_GDB:
+ InsertConfigString(pDbgSettings, "StubType", "Gdb");
+ break;
+ case GuestDebugProvider_KD:
+ InsertConfigString(pDbgSettings, "StubType", "Kd");
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+
+ switch (enmGstDbgIoProvider)
+ {
+ case GuestDebugIoProvider_TCP:
+ InsertConfigString(pDbgSettings, "Provider", "tcp");
+ break;
+ case GuestDebugIoProvider_UDP:
+ InsertConfigString(pDbgSettings, "Provider", "udp");
+ break;
+ case GuestDebugIoProvider_IPC:
+ InsertConfigString(pDbgSettings, "Provider", "ipc");
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+ }
}
}
catch (ConfigError &x)
diff --git a/src/VBox/Main/src-client/SessionImpl.cpp b/src/VBox/Main/src-client/SessionImpl.cpp
index 33b639e353c..5ed3a19accd 100644
--- a/src/VBox/Main/src-client/SessionImpl.cpp
+++ b/src/VBox/Main/src-client/SessionImpl.cpp
@@ -873,6 +873,23 @@ HRESULT Session::onDnDModeChange(DnDMode_T aDndMode)
#endif
}
+HRESULT Session::onGuestDebugControlChange(const ComPtr<IGuestDebugControl> &aGuestDebugControl)
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
+ AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
+#ifndef VBOX_COM_INPROC_API_CLIENT
+ AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
+
+ return mConsole->i_onGuestDebugControlChange(aGuestDebugControl);
+#else
+ RT_NOREF(aSerialPort);
+ return S_OK;
+#endif
+}
+
HRESULT Session::onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
const ComPtr<IVirtualBoxErrorInfo> &aError,
ULONG aMaskedInterfaces,
diff --git a/src/VBox/Main/src-server/GuestDebugControlImpl.cpp b/src/VBox/Main/src-server/GuestDebugControlImpl.cpp
new file mode 100644
index 00000000000..7e8dc43a022
--- /dev/null
+++ b/src/VBox/Main/src-server/GuestDebugControlImpl.cpp
@@ -0,0 +1,457 @@
+/* $Id$ */
+/** @file
+ * VirtualBox/GuestDebugControl COM class implementation
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#define LOG_GROUP LOG_GROUP_MAIN_GUESTDEBUGCONTROL
+#include "GuestDebugControlImpl.h"
+#include "MachineImpl.h"
+#include "VirtualBoxImpl.h"
+#include "GuestOSTypeImpl.h"
+
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#include <iprt/cpp/utils.h>
+
+#include <VBox/settings.h>
+
+#include "AutoStateDep.h"
+#include "AutoCaller.h"
+#include "LoggingNew.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// GuestDebugControl private data definition
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+struct GuestDebugControl::Data
+{
+ Data()
+ : pMachine(NULL)
+ { }
+
+ Machine * const pMachine;
+ const ComObjPtr<GuestDebugControl> pPeer;
+ Backupable<settings::Debugging> bd;
+};
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(GuestDebugControl)
+
+HRESULT GuestDebugControl::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void GuestDebugControl::FinalRelease()
+{
+ uninit();
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the Guest Debug Control object.
+ *
+ * @param aParent Handle of the parent object.
+ */
+HRESULT GuestDebugControl::init(Machine *aParent)
+{
+ LogFlowThisFunc(("aParent=%p\n", aParent));
+
+ ComAssertRet(aParent, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ /* m->pPeer is left null */
+
+ m->bd.allocate();
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the Guest Debug Control object given another Guest Debug Control object
+ * (a kind of copy constructor). This object shares data with
+ * the object passed as an argument.
+ *
+ * @note This object must be destroyed before the original object
+ * it shares data with is destroyed.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT GuestDebugControl::init(Machine *aParent, GuestDebugControl *aThat)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ unconst(m->pPeer) = aThat;
+
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.rc());
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ m->bd.share(aThat->m->bd);
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the guest object given another guest object
+ * (a kind of copy constructor). This object makes a private copy of data
+ * of the original object passed as an argument.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT GuestDebugControl::initCopy(Machine *aParent, GuestDebugControl *aThat)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ m = new Data();
+
+ unconst(m->pMachine) = aParent;
+ /* pPeer is left null */
+
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.rc());
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ m->bd.attachCopy(aThat->m->bd);
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void GuestDebugControl::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+ m->bd.free();
+
+ unconst(m->pPeer) = NULL;
+ unconst(m->pMachine) = NULL;
+
+ delete m;
+ m = NULL;
+}
+
+// IGuestDebugControl properties
+/////////////////////////////////////////////////////////////////////////////
+
+HRESULT GuestDebugControl::getDebugProvider(GuestDebugProvider_T *aDebugProvider)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aDebugProvider = m->bd->enmDbgProvider;
+ return S_OK;
+}
+
+
+HRESULT GuestDebugControl::setDebugProvider(GuestDebugProvider_T aDebugProvider)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->enmDbgProvider != aDebugProvider)
+ {
+ m->bd.backup();
+ m->bd->enmDbgProvider = aDebugProvider;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_GuestDebugControl);
+ mlock.release();
+
+ m->pMachine->i_onGuestDebugControlChange(this);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT GuestDebugControl::getDebugIoProvider(GuestDebugIoProvider_T *aDebugIoProvider)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aDebugIoProvider = m->bd->enmIoProvider;
+ return S_OK;
+}
+
+HRESULT GuestDebugControl::setDebugIoProvider(GuestDebugIoProvider_T aDebugIoProvider)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->enmIoProvider != aDebugIoProvider)
+ {
+ m->bd.backup();
+ m->bd->enmIoProvider = aDebugIoProvider;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_GuestDebugControl);
+ mlock.release();
+
+ m->pMachine->i_onGuestDebugControlChange(this);
+ }
+
+ return S_OK;
+}
+
+HRESULT GuestDebugControl::getDebugAddress(com::Utf8Str &aAddress)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aAddress = m->bd->strAddress;
+
+ return S_OK;
+}
+
+
+HRESULT GuestDebugControl::setDebugAddress(const com::Utf8Str &aAddress)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aAddress != m->bd->strAddress)
+ {
+ m->bd.backup();
+ m->bd->strAddress = aAddress;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_GuestDebugControl);
+ mlock.release();
+
+ m->pMachine->i_onGuestDebugControlChange(this);
+ }
+
+ return S_OK;
+}
+
+HRESULT GuestDebugControl::getDebugPort(ULONG *aPort)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aPort = m->bd->ulPort;
+ return S_OK;
+}
+
+HRESULT GuestDebugControl::setDebugPort(ULONG aPort)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd->ulPort != aPort)
+ {
+ m->bd.backup();
+ m->bd->ulPort = aPort;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
+ m->pMachine->i_setModified(Machine::IsModified_GuestDebugControl);
+ mlock.release();
+
+ m->pMachine->i_onGuestDebugControlChange(this);
+ }
+
+ return S_OK;
+}
+
+// public methods only for internal purposes
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Loads debug settings from the given settings.
+ * May be called once right after this object creation.
+ *
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT GuestDebugControl::i_loadSettings(const settings::Debugging &data)
+{
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ // simply copy
+ *m->bd.data() = data;
+
+ return S_OK;
+}
+
+/**
+ * Saves the debug settings to the given settings.
+ *
+ * Note that the given Port node is completely empty on input.
+ *
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT GuestDebugControl::i_saveSettings(settings::Debugging &data)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ // simply copy
+ data = *m->bd.data();
+
+ return S_OK;
+}
+
+/**
+ * @note Locks this object for writing.
+ */
+void GuestDebugControl::i_rollback()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ m->bd.rollback();
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object (also
+ * for writing) if there is one.
+ */
+void GuestDebugControl::i_commit()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller peerCaller(m->pPeer);
+ AssertComRCReturnVoid(peerCaller.rc());
+
+ /* lock both for writing since we modify both (pPeer is "master" so locked
+ * first) */
+ AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
+
+ if (m->bd.isBackedUp())
+ {
+ m->bd.commit();
+ if (m->pPeer)
+ {
+ /* attach new data to the peer and reshare it */
+ m->pPeer->m->bd.attach(m->bd);
+ }
+ }
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object
+ * represented by @a aThat (locked for reading).
+ */
+void GuestDebugControl::i_copyFrom(GuestDebugControl *aThat)
+{
+ AssertReturnVoid(aThat != NULL);
+
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnVoid(thatCaller.rc());
+
+ /* peer is not modified, lock it for reading (aThat is "master" so locked
+ * first) */
+ AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
+
+ /* this will back up current data */
+ m->bd.assignCopy(aThat->m->bd);
+}
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index aff5064e155..74850816761 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -3270,6 +3270,13 @@ HRESULT Machine::getLogKeyStore(com::Utf8Str &aKeyStore)
return S_OK;
}
+HRESULT Machine::getGuestDebugControl(ComPtr<IGuestDebugControl> &aGuestDebugControl)
+{
+ mGuestDebugControl.queryInterfaceTo(aGuestDebugControl.asOutParam());
+
+ return S_OK;
+}
+
/**
* @note Locks objects!
@@ -8695,6 +8702,10 @@ HRESULT Machine::initDataAndChildObjects()
unconst(mBandwidthControl).createObject();
mBandwidthControl->init(this);
+ /* create the guest debug control object */
+ unconst(mGuestDebugControl).createObject();
+ mGuestDebugControl->init(this);
+
return S_OK;
}
@@ -8717,6 +8728,12 @@ void Machine::uninitDataAndChildObjects()
|| getObjectState().getState() == ObjectState::Limited);
/* tell all our other child objects we've been uninitialized */
+ if (mGuestDebugControl)
+ {
+ mGuestDebugControl->uninit();
+ unconst(mGuestDebugControl).setNull();
+ }
+
if (mBandwidthControl)
{
mBandwidthControl->uninit();
@@ -9572,6 +9589,10 @@ HRESULT Machine::i_loadDebugging(const settings::Debugging *pDbg)
{
mHWData->mDebugging = *pDbg;
/* no more processing currently required, this will probably change. */
+
+ HRESULT rc = mGuestDebugControl->i_loadSettings(*pDbg);
+ if (FAILED(rc)) return rc;
+
return S_OK;
}
@@ -10955,7 +10976,10 @@ HRESULT Machine::i_saveHardware(settings::Hardware &data, settings::Debugging *p
mData->mGuestPropertiesModified = FALSE;
#endif /* VBOX_WITH_GUEST_PROPS defined */
- *pDbg = mHWData->mDebugging;
+ rc = mGuestDebugControl->i_saveSettings(mHWData->mDebugging);
+ if (FAILED(rc)) throw rc;
+
+ *pDbg = mHWData->mDebugging; /// @todo r=aeichner: Move this to guest debug control. */
*pAutostart = mHWData->mAutostart;
data.strDefaultFrontend = mHWData->mDefaultFrontend;
@@ -12363,6 +12387,9 @@ void Machine::i_rollback(bool aNotify)
if (mBandwidthControl && (mData->flModifications & IsModified_BandwidthControl))
mBandwidthControl->i_rollback();
+ if (mGuestDebugControl && (mData->flModifications & IsModified_GuestDebugControl))
+ mGuestDebugControl->i_rollback();
+
if (!mHWData.isNull())
mNetworkAdapters.resize(Global::getMaxNetworkAdapters(mHWData->mChipsetType));
NetworkAdapterVector networkAdapters(mNetworkAdapters.size());
@@ -12433,6 +12460,8 @@ void Machine::i_rollback(bool aNotify)
}
}
+ if (flModifications & IsModified_GuestDebugControl)
+ that->i_onGuestDebugControlChange(mGuestDebugControl);
#if 0
if (flModifications & IsModified_BandwidthControl)
@@ -12478,6 +12507,7 @@ void Machine::i_commit()
mAudioSettings->i_commit();
mUSBDeviceFilters->i_commit();
mBandwidthControl->i_commit();
+ mGuestDebugControl->i_commit();
/* Since mNetworkAdapters is a list which might have been changed (resized)
* without using the Backupable<> template we need to handle the copying
@@ -12734,6 +12764,7 @@ void Machine::i_copyFrom(Machine *aThat)
mAudioSettings->i_copyFrom(aThat->mAudioSettings);
mUSBDeviceFilters->i_copyFrom(aThat->mUSBDeviceFilters);
mBandwidthControl->i_copyFrom(aThat->mBandwidthControl);
+ mGuestDebugControl->i_copyFrom(aThat->mGuestDebugControl);
/* create private copies of all controllers */
mStorageControllers.backup();
@@ -13151,6 +13182,9 @@ HRESULT SessionMachine::init(Machine *aMachine)
unconst(mBandwidthControl).createObject();
mBandwidthControl->init(this, aMachine->mBandwidthControl);
+ unconst(mGuestDebugControl).createObject();
+ mGuestDebugControl->init(this, aMachine->mGuestDebugControl);
+
/* default is to delete saved state on Saved -> PoweredOff transition */
mRemoveSavedState = true;
@@ -15000,6 +15034,30 @@ HRESULT SessionMachine::i_onStorageDeviceChange(IMediumAttachment *aAttachment,
}
/**
+ * @note Locks this object for reading.
+ */
+HRESULT SessionMachine::i_onGuestDebugControlChange(IGuestDebugControl *guestDebugControl)
+{
+ LogFlowThisFunc(("\n"));
+
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
+
+ ComPtr<IInternalSessionControl> directControl;
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (mData->mSession.mLockType == LockType_VM)
+ directControl = mData->mSession.mDirectControl;
+ }
+
+ /* ignore notifications sent after #OnSessionEnd() is called */
+ if (!directControl)
+ return S_OK;
+
+ return directControl->OnGuestDebugControlChange(guestDebugControl);
+}
+
+/**
* Returns @c true if this machine's USB controller reports it has a matching
* filter for the given USB device and @c false otherwise.
*
diff --git a/src/VBox/Main/src-server/SnapshotImpl.cpp b/src/VBox/Main/src-server/SnapshotImpl.cpp
index 70db2263b25..0320b49812a 100644
--- a/src/VBox/Main/src-server/SnapshotImpl.cpp
+++ b/src/VBox/Main/src-server/SnapshotImpl.cpp
@@ -1239,6 +1239,10 @@ HRESULT SnapshotMachine::init(SessionMachine *aSessionMachine,
rc = mBandwidthControl->initCopy(this, pMachine->mBandwidthControl);
if (FAILED(rc)) return rc;
+ unconst(mGuestDebugControl).createObject();
+ rc = mGuestDebugControl->initCopy(this, pMachine->mGuestDebugControl);
+ if (FAILED(rc)) return rc;
+
/* Confirm a successful initialization when it's the case */
autoInitSpan.setSucceeded();
@@ -1353,6 +1357,9 @@ HRESULT SnapshotMachine::initFromSettings(Machine *aMachine,
unconst(mBandwidthControl).createObject();
mBandwidthControl->init(this);
+ unconst(mGuestDebugControl).createObject();
+ mGuestDebugControl->init(this);
+
/* load hardware and storage settings */
HRESULT hrc = i_loadHardware(NULL, &mSnapshotId, hardware, pDbg, pAutostart, recording);
if (SUCCEEDED(hrc))
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index 37cc1938865..0bd8a29fe64 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -4175,7 +4175,11 @@ bool Storage::operator==(const Storage &s) const
Debugging::Debugging() :
fTracingEnabled(false),
fAllowTracingToAccessVM(false),
- strTracingConfig()
+ strTracingConfig(),
+ enmDbgProvider(GuestDebugProvider_None),
+ enmIoProvider(GuestDebugIoProvider_None),
+ strAddress(),
+ ulPort(0)
{
}
@@ -4186,7 +4190,11 @@ bool Debugging::areDefaultSettings() const
{
return !fTracingEnabled
&& !fAllowTracingToAccessVM
- && strTracingConfig.isEmpty();
+ && strTracingConfig.isEmpty()
+ && enmDbgProvider == GuestDebugProvider_None
+ && enmIoProvider == GuestDebugIoProvider_None
+ && strAddress.isEmpty()
+ && ulPort == 0;
}
/**
@@ -4199,7 +4207,11 @@ bool Debugging::operator==(const Debugging &d) const
return (this == &d)
|| ( fTracingEnabled == d.fTracingEnabled
&& fAllowTracingToAccessVM == d.fAllowTracingToAccessVM
- && strTracingConfig == d.strTracingConfig);
+ && strTracingConfig == d.strTracingConfig
+ && enmDbgProvider == d.enmDbgProvider
+ && enmIoProvider == d.enmIoProvider
+ && strAddress == d.strAddress
+ && ulPort == d.ulPort);
}
/**
@@ -6222,6 +6234,36 @@ void MachineConfigFile::readDebugging(const xml::ElementNode &elmDebugging, Debu
pelmTracing->getAttributeValue("allowTracingToAccessVM", dbg.fAllowTracingToAccessVM);
pelmTracing->getAttributeValue("config", dbg.strTracingConfig);
}
+
+ const xml::ElementNode *pelmGuestDebug = elmDebugging.findChildElement("GuestDebug");
+ if (pelmGuestDebug)
+ {
+ Utf8Str strTmp;
+ pelmGuestDebug->getAttributeValue("provider", strTmp);
+ if (strTmp == "None")
+ dbg.enmDbgProvider = GuestDebugProvider_None;
+ else if (strTmp == "GDB")
+ dbg.enmDbgProvider = GuestDebugProvider_GDB;
+ else if (strTmp == "KD")
+ dbg.enmDbgProvider = GuestDebugProvider_KD;
+ else
+ throw ConfigFileError(this, pelmGuestDebug, N_("Invalid value '%s' for GuestDebug/@provider attribute"), strTmp.c_str());
+
+ pelmGuestDebug->getAttributeValue("io", strTmp);
+ if (strTmp == "None")
+ dbg.enmIoProvider = GuestDebugIoProvider_None;
+ else if (strTmp == "TCP")
+ dbg.enmIoProvider = GuestDebugIoProvider_TCP;
+ else if (strTmp == "UDP")
+ dbg.enmIoProvider = GuestDebugIoProvider_UDP;
+ else if (strTmp == "IPC")
+ dbg.enmIoProvider = GuestDebugIoProvider_IPC;
+ else
+ throw ConfigFileError(this, pelmGuestDebug, N_("Invalid value '%s' for GuestDebug/@io attribute"), strTmp.c_str());
+
+ pelmGuestDebug->getAttributeValue("address", dbg.strAddress);
+ pelmGuestDebug->getAttributeValue("port", dbg.ulPort);
+ }
}
/**
@@ -8282,6 +8324,32 @@ void MachineConfigFile::buildDebuggingXML(xml::ElementNode &elmParent, const Deb
pElmTracing->setAttribute("enabled", dbg.fTracingEnabled);
pElmTracing->setAttribute("allowTracingToAccessVM", dbg.fAllowTracingToAccessVM);
pElmTracing->setAttribute("config", dbg.strTracingConfig);
+
+ xml::ElementNode *pElmGuestDebug = pElmDebugging->createChild("GuestDebug");
+ const char *pcszDebugProvider = NULL;
+ const char *pcszIoProvider = NULL;
+
+ switch (dbg.enmDbgProvider)
+ {
+ case GuestDebugProvider_None: pcszDebugProvider = "None"; break;
+ case GuestDebugProvider_GDB: pcszDebugProvider = "GDB"; break;
+ case GuestDebugProvider_KD: pcszDebugProvider = "KD"; break;
+ default: AssertFailed(); pcszDebugProvider = "None"; break;
+ }
+
+ switch (dbg.enmIoProvider)
+ {
+ case GuestDebugIoProvider_None: pcszIoProvider = "None"; break;
+ case GuestDebugIoProvider_TCP: pcszIoProvider = "TCP"; break;
+ case GuestDebugIoProvider_UDP: pcszIoProvider = "UDP"; break;
+ case GuestDebugIoProvider_IPC: pcszIoProvider = "IPC"; break;
+ default: AssertFailed(); pcszIoProvider = "None"; break;
+ }
+
+ pElmGuestDebug->setAttribute("provider", pcszDebugProvider);
+ pElmGuestDebug->setAttribute("io", pcszIoProvider);
+ pElmGuestDebug->setAttribute("address", dbg.strAddress);
+ pElmGuestDebug->setAttribute("port", dbg.ulPort);
}
/**
@@ -8961,6 +9029,16 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
}
#endif /* VBOX_WITH_VMNET */
}
+
+ // VirtualBox 7.0 adds guest debug settings.
+ if ( debugging.enmDbgProvider != GuestDebugProvider_None
+ || debugging.enmIoProvider != GuestDebugIoProvider_None
+ || debugging.strAddress.isNotEmpty()
+ || debugging.ulPort != 0)
+ {
+ m->sv = SettingsVersion_v1_19;
+ return;
+ }
}
if (m->sv < SettingsVersion_v1_18)