Support loading cDAC from SOS installations#5874
Open
hoyosjs wants to merge 6 commits into
Open
Conversation
max-charlamb
added a commit
to dotnet/runtime
that referenced
this pull request
Jun 17, 2026
…ntract (#129456) > [!NOTE] > This PR was authored with assistance from GitHub Copilot. ## Summary Fixes a cDAC `GetCodeHeaderData` failure that surfaced as `Unable to get codeHeader information` when SOS ran `!clru` against an IL stub MethodDesc on **Windows x86** with cDAC enabled (the new default behavior on .NET 11 introduced by [dotnet/diagnostics#5874](dotnet/diagnostics#5874)). The CI failure that motivated this is `SOSMethodTests.VarargPInvokeInteropMD` on x86 in dotnet/diagnostics: `!IP2MD` returned the IL stub MethodDesc correctly, but the immediate follow-up `!clru <MD>` printed only `Unable to get codeHeader information`. x64 / arm64 / .NET 8/9/10 were unaffected. ## Root cause x86 uses a fundamentally different GC info encoding from every other architecture: the legacy bit-packed `InfoHdr` byte-stream format from [`src/coreclr/vm/gc_unwind_x86.inl`](https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/gc_unwind_x86.inl) and [`src/coreclr/inc/gcdecoder.cpp`](https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/gcdecoder.cpp) (`USE_GC_INFO_DECODER` is defined for every target except x86, see `eetwain.h:34`). The cDAC `GCInfo` contract registered IGCInfo implementations for X64/Arm64/Arm/LoongArch64/RiscV64 but **not** X86 -- so on x86 it fell through to `default(GCInfo)` and threw `NotImplementedException` from the interface's default `DecodePlatformSpecificGCInfo`. Any SOS path that needed method size on x86 (`!clru`, `GetCodeHeaderData`, `GetMethodRegionInfo`) failed. ## Approach The cDAC already had a substantial x86 `InfoHdr` decoder under `Contracts/StackWalk/Context/X86/GCInfoDecoding/`, used by the x86 stack walker. Rather than write a parallel decoder, this PR **relocates** that existing decoder under the `GCInfo` contract so there is **one canonical x86 GC info implementation** shared between SOS callers and the stack walker -- mirroring how the other architectures' decoders are structured. ## Changes * **Move** `Contracts/StackWalk/Context/X86/GCInfoDecoding/*` → `Contracts/GCInfo/X86/*` (6 files, tracked as renames). Rename namespace `StackWalkHelpers.X86` → `GCInfoHelpers.X86`. * **Rename** the moved class `GCInfo` → `X86GCInfo` to avoid collision with the empty `Contracts.GCInfo` IGCInfo fallback struct. * Make `relativeOffset` ctor arg optional. Implement `IGCInfoDecoder` directly on `X86GCInfo`: `GetCodeLength` / `GetStackBaseRegister` / `GetSizeOfStackParameterArea` are wired up. `GetInterruptibleRanges` and `EnumerateLiveSlots` throw `NotSupportedException` (future work, needed for `!gcroot` / `!clrstack -l` etc.). * Add `GCInfoX86_1` IGCInfo for x86; register it in `CoreCLRContracts.cs` for `RuntimeInfoArchitecture.X86`. * Update `ExecutionManagerCore.GetStackParameterSize` to delegate to `IGCInfo.GetSizeOfStackParameterArea` (one source of truth). * `X86Unwinder` continues to construct `X86GCInfo` directly because it needs offset-bound state (`IsInProlog` / `IsInEpilog` / `PushedArgSize`) not exposed through `IGCInfoDecoder`. ## Tests * New `VarargPInvoke_GetCodeHeaderDataForILStub_ReturnsMethodSize` regression test in `cdac/tests/DumpTests/StackWalkDumpTests.cs` -- asserts the IL stub path returns S_OK with non-zero `MethodSize`. Runs against the existing cdac-dump-helix `windows_x86` matrix on every PR (no pipeline changes needed). * Existing 2509 cDAC unit tests still pass. * Validated end-to-end against `SOSMethodTests.VarargPInvokeInteropMD` x86 .NET 11prev6 cDAC: 4/4 pass after this fix; failed before. ## Docs * `docs/design/datacontracts/GCInfo.md` -- intro now reflects partial x86 support; `GetSizeOfStackParameterArea` API documented; per-method status notes for x86. * `docs/design/datacontracts/StackWalk.md` -- x86 section points at the consolidated decoder location and explains how it's shared. ## Out of scope (future work) * `GetInterruptibleRanges` and `EnumerateLiveSlots` for x86. The underlying transition data is decoded but the adapter to the cDAC `IGCInfoDecoder` shape is not wired up yet. This is what's needed to unblock `!gcroot`, `!clrstack -l`, `!pe` on x86 cDAC. The two pre-existing `[SkipOnArch("x86", "GCInfo decoder does not support x86")]` markers in `StackReferenceDumpTests.cs` should become removable once that lands. --------- Co-authored-by: Max Charlamb <maxcharlamb@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates SOS/tool packaging and runtime-loading behavior to bundle and preferentially load the cDAC (mscordaccore_universal) from diagnostics tool installations, with a default policy for .NET 11+ and a new tri-state user control surface.
Changes:
- Add cDAC discovery/loading paths across native SOS, SOS.Hosting, and ClrMD runtime creation (including contract descriptor plumbing via
ICLRContractLocator). - Introduce an asset/layout resolver (
IHostAssetResolver+SOSPackageLayout) so tools consistently locate native binaries (including bundled cDAC) regardless of host. - Update packaging/build logic to optionally bundle cDAC into tool packages and adjust tests/scripts for current SOS output differences.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tests/SOS.UnitTests/SOS.cs | Updates test skip conditions (notably Win-x86) for tracked regression coverage. |
| src/tests/SOS.UnitTests/Scripts/StackAndOtherTests.script | Makes stack verification tolerant to shifted source line numbers. |
| src/SOS/Strike/util.cpp | Requests cDAC-capable CLR data process in the main SOS load path; whitespace cleanup. |
| src/SOS/Strike/platform/runtimeimpl.h | Adds cDAC path/process members and policy/helpers to native Runtime. |
| src/SOS/Strike/platform/runtimeimpl.cpp | Implements cDAC path resolution (next to SOS), policy, IXCLRDataProcess creation, and contract descriptor lookup. |
| src/SOS/Strike/platform/datatarget.h | Extends DataTarget to implement ICLRContractLocator. |
| src/SOS/Strike/platform/datatarget.cpp | Implements ICLRContractLocator::GetContractDescriptor and QueryInterface wiring. |
| src/SOS/Strike/clrma/managedanalysis.cpp | Improves tracing when runtime-based DAC retrieval fails and falls back. |
| src/SOS/SOS.Package/SOS.Symbol.Package.csproj | Adds single-RID packing support via conditional symbol inclusion. |
| src/SOS/SOS.Package/SOS.Package.csproj | Ensures dotnet run for manifest generation uses the active configuration. |
| src/SOS/SOS.Package/GenerateManifest/Directory.Build.targets | Shields file-based app build by preventing repo targets import (intentionally empty). |
| src/SOS/SOS.Package/GenerateManifest/Directory.Build.props | Shields file-based app build by preventing repo props import (intentionally empty). |
| src/SOS/SOS.InstallHelper/SOS.InstallHelper.csproj | Links shared SOSPackageLayout implementation into InstallHelper. |
| src/SOS/SOS.InstallHelper/InstallHelper.cs | Switches native/managed source path resolution to SOSPackageLayout. |
| src/SOS/SOS.Hosting/SOSPackageLayout.cs | Defines package-relative layout rules for native vs managed SOS assets. |
| src/SOS/SOS.Hosting/SOSLibrary.cs | Uses IHostAssetResolver for native binary location; updates ISOSModule semantics/comments. |
| src/SOS/SOS.Hosting/SOS.Hosting.csproj | Removes InstallHelper project reference (no longer needed). |
| src/SOS/SOS.Hosting/RuntimeWrapper.cs | Prefers cDAC for IXCLRDataProcess path; refactors DAC/cDAC load handling. |
| src/SOS/SOS.Hosting/HostAssetResolver.cs | New global service that resolves native binaries directory and cDAC path. |
| src/SOS/SOS.Extensions/HostServices.cs | Removes unnecessary unsafe modifier; continues to expose ISOSModule data. |
| src/sos-packaging.props | Reworks packaging inputs/conditions, adds SingleTargetRidPackage/PackageWithCDac semantics. |
| src/Microsoft.Diagnostics.ExtensionCommands/Host/RuntimesCommand.cs | Replaces previous flags with tri-state `--usecdac true |
| src/Microsoft.Diagnostics.ExtensionCommands/Host/CommandFormatHelpers.cs | Updates settings output to reflect tri-state cDAC policy. |
| src/Microsoft.Diagnostics.DebugServices/ISettingsService.cs | Replaces prior cDAC flags with bool? UseCDac and documents policy semantics. |
| src/Microsoft.Diagnostics.DebugServices/IRuntime.cs | Clarifies DAC vs cDAC path responsibilities and nullability for cDAC. |
| src/Microsoft.Diagnostics.DebugServices/IHostAssetResolver.cs | New contract for resolving host-native asset locations (including cDAC). |
| src/Microsoft.Diagnostics.DebugServices.Implementation/ServiceManager.cs | Removes SOS.InstallHelper from default assemblies list for extension loading. |
| src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs | Adds signature-verification override for the trusted bundled cDAC path. |
| src/Microsoft.Diagnostics.DebugServices.Implementation/Runtime.cs | Implements cDAC policy, uses host resolver for cDAC path, and prefers cDAC for ClrMD runtime creation. |
| src/Microsoft.Diagnostics.DebugServices.Implementation/Host.cs | Updates settings storage to bool? UseCDac. |
| src/dbgshim/pkg/Microsoft.Diagnostics.DbgShim.props | Optionally packages cDAC next to dbgshim when enabled. |
| eng/Versions.props | Defaults PackageWithCDac=true on preview branches unless overridden. |
| eng/InstallNativePackages.targets | Downloads/stages cDAC transport pack content when PackageWithCDac=true. |
| eng/CdacPackageItems.props | Removes prior per-RID cDAC transport pack itemization (now in targets). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ExtDbgOut("GetCDacFilePath: dladdr failed to locate the sos module\n"); | ||
| return nullptr; | ||
| } | ||
| strcpy_s(szSOSModulePath.GetPtr(), MAX_LONGPATH, info.dli_fname); |
Comment on lines
+24
to
+28
| <ItemGroup Condition="'$(PackageWithCDac)' == 'true'"> | ||
| <PackageDownload Include="runtime.$(TargetRid).Microsoft.DotNet.Cdac.Transport" | ||
| Version="[$(runtimewinx64MicrosoftDotNetCdacTransportVersion)]" /> | ||
| <PackageSourceFiles Include="$(NuGetPackageRoot)runtime.$(TargetRid).microsoft.dotnet.cdac.transport\$(runtimewinx64MicrosoftDotNetCdacTransportVersion)\runtimes\$(TargetRid)\native\*" /> | ||
| </ItemGroup> |
Comment on lines
+241
to
+245
| // Prefer the cDAC for the data-access (IXCLRDataProcess) path when the runtime policy | ||
| // selects it (GetCDacFilePath returns non-null); fall back to the in-box DAC otherwise. | ||
| // The ICorDebug/DBI path (CreateCorDebugProcess) always uses the in-box DAC. The flags | ||
| // parameter is retained for the native IRuntime contract but no longer consulted here. | ||
| if (_cdacDataProcess == IntPtr.Zero) |
steveisok
approved these changes
Jun 17, 2026
max-charlamb
approved these changes
Jun 17, 2026
| public bool UseContractReader { get; set; } | ||
|
|
||
| public bool ForceUseContractReader { get; set; } | ||
| public bool? UseCDac { get; set; } |
Member
There was a problem hiding this comment.
nit: I'd prefer an enum here, something like:
enum CDacLoadPolicy
{
Default = 0,
UseCDac,
UseLegacyDac
}
Member
Author
There was a problem hiding this comment.
I don't mind in this layer. Do you think this should be surfaced to the command?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bundle the cDAC into diagnostics tool packages and implement interim loading policy for DAC/cDAC:
UseCDac(null= default policy described above, true=force, false=never) with--usecdac true|false|policy**DataTargetimplementsICLRContractLocatorand stores resolved contract descriptor address for cDAC initializationsos-packaging.propscleanup to allow any arch packaging;PackageWithCDac=trueby default on main branch so all platforms (win-x64/x86/arm64, linux-*, osx-*) bundle cDAC alongside sos.