From 043157d754203e3ff2e1141366ebb4f4e50a1af4 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:21:39 -0400 Subject: [PATCH 01/18] cDAC: Add no-fallback mode via CDAC_NO_FALLBACK env var When CDAC_NO_FALLBACK=1 is set alongside DOTNET_ENABLE_CDAC=1, the managed cDAC entrypoints (CreateSosInterface, CreateDacDbiInterface) skip wiring up the legacy DAC for fallback but hold an RCW reference to prevent use-after-free of the native CDAC::m_legacyImpl raw pointer. - Add _prevent_release field to SOSDacImpl and DacDbiImpl - Add no-fallback pipeline leg to runtime-diagnostics.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/pipelines/runtime-diagnostics.yml | 57 +++++++++++++++++++ src/coreclr/inc/crosscomp.h | 6 ++ .../Dbi/DacDbiImpl.cs | 4 +- .../SOSDacImpl.cs | 8 ++- .../mscordaccore_universal/Entrypoints.cs | 44 +++++++++++--- 5 files changed, 108 insertions(+), 11 deletions(-) diff --git a/eng/pipelines/runtime-diagnostics.yml b/eng/pipelines/runtime-diagnostics.yml index 013c57cc6bc167..e6b53e8aaa9a8f 100644 --- a/eng/pipelines/runtime-diagnostics.yml +++ b/eng/pipelines/runtime-diagnostics.yml @@ -144,6 +144,63 @@ extends: displayName: 'Publish Test Results and SOS Logs' continueOnError: true condition: failed() + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml + buildConfig: release + platforms: + - windows_x64 + # Workaround: microsoft/azure-pipelines-tasks#21871 + variables: + - name: AllowPtrToDetectTestRunRetryFiles + value: false + - name: DOTNET_ENABLE_CDAC + value: '1' + - name: CDAC_NO_FALLBACK + value: '1' + jobParameters: + name: cDAC_no_fallback + useCdac: true + classFilter: SOS + isOfficialBuild: ${{ variables.isOfficialBuild }} + liveRuntimeDir: $(Build.SourcesDirectory)/artifacts/runtime + timeoutInMinutes: 360 + dependsOn: + - build_windows_x64_release_AllSubsets_CoreCLR + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_coreclr + artifactFileName: BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_coreclr$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/runtime + displayName: 'Runtime Build Artifacts' + postBuildSteps: + - task: PublishTestResults@2 + inputs: + testResultsFormat: xUnit + testResultsFiles: '**/*.xml' + searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults' + testRunTitle: 'Tests $(_PhaseName)' + failTaskOnFailedTests: true + publishRunAttachments: true + mergeTestResults: true + buildConfiguration: $(_BuildConfig) + continueOnError: true + condition: always() + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.SourcesDirectory)/artifacts/tmp/$(_BuildConfig)/dumps' + artifactName: 'Dumps_cDAC_no_fallback_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)' + displayName: 'Publish Crash Dumps' + continueOnError: true + condition: failed() + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.SourcesDirectory)/artifacts/TestResults' + artifactName: 'TestResults_cDAC_no_fallback_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig)_Attempt$(System.JobAttempt)' + displayName: 'Publish Test Results and SOS Logs' + continueOnError: true + condition: failed() - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/diagnostics/runtime-diag-job.yml diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h index 4c30eb01ba8ae9..5473076a59398a 100644 --- a/src/coreclr/inc/crosscomp.h +++ b/src/coreclr/inc/crosscomp.h @@ -210,7 +210,9 @@ typedef struct _T_DISPATCHER_CONTEXT { #define ARM64_MAX_BREAKPOINTS 8 #define ARM64_MAX_WATCHPOINTS 2 +#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 +#endif typedef union _NEON128 { struct { @@ -413,7 +415,9 @@ enum #define LOONGARCH64_MAX_BREAKPOINTS 8 #define LOONGARCH64_MAX_WATCHPOINTS 2 +#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 +#endif typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { @@ -546,7 +550,9 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { #define RISCV64_MAX_BREAKPOINTS 8 #define RISCV64_MAX_WATCHPOINTS 2 +#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 +#endif typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { 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 30eaa905e1b078..118e058140b07b 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 @@ -16,6 +16,7 @@ public sealed unsafe partial class DacDbiImpl : IDacDbiInterface { private readonly Target _target; private readonly IDacDbiInterface? _legacy; + private readonly object? _prevent_release; // IStringHolder is a native C++ abstract class (not COM) with a single virtual method: // virtual HRESULT AssignCopy(const WCHAR* psz) = 0; @@ -37,10 +38,11 @@ private int StringHolderAssignCopy(nint stringHolder, string str) } } - public DacDbiImpl(Target target, object? legacyObj) + public DacDbiImpl(Target target, object? legacyObj, object? prevent_release = null) { _target = target; _legacy = legacyObj as IDacDbiInterface; + _prevent_release = prevent_release; } public int CheckDbiVersion(DbiVersion* pVersion) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 1b94d137f9159f..003bac028a6e7a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -44,6 +44,11 @@ public sealed unsafe partial class SOSDacImpl private readonly Lazy _objectMethodTable; private readonly ulong _rcwMask = 1UL; + // Prevents the legacy DAC RCW from being released when fallback is disabled. + // The native CDAC class holds a raw pointer (m_legacyImpl) to the legacy DAC + // that must remain valid for the lifetime of this object. + private readonly object? _prevent_release; + private readonly ISOSDacInterface? _legacyImpl; private readonly ISOSDacInterface2? _legacyImpl2; private readonly ISOSDacInterface3? _legacyImpl3; @@ -64,9 +69,10 @@ public sealed unsafe partial class SOSDacImpl private readonly IXCLRDataProcess2? _legacyProcess2; private readonly ICLRDataEnumMemoryRegions? _legacyEnumMemory; - public SOSDacImpl(Target target, object? legacyObj) + public SOSDacImpl(Target target, object? legacyObj, object? prevent_release = null) { _target = target; + _prevent_release = prevent_release; _stringMethodTable = new Lazy( () => _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.StringMethodTable))); diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index af14a0a1dbba09..3ecc7289b687e0 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -77,10 +77,26 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr if (target == null) return -1; - object? legacyImpl = legacyImplPtr != IntPtr.Zero - ? cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None) - : null; - Legacy.SOSDacImpl impl = new(target, legacyImpl); + object? legacyImpl = null; + object? prevent_release = null; + if (legacyImplPtr != IntPtr.Zero) + { + object legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); + // When CDAC_NO_FALLBACK is set, we don't use the legacy impl for fallback + // but we must hold a reference to it because the native CDAC class stores + // a raw pointer (m_legacyImpl) that assumes it outlives the CDAC. + bool noFallback = Environment.GetEnvironmentVariable("CDAC_NO_FALLBACK") == "1"; + if (noFallback) + { + prevent_release = legacyObj; + } + else + { + legacyImpl = legacyObj; + } + } + + Legacy.SOSDacImpl impl = new(target, legacyImpl, prevent_release); nint ptr = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); *obj = ptr; return 0; @@ -112,17 +128,27 @@ private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImpl ComWrappers cw = new StrategyBasedComWrappers(); object? legacyObj = null; + object? prevent_release = null; if (legacyImplPtr != IntPtr.Zero) { - legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); - if (legacyObj is not Legacy.IDacDbiInterface) + object wrapped = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); + bool noFallback = Environment.GetEnvironmentVariable("CDAC_NO_FALLBACK") == "1"; + if (noFallback) + { + prevent_release = wrapped; + } + else { - *obj = IntPtr.Zero; - return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE + legacyObj = wrapped; + if (legacyObj is not Legacy.IDacDbiInterface) + { + *obj = IntPtr.Zero; + return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE + } } } - Legacy.DacDbiImpl impl = new(target, legacyObj); + Legacy.DacDbiImpl impl = new(target, legacyObj, prevent_release); *obj = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); return HResults.S_OK; } From ede7a70ecd003be31a426a5d6c35018b02d1323e Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:19:32 -0400 Subject: [PATCH 02/18] cDAC: Always delegate ICLRDataEnumMemoryRegions to legacy DAC The cDAC does not implement memory enumeration for dump creation. When CDAC_NO_FALLBACK is set, the legacy impl is stored in prevent_release but not used for delegation. This causes GenGetAuxMemory to return E_NOTIMPL during dump creation, resulting in dumps missing CLR auxiliary memory (e.g. ThreadStore). Extract ICLRDataEnumMemoryRegions from prevent_release so dump creation always delegates to the legacy DAC regardless of fallback mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SOSDacImpl.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 003bac028a6e7a..125e5e78c75011 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -104,6 +104,15 @@ public SOSDacImpl(Target target, object? legacyObj, object? prevent_release = nu _legacyEnumMemory = legacyObj as ICLRDataEnumMemoryRegions; } + + // ICLRDataEnumMemoryRegions is always delegated to the legacy DAC because + // the cDAC does not implement memory enumeration for dump creation. + // Even when CDAC_NO_FALLBACK is set, we must allow this to work so that + // dumps contain the CLR auxiliary memory needed for later analysis. + if (_legacyEnumMemory is null && prevent_release is not null) + { + _legacyEnumMemory = prevent_release as ICLRDataEnumMemoryRegions; + } } #region ISOSDacInterface From 5b89ccce6154023f2b158592de56fd660f8faed4 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:58:55 -0400 Subject: [PATCH 03/18] Revert crosscomp.h changes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/crosscomp.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h index 5473076a59398a..4c30eb01ba8ae9 100644 --- a/src/coreclr/inc/crosscomp.h +++ b/src/coreclr/inc/crosscomp.h @@ -210,9 +210,7 @@ typedef struct _T_DISPATCHER_CONTEXT { #define ARM64_MAX_BREAKPOINTS 8 #define ARM64_MAX_WATCHPOINTS 2 -#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 -#endif typedef union _NEON128 { struct { @@ -415,9 +413,7 @@ enum #define LOONGARCH64_MAX_BREAKPOINTS 8 #define LOONGARCH64_MAX_WATCHPOINTS 2 -#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 -#endif typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { @@ -550,9 +546,7 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { #define RISCV64_MAX_BREAKPOINTS 8 #define RISCV64_MAX_WATCHPOINTS 2 -#ifndef CONTEXT_UNWOUND_TO_CALL #define CONTEXT_UNWOUND_TO_CALL 0x20000000 -#endif typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { From cd484746c1f75a2094130fde01916ddd4c2ce253 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:50:31 -0400 Subject: [PATCH 04/18] cDAC: Fix AuxiliarySymbolInfo.Address type to CodePointer The Address field in AuxiliarySymbolInfo was declared as T_POINTER but is read using ReadCodePointerField in the managed cDAC. Fix the declaration to use TYPE(CodePointer) to match the reader, resolving Debug.Assert type mismatch crashes during SOS tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- 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 033f4103bffaf3..9d723e858f6dde 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1274,7 +1274,7 @@ CDAC_TYPE_END(SyncBlockCache) CDAC_TYPE_BEGIN(AuxiliarySymbolInfo) CDAC_TYPE_SIZE(sizeof(VMAUXILIARYSYMBOLDEF)) -CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) +CDAC_TYPE_FIELD(AuxiliarySymbolInfo, TYPE(CodePointer), Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Name, offsetof(VMAUXILIARYSYMBOLDEF, name)) CDAC_TYPE_END(AuxiliarySymbolInfo) From bf0cb57a9e45f82aa4c6b12af36f88a31f92756f Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:08:35 -0400 Subject: [PATCH 05/18] Replace binary no-fallback switch with granular LegacyFallbackHelper Replace the all-or-nothing CDAC_NO_FALLBACK mechanism with a per-method allowlist-based approach using LegacyFallbackHelper.CanFallback(). Previously, CDAC_NO_FALLBACK=1 nulled out all legacy DAC references at construction time, making every delegation-only API return E_NOTIMPL. This made it impossible to allow fallback for specific APIs while testing the rest standalone. Now: - Legacy refs are always kept alive (remove prevent_release pattern) - Each delegation-only call site gates on LegacyFallbackHelper.CanFallback() - In normal mode: CanFallback() returns true immediately (single bool check) - In no-fallback mode: only allowlisted methods can delegate - Initial allowlist: EnumMemoryRegion/EnumMemoryRegionsWrapper (dump creation) This enables granular testing where specific APIs can be selectively allowed to fall back while verifying all other APIs work standalone. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ClrDataAppDomain.cs | 6 +- .../ClrDataExceptionState.cs | 6 +- .../ClrDataFrame.cs | 12 +- .../ClrDataMethodDefinition.cs | 32 +-- .../ClrDataMethodInstance.cs | 24 +- .../ClrDataModule.cs | 56 ++--- .../ClrDataStackWalk.cs | 8 +- .../ClrDataTask.cs | 24 +- .../Dbi/DacDbiImpl.cs | 220 +++++++++--------- .../LegacyFallbackHelper.cs | 41 ++++ .../SOSDacImpl.ICLRDataEnumMemoryRegions.cs | 2 +- .../SOSDacImpl.IXCLRDataProcess.cs | 79 ++++--- .../SOSDacImpl.cs | 42 ++-- .../mscordaccore_universal/Entrypoints.cs | 40 +--- 14 files changed, 298 insertions(+), 294 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs index 90d2b14c91a899..24eb8406436640 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs @@ -26,7 +26,7 @@ public ClrDataAppDomain(Target target, TargetPointer appDomain, IXCLRDataAppDoma } int IXCLRDataAppDomain.GetProcess(DacComNullableByRef process) - => _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; int IXCLRDataAppDomain.GetName(uint bufLen, uint* nameLen, char* name) { @@ -181,8 +181,8 @@ int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) } int IXCLRDataAppDomain.GetManagedObject(DacComNullableByRef value) - => _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; int IXCLRDataAppDomain.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs index 796dbe029940dd..21469f6b53ffc8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs @@ -112,7 +112,7 @@ int IXCLRDataExceptionState.GetPrevious(DacComNullableByRef value) - => _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; int IXCLRDataExceptionState.GetBaseType(/*CLRDataBaseExceptionType*/ uint* type) => HResults.E_NOTIMPL; @@ -213,9 +213,9 @@ int IXCLRDataExceptionState.Request(uint reqCode, uint inBufferSize, byte* inBuf } int IXCLRDataExceptionState.IsSameState(EXCEPTION_RECORD64* exRecord, uint contextSize, byte* cxRecord) - => _legacyImpl is not null ? _legacyImpl.IsSameState(exRecord, contextSize, cxRecord) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameState(exRecord, contextSize, cxRecord) : HResults.E_NOTIMPL; int IXCLRDataExceptionState.IsSameState2(uint flags, EXCEPTION_RECORD64* exRecord, uint contextSize, byte* cxRecord) - => _legacyImpl is not null ? _legacyImpl.IsSameState2(flags, exRecord, contextSize, cxRecord) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameState2(flags, exRecord, contextSize, cxRecord) : HResults.E_NOTIMPL; int IXCLRDataExceptionState.GetTask(DacComNullableByRef task) { int hr = HResults.S_OK, hrLocal = HResults.S_OK; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs index d73fa39c6b3478..d7444056bc5f6e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs @@ -34,7 +34,7 @@ public ClrDataFrame(Target target, IStackDataFrameHandle dataFrame, IXCLRDataFra // IXCLRDataFrame implementation int IXCLRDataFrame.GetFrameType(uint* simpleType, uint* detailedType) - => _legacyImpl is not null ? _legacyImpl.GetFrameType(simpleType, detailedType) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFrameType(simpleType, detailedType) : HResults.E_NOTIMPL; int IXCLRDataFrame.GetContext( uint contextFlags, @@ -332,7 +332,7 @@ int IXCLRDataFrame.GetCodeName( uint bufLen, uint* nameLen, char* nameBuf) - => _legacyImpl is not null ? _legacyImpl.GetCodeName(flags, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetCodeName(flags, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; int IXCLRDataFrame.GetMethodInstance(DacComNullableByRef method) { @@ -384,17 +384,17 @@ int IXCLRDataFrame.Request( byte* inBuffer, uint outBufferSize, byte* outBuffer) - => _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; int IXCLRDataFrame.GetNumTypeArguments(uint* numTypeArgs) - => _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; int IXCLRDataFrame.GetTypeArgumentByIndex(uint index, DacComNullableByRef typeArg) - => _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; // IXCLRDataFrame2 implementation int IXCLRDataFrame2.GetExactGenericArgsToken(DacComNullableByRef genericToken) - => _legacyImpl2 is not null ? _legacyImpl2.GetExactGenericArgsToken(genericToken) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl2 is not null ? _legacyImpl2.GetExactGenericArgsToken(genericToken) : HResults.E_NOTIMPL; // ========== Metadata resolution helpers ========== diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs index 79d21e24a062b5..95e6c238a4ae2e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs @@ -27,19 +27,19 @@ public ClrDataMethodDefinition( _legacyImpl = legacyImpl; } int IXCLRDataMethodDefinition.GetTypeDefinition(DacComNullableByRef typeDefinition) - => _legacyImpl is not null ? _legacyImpl.GetTypeDefinition(typeDefinition) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeDefinition(typeDefinition) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.StartEnumInstances(IXCLRDataAppDomain? appDomain, ulong* handle) - => _legacyImpl is not null ? _legacyImpl.StartEnumInstances(appDomain, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumInstances(appDomain, handle) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.EnumInstance(ulong* handle, DacComNullableByRef instance) - => _legacyImpl is not null ? _legacyImpl.EnumInstance(handle, instance) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumInstance(handle, instance) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.EndEnumInstances(ulong handle) - => _legacyImpl is not null ? _legacyImpl.EndEnumInstances(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumInstances(handle) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.GetName(uint flags, uint bufLen, uint* nameLen, char* name) - => _legacyImpl is not null ? _legacyImpl.GetName(flags, bufLen, nameLen, name) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetName(flags, bufLen, nameLen, name) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.GetTokenAndScope(uint* token, DacComNullableByRef mod) { @@ -93,35 +93,35 @@ int IXCLRDataMethodDefinition.GetTokenAndScope(uint* token, DacComNullableByRef< } int IXCLRDataMethodDefinition.GetFlags(uint* flags) - => _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.IsSameObject(IXCLRDataMethodDefinition? method) - => _legacyImpl is not null ? _legacyImpl.IsSameObject(method) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(method) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.GetLatestEnCVersion(uint* version) - => _legacyImpl is not null ? _legacyImpl.GetLatestEnCVersion(version) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetLatestEnCVersion(version) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.StartEnumExtents(ulong* handle) - => _legacyImpl is not null ? _legacyImpl.StartEnumExtents(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumExtents(handle) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionExtent* extent) - => _legacyImpl is not null ? _legacyImpl.EnumExtent(handle, extent) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumExtent(handle, extent) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.EndEnumExtents(ulong handle) - => _legacyImpl is not null ? _legacyImpl.EndEnumExtents(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumExtents(handle) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.GetCodeNotification(uint* flags) - => _legacyImpl is not null ? _legacyImpl.GetCodeNotification(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetCodeNotification(flags) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.SetCodeNotification(uint flags) - => _legacyImpl is not null ? _legacyImpl.SetCodeNotification(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetCodeNotification(flags) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr) - => _legacyImpl is not null ? _legacyImpl.GetRepresentativeEntryAddress(addr) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetRepresentativeEntryAddress(addr) : HResults.E_NOTIMPL; int IXCLRDataMethodDefinition.HasClassOrMethodInstantiation(int* bGeneric) - => _legacyImpl is not null ? _legacyImpl.HasClassOrMethodInstantiation(bGeneric) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.HasClassOrMethodInstantiation(bGeneric) : HResults.E_NOTIMPL; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs index f7af21b0cb3c49..3a8a25284afb21 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs @@ -34,10 +34,10 @@ public ClrDataMethodInstance( } int IXCLRDataMethodInstance.GetTypeInstance(DacComNullableByRef typeInstance) - => _legacyImpl is not null ? _legacyImpl.GetTypeInstance(typeInstance) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeInstance(typeInstance) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetDefinition(DacComNullableByRef methodDefinition) - => _legacyImpl is not null ? _legacyImpl.GetDefinition(methodDefinition) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetDefinition(methodDefinition) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetTokenAndScope(uint* token, DacComNullableByRef mod) { @@ -174,19 +174,19 @@ int IXCLRDataMethodInstance.GetName(uint flags, uint bufLen, uint* nameLen, char } int IXCLRDataMethodInstance.GetFlags(uint* flags) - => _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.IsSameObject(IXCLRDataMethodInstance* method) - => _legacyImpl is not null ? _legacyImpl.IsSameObject(method) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(method) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetEnCVersion(uint* version) - => _legacyImpl is not null ? _legacyImpl.GetEnCVersion(version) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetEnCVersion(version) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetNumTypeArguments(uint* numTypeArgs) - => _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetTypeArgumentByIndex(uint index, DacComNullableByRef typeArg) - => _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetILOffsetsByAddress(ClrDataAddress address, uint offsetsLen, uint* offsetsNeeded, uint* ilOffsets) { @@ -279,7 +279,7 @@ int IXCLRDataMethodInstance.GetILOffsetsByAddress(ClrDataAddress address, uint o } int IXCLRDataMethodInstance.GetAddressRangesByILOffset(uint ilOffset, uint rangesLen, uint* rangesNeeded, void* addressRanges) - => _legacyImpl is not null ? _legacyImpl.GetAddressRangesByILOffset(ilOffset, rangesLen, rangesNeeded, addressRanges) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetAddressRangesByILOffset(ilOffset, rangesLen, rangesNeeded, addressRanges) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetILAddressMap(uint mapLen, uint* mapNeeded, [In, Out, MarshalUsing(CountElementName = "mapLen")] ClrDataILAddressMap[]? maps) { @@ -371,16 +371,16 @@ int IXCLRDataMethodInstance.GetILAddressMap(uint mapLen, uint* mapNeeded, [In, O } int IXCLRDataMethodInstance.StartEnumExtents(ulong* handle) - => _legacyImpl is not null ? _legacyImpl.StartEnumExtents(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumExtents(handle) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.EnumExtent(ulong* handle, void* extent) - => _legacyImpl is not null ? _legacyImpl.EnumExtent(handle, extent) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumExtent(handle, extent) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.EndEnumExtents(ulong handle) - => _legacyImpl is not null ? _legacyImpl.EndEnumExtents(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumExtents(handle) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; int IXCLRDataMethodInstance.GetRepresentativeEntryAddress(ClrDataAddress* addr) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 6831c351847283..537dc0b85b95d3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -183,42 +183,42 @@ private IEnumerable IterateMethodDefinitions() } int IXCLRDataModule.StartEnumAssemblies(ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumAssemblies(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumAssemblies(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumAssembly(ulong* handle, DacComNullableByRef assembly) - => _legacyModule is not null ? _legacyModule.EnumAssembly(handle, assembly) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumAssembly(handle, assembly) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumAssemblies(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumAssemblies(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumAssemblies(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumTypeDefinitions(ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumTypeDefinition(ulong* handle, DacComNullableByRef typeDefinition) - => _legacyModule is not null ? _legacyModule.EnumTypeDefinition(handle, typeDefinition) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeDefinition(handle, typeDefinition) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumTypeDefinitions(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumTypeInstances(IXCLRDataAppDomain? appDomain, ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumTypeInstances(appDomain, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeInstances(appDomain, handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumTypeInstance(ulong* handle, DacComNullableByRef typeInstance) - => _legacyModule is not null ? _legacyModule.EnumTypeInstance(handle, typeInstance) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeInstance(handle, typeInstance) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumTypeInstances(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumTypeInstances(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeInstances(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumTypeDefinitionsByName(char* name, uint flags, ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitionsByName(name, flags, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitionsByName(name, flags, handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumTypeDefinitionByName(ulong* handle, DacComNullableByRef type) - => _legacyModule is not null ? _legacyModule.EnumTypeDefinitionByName(handle, type) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeDefinitionByName(handle, type) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumTypeDefinitionsByName(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitionsByName(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitionsByName(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumTypeInstancesByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumTypeInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumTypeInstanceByName(ulong* handle, DacComNullableByRef type) - => _legacyModule is not null ? _legacyModule.EnumTypeInstanceByName(handle, type) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeInstanceByName(handle, type) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumTypeInstancesByName(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumTypeInstancesByName(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeInstancesByName(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.GetTypeDefinitionByToken(/*mdTypeDef*/ uint token, DacComNullableByRef typeDefinition) - => _legacyModule is not null ? _legacyModule.GetTypeDefinitionByToken(token, typeDefinition) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.GetTypeDefinitionByToken(token, typeDefinition) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumMethodDefinitionsByName(char* name, uint flags, ulong* handle) { @@ -348,21 +348,21 @@ int IXCLRDataModule.EndEnumMethodDefinitionsByName(ulong handle) return hr; } int IXCLRDataModule.StartEnumMethodInstancesByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumMethodInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumMethodInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumMethodInstanceByName(ulong* handle, DacComNullableByRef method) - => _legacyModule is not null ? _legacyModule.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumMethodInstancesByName(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.GetMethodDefinitionByToken(/*mdMethodDef*/ uint token, DacComNullableByRef methodDefinition) - => _legacyModule is not null ? _legacyModule.GetMethodDefinitionByToken(token, methodDefinition) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.GetMethodDefinitionByToken(token, methodDefinition) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumDataByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, IXCLRDataTask? tlsTask, ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumDataByName(name, flags, appDomain, tlsTask, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumDataByName(name, flags, appDomain, tlsTask, handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumDataByName(ulong* handle, DacComNullableByRef value) - => _legacyModule is not null ? _legacyModule.EnumDataByName(handle, value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumDataByName(handle, value) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumDataByName(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumDataByName(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumDataByName(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.GetName(uint bufLen, uint* nameLen, char* name) { @@ -498,7 +498,7 @@ int IXCLRDataModule.GetFlags(uint* flags) } int IXCLRDataModule.IsSameObject(IXCLRDataModule* mod) - => _legacyModule is not null ? _legacyModule.IsSameObject(mod) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.IsSameObject(mod) : HResults.E_NOTIMPL; int IXCLRDataModule.StartEnumExtents(ulong* handle) { @@ -709,14 +709,14 @@ private void PopulateModuleData(DacpGetModuleData* getModuleData) } int IXCLRDataModule.StartEnumAppDomains(ulong* handle) - => _legacyModule is not null ? _legacyModule.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.EnumAppDomain(ulong* handle, /*IXCLRDataAppDomain*/ void** appDomain) - => _legacyModule is not null ? _legacyModule.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; int IXCLRDataModule.EndEnumAppDomains(ulong handle) - => _legacyModule is not null ? _legacyModule.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; int IXCLRDataModule.GetVersionId(Guid* vid) - => _legacyModule is not null ? _legacyModule.GetVersionId(vid) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.GetVersionId(vid) : HResults.E_NOTIMPL; int IXCLRDataModule2.SetJITCompilerFlags(uint flags) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs index 457516168710d5..993213863d263e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs @@ -113,9 +113,9 @@ int IXCLRDataStackWalk.GetFrame(DacComNullableByRef frame) return hr; } int IXCLRDataStackWalk.GetFrameType(uint* simpleType, uint* detailedType) - => _legacyImpl is not null ? _legacyImpl.GetFrameType(simpleType, detailedType) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFrameType(simpleType, detailedType) : HResults.E_NOTIMPL; int IXCLRDataStackWalk.GetStackSizeSkipped(ulong* stackSizeSkipped) - => _legacyImpl is not null ? _legacyImpl.GetStackSizeSkipped(stackSizeSkipped) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStackSizeSkipped(stackSizeSkipped) : HResults.E_NOTIMPL; int IXCLRDataStackWalk.Next() { int hr; @@ -186,7 +186,7 @@ int IXCLRDataStackWalk.Request(uint reqCode, uint inBufferSize, byte* inBuffer, return hr; } int IXCLRDataStackWalk.SetContext(uint contextSize, [In, MarshalUsing(CountElementName = "contextSize")] byte[] context) - => _legacyImpl is not null ? _legacyImpl.SetContext(contextSize, context) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetContext(contextSize, context) : HResults.E_NOTIMPL; int IXCLRDataStackWalk.SetContext2(uint flags, uint contextSize, [In, MarshalUsing(CountElementName = "contextSize")] byte[] context) - => _legacyImpl is not null ? _legacyImpl.SetContext2(flags, contextSize, context) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetContext2(flags, contextSize, context) : HResults.E_NOTIMPL; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs index a944695326c5a4..a764ce83194786 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs @@ -24,7 +24,7 @@ public ClrDataTask(TargetPointer address, Target target, IXCLRDataTask? legacyIm } int IXCLRDataTask.GetProcess(/*IXCLRDataProcess*/ void** process) - => _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL; int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef appDomain) { int hr = HResults.S_OK, hrLocal = HResults.S_OK; @@ -54,17 +54,17 @@ int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef ap return hr; } int IXCLRDataTask.GetUniqueID(ulong* id) - => _legacyImpl is not null ? _legacyImpl.GetUniqueID(id) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetUniqueID(id) : HResults.E_NOTIMPL; int IXCLRDataTask.GetFlags(uint* flags) - => _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; int IXCLRDataTask.IsSameObject(IXCLRDataTask* task) - => _legacyImpl is not null ? _legacyImpl.IsSameObject(task) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(task) : HResults.E_NOTIMPL; int IXCLRDataTask.GetManagedObject(DacComNullableByRef value) - => _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL; int IXCLRDataTask.GetDesiredExecutionState(uint* state) - => _legacyImpl is not null ? _legacyImpl.GetDesiredExecutionState(state) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetDesiredExecutionState(state) : HResults.E_NOTIMPL; int IXCLRDataTask.SetDesiredExecutionState(uint state) - => _legacyImpl is not null ? _legacyImpl.SetDesiredExecutionState(state) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetDesiredExecutionState(state) : HResults.E_NOTIMPL; int IXCLRDataTask.CreateStackWalk(uint flags, DacComNullableByRef stackWalk) { @@ -87,11 +87,11 @@ int IXCLRDataTask.CreateStackWalk(uint flags, DacComNullableByRef _legacyImpl is not null ? _legacyImpl.GetOSThreadID(id) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetOSThreadID(id) : HResults.E_NOTIMPL; int IXCLRDataTask.GetContext(uint contextFlags, uint contextBufSize, uint* contextSize, byte* contextBuffer) - => _legacyImpl is not null ? _legacyImpl.GetContext(contextFlags, contextBufSize, contextSize, contextBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetContext(contextFlags, contextBufSize, contextSize, contextBuffer) : HResults.E_NOTIMPL; int IXCLRDataTask.SetContext(uint contextSize, byte* context) - => _legacyImpl is not null ? _legacyImpl.SetContext(contextSize, context) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetContext(contextSize, context) : HResults.E_NOTIMPL; int IXCLRDataTask.GetCurrentExceptionState(DacComNullableByRef exception) { @@ -131,9 +131,9 @@ int IXCLRDataTask.GetCurrentExceptionState(DacComNullableByRef _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; int IXCLRDataTask.GetName(uint bufLen, uint* nameLen, char* nameBuffer) - => _legacyImpl is not null ? _legacyImpl.GetName(bufLen, nameLen, nameBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetName(bufLen, nameLen, nameBuffer) : HResults.E_NOTIMPL; int IXCLRDataTask.GetLastExceptionState(DacComNullableByRef exception) { int hr = HResults.S_OK, hrLocal = HResults.S_OK; 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 118e058140b07b..9824ddc4ead5ef 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 @@ -46,7 +46,7 @@ public DacDbiImpl(Target target, object? legacyObj, object? prevent_release = nu } public int CheckDbiVersion(DbiVersion* pVersion) - => _legacy is not null ? _legacy.CheckDbiVersion(pVersion) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CheckDbiVersion(pVersion) : HResults.E_NOTIMPL; public int FlushCache() { @@ -55,7 +55,7 @@ public int FlushCache() } public int DacSetTargetConsistencyChecks(Interop.BOOL fEnableAsserts) - => _legacy is not null ? _legacy.DacSetTargetConsistencyChecks(fEnableAsserts) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.DacSetTargetConsistencyChecks(fEnableAsserts) : HResults.E_NOTIMPL; public int IsLeftSideInitialized(Interop.BOOL* pResult) { @@ -110,7 +110,7 @@ public int GetAppDomainId(ulong vmAppDomain, uint* pRetVal) } public int GetAppDomainObject(ulong vmAppDomain, ulong* pRetVal) - => _legacy is not null ? _legacy.GetAppDomainObject(vmAppDomain, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetAppDomainObject(vmAppDomain, pRetVal) : HResults.E_NOTIMPL; public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) { @@ -135,7 +135,7 @@ public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) } public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) - => _legacy is not null ? _legacy.GetModuleSimpleName(vmModule, pStrFilename) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetModuleSimpleName(vmModule, pStrFilename) : HResults.E_NOTIMPL; public int GetAssemblyPath(ulong vmAssembly, nint pStrFilename, Interop.BOOL* pResult) { @@ -174,7 +174,7 @@ public int GetAssemblyPath(ulong vmAssembly, nint pStrFilename, Interop.BOOL* pR } public int ResolveTypeReference(DacDbiTypeRefData* pTypeRefInfo, DacDbiTypeRefData* pTargetRefInfo) - => _legacy is not null ? _legacy.ResolveTypeReference(pTypeRefInfo, pTargetRefInfo) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.ResolveTypeReference(pTypeRefInfo, pTargetRefInfo) : HResults.E_NOTIMPL; public int GetModulePath(ulong vmModule, nint pStrFilename, Interop.BOOL* pResult) { @@ -213,52 +213,52 @@ public int GetModulePath(ulong vmModule, nint pStrFilename, Interop.BOOL* pResul } public int GetMetadata(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer) - => _legacy is not null ? _legacy.GetMetadata(vmModule, pTargetBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetMetadata(vmModule, pTargetBuffer) : HResults.E_NOTIMPL; public int GetSymbolsBuffer(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer, int* pSymbolFormat) - => _legacy is not null ? _legacy.GetSymbolsBuffer(vmModule, pTargetBuffer, pSymbolFormat) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetSymbolsBuffer(vmModule, pTargetBuffer, pSymbolFormat) : HResults.E_NOTIMPL; public int GetModuleData(ulong vmModule, DacDbiModuleInfo* pData) - => _legacy is not null ? _legacy.GetModuleData(vmModule, pData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetModuleData(vmModule, pData) : HResults.E_NOTIMPL; public int GetAssemblyInfo(ulong vmAssembly, DacDbiAssemblyInfo* pData) - => _legacy is not null ? _legacy.GetAssemblyInfo(vmAssembly, pData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetAssemblyInfo(vmAssembly, pData) : HResults.E_NOTIMPL; public int GetModuleForAssembly(ulong vmAssembly, ulong* pModule) - => _legacy is not null ? _legacy.GetModuleForAssembly(vmAssembly, pModule) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetModuleForAssembly(vmAssembly, pModule) : HResults.E_NOTIMPL; public int GetAddressType(ulong address, int* pRetVal) - => _legacy is not null ? _legacy.GetAddressType(address, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetAddressType(address, pRetVal) : HResults.E_NOTIMPL; public int IsTransitionStub(ulong address, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsTransitionStub(address, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsTransitionStub(address, pResult) : HResults.E_NOTIMPL; public int GetCompilerFlags(ulong vmAssembly, Interop.BOOL* pfAllowJITOpts, Interop.BOOL* pfEnableEnC) - => _legacy is not null ? _legacy.GetCompilerFlags(vmAssembly, pfAllowJITOpts, pfEnableEnC) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetCompilerFlags(vmAssembly, pfAllowJITOpts, pfEnableEnC) : HResults.E_NOTIMPL; public int SetCompilerFlags(ulong vmAssembly, Interop.BOOL fAllowJitOpts, Interop.BOOL fEnableEnC) - => _legacy is not null ? _legacy.SetCompilerFlags(vmAssembly, fAllowJitOpts, fEnableEnC) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.SetCompilerFlags(vmAssembly, fAllowJitOpts, fEnableEnC) : HResults.E_NOTIMPL; public int EnumerateAssembliesInAppDomain(ulong vmAppDomain, nint fpCallback, nint pUserData) - => _legacy is not null ? _legacy.EnumerateAssembliesInAppDomain(vmAppDomain, fpCallback, pUserData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnumerateAssembliesInAppDomain(vmAppDomain, fpCallback, pUserData) : HResults.E_NOTIMPL; public int EnumerateModulesInAssembly(ulong vmAssembly, nint fpCallback, nint pUserData) - => _legacy is not null ? _legacy.EnumerateModulesInAssembly(vmAssembly, fpCallback, pUserData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnumerateModulesInAssembly(vmAssembly, fpCallback, pUserData) : HResults.E_NOTIMPL; public int RequestSyncAtEvent() - => _legacy is not null ? _legacy.RequestSyncAtEvent() : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.RequestSyncAtEvent() : HResults.E_NOTIMPL; public int SetSendExceptionsOutsideOfJMC(Interop.BOOL sendExceptionsOutsideOfJMC) - => _legacy is not null ? _legacy.SetSendExceptionsOutsideOfJMC(sendExceptionsOutsideOfJMC) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.SetSendExceptionsOutsideOfJMC(sendExceptionsOutsideOfJMC) : HResults.E_NOTIMPL; public int MarkDebuggerAttachPending() - => _legacy is not null ? _legacy.MarkDebuggerAttachPending() : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.MarkDebuggerAttachPending() : HResults.E_NOTIMPL; public int MarkDebuggerAttached(Interop.BOOL fAttached) - => _legacy is not null ? _legacy.MarkDebuggerAttached(fAttached) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.MarkDebuggerAttached(fAttached) : HResults.E_NOTIMPL; 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; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.Hijack(vmThread, dwThreadId, pRecord, pOriginalContext, cbSizeContext, reason, pUserData, pRemoteContextAddr) : HResults.E_NOTIMPL; public int EnumerateThreads(nint fpCallback, nint pUserData) { @@ -347,25 +347,25 @@ public int IsThreadMarkedDead(ulong vmThread, Interop.BOOL* pResult) } public int GetThreadHandle(ulong vmThread, nint pRetVal) - => _legacy is not null ? _legacy.GetThreadHandle(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetThreadHandle(vmThread, pRetVal) : HResults.E_NOTIMPL; public int GetThreadObject(ulong vmThread, ulong* pRetVal) - => _legacy is not null ? _legacy.GetThreadObject(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetThreadObject(vmThread, pRetVal) : HResults.E_NOTIMPL; public int GetThreadAllocInfo(ulong vmThread, DacDbiThreadAllocInfo* pThreadAllocInfo) - => _legacy is not null ? _legacy.GetThreadAllocInfo(vmThread, pThreadAllocInfo) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetThreadAllocInfo(vmThread, pThreadAllocInfo) : HResults.E_NOTIMPL; public int SetDebugState(ulong vmThread, int debugState) - => _legacy is not null ? _legacy.SetDebugState(vmThread, debugState) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.SetDebugState(vmThread, debugState) : HResults.E_NOTIMPL; public int HasUnhandledException(ulong vmThread, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.HasUnhandledException(vmThread, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.HasUnhandledException(vmThread, pResult) : HResults.E_NOTIMPL; public int GetUserState(ulong vmThread, int* pRetVal) - => _legacy is not null ? _legacy.GetUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; public int GetPartialUserState(ulong vmThread, int* pRetVal) - => _legacy is not null ? _legacy.GetPartialUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetPartialUserState(vmThread, pRetVal) : HResults.E_NOTIMPL; public int GetConnectionID(ulong vmThread, uint* pRetVal) { @@ -483,10 +483,10 @@ public int GetCurrentException(ulong vmThread, ulong* pRetVal) } public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal) - => _legacy is not null ? _legacy.GetObjectForCCW(ccwPtr, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectForCCW(ccwPtr, pRetVal) : HResults.E_NOTIMPL; public int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal) - => _legacy is not null ? _legacy.GetCurrentCustomDebuggerNotification(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetCurrentCustomDebuggerNotification(vmThread, pRetVal) : HResults.E_NOTIMPL; public int GetCurrentAppDomain(ulong* pRetVal) { @@ -515,64 +515,64 @@ public int GetCurrentAppDomain(ulong* pRetVal) } public int ResolveAssembly(ulong vmScope, uint tkAssemblyRef, ulong* pRetVal) - => _legacy is not null ? _legacy.ResolveAssembly(vmScope, tkAssemblyRef, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.ResolveAssembly(vmScope, tkAssemblyRef, pRetVal) : HResults.E_NOTIMPL; public int GetNativeCodeSequencePointsAndVarInfo(ulong vmMethodDesc, ulong startAddress, Interop.BOOL fCodeAvailable, nint pNativeVarData, nint pSequencePoints) - => _legacy is not null ? _legacy.GetNativeCodeSequencePointsAndVarInfo(vmMethodDesc, startAddress, fCodeAvailable, pNativeVarData, pSequencePoints) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetNativeCodeSequencePointsAndVarInfo(vmMethodDesc, startAddress, fCodeAvailable, pNativeVarData, pSequencePoints) : HResults.E_NOTIMPL; public int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal) - => _legacy is not null ? _legacy.GetManagedStoppedContext(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetManagedStoppedContext(vmThread, pRetVal) : HResults.E_NOTIMPL; public int CreateStackWalk(ulong vmThread, nint pInternalContextBuffer, nuint* ppSFIHandle) - => _legacy is not null ? _legacy.CreateStackWalk(vmThread, pInternalContextBuffer, ppSFIHandle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateStackWalk(vmThread, pInternalContextBuffer, ppSFIHandle) : HResults.E_NOTIMPL; public int DeleteStackWalk(nuint ppSFIHandle) - => _legacy is not null ? _legacy.DeleteStackWalk(ppSFIHandle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.DeleteStackWalk(ppSFIHandle) : HResults.E_NOTIMPL; public int GetStackWalkCurrentContext(nuint pSFIHandle, nint pContext) - => _legacy is not null ? _legacy.GetStackWalkCurrentContext(pSFIHandle, pContext) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetStackWalkCurrentContext(pSFIHandle, pContext) : HResults.E_NOTIMPL; public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, nint pContext) - => _legacy is not null ? _legacy.SetStackWalkCurrentContext(vmThread, pSFIHandle, flag, pContext) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.SetStackWalkCurrentContext(vmThread, pSFIHandle, flag, pContext) : HResults.E_NOTIMPL; public int UnwindStackWalkFrame(nuint pSFIHandle, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.UnwindStackWalkFrame(pSFIHandle, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.UnwindStackWalkFrame(pSFIHandle, pResult) : HResults.E_NOTIMPL; public int CheckContext(ulong vmThread, nint pContext) - => _legacy is not null ? _legacy.CheckContext(vmThread, pContext) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CheckContext(vmThread, pContext) : HResults.E_NOTIMPL; public int GetStackWalkCurrentFrameInfo(nuint pSFIHandle, nint pFrameData, int* pRetVal) - => _legacy is not null ? _legacy.GetStackWalkCurrentFrameInfo(pSFIHandle, pFrameData, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetStackWalkCurrentFrameInfo(pSFIHandle, pFrameData, pRetVal) : HResults.E_NOTIMPL; public int GetCountOfInternalFrames(ulong vmThread, uint* pRetVal) - => _legacy is not null ? _legacy.GetCountOfInternalFrames(vmThread, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetCountOfInternalFrames(vmThread, pRetVal) : HResults.E_NOTIMPL; public int EnumerateInternalFrames(ulong vmThread, nint fpCallback, nint pUserData) - => _legacy is not null ? _legacy.EnumerateInternalFrames(vmThread, fpCallback, pUserData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnumerateInternalFrames(vmThread, fpCallback, pUserData) : HResults.E_NOTIMPL; public int IsMatchingParentFrame(ulong fpToCheck, ulong fpParent, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsMatchingParentFrame(fpToCheck, fpParent, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsMatchingParentFrame(fpToCheck, fpParent, pResult) : HResults.E_NOTIMPL; public int GetStackParameterSize(ulong controlPC, uint* pRetVal) - => _legacy is not null ? _legacy.GetStackParameterSize(controlPC, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetStackParameterSize(controlPC, pRetVal) : HResults.E_NOTIMPL; public int GetFramePointer(nuint pSFIHandle, ulong* pRetVal) - => _legacy is not null ? _legacy.GetFramePointer(pSFIHandle, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetFramePointer(pSFIHandle, pRetVal) : HResults.E_NOTIMPL; public int IsLeafFrame(ulong vmThread, nint pContext, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsLeafFrame(vmThread, pContext, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsLeafFrame(vmThread, pContext, pResult) : HResults.E_NOTIMPL; public int GetContext(ulong vmThread, nint pContextBuffer) - => _legacy is not null ? _legacy.GetContext(vmThread, pContextBuffer) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetContext(vmThread, pContextBuffer) : HResults.E_NOTIMPL; public int ConvertContextToDebuggerRegDisplay(nint pInContext, nint pOutDRD, Interop.BOOL fActive) - => _legacy is not null ? _legacy.ConvertContextToDebuggerRegDisplay(pInContext, pOutDRD, fActive) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.ConvertContextToDebuggerRegDisplay(pInContext, pOutDRD, fActive) : HResults.E_NOTIMPL; public int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal) - => _legacy is not null ? _legacy.IsDiagnosticsHiddenOrLCGMethod(vmMethodDesc, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsDiagnosticsHiddenOrLCGMethod(vmMethodDesc, pRetVal) : HResults.E_NOTIMPL; public int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuffer* pRetVal) - => _legacy is not null ? _legacy.GetVarArgSig(VASigCookieAddr, pArgBase, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetVarArgSig(VASigCookieAddr, pArgBase, pRetVal) : HResults.E_NOTIMPL; public int RequiresAlign8(ulong thExact, Interop.BOOL* pResult) { @@ -611,16 +611,16 @@ public int RequiresAlign8(ulong thExact, Interop.BOOL* pResult) } public int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong rawToken, ulong* pRetVal) - => _legacy is not null ? _legacy.ResolveExactGenericArgsToken(dwExactGenericArgsTokenIndex, rawToken, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.ResolveExactGenericArgsToken(dwExactGenericArgsTokenIndex, rawToken, pRetVal) : HResults.E_NOTIMPL; public int GetILCodeAndSig(ulong vmAssembly, uint functionToken, DacDbiTargetBuffer* pTargetBuffer, uint* pLocalSigToken) - => _legacy is not null ? _legacy.GetILCodeAndSig(vmAssembly, functionToken, pTargetBuffer, pLocalSigToken) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetILCodeAndSig(vmAssembly, functionToken, pTargetBuffer, pLocalSigToken) : HResults.E_NOTIMPL; public int GetNativeCodeInfo(ulong vmAssembly, uint functionToken, nint pJitManagerList) - => _legacy is not null ? _legacy.GetNativeCodeInfo(vmAssembly, functionToken, pJitManagerList) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetNativeCodeInfo(vmAssembly, functionToken, pJitManagerList) : HResults.E_NOTIMPL; public int GetNativeCodeInfoForAddr(ulong codeAddress, nint pCodeInfo, ulong* pVmModule, uint* pFunctionToken) - => _legacy is not null ? _legacy.GetNativeCodeInfoForAddr(codeAddress, pCodeInfo, pVmModule, pFunctionToken) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetNativeCodeInfoForAddr(codeAddress, pCodeInfo, pVmModule, pFunctionToken) : HResults.E_NOTIMPL; public int IsValueType(ulong vmTypeHandle, Interop.BOOL* pResult) { @@ -678,19 +678,19 @@ public int HasTypeParams(ulong vmTypeHandle, Interop.BOOL* pResult) } public int GetClassInfo(ulong thExact, nint pData) - => _legacy is not null ? _legacy.GetClassInfo(thExact, pData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetClassInfo(thExact, pData) : HResults.E_NOTIMPL; public int GetInstantiationFieldInfo(ulong vmAssembly, ulong vmTypeHandle, ulong vmExactMethodTable, nint pFieldList, nuint* pObjectSize) - => _legacy is not null ? _legacy.GetInstantiationFieldInfo(vmAssembly, vmTypeHandle, vmExactMethodTable, pFieldList, pObjectSize) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetInstantiationFieldInfo(vmAssembly, vmTypeHandle, vmExactMethodTable, pFieldList, pObjectSize) : HResults.E_NOTIMPL; public int TypeHandleToExpandedTypeInfo(int boxed, ulong vmTypeHandle, nint pData) - => _legacy is not null ? _legacy.TypeHandleToExpandedTypeInfo(boxed, vmTypeHandle, pData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.TypeHandleToExpandedTypeInfo(boxed, vmTypeHandle, pData) : HResults.E_NOTIMPL; public int GetObjectExpandedTypeInfo(int boxed, ulong addr, nint pTypeInfo) - => _legacy is not null ? _legacy.GetObjectExpandedTypeInfo(boxed, addr, pTypeInfo) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectExpandedTypeInfo(boxed, addr, pTypeInfo) : HResults.E_NOTIMPL; public int GetObjectExpandedTypeInfoFromID(int boxed, COR_TYPEID id, nint pTypeInfo) - => _legacy is not null ? _legacy.GetObjectExpandedTypeInfoFromID(boxed, id, pTypeInfo) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectExpandedTypeInfoFromID(boxed, id, pTypeInfo) : HResults.E_NOTIMPL; public int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal) { @@ -732,13 +732,13 @@ public int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal) } public int GetApproxTypeHandle(nint pTypeData, ulong* pRetVal) - => _legacy is not null ? _legacy.GetApproxTypeHandle(pTypeData, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetApproxTypeHandle(pTypeData, pRetVal) : HResults.E_NOTIMPL; public int GetExactTypeHandle(nint pTypeData, nint pArgInfo, ulong* pVmTypeHandle) - => _legacy is not null ? _legacy.GetExactTypeHandle(pTypeData, pArgInfo, pVmTypeHandle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetExactTypeHandle(pTypeData, pArgInfo, pVmTypeHandle) : HResults.E_NOTIMPL; public int GetMethodDescParams(ulong vmMethodDesc, ulong genericsToken, uint* pcGenericClassTypeParams, nint pGenericTypeParams) - => _legacy is not null ? _legacy.GetMethodDescParams(vmMethodDesc, genericsToken, pcGenericClassTypeParams, pGenericTypeParams) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetMethodDescParams(vmMethodDesc, genericsToken, pcGenericClassTypeParams, pGenericTypeParams) : HResults.E_NOTIMPL; public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* pRetVal) { @@ -774,49 +774,49 @@ public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* p } public int GetCollectibleTypeStaticAddress(ulong vmField, ulong* pRetVal) - => _legacy is not null ? _legacy.GetCollectibleTypeStaticAddress(vmField, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetCollectibleTypeStaticAddress(vmField, pRetVal) : HResults.E_NOTIMPL; public int GetEnCHangingFieldInfo(nint pEnCFieldInfo, nint pFieldData, Interop.BOOL* pfStatic) - => _legacy is not null ? _legacy.GetEnCHangingFieldInfo(pEnCFieldInfo, pFieldData, pfStatic) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetEnCHangingFieldInfo(pEnCFieldInfo, pFieldData, pfStatic) : HResults.E_NOTIMPL; public int GetTypeHandleParams(ulong vmTypeHandle, nint pParams) - => _legacy is not null ? _legacy.GetTypeHandleParams(vmTypeHandle, pParams) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetTypeHandleParams(vmTypeHandle, pParams) : HResults.E_NOTIMPL; public int GetSimpleType(int simpleType, uint* pMetadataToken, ulong* pVmModule) - => _legacy is not null ? _legacy.GetSimpleType(simpleType, pMetadataToken, pVmModule) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetSimpleType(simpleType, pMetadataToken, pVmModule) : HResults.E_NOTIMPL; public int IsExceptionObject(ulong vmObject, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsExceptionObject(vmObject, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsExceptionObject(vmObject, pResult) : HResults.E_NOTIMPL; public int GetStackFramesFromException(ulong vmObject, nint pDacStackFrames) - => _legacy is not null ? _legacy.GetStackFramesFromException(vmObject, pDacStackFrames) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetStackFramesFromException(vmObject, pDacStackFrames) : HResults.E_NOTIMPL; public int IsRcw(ulong vmObject, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsRcw(vmObject, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsRcw(vmObject, pResult) : HResults.E_NOTIMPL; public int GetRcwCachedInterfacePointers(ulong vmObject, Interop.BOOL bIInspectableOnly, nint pDacItfPtrs) - => _legacy is not null ? _legacy.GetRcwCachedInterfacePointers(vmObject, bIInspectableOnly, pDacItfPtrs) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetRcwCachedInterfacePointers(vmObject, bIInspectableOnly, pDacItfPtrs) : HResults.E_NOTIMPL; public int GetTypedByRefInfo(ulong pTypedByRef, nint pObjectData) - => _legacy is not null ? _legacy.GetTypedByRefInfo(pTypedByRef, pObjectData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetTypedByRefInfo(pTypedByRef, pObjectData) : HResults.E_NOTIMPL; public int GetStringData(ulong objectAddress, nint pObjectData) - => _legacy is not null ? _legacy.GetStringData(objectAddress, pObjectData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetStringData(objectAddress, pObjectData) : HResults.E_NOTIMPL; public int GetArrayData(ulong objectAddress, nint pObjectData) - => _legacy is not null ? _legacy.GetArrayData(objectAddress, pObjectData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetArrayData(objectAddress, pObjectData) : HResults.E_NOTIMPL; public int GetBasicObjectInfo(ulong objectAddress, int type, nint pObjectData) - => _legacy is not null ? _legacy.GetBasicObjectInfo(objectAddress, type, pObjectData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetBasicObjectInfo(objectAddress, type, pObjectData) : HResults.E_NOTIMPL; public int TestCrst(ulong vmCrst) - => _legacy is not null ? _legacy.TestCrst(vmCrst) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.TestCrst(vmCrst) : HResults.E_NOTIMPL; public int TestRWLock(ulong vmRWLock) - => _legacy is not null ? _legacy.TestRWLock(vmRWLock) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.TestRWLock(vmRWLock) : HResults.E_NOTIMPL; public int GetDebuggerControlBlockAddress(ulong* pRetVal) - => _legacy is not null ? _legacy.GetDebuggerControlBlockAddress(pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetDebuggerControlBlockAddress(pRetVal) : HResults.E_NOTIMPL; public int GetObjectFromRefPtr(ulong ptr, ulong* pRetVal) { @@ -939,13 +939,13 @@ public int GetHandleAddressFromVmHandle(ulong vmHandle, ulong* pRetVal) } public int GetObjectContents(ulong obj, DacDbiTargetBuffer* pRetVal) - => _legacy is not null ? _legacy.GetObjectContents(obj, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectContents(obj, pRetVal) : HResults.E_NOTIMPL; public int GetThreadOwningMonitorLock(ulong vmObject, DacDbiMonitorLockInfo* pRetVal) - => _legacy is not null ? _legacy.GetThreadOwningMonitorLock(vmObject, pRetVal) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetThreadOwningMonitorLock(vmObject, pRetVal) : HResults.E_NOTIMPL; public int EnumerateMonitorEventWaitList(ulong vmObject, nint fpCallback, nint pUserData) - => _legacy is not null ? _legacy.EnumerateMonitorEventWaitList(vmObject, fpCallback, pUserData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnumerateMonitorEventWaitList(vmObject, fpCallback, pUserData) : HResults.E_NOTIMPL; public int GetAttachStateFlags(int* pRetVal) { @@ -975,10 +975,10 @@ public int GetAttachStateFlags(int* pRetVal) } public int GetMetaDataFileInfoFromPEFile(ulong vmPEAssembly, uint* dwTimeStamp, uint* dwImageSize, nint pStrFilename, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.GetMetaDataFileInfoFromPEFile(vmPEAssembly, dwTimeStamp, dwImageSize, pStrFilename, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetMetaDataFileInfoFromPEFile(vmPEAssembly, dwTimeStamp, dwImageSize, pStrFilename, pResult) : HResults.E_NOTIMPL; public int IsThreadSuspendedOrHijacked(ulong vmThread, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsThreadSuspendedOrHijacked(vmThread, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsThreadSuspendedOrHijacked(vmThread, pResult) : HResults.E_NOTIMPL; public int AreGCStructuresValid(Interop.BOOL* pResult) { @@ -1000,28 +1000,28 @@ public int AreGCStructuresValid(Interop.BOOL* pResult) } public int CreateHeapWalk(nuint* pHandle) - => _legacy is not null ? _legacy.CreateHeapWalk(pHandle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateHeapWalk(pHandle) : HResults.E_NOTIMPL; public int DeleteHeapWalk(nuint handle) - => _legacy is not null ? _legacy.DeleteHeapWalk(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.DeleteHeapWalk(handle) : HResults.E_NOTIMPL; public int WalkHeap(nuint handle, uint count, COR_HEAPOBJECT* objects, uint* fetched) - => _legacy is not null ? _legacy.WalkHeap(handle, count, objects, fetched) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.WalkHeap(handle, count, objects, fetched) : HResults.E_NOTIMPL; public int GetHeapSegments(nint pSegments) - => _legacy is not null ? _legacy.GetHeapSegments(pSegments) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetHeapSegments(pSegments) : HResults.E_NOTIMPL; public int IsValidObject(ulong obj, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsValidObject(obj, pResult) : HResults.E_NOTIMPL; public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, Interop.BOOL walkFQ, uint handleWalkMask) - => _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.CreateRefWalk(pHandle, walkStacks, walkFQ, handleWalkMask) : HResults.E_NOTIMPL; public int DeleteRefWalk(nuint handle) - => _legacy is not null ? _legacy.DeleteRefWalk(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.DeleteRefWalk(handle) : HResults.E_NOTIMPL; public int WalkRefs(nuint handle, uint count, nint refs, uint* pFetched) - => _legacy is not null ? _legacy.WalkRefs(handle, count, refs, pFetched) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.WalkRefs(handle, count, refs, pFetched) : HResults.E_NOTIMPL; public int GetTypeID(ulong obj, COR_TYPEID* pType) { @@ -1087,13 +1087,13 @@ public int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId) } public int GetObjectFields(nint id, uint celt, COR_FIELD* layout, uint* pceltFetched) - => _legacy is not null ? _legacy.GetObjectFields(id, celt, layout, pceltFetched) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectFields(id, celt, layout, pceltFetched) : HResults.E_NOTIMPL; public int GetTypeLayout(nint id, COR_TYPE_LAYOUT* pLayout) - => _legacy is not null ? _legacy.GetTypeLayout(id, pLayout) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetTypeLayout(id, pLayout) : HResults.E_NOTIMPL; public int GetArrayLayout(nint id, nint pLayout) - => _legacy is not null ? _legacy.GetArrayLayout(id, pLayout) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetArrayLayout(id, pLayout) : HResults.E_NOTIMPL; public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo) { @@ -1137,10 +1137,10 @@ public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo) } public int GetPEFileMDInternalRW(ulong vmPEAssembly, ulong* pAddrMDInternalRW) - => _legacy is not null ? _legacy.GetPEFileMDInternalRW(vmPEAssembly, pAddrMDInternalRW) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetPEFileMDInternalRW(vmPEAssembly, pAddrMDInternalRW) : HResults.E_NOTIMPL; public int AreOptimizationsDisabled(ulong vmModule, uint methodTk, Interop.BOOL* pOptimizationsDisabled) - => _legacy is not null ? _legacy.AreOptimizationsDisabled(vmModule, methodTk, pOptimizationsDisabled) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.AreOptimizationsDisabled(vmModule, methodTk, pOptimizationsDisabled) : HResults.E_NOTIMPL; public int GetDefinesBitField(uint* pDefines) { @@ -1201,37 +1201,37 @@ public int GetMDStructuresVersion(uint* pMDStructuresVersion) } public int GetActiveRejitILCodeVersionNode(ulong vmModule, uint methodTk, ulong* pVmILCodeVersionNode) - => _legacy is not null ? _legacy.GetActiveRejitILCodeVersionNode(vmModule, methodTk, pVmILCodeVersionNode) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetActiveRejitILCodeVersionNode(vmModule, methodTk, pVmILCodeVersionNode) : HResults.E_NOTIMPL; public int GetNativeCodeVersionNode(ulong vmMethod, ulong codeStartAddress, ulong* pVmNativeCodeVersionNode) - => _legacy is not null ? _legacy.GetNativeCodeVersionNode(vmMethod, codeStartAddress, pVmNativeCodeVersionNode) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetNativeCodeVersionNode(vmMethod, codeStartAddress, pVmNativeCodeVersionNode) : HResults.E_NOTIMPL; public int GetILCodeVersionNode(ulong vmNativeCodeVersionNode, ulong* pVmILCodeVersionNode) - => _legacy is not null ? _legacy.GetILCodeVersionNode(vmNativeCodeVersionNode, pVmILCodeVersionNode) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetILCodeVersionNode(vmNativeCodeVersionNode, pVmILCodeVersionNode) : HResults.E_NOTIMPL; public int GetILCodeVersionNodeData(ulong ilCodeVersionNode, DacDbiSharedReJitInfo* pData) - => _legacy is not null ? _legacy.GetILCodeVersionNodeData(ilCodeVersionNode, pData) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetILCodeVersionNodeData(ilCodeVersionNode, pData) : HResults.E_NOTIMPL; public int EnableGCNotificationEvents(Interop.BOOL fEnable) - => _legacy is not null ? _legacy.EnableGCNotificationEvents(fEnable) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnableGCNotificationEvents(fEnable) : HResults.E_NOTIMPL; public int IsDelegate(ulong vmObject, Interop.BOOL* pResult) - => _legacy is not null ? _legacy.IsDelegate(vmObject, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsDelegate(vmObject, pResult) : HResults.E_NOTIMPL; public int GetDelegateType(ulong delegateObject, int* delegateType) - => _legacy is not null ? _legacy.GetDelegateType(delegateObject, delegateType) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetDelegateType(delegateObject, delegateType) : HResults.E_NOTIMPL; public int GetDelegateFunctionData(int delegateType, ulong delegateObject, ulong* ppFunctionAssembly, uint* pMethodDef) - => _legacy is not null ? _legacy.GetDelegateFunctionData(delegateType, delegateObject, ppFunctionAssembly, pMethodDef) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetDelegateFunctionData(delegateType, delegateObject, ppFunctionAssembly, pMethodDef) : HResults.E_NOTIMPL; public int GetDelegateTargetObject(int delegateType, ulong delegateObject, ulong* ppTargetObj, ulong* ppTargetAppDomain) - => _legacy is not null ? _legacy.GetDelegateTargetObject(delegateType, delegateObject, ppTargetObj, ppTargetAppDomain) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetDelegateTargetObject(delegateType, delegateObject, ppTargetObj, ppTargetAppDomain) : HResults.E_NOTIMPL; public int GetLoaderHeapMemoryRanges(nint pRanges) - => _legacy is not null ? _legacy.GetLoaderHeapMemoryRanges(pRanges) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetLoaderHeapMemoryRanges(pRanges) : HResults.E_NOTIMPL; public int IsModuleMapped(ulong pModule, int* isModuleMapped) - => _legacy is not null ? _legacy.IsModuleMapped(pModule, isModuleMapped) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.IsModuleMapped(pModule, isModuleMapped) : HResults.E_NOTIMPL; public int MetadataUpdatesApplied(Interop.BOOL* pResult) { @@ -1261,14 +1261,14 @@ public int MetadataUpdatesApplied(Interop.BOOL* pResult) } public int GetAssemblyFromModule(ulong vmModule, ulong* pVmAssembly) - => _legacy is not null ? _legacy.GetAssemblyFromModule(vmModule, pVmAssembly) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetAssemblyFromModule(vmModule, pVmAssembly) : HResults.E_NOTIMPL; public int ParseContinuation(ulong continuationAddress, ulong* pDiagnosticIP, ulong* pNextContinuation, uint* pState) - => _legacy is not null ? _legacy.ParseContinuation(continuationAddress, pDiagnosticIP, pNextContinuation, pState) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.ParseContinuation(continuationAddress, pDiagnosticIP, pNextContinuation, pState) : HResults.E_NOTIMPL; public int GetAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, nint pAsyncLocals) - => _legacy is not null ? _legacy.GetAsyncLocals(vmMethod, codeAddr, state, pAsyncLocals) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetAsyncLocals(vmMethod, codeAddr, state, pAsyncLocals) : HResults.E_NOTIMPL; public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) - => _legacy is not null ? _legacy.GetGenericArgTokenIndex(vmMethod, pIndex) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetGenericArgTokenIndex(vmMethod, pIndex) : HResults.E_NOTIMPL; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs new file mode 100644 index 00000000000000..e77c4fb06fbf18 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +/// +/// Controls whether delegation-only APIs can fall back to the legacy DAC implementation. +/// When CDAC_NO_FALLBACK=1 is set, only explicitly allowlisted methods may delegate. +/// +internal static class LegacyFallbackHelper +{ + private static readonly bool s_noFallback = + Environment.GetEnvironmentVariable("CDAC_NO_FALLBACK") == "1"; + + // Methods that are allowed to fall back even in no-fallback mode. + // Use the method name as it appears via [CallerMemberName]. + private static readonly HashSet s_allowlist = new(StringComparer.Ordinal) + { + // Dump creation — the cDAC does not implement memory enumeration. + "EnumMemoryRegion", + "EnumMemoryRegionsWrapper", + }; + + /// + /// Returns true if the calling method is allowed to delegate to the legacy DAC. + /// In normal mode (no CDAC_NO_FALLBACK), always returns true. + /// In no-fallback mode, returns true only for allowlisted methods. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool CanFallback([CallerMemberName] string name = "") + { + if (!s_noFallback) + return true; + + return s_allowlist.Contains(name); + } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs index 4c5be79950a737..7e30e2ad47f875 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs @@ -12,5 +12,5 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; public sealed unsafe partial class SOSDacImpl : ICLRDataEnumMemoryRegions { int ICLRDataEnumMemoryRegions.EnumMemoryRegions(void* callback, uint miniDumpFlags, int clrFlags) - => _legacyEnumMemory is not null ? _legacyEnumMemory.EnumMemoryRegions(callback, miniDumpFlags, clrFlags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyEnumMemory is not null ? _legacyEnumMemory.EnumMemoryRegions(callback, miniDumpFlags, clrFlags) : HResults.E_NOTIMPL; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index 58e6781c7092a4..8d5c9a79c094f8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -22,21 +22,20 @@ int IXCLRDataProcess.Flush() { _target.Flush(); - // As long as any part of cDAC falls back to the legacy DAC, we need to propagate the Flush call - if (_legacyProcess is not null) + if (LegacyFallbackHelper.CanFallback() && _legacyProcess is not null) return _legacyProcess.Flush(); return HResults.S_OK; } int IXCLRDataProcess.StartEnumTasks(ulong* handle) - => _legacyProcess is not null ? _legacyProcess.StartEnumTasks(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumTasks(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.EnumTask(ulong* handle, DacComNullableByRef task) - => _legacyProcess is not null ? _legacyProcess.EnumTask(handle, task) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EnumTask(handle, task) : HResults.E_NOTIMPL; int IXCLRDataProcess.EndEnumTasks(ulong handle) - => _legacyProcess is not null ? _legacyProcess.EndEnumTasks(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EndEnumTasks(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, DacComNullableByRef task) { @@ -74,25 +73,25 @@ int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, DacComNullableByRef task) - => _legacyProcess is not null ? _legacyProcess.GetTaskByUniqueID(taskID, task) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetTaskByUniqueID(taskID, task) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetFlags(uint* flags) - => _legacyProcess is not null ? _legacyProcess.GetFlags(flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetFlags(flags) : HResults.E_NOTIMPL; int IXCLRDataProcess.IsSameObject(IXCLRDataProcess* process) - => _legacyProcess is not null ? _legacyProcess.IsSameObject(process) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.IsSameObject(process) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetManagedObject(DacComNullableByRef value) - => _legacyProcess is not null ? _legacyProcess.GetManagedObject(value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetManagedObject(value) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetDesiredExecutionState(uint* state) - => _legacyProcess is not null ? _legacyProcess.GetDesiredExecutionState(state) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetDesiredExecutionState(state) : HResults.E_NOTIMPL; int IXCLRDataProcess.SetDesiredExecutionState(uint state) - => _legacyProcess is not null ? _legacyProcess.SetDesiredExecutionState(state) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.SetDesiredExecutionState(state) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetAddressType(ClrDataAddress address, /*CLRDataAddressType*/ uint* type) - => _legacyProcess is not null ? _legacyProcess.GetAddressType(address, type) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetAddressType(address, type) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetRuntimeNameByAddress( ClrDataAddress address, @@ -101,40 +100,40 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( uint* nameLen, char* nameBuf, ClrDataAddress* displacement) - => _legacyProcess is not null ? _legacyProcess.GetRuntimeNameByAddress(address, flags, bufLen, nameLen, nameBuf, displacement) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetRuntimeNameByAddress(address, flags, bufLen, nameLen, nameBuf, displacement) : HResults.E_NOTIMPL; int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) - => _legacyProcess is not null ? _legacyProcess.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.EnumAppDomain(ulong* handle, /*IXCLRDataAppDomain*/ void** appDomain) - => _legacyProcess is not null ? _legacyProcess.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; int IXCLRDataProcess.EndEnumAppDomains(ulong handle) - => _legacyProcess is not null ? _legacyProcess.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetAppDomainByUniqueID(ulong id, /*IXCLRDataAppDomain*/ void** appDomain) - => _legacyProcess is not null ? _legacyProcess.GetAppDomainByUniqueID(id, appDomain) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetAppDomainByUniqueID(id, appDomain) : HResults.E_NOTIMPL; int IXCLRDataProcess.StartEnumAssemblies(ulong* handle) - => _legacyProcess is not null ? _legacyProcess.StartEnumAssemblies(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumAssemblies(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.EnumAssembly(ulong* handle, DacComNullableByRef assembly) - => _legacyProcess is not null ? _legacyProcess.EnumAssembly(handle, assembly) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EnumAssembly(handle, assembly) : HResults.E_NOTIMPL; int IXCLRDataProcess.EndEnumAssemblies(ulong handle) - => _legacyProcess is not null ? _legacyProcess.EndEnumAssemblies(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EndEnumAssemblies(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.StartEnumModules(ulong* handle) - => _legacyProcess is not null ? _legacyProcess.StartEnumModules(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumModules(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.EnumModule(ulong* handle, DacComNullableByRef mod) - => _legacyProcess is not null ? _legacyProcess.EnumModule(handle, mod) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EnumModule(handle, mod) : HResults.E_NOTIMPL; int IXCLRDataProcess.EndEnumModules(ulong handle) - => _legacyProcess is not null ? _legacyProcess.EndEnumModules(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EndEnumModules(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetModuleByAddress(ClrDataAddress address, DacComNullableByRef mod) - => _legacyProcess is not null ? _legacyProcess.GetModuleByAddress(address, mod) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetModuleByAddress(address, mod) : HResults.E_NOTIMPL; internal sealed class EnumMethodInstances : IEnum { @@ -475,10 +474,10 @@ int IXCLRDataProcess.GetDataByAddress( char* nameBuf, DacComNullableByRef value, ClrDataAddress* displacement) - => _legacyProcess is not null ? _legacyProcess.GetDataByAddress(address, flags, appDomain, tlsTask, bufLen, nameLen, nameBuf, value, displacement) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetDataByAddress(address, flags, appDomain, tlsTask, bufLen, nameLen, nameBuf, value, displacement) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetExceptionStateByExceptionRecord(EXCEPTION_RECORD64* record, DacComNullableByRef exState) - => _legacyProcess is not null ? _legacyProcess.GetExceptionStateByExceptionRecord(record, exState) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetExceptionStateByExceptionRecord(record, exState) : HResults.E_NOTIMPL; int IXCLRDataProcess.TranslateExceptionRecordToNotification(EXCEPTION_RECORD64* record, [MarshalUsing(typeof(UniqueComInterfaceMarshaller))] IXCLRDataExceptionNotification notify) { @@ -630,7 +629,7 @@ int IXCLRDataProcess.Request(uint reqCode, uint inBufferSize, byte* inBuffer, ui } else { - return _legacyProcess is not null ? _legacyProcess.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + return LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; } #if DEBUG if (_legacyProcess is not null) @@ -659,13 +658,13 @@ int IXCLRDataProcess.CreateMemoryValue( IXCLRDataTypeInstance? type, ClrDataAddress addr, DacComNullableByRef value) - => _legacyProcess is not null ? _legacyProcess.CreateMemoryValue(appDomain, tlsTask, type, addr, value) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.CreateMemoryValue(appDomain, tlsTask, type, addr, value) : HResults.E_NOTIMPL; int IXCLRDataProcess.SetAllTypeNotifications(IXCLRDataModule? mod, uint flags) - => _legacyProcess is not null ? _legacyProcess.SetAllTypeNotifications(mod, flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.SetAllTypeNotifications(mod, flags) : HResults.E_NOTIMPL; int IXCLRDataProcess.SetAllCodeNotifications(IXCLRDataModule? mod, uint flags) - => _legacyProcess is not null ? _legacyProcess.SetAllCodeNotifications(mod, flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.SetAllCodeNotifications(mod, flags) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetTypeNotifications( uint numTokens, @@ -673,7 +672,7 @@ int IXCLRDataProcess.GetTypeNotifications( IXCLRDataModule? singleMod, [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdTypeDef*/ uint[] tokens, [In, Out, MarshalUsing(CountElementName = nameof(numTokens))] uint[] flags) - => _legacyProcess is not null ? _legacyProcess.GetTypeNotifications(numTokens, mods, singleMod, tokens, flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetTypeNotifications(numTokens, mods, singleMod, tokens, flags) : HResults.E_NOTIMPL; int IXCLRDataProcess.SetTypeNotifications( uint numTokens, @@ -682,7 +681,7 @@ int IXCLRDataProcess.SetTypeNotifications( [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdTypeDef*/ uint[] tokens, [In, MarshalUsing(CountElementName = nameof(numTokens))] uint[] flags, uint singleFlags) - => _legacyProcess is not null ? _legacyProcess.SetTypeNotifications(numTokens, mods, singleMod, tokens, flags, singleFlags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.SetTypeNotifications(numTokens, mods, singleMod, tokens, flags, singleFlags) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetCodeNotifications( uint numTokens, @@ -690,7 +689,7 @@ int IXCLRDataProcess.GetCodeNotifications( IXCLRDataModule? singleMod, [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdMethodDef*/ uint[] tokens, [In, Out, MarshalUsing(CountElementName = nameof(numTokens))] uint[] flags) - => _legacyProcess is not null ? _legacyProcess.GetCodeNotifications(numTokens, mods, singleMod, tokens, flags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.GetCodeNotifications(numTokens, mods, singleMod, tokens, flags) : HResults.E_NOTIMPL; int IXCLRDataProcess.SetCodeNotifications( uint numTokens, @@ -699,7 +698,7 @@ int IXCLRDataProcess.SetCodeNotifications( [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdMethodDef */ uint[] tokens, [In, MarshalUsing(CountElementName = nameof(numTokens))] uint[] flags, uint singleFlags) - => _legacyProcess is not null ? _legacyProcess.SetCodeNotifications(numTokens, mods, singleMod, tokens, flags, singleFlags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.SetCodeNotifications(numTokens, mods, singleMod, tokens, flags, singleFlags) : HResults.E_NOTIMPL; int IXCLRDataProcess.GetOtherNotificationFlags(uint* flags) { @@ -775,13 +774,13 @@ int IXCLRDataProcess.SetOtherNotificationFlags(uint flags) } int IXCLRDataProcess.StartEnumMethodDefinitionsByAddress(ClrDataAddress address, ulong* handle) - => _legacyProcess is not null ? _legacyProcess.StartEnumMethodDefinitionsByAddress(address, handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.StartEnumMethodDefinitionsByAddress(address, handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.EnumMethodDefinitionByAddress(ulong* handle, DacComNullableByRef method) - => _legacyProcess is not null ? _legacyProcess.EnumMethodDefinitionByAddress(handle, method) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EnumMethodDefinitionByAddress(handle, method) : HResults.E_NOTIMPL; int IXCLRDataProcess.EndEnumMethodDefinitionsByAddress(ulong handle) - => _legacyProcess is not null ? _legacyProcess.EndEnumMethodDefinitionsByAddress(handle) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.EndEnumMethodDefinitionsByAddress(handle) : HResults.E_NOTIMPL; int IXCLRDataProcess.FollowStub( uint inFlags, @@ -790,7 +789,7 @@ int IXCLRDataProcess.FollowStub( ClrDataAddress* outAddr, /*struct CLRDATA_FOLLOW_STUB_BUFFER*/ void* outBuffer, uint* outFlags) - => _legacyProcess is not null ? _legacyProcess.FollowStub(inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub(inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; int IXCLRDataProcess.FollowStub2( IXCLRDataTask? task, @@ -800,7 +799,7 @@ int IXCLRDataProcess.FollowStub2( ClrDataAddress* outAddr, /*struct CLRDATA_FOLLOW_STUB_BUFFER*/ void* outBuffer, uint* outFlags) - => _legacyProcess is not null ? _legacyProcess.FollowStub2(task, inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub2(task, inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; int IXCLRDataProcess.DumpNativeImage( ClrDataAddress loadedBase, @@ -808,7 +807,7 @@ int IXCLRDataProcess.DumpNativeImage( /*IXCLRDataDisplay*/ void* display, /*IXCLRLibrarySupport*/ void* libSupport, /*IXCLRDisassemblySupport*/ void* dis) - => _legacyProcess is not null ? _legacyProcess.DumpNativeImage(loadedBase, name, display, libSupport, dis) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.DumpNativeImage(loadedBase, name, display, libSupport, dis) : HResults.E_NOTIMPL; int IXCLRDataProcess2.GetGcNotification(GcEvtArgs* gcEvtArgs) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 125e5e78c75011..8629931fb4eb0d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -44,11 +44,6 @@ public sealed unsafe partial class SOSDacImpl private readonly Lazy _objectMethodTable; private readonly ulong _rcwMask = 1UL; - // Prevents the legacy DAC RCW from being released when fallback is disabled. - // The native CDAC class holds a raw pointer (m_legacyImpl) to the legacy DAC - // that must remain valid for the lifetime of this object. - private readonly object? _prevent_release; - private readonly ISOSDacInterface? _legacyImpl; private readonly ISOSDacInterface2? _legacyImpl2; private readonly ISOSDacInterface3? _legacyImpl3; @@ -69,17 +64,15 @@ public sealed unsafe partial class SOSDacImpl private readonly IXCLRDataProcess2? _legacyProcess2; private readonly ICLRDataEnumMemoryRegions? _legacyEnumMemory; - public SOSDacImpl(Target target, object? legacyObj, object? prevent_release = null) + public SOSDacImpl(Target target, object? legacyObj) { _target = target; - _prevent_release = prevent_release; _stringMethodTable = new Lazy( () => _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.StringMethodTable))); _objectMethodTable = new Lazy( () => _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))); - // Get all the interfaces for delegating to the legacy DAC if (legacyObj is not null) { _legacyImpl = legacyObj as ISOSDacInterface; @@ -104,15 +97,6 @@ public SOSDacImpl(Target target, object? legacyObj, object? prevent_release = nu _legacyEnumMemory = legacyObj as ICLRDataEnumMemoryRegions; } - - // ICLRDataEnumMemoryRegions is always delegated to the legacy DAC because - // the cDAC does not implement memory enumeration for dump creation. - // Even when CDAC_NO_FALLBACK is set, we must allow this to work so that - // dumps contain the CLR auxiliary memory needed for later analysis. - if (_legacyEnumMemory is null && prevent_release is not null) - { - _legacyEnumMemory = prevent_release as ICLRDataEnumMemoryRegions; - } } #region ISOSDacInterface @@ -503,7 +487,7 @@ int ISOSDacInterface.GetAssemblyList(ClrDataAddress addr, int count, [In, Marsha return hr; } int ISOSDacInterface.GetAssemblyLocation(ClrDataAddress assembly, int count, char* location, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetAssemblyLocation(assembly, count, location, pNeeded) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetAssemblyLocation(assembly, count, location, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetAssemblyModuleList(ClrDataAddress assembly, uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[]? modules, uint* pNeeded) { int hr = HResults.S_OK; @@ -958,7 +942,7 @@ int ISOSDacInterface.GetCodeHeapList(ClrDataAddress jitManager, uint count, [In, return hr; } int ISOSDacInterface.GetDacModuleHandle(void* phModule) - => _legacyImpl is not null ? _legacyImpl.GetDacModuleHandle(phModule) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetDacModuleHandle(phModule) : HResults.E_NOTIMPL; int ISOSDacInterface.GetDomainFromContext(ClrDataAddress context, ClrDataAddress* domain) { int hr = HResults.S_OK; @@ -1033,11 +1017,11 @@ int ISOSDacInterface.GetDomainLocalModuleDataFromModule(ClrDataAddress moduleAdd return hr; } int ISOSDacInterface.GetFailedAssemblyData(ClrDataAddress assembly, uint* pContext, int* pResult) - => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyData(assembly, pContext, pResult) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyData(assembly, pContext, pResult) : HResults.E_NOTIMPL; int ISOSDacInterface.GetFailedAssemblyDisplayName(ClrDataAddress assembly, uint count, char* name, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyDisplayName(assembly, count, name, pNeeded) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyDisplayName(assembly, count, name, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetFailedAssemblyList(ClrDataAddress appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[] values, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyList(appDomain, count, values, pNeeded) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFailedAssemblyList(appDomain, count, values, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetFailedAssemblyLocation(ClrDataAddress assembly, uint count, char* location, uint* pNeeded) { int hr = HResults.S_OK; @@ -1877,7 +1861,7 @@ int ISOSDacInterface.GetHandleEnum(DacComNullableByRef ppHandleE return hr; } int ISOSDacInterface.GetHandleEnumForGC(uint gen, DacComNullableByRef ppHandleEnum) - => _legacyImpl is not null ? _legacyImpl.GetHandleEnumForGC(gen, ppHandleEnum) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetHandleEnumForGC(gen, ppHandleEnum) : HResults.E_NOTIMPL; int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = "count")] uint[] types, uint count, DacComNullableByRef ppHandleEnum) { int hr = HResults.S_OK; @@ -1904,7 +1888,7 @@ int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = return hr; } int ISOSDacInterface.GetHeapAllocData(uint count, void* data, uint* pNeeded) - => _legacyImpl is not null ? _legacyImpl.GetHeapAllocData(count, data, pNeeded) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetHeapAllocData(count, data, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetHeapAnalyzeData(ClrDataAddress addr, DacpGcHeapAnalyzeData* data) { int hr = HResults.S_OK; @@ -4664,7 +4648,7 @@ int ISOSDacInterface.TraverseEHInfo(ClrDataAddress ip, delegate* unmanaged _legacyImpl is not null ? _legacyImpl.TraverseLoaderHeap(loaderHeapAddr, pCallback) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.TraverseLoaderHeap(loaderHeapAddr, pCallback) : HResults.E_NOTIMPL; #if DEBUG [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] @@ -4792,7 +4776,7 @@ int ISOSDacInterface.TraverseRCWCleanupList(ClrDataAddress cleanupListPtr, deleg return hr; } int ISOSDacInterface.TraverseVirtCallStubHeap(ClrDataAddress pAppDomain, int heaptype, void* pCallback) - => _legacyImpl is not null ? _legacyImpl.TraverseVirtCallStubHeap(pAppDomain, heaptype, pCallback) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.TraverseVirtCallStubHeap(pAppDomain, heaptype, pCallback) : HResults.E_NOTIMPL; #endregion ISOSDacInterface #region ISOSDacInterface2 @@ -6090,9 +6074,9 @@ int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* #region ISOSDacInterface11 int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTrackedType, Interop.BOOL* hasTaggedMemory) - => _legacyImpl11 is not null ? _legacyImpl11.IsTrackedType(objAddr, isTrackedType, hasTaggedMemory) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl11 is not null ? _legacyImpl11.IsTrackedType(objAddr, isTrackedType, hasTaggedMemory) : HResults.E_NOTIMPL; int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* taggedMemory, nuint* taggedMemorySizeInBytes) - => _legacyImpl11 is not null ? _legacyImpl11.GetTaggedMemory(objAddr, taggedMemory, taggedMemorySizeInBytes) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl11 is not null ? _legacyImpl11.GetTaggedMemory(objAddr, taggedMemory, taggedMemorySizeInBytes) : HResults.E_NOTIMPL; #endregion ISOSDacInterface11 #region ISOSDacInterface12 @@ -6134,7 +6118,7 @@ int ISOSDacInterface12.GetGlobalAllocationContext(ClrDataAddress* allocPtr, ClrD #region ISOSDacInterface13 int ISOSDacInterface13.TraverseLoaderHeap(ClrDataAddress loaderHeapAddr, /*LoaderHeapKind*/ int kind, /*VISITHEAP*/ delegate* unmanaged pCallback) - => _legacyImpl13 is not null ? _legacyImpl13.TraverseLoaderHeap(loaderHeapAddr, kind, pCallback) : HResults.E_NOTIMPL; + => LegacyFallbackHelper.CanFallback() && _legacyImpl13 is not null ? _legacyImpl13.TraverseLoaderHeap(loaderHeapAddr, kind, pCallback) : HResults.E_NOTIMPL; int ISOSDacInterface13.GetDomainLoaderAllocator(ClrDataAddress domainAddress, ClrDataAddress* pLoaderAllocator) { int hr = HResults.S_OK; diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index 3ecc7289b687e0..538c63c61f4ad1 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -78,25 +78,14 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr return -1; object? legacyImpl = null; - object? prevent_release = null; if (legacyImplPtr != IntPtr.Zero) { - object legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); - // When CDAC_NO_FALLBACK is set, we don't use the legacy impl for fallback - // but we must hold a reference to it because the native CDAC class stores - // a raw pointer (m_legacyImpl) that assumes it outlives the CDAC. - bool noFallback = Environment.GetEnvironmentVariable("CDAC_NO_FALLBACK") == "1"; - if (noFallback) - { - prevent_release = legacyObj; - } - else - { - legacyImpl = legacyObj; - } + legacyImpl = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); } - Legacy.SOSDacImpl impl = new(target, legacyImpl, prevent_release); + // Fallback gating is handled by LegacyFallbackHelper at each call site, + // so always pass the legacy impl. The helper checks CDAC_NO_FALLBACK. + Legacy.SOSDacImpl impl = new(target, legacyImpl); nint ptr = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); *obj = ptr; return 0; @@ -128,27 +117,18 @@ private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImpl ComWrappers cw = new StrategyBasedComWrappers(); object? legacyObj = null; - object? prevent_release = null; if (legacyImplPtr != IntPtr.Zero) { - object wrapped = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); - bool noFallback = Environment.GetEnvironmentVariable("CDAC_NO_FALLBACK") == "1"; - if (noFallback) + legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); + if (legacyObj is not Legacy.IDacDbiInterface) { - prevent_release = wrapped; - } - else - { - legacyObj = wrapped; - if (legacyObj is not Legacy.IDacDbiInterface) - { - *obj = IntPtr.Zero; - return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE - } + *obj = IntPtr.Zero; + return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE } } - Legacy.DacDbiImpl impl = new(target, legacyObj, prevent_release); + // Fallback gating is handled by LegacyFallbackHelper at each call site. + Legacy.DacDbiImpl impl = new(target, legacyObj); *obj = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); return HResults.S_OK; } From dc569ce1da7f72b0d5c1d2100426551a79c755fd Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:12:51 -0400 Subject: [PATCH 06/18] Fix allowlist to use nameof and correct method name The allowlist had two bugs: 'EnumMemoryRegion' (singular) and 'EnumMemoryRegionsWrapper' (nonexistent) would never match the actual CallerMemberName 'EnumMemoryRegions'. Use nameof() to prevent this class of error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index e77c4fb06fbf18..0755b0c1e7b04c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -21,8 +21,7 @@ internal static class LegacyFallbackHelper private static readonly HashSet s_allowlist = new(StringComparer.Ordinal) { // Dump creation — the cDAC does not implement memory enumeration. - "EnumMemoryRegion", - "EnumMemoryRegionsWrapper", + nameof(ICLRDataEnumMemoryRegions.EnumMemoryRegions), }; /// From 352cf0638e6ecb44b6b1befb3221111181beeaa3 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:16:25 -0400 Subject: [PATCH 07/18] Simplify CreateDacDbiInterface to match CreateSosInterface pattern Remove redundant null/type checks from CreateDacDbiInterface. The DacDbiImpl constructor handles interface mismatches gracefully via 'as' cast, and LegacyFallbackHelper gates all call sites. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../mscordaccore_universal/Entrypoints.cs | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index 538c63c61f4ad1..25dcf720a4f205 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -100,37 +100,20 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr [UnmanagedCallersOnly(EntryPoint = $"{CDAC}create_dacdbi_interface")] private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImplPtr, nint* obj) { - if (obj == null) - return HResults.E_INVALIDARG; - if (handle == IntPtr.Zero) - { - *obj = IntPtr.Zero; - return HResults.E_NOTIMPL; - } - + ComWrappers cw = new StrategyBasedComWrappers(); Target? target = GCHandle.FromIntPtr(handle).Target as Target; if (target is null) - { - *obj = IntPtr.Zero; - return HResults.E_INVALIDARG; - } + return -1; - ComWrappers cw = new StrategyBasedComWrappers(); object? legacyObj = null; if (legacyImplPtr != IntPtr.Zero) { legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); - if (legacyObj is not Legacy.IDacDbiInterface) - { - *obj = IntPtr.Zero; - return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE - } } - // Fallback gating is handled by LegacyFallbackHelper at each call site. Legacy.DacDbiImpl impl = new(target, legacyObj); *obj = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); - return HResults.S_OK; + return 0; } [UnmanagedCallersOnly(EntryPoint = "CLRDataCreateInstanceWithFallback")] From 5172453a0753dab6af4b592258930a8d9d143509 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:22:52 -0400 Subject: [PATCH 08/18] Gate IMetaDataImport QI fallback through LegacyFallbackHelper The ICustomQueryInterface.GetInterface method in ClrDataModule delegates IMetaDataImport QIs to the legacy module pointer. Gate this with CanFallback() so no-fallback mode blocks it, allowing PR #127028's managed MetadataReader wrapper to provide metadata instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ClrDataModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 537dc0b85b95d3..38047994bffbef 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -54,7 +54,7 @@ public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? lega CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out nint ppv) { ppv = default; - if (_legacyModulePointer == 0) + if (!LegacyFallbackHelper.CanFallback() || _legacyModulePointer == 0) return CustomQueryInterfaceResult.NotHandled; // Legacy DAC implementation of IXCLRDataModule handles QIs for IMetaDataImport by creating and From b7f57b0f2b6fd04b5d5f1a089a90bd2c02f999d3 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:26:29 -0400 Subject: [PATCH 09/18] Track blocked fallback calls and log on process exit When CDAC_NO_FALLBACK=1, blocked legacy delegation attempts are now counted per-method in a ConcurrentDictionary. On process exit, a summary is written to ~/cdac_blocked_fallbacks.log showing which APIs were called, how many times, and were denied fallback. This makes it easy to identify which unimplemented APIs are actually exercised during test runs without separate instrumentation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index 0755b0c1e7b04c..79e7ca19b9f318 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Runtime.CompilerServices; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -10,6 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// /// Controls whether delegation-only APIs can fall back to the legacy DAC implementation. /// When CDAC_NO_FALLBACK=1 is set, only explicitly allowlisted methods may delegate. +/// Blocked calls are tracked and written to a log file on process exit. /// internal static class LegacyFallbackHelper { @@ -24,10 +27,22 @@ internal static class LegacyFallbackHelper nameof(ICLRDataEnumMemoryRegions.EnumMemoryRegions), }; + // Tracks APIs that attempted fallback but were blocked in no-fallback mode. + private static readonly ConcurrentDictionary s_blockedCalls = new(); + + static LegacyFallbackHelper() + { + if (s_noFallback) + { + AppDomain.CurrentDomain.ProcessExit += (_, _) => FlushBlockedCallLog(); + } + } + /// /// Returns true if the calling method is allowed to delegate to the legacy DAC. /// In normal mode (no CDAC_NO_FALLBACK), always returns true. /// In no-fallback mode, returns true only for allowlisted methods. + /// Blocked calls are recorded for diagnostics. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool CanFallback([CallerMemberName] string name = "") @@ -35,6 +50,42 @@ internal static bool CanFallback([CallerMemberName] string name = "") if (!s_noFallback) return true; - return s_allowlist.Contains(name); + if (s_allowlist.Contains(name)) + return true; + + s_blockedCalls.AddOrUpdate(name, 1, (_, count) => count + 1); + return false; + } + + private static void FlushBlockedCallLog() + { + if (s_blockedCalls.IsEmpty) + return; + + try + { + string logPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "cdac_blocked_fallbacks.log"); + + using StreamWriter writer = new(logPath, append: false); + writer.WriteLine("== cDAC Blocked Legacy Fallback Calls =="); + writer.WriteLine($"Timestamp: {DateTime.UtcNow:O}"); + writer.WriteLine(); + writer.WriteLine($"{"API",-60} {"Hits",8}"); + writer.WriteLine(new string('-', 70)); + + foreach (KeyValuePair entry in s_blockedCalls) + { + writer.WriteLine($"{entry.Key,-60} {entry.Value,8}"); + } + + writer.WriteLine(); + writer.WriteLine($"Total: {s_blockedCalls.Count} unique APIs blocked"); + } + catch + { + // Best-effort logging — don't crash the process on exit. + } } } From 3839a5d2684a4ddda928d7a1807626fd950f5ef4 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:52:15 -0400 Subject: [PATCH 10/18] Allowlist GetInterface QI, switch blocked fallback logging to stderr - Add ICustomQueryInterface.GetInterface to the allowlist (needed until managed MetadataReader wrapper lands in PR #127028) - Replace file-based logging with Console.Error.WriteLine so blocked fallback calls appear directly in test output (captured by ProcessRunner) - Simplify tracking to ConcurrentDictionary with TryAdd - Remove Flush() CanFallback gate (cache management, not data retrieval) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 65 +++++++------------ .../SOSDacImpl.IXCLRDataProcess.cs | 3 +- 2 files changed, 24 insertions(+), 44 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index 79e7ca19b9f318..6b5a89cc5046cd 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -6,13 +6,14 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// /// Controls whether delegation-only APIs can fall back to the legacy DAC implementation. /// When CDAC_NO_FALLBACK=1 is set, only explicitly allowlisted methods may delegate. -/// Blocked calls are tracked and written to a log file on process exit. +/// Blocked calls are logged to stderr for capture by the test infrastructure. /// internal static class LegacyFallbackHelper { @@ -25,27 +26,25 @@ internal static class LegacyFallbackHelper { // Dump creation — the cDAC does not implement memory enumeration. nameof(ICLRDataEnumMemoryRegions.EnumMemoryRegions), - }; - // Tracks APIs that attempted fallback but were blocked in no-fallback mode. - private static readonly ConcurrentDictionary s_blockedCalls = new(); + // IMetaDataImport QI — needed until managed MetadataReader wrapper lands (PR #127028). + nameof(ICustomQueryInterface.GetInterface), + }; - static LegacyFallbackHelper() - { - if (s_noFallback) - { - AppDomain.CurrentDomain.ProcessExit += (_, _) => FlushBlockedCallLog(); - } - } + // Tracks unique call sites that attempted fallback but were blocked. + private static readonly ConcurrentDictionary s_blockedCalls = new(); /// /// Returns true if the calling method is allowed to delegate to the legacy DAC. /// In normal mode (no CDAC_NO_FALLBACK), always returns true. /// In no-fallback mode, returns true only for allowlisted methods. - /// Blocked calls are recorded for diagnostics. + /// Blocked calls are logged to stderr on first occurrence. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool CanFallback([CallerMemberName] string name = "") + internal static bool CanFallback( + [CallerMemberName] string name = "", + [CallerFilePath] string file = "", + [CallerLineNumber] int line = 0) { if (!s_noFallback) return true; @@ -53,39 +52,19 @@ internal static bool CanFallback([CallerMemberName] string name = "") if (s_allowlist.Contains(name)) return true; - s_blockedCalls.AddOrUpdate(name, 1, (_, count) => count + 1); - return false; - } - - private static void FlushBlockedCallLog() - { - if (s_blockedCalls.IsEmpty) - return; - - try + string key = $"{name}@{Path.GetFileName(file)}:{line}"; + if (s_blockedCalls.TryAdd(key, true)) { - string logPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - "cdac_blocked_fallbacks.log"); - - using StreamWriter writer = new(logPath, append: false); - writer.WriteLine("== cDAC Blocked Legacy Fallback Calls =="); - writer.WriteLine($"Timestamp: {DateTime.UtcNow:O}"); - writer.WriteLine(); - writer.WriteLine($"{"API",-60} {"Hits",8}"); - writer.WriteLine(new string('-', 70)); - - foreach (KeyValuePair entry in s_blockedCalls) + try { - writer.WriteLine($"{entry.Key,-60} {entry.Value,8}"); + Console.Error.WriteLine($"[cDAC] Blocked fallback: {name} at {Path.GetFileName(file)}:{line}"); + } + catch + { + // Best-effort logging — don't crash the debugger process. } - - writer.WriteLine(); - writer.WriteLine($"Total: {s_blockedCalls.Count} unique APIs blocked"); - } - catch - { - // Best-effort logging — don't crash the process on exit. } + + return false; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index 8d5c9a79c094f8..590e529ffc480f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -22,7 +22,8 @@ int IXCLRDataProcess.Flush() { _target.Flush(); - if (LegacyFallbackHelper.CanFallback() && _legacyProcess is not null) + // Flush is always propagated — it's cache management, not data retrieval. + if (_legacyProcess is not null) return _legacyProcess.Flush(); return HResults.S_OK; From 8723a34b64db568947122e948580b85ad90f23f3 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:09:05 -0400 Subject: [PATCH 11/18] Log every fallback attempt (allowed and blocked) to stderr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove deduplication — log every call for full visibility. Also log allowed fallback calls so the test output shows the complete picture of legacy DAC usage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index 6b5a89cc5046cd..642af5d1ca7a9a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; @@ -13,7 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// /// Controls whether delegation-only APIs can fall back to the legacy DAC implementation. /// When CDAC_NO_FALLBACK=1 is set, only explicitly allowlisted methods may delegate. -/// Blocked calls are logged to stderr for capture by the test infrastructure. +/// All fallback attempts are logged to stderr for capture by the test infrastructure. /// internal static class LegacyFallbackHelper { @@ -31,14 +30,11 @@ internal static class LegacyFallbackHelper nameof(ICustomQueryInterface.GetInterface), }; - // Tracks unique call sites that attempted fallback but were blocked. - private static readonly ConcurrentDictionary s_blockedCalls = new(); - /// /// Returns true if the calling method is allowed to delegate to the legacy DAC. /// In normal mode (no CDAC_NO_FALLBACK), always returns true. /// In no-fallback mode, returns true only for allowlisted methods. - /// Blocked calls are logged to stderr on first occurrence. + /// All fallback attempts (allowed and blocked) are logged to stderr. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool CanFallback( @@ -50,19 +46,26 @@ internal static bool CanFallback( return true; if (s_allowlist.Contains(name)) - return true; - - string key = $"{name}@{Path.GetFileName(file)}:{line}"; - if (s_blockedCalls.TryAdd(key, true)) { try { - Console.Error.WriteLine($"[cDAC] Blocked fallback: {name} at {Path.GetFileName(file)}:{line}"); + Console.Error.WriteLine($"[cDAC] Allowed fallback: {name} at {Path.GetFileName(file)}:{line}"); } catch { // Best-effort logging — don't crash the debugger process. } + + return true; + } + + try + { + Console.Error.WriteLine($"[cDAC] Blocked fallback: {name} at {Path.GetFileName(file)}:{line}"); + } + catch + { + // Best-effort logging — don't crash the debugger process. } return false; From dd401b33516a22412c9c7a02da616027278ff2c1 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 16 Apr 2026 20:25:55 -0400 Subject: [PATCH 12/18] Allowlist remaining blocked APIs and add file-level DBI allowlist Add per-method allowlist entries for IXCLRDataModule.GetMethodDefinitionByToken, ISOSDacInterface11.IsTrackedType, and ISOSDacInterface.TraverseLoaderHeap. Add file-level allowlist for DacDbiImpl.cs since the entire DBI interface (122 delegation-only methods) is deferred and not implemented in the cDAC. SOS test results with CDAC_NO_FALLBACK=1: 24 passed, 0 blocked fallbacks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index 642af5d1ca7a9a..c555097a423bc8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -28,6 +28,22 @@ internal static class LegacyFallbackHelper // IMetaDataImport QI — needed until managed MetadataReader wrapper lands (PR #127028). nameof(ICustomQueryInterface.GetInterface), + + // IXCLRDataModule — not yet implemented in the cDAC. + nameof(IXCLRDataModule.GetMethodDefinitionByToken), + + // GC heap analysis — not yet implemented in the cDAC (PR #125895). + nameof(ISOSDacInterface11.IsTrackedType), + + // Loader heap traversal — not yet implemented in the cDAC (PR #125129). + nameof(ISOSDacInterface.TraverseLoaderHeap), + }; + + // Files whose methods are all allowed to fall back. + // The entire DBI interface is deferred — the cDAC does not implement ICorDebug data access yet. + private static readonly HashSet s_fileAllowlist = new(StringComparer.OrdinalIgnoreCase) + { + "DacDbiImpl.cs", }; /// @@ -45,7 +61,7 @@ internal static bool CanFallback( if (!s_noFallback) return true; - if (s_allowlist.Contains(name)) + if (s_allowlist.Contains(name) || s_fileAllowlist.Contains(Path.GetFileName(file))) { try { From bee8db9d4d9c372631128f5375e675edb3ffca93 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 12:21:18 -0400 Subject: [PATCH 13/18] Use -noFallback flag in CI and remove unnecessary try/catch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update runtime-diagnostics pipeline to use the -noFallback build flag from dotnet/diagnostics#5806 instead of setting CDAC_NO_FALLBACK as a pipeline-level environment variable. The -noFallback flag properly sets the env var on the debugger process and enables CDAC_NO_FALLBACK_TESTING defines to skip ClrStack -i tests. Add noFallback parameter to runtime-diag-job.yml template and wire it through to the build script. Remove unnecessary try/catch around Console.Error.WriteLine in LegacyFallbackHelper — stderr writes don't throw when the stream is unavailable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../diagnostics/runtime-diag-job.yml | 6 ++++++ eng/pipelines/runtime-diagnostics.yml | 5 +---- .../LegacyFallbackHelper.cs | 20 ++----------------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/eng/pipelines/diagnostics/runtime-diag-job.yml b/eng/pipelines/diagnostics/runtime-diag-job.yml index 9916a42663822c..99b663d3dc9048 100644 --- a/eng/pipelines/diagnostics/runtime-diag-job.yml +++ b/eng/pipelines/diagnostics/runtime-diag-job.yml @@ -38,6 +38,7 @@ parameters: disableComponentGovernance: '' liveRuntimeDir: '' useCdac: false + noFallback: false classFilter: '' jobs: @@ -89,6 +90,7 @@ jobs: - _TestArgs: '-test' - _Cross: '' - _CdacArgs: '' + - _NoFallbackArgs: '' - _ClassFilterArgs: '' - _buildScript: $(Build.SourcesDirectory)$(dir)build$(scriptExt) @@ -105,6 +107,9 @@ jobs: - ${{ if eq(parameters.useCdac, 'true') }}: - _CdacArgs: '-useCdac' + - ${{ if eq(parameters.noFallback, 'true') }}: + - _NoFallbackArgs: '-noFallback' + - ${{ if ne(parameters.classFilter, '') }}: - _ClassFilterArgs: '-classfilter ${{ parameters.classFilter }}' @@ -201,6 +206,7 @@ jobs: -architecture ${{ parameters.archType }} -privatebuild $(_CdacArgs) + $(_NoFallbackArgs) -liveRuntimeDir ${{ parameters.liveRuntimeDir }} $(_TestArgs) $(_Cross) diff --git a/eng/pipelines/runtime-diagnostics.yml b/eng/pipelines/runtime-diagnostics.yml index e6b53e8aaa9a8f..f6a3f9215fdd0b 100644 --- a/eng/pipelines/runtime-diagnostics.yml +++ b/eng/pipelines/runtime-diagnostics.yml @@ -154,13 +154,10 @@ extends: variables: - name: AllowPtrToDetectTestRunRetryFiles value: false - - name: DOTNET_ENABLE_CDAC - value: '1' - - name: CDAC_NO_FALLBACK - value: '1' jobParameters: name: cDAC_no_fallback useCdac: true + noFallback: true classFilter: SOS isOfficialBuild: ${{ variables.isOfficialBuild }} liveRuntimeDir: $(Build.SourcesDirectory)/artifacts/runtime diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index c555097a423bc8..c729a79d0c94e5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -63,27 +63,11 @@ internal static bool CanFallback( if (s_allowlist.Contains(name) || s_fileAllowlist.Contains(Path.GetFileName(file))) { - try - { - Console.Error.WriteLine($"[cDAC] Allowed fallback: {name} at {Path.GetFileName(file)}:{line}"); - } - catch - { - // Best-effort logging — don't crash the debugger process. - } - + Console.Error.WriteLine($"[cDAC] Allowed fallback: {name} at {Path.GetFileName(file)}:{line}"); return true; } - try - { - Console.Error.WriteLine($"[cDAC] Blocked fallback: {name} at {Path.GetFileName(file)}:{line}"); - } - catch - { - // Best-effort logging — don't crash the debugger process. - } - + Console.Error.WriteLine($"[cDAC] Blocked fallback: {name} at {Path.GetFileName(file)}:{line}"); return false; } } From f29fd2e84a14193f9a76b705d59bfbdc885cccce Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 12:59:47 -0400 Subject: [PATCH 14/18] Address PR review feedback - Revert Entrypoints.cs to main (no unnecessary changes) - Restore 'Get all the interfaces' comment in SOSDacImpl constructor - Reorder ClrDataModule GetInterface condition to check _legacyModulePointer before CanFallback() to avoid unnecessary logging Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ClrDataModule.cs | 2 +- .../SOSDacImpl.cs | 1 + .../mscordaccore_universal/Entrypoints.cs | 33 ++++++++++++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 38047994bffbef..5c6de7f7cefff2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -54,7 +54,7 @@ public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? lega CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out nint ppv) { ppv = default; - if (!LegacyFallbackHelper.CanFallback() || _legacyModulePointer == 0) + if (_legacyModulePointer == 0 || !LegacyFallbackHelper.CanFallback()) return CustomQueryInterfaceResult.NotHandled; // Legacy DAC implementation of IXCLRDataModule handles QIs for IMetaDataImport by creating and diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 8629931fb4eb0d..e1f2f405cb23cc 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -73,6 +73,7 @@ public SOSDacImpl(Target target, object? legacyObj) _objectMethodTable = new Lazy( () => _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.ObjectMethodTable))); + // Get all the interfaces for delegating to the legacy DAC if (legacyObj is not null) { _legacyImpl = legacyObj as ISOSDacInterface; diff --git a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs index 25dcf720a4f205..af14a0a1dbba09 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Entrypoints.cs @@ -77,14 +77,9 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr if (target == null) return -1; - object? legacyImpl = null; - if (legacyImplPtr != IntPtr.Zero) - { - legacyImpl = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); - } - - // Fallback gating is handled by LegacyFallbackHelper at each call site, - // so always pass the legacy impl. The helper checks CDAC_NO_FALLBACK. + object? legacyImpl = legacyImplPtr != IntPtr.Zero + ? cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None) + : null; Legacy.SOSDacImpl impl = new(target, legacyImpl); nint ptr = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); *obj = ptr; @@ -100,20 +95,36 @@ private static unsafe int CreateSosInterface(IntPtr handle, IntPtr legacyImplPtr [UnmanagedCallersOnly(EntryPoint = $"{CDAC}create_dacdbi_interface")] private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImplPtr, nint* obj) { - ComWrappers cw = new StrategyBasedComWrappers(); + if (obj == null) + return HResults.E_INVALIDARG; + if (handle == IntPtr.Zero) + { + *obj = IntPtr.Zero; + return HResults.E_NOTIMPL; + } + Target? target = GCHandle.FromIntPtr(handle).Target as Target; if (target is null) - return -1; + { + *obj = IntPtr.Zero; + return HResults.E_INVALIDARG; + } + ComWrappers cw = new StrategyBasedComWrappers(); object? legacyObj = null; if (legacyImplPtr != IntPtr.Zero) { legacyObj = cw.GetOrCreateObjectForComInstance(legacyImplPtr, CreateObjectFlags.None); + if (legacyObj is not Legacy.IDacDbiInterface) + { + *obj = IntPtr.Zero; + return HResults.COR_E_INVALIDCAST; // E_NOINTERFACE + } } Legacy.DacDbiImpl impl = new(target, legacyObj); *obj = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None); - return 0; + return HResults.S_OK; } [UnmanagedCallersOnly(EntryPoint = "CLRDataCreateInstanceWithFallback")] From 8ec4befe5210c57a1ce39c5224f4a5d8b9b32767 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:12:29 -0400 Subject: [PATCH 15/18] Remove unused _prevent_release field from DacDbiImpl Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Dbi/DacDbiImpl.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 9824ddc4ead5ef..a480fe86b576b4 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 @@ -16,7 +16,6 @@ public sealed unsafe partial class DacDbiImpl : IDacDbiInterface { private readonly Target _target; private readonly IDacDbiInterface? _legacy; - private readonly object? _prevent_release; // IStringHolder is a native C++ abstract class (not COM) with a single virtual method: // virtual HRESULT AssignCopy(const WCHAR* psz) = 0; @@ -38,11 +37,10 @@ private int StringHolderAssignCopy(nint stringHolder, string str) } } - public DacDbiImpl(Target target, object? legacyObj, object? prevent_release = null) + public DacDbiImpl(Target target, object? legacyObj) { _target = target; _legacy = legacyObj as IDacDbiInterface; - _prevent_release = prevent_release; } public int CheckDbiVersion(DbiVersion* pVersion) From 4884646461ba78e1332b350256ef92a90c76089d Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:24:42 -0400 Subject: [PATCH 16/18] Revert datadescriptor.inc and restore CanFallback check ordering - Revert AuxiliarySymbolInfo.Address type change (unrelated to this PR) - Restore CanFallback() before _legacyModulePointer check so fallback attempts are always logged Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/vm/datadescriptor/datadescriptor.inc | 2 +- .../ClrDataModule.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 9d723e858f6dde..033f4103bffaf3 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1274,7 +1274,7 @@ CDAC_TYPE_END(SyncBlockCache) CDAC_TYPE_BEGIN(AuxiliarySymbolInfo) CDAC_TYPE_SIZE(sizeof(VMAUXILIARYSYMBOLDEF)) -CDAC_TYPE_FIELD(AuxiliarySymbolInfo, TYPE(CodePointer), Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) +CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Name, offsetof(VMAUXILIARYSYMBOLDEF, name)) CDAC_TYPE_END(AuxiliarySymbolInfo) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 5c6de7f7cefff2..38047994bffbef 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -54,7 +54,7 @@ public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? lega CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out nint ppv) { ppv = default; - if (_legacyModulePointer == 0 || !LegacyFallbackHelper.CanFallback()) + if (!LegacyFallbackHelper.CanFallback() || _legacyModulePointer == 0) return CustomQueryInterfaceResult.NotHandled; // Legacy DAC implementation of IXCLRDataModule handles QIs for IMetaDataImport by creating and From 38cf5073a97b33364022e46b9afe36d249a16088 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:39:35 -0400 Subject: [PATCH 17/18] Fix AuxiliarySymbolInfo.Address type to CodePointer The managed cDAC reads this field with ReadCodePointerField() which asserts the declared type is CodePointer. Using T_POINTER causes Debug.Assert crashes in checked builds and incorrect address comparisons on ARM32 (missing THUMB_CODE tag bit). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- 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 033f4103bffaf3..9d723e858f6dde 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1274,7 +1274,7 @@ CDAC_TYPE_END(SyncBlockCache) CDAC_TYPE_BEGIN(AuxiliarySymbolInfo) CDAC_TYPE_SIZE(sizeof(VMAUXILIARYSYMBOLDEF)) -CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) +CDAC_TYPE_FIELD(AuxiliarySymbolInfo, TYPE(CodePointer), Address, offsetof(VMAUXILIARYSYMBOLDEF, pfnAuxiliarySymbol)) CDAC_TYPE_FIELD(AuxiliarySymbolInfo, T_POINTER, Name, offsetof(VMAUXILIARYSYMBOLDEF, name)) CDAC_TYPE_END(AuxiliarySymbolInfo) From 17974c60957de884a69cf55ab4b63080a7d789e6 Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:34:46 -0400 Subject: [PATCH 18/18] Remove AggressiveInlining from CanFallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../LegacyFallbackHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs index c729a79d0c94e5..52116e5130f19c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/LegacyFallbackHelper.cs @@ -52,7 +52,6 @@ internal static class LegacyFallbackHelper /// In no-fallback mode, returns true only for allowlisted methods. /// All fallback attempts (allowed and blocked) are logged to stderr. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool CanFallback( [CallerMemberName] string name = "", [CallerFilePath] string file = "",