diff --git a/docs/design/datacontracts/Debugger.md b/docs/design/datacontracts/Debugger.md index 30607994916306..3823f14b31a9fb 100644 --- a/docs/design/datacontracts/Debugger.md +++ b/docs/design/datacontracts/Debugger.md @@ -5,12 +5,14 @@ This contract is for reading debugger state from the target process, including i ## APIs of contract ```csharp -record struct DebuggerData(uint DefinesBitField, uint MDStructuresVersion); +record struct DebuggerData(bool IsLeftSideInitialized, uint DefinesBitField, uint MDStructuresVersion); ``` ```csharp bool TryGetDebuggerData(out DebuggerData data); int GetAttachStateFlags(); +void MarkDebuggerAttachPending(); +void MarkDebuggerAttached(bool fAttached); bool MetadataUpdatesApplied(); void RequestSyncAtEvent(); void SetSendExceptionsOutsideOfJMC(bool sendExceptionsOutsideOfJMC); @@ -26,6 +28,7 @@ The contract depends on the following globals | --- | --- | --- | | `Debugger` | TargetPointer | Address of the pointer to the Debugger instance (`&g_pDebugger`) | | `CLRJitAttachState` | TargetPointer | Pointer to the CLR JIT attach state flags | +| `CORDebuggerControlFlags` | TargetPointer | Pointer to `g_CORDebuggerControlFlags` | | `MetadataUpdatesApplied` | TargetPointer | Pointer to the g_metadataUpdatesApplied flag | The contract additionally depends on these data descriptors @@ -42,6 +45,13 @@ The contract additionally depends on these data descriptors | `DebuggerRCThread` | `DCB` | Pointer to `DebuggerIPCControlBlock` | ```csharp + +private enum DebuggerControlFlag_1 : uint +{ + PendingAttach = 0x0100, + Attached = 0x0200, +} + bool TryGetDebuggerData(out DebuggerData data) { data = default; @@ -53,10 +63,9 @@ bool TryGetDebuggerData(out DebuggerData data) TargetPointer debuggerPtr = target.ReadPointer(debuggerPtrPtr); if (debuggerPtr == TargetPointer.Null) return false; - int leftSideInitialized = target.Read(debuggerPtr + /* Debugger::LeftSideInitialized offset */); - if (leftSideInitialized == 0) - return false; + bool leftSideInitialized = target.Read(debuggerPtr + /* Debugger::LeftSideInitialized offset */) != 0; data = new DebuggerData( + IsLeftSideInitialized: leftSideInitialized, DefinesBitField: target.Read(debuggerPtr + /* Debugger::Defines offset */), MDStructuresVersion: target.Read(debuggerPtr + /* Debugger::MDStructuresVersion offset */)); return true; @@ -68,6 +77,17 @@ int GetAttachStateFlags() return (int)target.Read(addr); } +void MarkDebuggerAttachPending() +{ + /* OR global "CORDebuggerControlFlags" with PendingAttach flag */; +} + +void MarkDebuggerAttached(bool fAttached) +{ + // if fAttached is true, OR global "CORDebuggerControlFlags" with Attached flag + // otherwise clear both Attached and PendingAttach flags +} + bool MetadataUpdatesApplied() { if (target.TryReadGlobalPointer("MetadataUpdatesApplied", out TargetPointer addr)) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 80b707623dec32..e66fabd5e32563 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -234,7 +234,6 @@ bool IsLegalFatalError(HRESULT hr) { return (hr == CORDBG_E_INCOMPATIBLE_PROTOCOL) || - (hr == CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS) || (hr == CORDBG_E_INCOMPATIBLE_PLATFORMS) || (hr == CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS) || // This should only happen in the case of a security attack on us. @@ -7465,11 +7464,6 @@ void CordbProcess::VerifyControlBlock() ThrowHR(CORDBG_E_INCOMPATIBLE_PROTOCOL); #endif - if (GetDCB()->m_bHostingInFiber) - { - ThrowHR(CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS); - } - _ASSERTE(!GetDCB()->m_rightSideShouldCreateHelperThread); } // CordbProcess::VerifyControlBlock @@ -8377,7 +8371,7 @@ void CordbProcess::UnrecoverableError(HRESULT errorHR, CONSISTENCY_CHECK_MSGF(IsLegalFatalError(errorHR), ("Unrecoverable internal error: hr=0x%08x!", errorHR)); - if (!IsLegalFatalError(errorHR) || (errorHR != CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS)) + if (!IsLegalFatalError(errorHR)) { // This will throw everything into a Zombie state. The ATT_ macros will check this and fail immediately. m_unrecoverableError = true; diff --git a/src/coreclr/debug/ee/rcthread.cpp b/src/coreclr/debug/ee/rcthread.cpp index 078d57ced6cebb..7000961e3bb0d8 100644 --- a/src/coreclr/debug/ee/rcthread.cpp +++ b/src/coreclr/debug/ee/rcthread.cpp @@ -191,15 +191,6 @@ HRESULT DebuggerIPCControlBlock::Init( #else m_checkedBuild = false; #endif - m_bHostingInFiber = false; - - // Are we in fiber mode? In Whidbey, we do not support launch a fiber mode process - // nor do we support attach to a fiber mode process. - // - if (g_CORDebuggerControlFlags & DBCF_FIBERMODE) - { - m_bHostingInFiber = true; - } #if !defined(FEATURE_DBGIPC_TRANSPORT_VM) // Copy RSEA and RSER into the control block. diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index dfc8ede0cd1399..5affc01830077a 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -203,10 +203,7 @@ struct MSLAYOUT DebuggerIPCControlBlock // This next stuff fits in a DWORD. bool m_checkedBuild; // CLR build type for the Left Side. - // using the first padding byte to indicate if hosted in fiber mode. - // We actually just need one bit. So if needed, can turn this to a bit. - // BYTE padding1; - bool m_bHostingInFiber; + BYTE padding1; BYTE padding2; BYTE padding3; @@ -303,10 +300,7 @@ struct MSLAYOUT DebuggerIPCControlBlockTransport // This next stuff fits in a DWORD. bool m_checkedBuild; // CLR build type for the Left Side. - // using the first padding byte to indicate if hosted in fiber mode. - // We actually just need one bit. So if needed, can turn this to a bit. - // BYTE padding1; - bool m_bHostingInFiber; + BYTE padding1; BYTE padding2; BYTE padding3; diff --git a/src/coreclr/debug/shared/dbgtransportsession.cpp b/src/coreclr/debug/shared/dbgtransportsession.cpp index 1d61f5f28daf73..ceb5af5a059a2f 100644 --- a/src/coreclr/debug/shared/dbgtransportsession.cpp +++ b/src/coreclr/debug/shared/dbgtransportsession.cpp @@ -394,7 +394,6 @@ void MarshalDCBTransportToDCB(DebuggerIPCControlBlockTransport* pIn, DebuggerIPC pOut->m_verMajor = pIn->m_verMajor; pOut->m_verMinor = pIn->m_verMinor; pOut->m_checkedBuild = pIn->m_checkedBuild; - pOut->m_bHostingInFiber = pIn->m_bHostingInFiber; pOut->padding2 = pIn->padding2; pOut->padding3 = pIn->padding3; @@ -448,7 +447,6 @@ void MarshalDCBToDCBTransport(DebuggerIPCControlBlock* pIn, DebuggerIPCControlBl pOut->m_verMajor = pIn->m_verMajor; pOut->m_verMinor = pIn->m_verMinor; pOut->m_checkedBuild = pIn->m_checkedBuild; - pOut->m_bHostingInFiber = pIn->m_bHostingInFiber; pOut->padding2 = pIn->padding2; pOut->padding3 = pIn->padding3; diff --git a/src/coreclr/inc/cordbpriv.h b/src/coreclr/inc/cordbpriv.h index e323937df63ce2..cc14ef14c96580 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -33,16 +33,8 @@ enum DebuggerLaunchSetting enum DebuggerControlFlag { DBCF_NORMAL_OPERATION = 0x0000, - - DBCF_USER_MASK = 0x00FF, - DBCF_GENERATE_DEBUG_CODE = 0x0001, - DBCF_PROFILER_ENABLED = 0x0020, -// DBCF_ACTIVATE_REMOTE_DEBUGGING = 0x0040, Deprecated. DO NOT USE - - DBCF_INTERNAL_MASK = 0xFF00, - DBCF_PENDING_ATTACH = 0x0100, - DBCF_ATTACHED = 0x0200, - DBCF_FIBERMODE = 0x0400 + DBCF_PENDING_ATTACH = 0x0100, // [cDAC] [Debugger] : Contract depends on this value. + DBCF_ATTACHED = 0x0200, // [cDAC] [Debugger] : Contract depends on this value. }; // diff --git a/src/coreclr/inc/corerror.xml b/src/coreclr/inc/corerror.xml index 2dddc650ead94e..feea86b39e622f 100644 --- a/src/coreclr/inc/corerror.xml +++ b/src/coreclr/inc/corerror.xml @@ -1797,12 +1797,6 @@ Trying to shutdown out of order. - - CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS - "Debugging fiber mode managed process is not supported." - For Whidbey, we don't support debugging fiber mode managed process - - CORDBG_E_MUST_BE_IN_CREATE_PROCESS "Must be in context of CreateProcess callback to perform requested operation." diff --git a/src/coreclr/pal/prebuilt/corerror/mscorurt.rc b/src/coreclr/pal/prebuilt/corerror/mscorurt.rc index df0e680abdd4fb..10cd7373eeaced 100644 --- a/src/coreclr/pal/prebuilt/corerror/mscorurt.rc +++ b/src/coreclr/pal/prebuilt/corerror/mscorurt.rc @@ -246,7 +246,6 @@ BEGIN MSG_FOR_URT_HR(CORDBG_E_CANNOT_BE_ON_ATTACH) "Requested operation cannot be performed during an attach operation." MSG_FOR_URT_HR(CORDBG_E_NGEN_NOT_SUPPORTED) "NGEN is not supported." MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_SHUTDOWN_ORDER) "Trying to shutdown out of order." - MSG_FOR_URT_HR(CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS) "Debugging fiber mode managed process is not supported." MSG_FOR_URT_HR(CORDBG_E_MUST_BE_IN_CREATE_PROCESS) "Must be in context of CreateProcess callback to perform requested operation." MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_EVALS) "All outstanding func-evals have not completed, detaching is not allowed at this time." MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_STEPPERS) "All outstanding steppers have not been closed, detaching is not allowed at this time." diff --git a/src/coreclr/pal/prebuilt/inc/corerror.h b/src/coreclr/pal/prebuilt/inc/corerror.h index 7106a8bbf33614..b2b0e73d265399 100644 --- a/src/coreclr/pal/prebuilt/inc/corerror.h +++ b/src/coreclr/pal/prebuilt/inc/corerror.h @@ -318,7 +318,6 @@ #define CORDBG_E_CANNOT_BE_ON_ATTACH EMAKEHR(0x1c13) #define CORDBG_E_NGEN_NOT_SUPPORTED EMAKEHR(0x1c14) #define CORDBG_E_ILLEGAL_SHUTDOWN_ORDER EMAKEHR(0x1c15) -#define CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS EMAKEHR(0x1c16) #define CORDBG_E_MUST_BE_IN_CREATE_PROCESS EMAKEHR(0x1c17) #define CORDBG_E_DETACH_FAILED_OUTSTANDING_EVALS EMAKEHR(0x1c18) #define CORDBG_E_DETACH_FAILED_OUTSTANDING_STEPPERS EMAKEHR(0x1c19) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index a13b9b275ce31c..cb4cc19076d3ec 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1348,6 +1348,7 @@ CDAC_GLOBAL_POINTER(EEConfig, &::g_pConfig) #if defined(DEBUGGING_SUPPORTED) && !defined(TARGET_WASM) CDAC_GLOBAL_POINTER(Debugger, &::g_pDebugger) CDAC_GLOBAL_POINTER(CLRJitAttachState, &::CLRJitAttachState) +CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &::g_CORDebuggerControlFlags) #endif // DEBUGGING_SUPPORTED && !TARGET_WASM #ifdef FEATURE_METADATA_UPDATER CDAC_GLOBAL_POINTER(MetadataUpdatesApplied, &::g_metadataUpdatesApplied) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs index 13a8ad99e9ae43..1762e12dfc2ef4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs @@ -5,7 +5,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -public record struct DebuggerData(uint DefinesBitField, uint MDStructuresVersion); +public record struct DebuggerData(bool IsLeftSideInitialized, uint DefinesBitField, uint MDStructuresVersion); public interface IDebugger : IContract { @@ -13,6 +13,8 @@ public interface IDebugger : IContract bool TryGetDebuggerData(out DebuggerData data) => throw new NotImplementedException(); int GetAttachStateFlags() => throw new NotImplementedException(); + void MarkDebuggerAttachPending() => throw new NotImplementedException(); + void MarkDebuggerAttached(bool fAttached) => throw new NotImplementedException(); bool MetadataUpdatesApplied() => throw new NotImplementedException(); void RequestSyncAtEvent() => throw new NotImplementedException(); void SetSendExceptionsOutsideOfJMC(bool sendExceptionsOutsideOfJMC) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 41eccea4c65d96..a742aee2e29e52 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -15,6 +15,7 @@ public static class Globals public const string GCThread = nameof(GCThread); public const string Debugger = nameof(Debugger); public const string CLRJitAttachState = nameof(CLRJitAttachState); + public const string CORDebuggerControlFlags = nameof(CORDebuggerControlFlags); public const string MetadataUpdatesApplied = nameof(MetadataUpdatesApplied); public const string EEConfig = nameof(EEConfig); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs index 2dcf181d381d31..229b789f487178 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs @@ -5,6 +5,12 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct Debugger_1 : IDebugger { + private enum DebuggerControlFlag_1 : uint + { + PendingAttach = 0x0100, + Attached = 0x0200, + } + private readonly Target _target; internal Debugger_1(Target target) @@ -31,10 +37,7 @@ bool IDebugger.TryGetDebuggerData(out DebuggerData data) return false; Data.Debugger debugger = _target.ProcessedData.GetOrAdd(debuggerAddress); - if (debugger.LeftSideInitialized == 0) - return false; - - data = new DebuggerData(debugger.Defines, debugger.MDStructuresVersion); + data = new DebuggerData(debugger.LeftSideInitialized != 0, debugger.Defines, debugger.MDStructuresVersion); return true; } @@ -44,6 +47,27 @@ int IDebugger.GetAttachStateFlags() return (int)_target.Read(addr.Value); } + void IDebugger.MarkDebuggerAttachPending() + { + TargetPointer addr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags); + uint currentFlags = _target.Read(addr.Value); + _target.Write(addr.Value, currentFlags | (uint)DebuggerControlFlag_1.PendingAttach); + } + + void IDebugger.MarkDebuggerAttached(bool fAttached) + { + TargetPointer addr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags); + uint currentFlags = _target.Read(addr.Value); + if (fAttached) + { + _target.Write(addr.Value, currentFlags | (uint)DebuggerControlFlag_1.Attached); + } + else + { + _target.Write(addr.Value, currentFlags & ~((uint)DebuggerControlFlag_1.Attached | (uint)DebuggerControlFlag_1.PendingAttach)); + } + } + bool IDebugger.MetadataUpdatesApplied() { if (_target.TryReadGlobalPointer(Constants.Globals.MetadataUpdatesApplied, out TargetPointer? addr)) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 6448703ec5be38..c92007d6cf814a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -61,7 +61,7 @@ public int IsLeftSideInitialized(Interop.BOOL* pResult) int hr = HResults.S_OK; try { - *pResult = _target.Contracts.Debugger.TryGetDebuggerData(out _) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + *pResult = _target.Contracts.Debugger.TryGetDebuggerData(out Contracts.DebuggerData data) && data.IsLeftSideInitialized ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; } catch (System.Exception ex) { @@ -283,10 +283,66 @@ public int SetSendExceptionsOutsideOfJMC(Interop.BOOL sendExceptionsOutsideOfJMC } public int MarkDebuggerAttachPending() - => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.MarkDebuggerAttachPending() : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + Contracts.IDebugger debugger = _target.Contracts.Debugger; + if (debugger.TryGetDebuggerData(out _)) + { + debugger.MarkDebuggerAttachPending(); + } + else + { + throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_NOTREADY)!; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + int hrLocal = _legacy.MarkDebuggerAttachPending(); + Debug.ValidateHResult(hr, hrLocal); + } +#endif + + return hr; + } public int MarkDebuggerAttached(Interop.BOOL fAttached) - => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.MarkDebuggerAttached(fAttached) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + try + { + Contracts.IDebugger debugger = _target.Contracts.Debugger; + if (debugger.TryGetDebuggerData(out _)) + { + debugger.MarkDebuggerAttached(fAttached != Interop.BOOL.FALSE); + } + else if (fAttached != Interop.BOOL.FALSE) + { + throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_NOTREADY)!; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + +#if DEBUG + if (_legacy is not null) + { + int hrLocal = _legacy.MarkDebuggerAttached(fAttached); + Debug.ValidateHResult(hr, hrLocal); + } +#endif + + return hr; + } public int Hijack(ulong vmThread, uint dwThreadId, nint pRecord, nint pOriginalContext, uint cbSizeContext, int reason, nint pUserData, ulong* pRemoteContextAddr) => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.Hijack(vmThread, dwThreadId, pRecord, pOriginalContext, cbSizeContext, reason, pUserData, pRemoteContextAddr) : HResults.E_NOTIMPL; diff --git a/src/native/managed/cdac/tests/DebuggerTests.cs b/src/native/managed/cdac/tests/DebuggerTests.cs index ba4d890042130d..ef2dc7f8c71af9 100644 --- a/src/native/managed/cdac/tests/DebuggerTests.cs +++ b/src/native/managed/cdac/tests/DebuggerTests.cs @@ -10,6 +10,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Tests; public class DebuggerTests { + private const uint DebuggerControlFlagPendingAttach = 0x0100; + private const uint DebuggerControlFlagAttached = 0x0200; + /// /// Provides all standard architectures paired with each bool value, /// for testing write APIs that take a bool. @@ -51,6 +54,7 @@ private static TestPlaceholderTarget BuildTarget( uint defines, uint mdStructuresVersion, int? attachStateFlags = null, + uint? debuggerControlFlags = null, byte? metadataUpdatesApplied = null, ulong? debuggerControlBlockAddress = null) { @@ -98,6 +102,13 @@ private static TestPlaceholderTarget BuildTarget( builder.AddGlobals((Constants.Globals.CLRJitAttachState, attachFrag.Address)); } + if (debuggerControlFlags.HasValue) + { + MockMemorySpace.HeapFragment debuggerControlFlagsFrag = allocator.Allocate(sizeof(uint), "g_CORDebuggerControlFlags"); + helpers.Write(debuggerControlFlagsFrag.Data.AsSpan(0, sizeof(uint)), debuggerControlFlags.Value); + builder.AddGlobals((Constants.Globals.CORDebuggerControlFlags, debuggerControlFlagsFrag.Address)); + } + if (metadataUpdatesApplied.HasValue) { MockMemorySpace.HeapFragment metadataFrag = allocator.Allocate(1, "MetadataUpdatesApplied"); @@ -126,6 +137,12 @@ private static TestPlaceholderTarget BuildNullDebuggerTarget(MockTarget.Architec return builder.Build(); } + private static uint GetDebuggerControlFlags(Target target) + { + TargetPointer addr = target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags); + return target.Read(addr.Value); + } + [Theory] [ClassData(typeof(MockTarget.StdArch))] public void TryGetDebuggerData_ReturnsTrue_WhenInitialized(MockTarget.Architecture arch) @@ -134,18 +151,22 @@ public void TryGetDebuggerData_ReturnsTrue_WhenInitialized(MockTarget.Architectu IDebugger debugger = target.Contracts.Debugger; Assert.True(debugger.TryGetDebuggerData(out DebuggerData data)); + Assert.True(data.IsLeftSideInitialized); Assert.Equal(0xDEADBEEFu, data.DefinesBitField); Assert.Equal(42u, data.MDStructuresVersion); } [Theory] [ClassData(typeof(MockTarget.StdArch))] - public void TryGetDebuggerData_ReturnsFalse_WhenNotInitialized(MockTarget.Architecture arch) + public void TryGetDebuggerData_ReturnsTrue_WhenNotInitialized(MockTarget.Architecture arch) { - Target target = BuildTarget(arch, leftSideInitialized: 0, defines: 0, mdStructuresVersion: 0); + Target target = BuildTarget(arch, leftSideInitialized: 0, defines: 0xCAFE, mdStructuresVersion: 7); IDebugger debugger = target.Contracts.Debugger; - Assert.False(debugger.TryGetDebuggerData(out _)); + Assert.True(debugger.TryGetDebuggerData(out DebuggerData data)); + Assert.False(data.IsLeftSideInitialized); + Assert.Equal(0xCAFEu, data.DefinesBitField); + Assert.Equal(7u, data.MDStructuresVersion); } [Theory] @@ -178,6 +199,43 @@ public void GetAttachStateFlags_ReturnsZero_WhenValueIsZero(MockTarget.Architect Assert.Equal(0, debugger.GetAttachStateFlags()); } + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void MarkDebuggerAttachPending_SetsPendingAttachFlag(MockTarget.Architecture arch) + { + Target target = BuildTarget(arch, leftSideInitialized: 1, defines: 0, mdStructuresVersion: 0, attachStateFlags: 0, debuggerControlFlags: 0x42); + IDebugger debugger = target.Contracts.Debugger; + + debugger.MarkDebuggerAttachPending(); + + Assert.Equal(0x42u | DebuggerControlFlagPendingAttach, GetDebuggerControlFlags(target)); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void MarkDebuggerAttached_SetsAttachedFlag_WhenTrue(MockTarget.Architecture arch) + { + Target target = BuildTarget(arch, leftSideInitialized: 1, defines: 0, mdStructuresVersion: 0, attachStateFlags: 0, debuggerControlFlags: DebuggerControlFlagPendingAttach); + IDebugger debugger = target.Contracts.Debugger; + + debugger.MarkDebuggerAttached(true); + + Assert.Equal(DebuggerControlFlagPendingAttach | DebuggerControlFlagAttached, GetDebuggerControlFlags(target)); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void MarkDebuggerAttached_ClearsAttachedAndPending_WhenFalse(MockTarget.Architecture arch) + { + const uint originalFlags = 0x0042u | DebuggerControlFlagPendingAttach | DebuggerControlFlagAttached; + Target target = BuildTarget(arch, leftSideInitialized: 1, defines: 0, mdStructuresVersion: 0, attachStateFlags: 0, debuggerControlFlags: originalFlags); + IDebugger debugger = target.Contracts.Debugger; + + debugger.MarkDebuggerAttached(false); + + Assert.Equal(0x42u, GetDebuggerControlFlags(target)); + } + [Theory] [ClassData(typeof(MockTarget.StdArch))] public void MetadataUpdatesApplied_ReturnsTrue_WhenSet(MockTarget.Architecture arch) diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs index 718f1a9273a3a8..b4743abe6ca36c 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs @@ -90,8 +90,8 @@ public unsafe void IsLeftSideInitialized_CrossValidateWithContract(TestConfigura int hr = dbi.IsLeftSideInitialized(&dbiResult); Assert.Equal(System.HResults.S_OK, hr); - bool contractResult = Target.Contracts.Debugger.TryGetDebuggerData(out _); - Assert.Equal(contractResult, dbiResult != Interop.BOOL.FALSE); + bool contractResult = Target.Contracts.Debugger.TryGetDebuggerData(out Contracts.DebuggerData data); + Assert.Equal(contractResult && data.IsLeftSideInitialized, dbiResult != Interop.BOOL.FALSE); } [ConditionalTheory]