diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-09-26 19:29:50 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-09-26 19:29:50 +0000 |
commit | b2e4c55d1ca2cbba0f971eb4409c0a81a17546fa (patch) | |
tree | 8808f7d1e2cb5d3328de15df2e5d0d49db6cb417 /src | |
parent | cf314082b4c736a8bee3a72826f7bd24297a0839 (diff) | |
download | VirtualBox-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.cpp | 80 | ||||
-rw-r--r-- | src/VBox/Main/Makefile.kmk | 1 | ||||
-rw-r--r-- | src/VBox/Main/idl/VirtualBox.xidl | 137 | ||||
-rw-r--r-- | src/VBox/Main/include/ConsoleImpl.h | 1 | ||||
-rw-r--r-- | src/VBox/Main/include/GuestDebugControlImpl.h | 82 | ||||
-rw-r--r-- | src/VBox/Main/include/MachineImpl.h | 7 | ||||
-rw-r--r-- | src/VBox/Main/include/SessionImpl.h | 1 | ||||
-rw-r--r-- | src/VBox/Main/src-client/ConsoleImpl.cpp | 27 | ||||
-rw-r--r-- | src/VBox/Main/src-client/ConsoleImpl2.cpp | 57 | ||||
-rw-r--r-- | src/VBox/Main/src-client/SessionImpl.cpp | 17 | ||||
-rw-r--r-- | src/VBox/Main/src-server/GuestDebugControlImpl.cpp | 457 | ||||
-rw-r--r-- | src/VBox/Main/src-server/MachineImpl.cpp | 60 | ||||
-rw-r--r-- | src/VBox/Main/src-server/SnapshotImpl.cpp | 7 | ||||
-rw-r--r-- | src/VBox/Main/xml/Settings.cpp | 84 |
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) |