From 33ce47961373fdbd9c1b1b1b76ac6999b46c7ecf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:21:40 +0000 Subject: [PATCH 1/7] Implement debugger attach flag methods in cDAC debugger contract and DacDbi Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3f4fdba8-737a-48ee-b4de-df5fc4139ae0 Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3f4fdba8-737a-48ee-b4de-df5fc4139ae0 --- docs/design/datacontracts/Debugger.md | 21 +++++++ src/coreclr/inc/cordbpriv.h | 4 +- .../vm/datadescriptor/datadescriptor.inc | 5 +- .../Contracts/IDebugger.cs | 2 + .../Constants.cs | 1 + .../Contracts/Debugger_1.cs | 27 +++++++++ .../Dbi/DacDbiImpl.cs | 60 ++++++++++++++++++- .../managed/cdac/tests/DebuggerTests.cs | 55 +++++++++++++++++ 8 files changed, 169 insertions(+), 6 deletions(-) diff --git a/docs/design/datacontracts/Debugger.md b/docs/design/datacontracts/Debugger.md index 03ee1ebae704d2..674b1d035058e9 100644 --- a/docs/design/datacontracts/Debugger.md +++ b/docs/design/datacontracts/Debugger.md @@ -11,6 +11,8 @@ record struct DebuggerData(uint DefinesBitField, uint MDStructuresVersion); ```csharp bool TryGetDebuggerData(out DebuggerData data); int GetAttachStateFlags(); +void MarkDebuggerAttachPending(); +void MarkDebuggerAttached(bool fAttached); bool MetadataUpdatesApplied(); ``` @@ -22,6 +24,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 @@ -33,6 +36,13 @@ The contract additionally depends on these data descriptors | `Debugger` | `MDStructuresVersion` | Version of metadata data structures | ```csharp + +private enum DebuggerControlFlag_1 : uint +{ + PendingAttach = 0x0100, + Attached = 0x0200, +} + bool TryGetDebuggerData(out DebuggerData data) { data = default; @@ -59,6 +69,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/inc/cordbpriv.h b/src/coreclr/inc/cordbpriv.h index 32a85c28b07401..6dc71bc97a5e01 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -41,8 +41,8 @@ enum DebuggerControlFlag // DBCF_ACTIVATE_REMOTE_DEBUGGING = 0x0040, Deprecated. DO NOT USE DBCF_INTERNAL_MASK = 0xFF00, - DBCF_PENDING_ATTACH = 0x0100, - DBCF_ATTACHED = 0x0200, + DBCF_PENDING_ATTACH = 0x0100, // [cDAC] [Debugger] : Contract depends on this value. + DBCF_ATTACHED = 0x0200, // [cDAC] [Debugger] : Contract depends on this value. DBCF_FIBERMODE = 0x0400 }; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 0ee65734c32da2..71886133122985 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1329,10 +1329,11 @@ CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) CDAC_GLOBAL_POINTER(FinalizerThread, &::g_pFinalizerThread) CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) -#if defined(DEBUGGING_SUPPORTED) && !defined(TARGET_WASM) +#if defined(DEBUGGING_SUPPORTED) CDAC_GLOBAL_POINTER(Debugger, &::g_pDebugger) CDAC_GLOBAL_POINTER(CLRJitAttachState, &::CLRJitAttachState) -#endif // DEBUGGING_SUPPORTED && !TARGET_WASM +CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &::g_CORDebuggerControlFlags) +#endif // DEBUGGING_SUPPORTED #ifdef FEATURE_METADATA_UPDATER CDAC_GLOBAL_POINTER(MetadataUpdatesApplied, &::g_metadataUpdatesApplied) #endif 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 e8a8a237afc800..663bb112a000c6 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 @@ -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(); } 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 c2cc5f234141a1..f803f302bf1ea4 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 FeatureCOMInterop = nameof(FeatureCOMInterop); 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 fab0ca1c91557b..6b322b0f714846 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) @@ -37,6 +43,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 ce9e28ca54aa36..3184b1c218d2c8 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 @@ -315,10 +315,66 @@ public int SetSendExceptionsOutsideOfJMC(Interop.BOOL sendExceptionsOutsideOfJMC => _legacy is not null ? _legacy.SetSendExceptionsOutsideOfJMC(sendExceptionsOutsideOfJMC) : HResults.E_NOTIMPL; public int MarkDebuggerAttachPending() - => _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) - => _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) => _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 a1526abeb941c7..091f0ee14a5f34 100644 --- a/src/native/managed/cdac/tests/DebuggerTests.cs +++ b/src/native/managed/cdac/tests/DebuggerTests.cs @@ -9,6 +9,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Tests; public class DebuggerTests { + private const uint DebuggerControlFlagPendingAttach = 0x0100; + private const uint DebuggerControlFlagAttached = 0x0200; + private static TargetTestHelpers.LayoutResult GetDebuggerLayout(TargetTestHelpers helpers) { return helpers.LayoutFields( @@ -25,6 +28,7 @@ private static TestPlaceholderTarget BuildTarget( uint defines, uint mdStructuresVersion, int? attachStateFlags = null, + uint? debuggerControlFlags = null, byte? metadataUpdatesApplied = null) { TargetTestHelpers helpers = new(arch); @@ -57,6 +61,14 @@ 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); + memBuilder.AddHeapFragment(debuggerControlFlagsFrag); + builder.AddGlobals((Constants.Globals.CORDebuggerControlFlags, debuggerControlFlagsFrag.Address)); + } + if (metadataUpdatesApplied.HasValue) { MockMemorySpace.HeapFragment metadataFrag = allocator.Allocate(1, "MetadataUpdatesApplied"); @@ -87,6 +99,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) @@ -139,6 +157,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) From db9a5f5cc8940e4bea92858ad5dab7e4313cb8a2 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sat, 11 Apr 2026 17:31:46 -0700 Subject: [PATCH 2/7] fix bug in TryGetDebuggerData --- docs/design/datacontracts/Debugger.md | 7 +++---- src/coreclr/vm/datadescriptor/datadescriptor.inc | 4 ++-- .../Contracts/IDebugger.cs | 2 +- .../Contracts/Debugger_1.cs | 5 +---- .../Dbi/DacDbiImpl.cs | 2 +- src/native/managed/cdac/tests/DebuggerTests.cs | 10 +++++++--- .../tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/design/datacontracts/Debugger.md b/docs/design/datacontracts/Debugger.md index 674b1d035058e9..9730110becee3f 100644 --- a/docs/design/datacontracts/Debugger.md +++ b/docs/design/datacontracts/Debugger.md @@ -5,7 +5,7 @@ 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 @@ -54,10 +54,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; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 71886133122985..032c7832d9acf5 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1329,11 +1329,11 @@ CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) CDAC_GLOBAL_POINTER(FinalizerThread, &::g_pFinalizerThread) CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) -#if defined(DEBUGGING_SUPPORTED) +#if defined(DEBUGGING_SUPPORTED) && !TARGET_WASM CDAC_GLOBAL_POINTER(Debugger, &::g_pDebugger) CDAC_GLOBAL_POINTER(CLRJitAttachState, &::CLRJitAttachState) CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &::g_CORDebuggerControlFlags) -#endif // DEBUGGING_SUPPORTED +#endif // DEBUGGING_SUPPORTED && !TARGET_WASM #ifdef FEATURE_METADATA_UPDATER CDAC_GLOBAL_POINTER(MetadataUpdatesApplied, &::g_metadataUpdatesApplied) #endif 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 663bb112a000c6..6244fee409fe55 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 { 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 6b322b0f714846..741671a565597a 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 @@ -30,10 +30,7 @@ bool IDebugger.TryGetDebuggerData(out DebuggerData data) return false; Data.Debugger debugger = _target.ProcessedData.GetOrAdd(debuggerPtr); - 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; } 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 3184b1c218d2c8..f1632496600a14 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) { diff --git a/src/native/managed/cdac/tests/DebuggerTests.cs b/src/native/managed/cdac/tests/DebuggerTests.cs index 091f0ee14a5f34..cd280f3fc33c7e 100644 --- a/src/native/managed/cdac/tests/DebuggerTests.cs +++ b/src/native/managed/cdac/tests/DebuggerTests.cs @@ -113,18 +113,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] 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] From 8b81953325accca3088732e9edd2f9b946148fb3 Mon Sep 17 00:00:00 2001 From: Rachel Date: Sat, 11 Apr 2026 17:37:08 -0700 Subject: [PATCH 3/7] Update datadescriptor.inc --- src/coreclr/vm/datadescriptor/datadescriptor.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 032c7832d9acf5..3d7c79e15e2035 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1329,7 +1329,7 @@ CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) CDAC_GLOBAL_POINTER(FinalizerThread, &::g_pFinalizerThread) CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) -#if defined(DEBUGGING_SUPPORTED) && !TARGET_WASM +#if defined(DEBUGGING_SUPPORTED) && !defined(TARGET_WASM) CDAC_GLOBAL_POINTER(Debugger, &::g_pDebugger) CDAC_GLOBAL_POINTER(CLRJitAttachState, &::CLRJitAttachState) CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &::g_CORDebuggerControlFlags) From b531763b0b6c2c8253109be8323fccb827632298 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Apr 2026 10:28:13 -0700 Subject: [PATCH 4/7] remove dead code --- src/coreclr/debug/di/process.cpp | 5 ----- src/coreclr/debug/ee/rcthread.cpp | 9 --------- src/coreclr/debug/inc/dbgipcevents.h | 10 ++-------- src/coreclr/debug/shared/dbgtransportsession.cpp | 2 -- src/coreclr/inc/cordbpriv.h | 7 ------- 5 files changed, 2 insertions(+), 31 deletions(-) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index b8639060c55cfc..fd7954e50d407a 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -7665,11 +7665,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 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 05be8d03666586..472c34766e4dfa 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 2e3226df9f7d58..98fffc61a49456 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 03f2ac2a72b48f..d0950183e5a78b 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -33,16 +33,9 @@ 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, // [cDAC] [Debugger] : Contract depends on this value. DBCF_ATTACHED = 0x0200, // [cDAC] [Debugger] : Contract depends on this value. - DBCF_FIBERMODE = 0x0400 }; // From 8fc5309e2144e20b0c34e2199ad1730832cf83ee Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Apr 2026 10:29:54 -0700 Subject: [PATCH 5/7] update test --- src/native/managed/cdac/tests/DebuggerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/managed/cdac/tests/DebuggerTests.cs b/src/native/managed/cdac/tests/DebuggerTests.cs index 94a55268301669..4b2804e6e5d0a4 100644 --- a/src/native/managed/cdac/tests/DebuggerTests.cs +++ b/src/native/managed/cdac/tests/DebuggerTests.cs @@ -62,7 +62,6 @@ private static TestPlaceholderTarget BuildTarget( { MockMemorySpace.HeapFragment debuggerControlFlagsFrag = allocator.Allocate(sizeof(uint), "g_CORDebuggerControlFlags"); helpers.Write(debuggerControlFlagsFrag.Data.AsSpan(0, sizeof(uint)), debuggerControlFlags.Value); - memBuilder.AddHeapFragment(debuggerControlFlagsFrag); builder.AddGlobals((Constants.Globals.CORDebuggerControlFlags, debuggerControlFlagsFrag.Address)); } From d2f371efb862de810379dd9fffc310d153f9fc65 Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 17 Apr 2026 10:32:18 -0700 Subject: [PATCH 6/7] Update src/coreclr/inc/cordbpriv.h Co-authored-by: Jan Kotas --- src/coreclr/inc/cordbpriv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/inc/cordbpriv.h b/src/coreclr/inc/cordbpriv.h index d0950183e5a78b..cc14ef14c96580 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -33,7 +33,6 @@ enum DebuggerLaunchSetting enum DebuggerControlFlag { DBCF_NORMAL_OPERATION = 0x0000, -// DBCF_ACTIVATE_REMOTE_DEBUGGING = 0x0040, Deprecated. DO NOT USE DBCF_PENDING_ATTACH = 0x0100, // [cDAC] [Debugger] : Contract depends on this value. DBCF_ATTACHED = 0x0200, // [cDAC] [Debugger] : Contract depends on this value. }; From 7cbd73a5262ab516706748eefa4757f8779a3113 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Apr 2026 11:52:15 -0700 Subject: [PATCH 7/7] remove more dead code --- src/coreclr/debug/di/process.cpp | 3 +-- src/coreclr/inc/corerror.xml | 6 ------ src/coreclr/pal/prebuilt/corerror/mscorurt.rc | 1 - src/coreclr/pal/prebuilt/inc/corerror.h | 1 - 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index fd7954e50d407a..7658c53e79465b 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. @@ -8572,7 +8571,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/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)