SOS: load DBI through dbgshim - #5980
Conversation
5d53e54 to
3e724e8
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates SOS’s DBI activation path so CoreCLR ICorDebugProcess creation is routed through dbgshim (preferring the bundled universal DBI + cDAC first), while keeping the existing direct mscordbi activation path for Desktop CLR. It also updates managed hosting to use the same dbgshim-based activation and packages the universal DBI alongside existing SOS assets.
Changes:
- Native SOS: add dbgshim-based
ICorDebugProcessactivation (CoreCLR) and factor Desktop CLR activation into a dedicated helper. - SOS.Hosting: introduce a managed
ICLRDebuggingLibraryProvider2implementation and route CorDebug activation through a newIClrDataProcessActivator.CreateCorDebugProcessAPI. - Packaging: include
mscordbi_universalin the shared SOS packaging (gated byPackageWithCDac).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/SOS/Strike/platform/runtimeimpl.h | Adds CreateDesktopCorDebugProcess declaration to separate Desktop CLR activation path. |
| src/SOS/Strike/platform/runtimeimpl.cpp | Implements Desktop CLR DBI activation helper and routes CoreCLR DBI activation through dbgshim + library provider. |
| src/SOS/SOS.Hosting/RuntimeWrapper.cs | Updates managed DBI activation to use IClrDataProcessActivator for CoreCLR and improves HRESULT propagation. |
| src/SOS/SOS.Hosting/RuntimeLibraryProvider.cs | Adds managed ICLRDebuggingLibraryProvider2 implementation to resolve DBI/DAC paths for dbgshim. |
| src/SOS/SOS.Hosting/ClrDataProcessActivator.cs | Refactors dbgshim initialization and adds CreateCorDebugProcess to activate ICorDebugProcess via dbgshim. |
| src/sos-packaging.props | Packages mscordbi_universal for supported RIDs when PackageWithCDac is enabled. |
| src/Microsoft.Diagnostics.DebugServices/IClrDataProcessActivator.cs | Extends the activator interface with a new CorDebug activation API. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| ArrayHolder<WCHAR> dacModulePath = new WCHAR[MAX_LONGPATH + 1]; | ||
| if (MultiByteToWideChar(CP_ACP, 0, dacFilePath, -1, dacModulePath, MAX_LONGPATH) <= 0) | ||
| { | ||
| return HRESULT_FROM_WIN32(GetLastError()); | ||
| } |
| modulePath = IntPtr.Zero; | ||
|
|
||
| string path = fileName?.IndexOf("mscordbi", StringComparison.OrdinalIgnoreCase) >= 0 | ||
| ? _getDbiPath() | ||
| : _getDacPath(); | ||
| if (string.IsNullOrEmpty(path)) | ||
| { | ||
| Trace.TraceError($"RuntimeLibraryProvider: could not resolve {fileName}"); | ||
| return HResult.E_NOINTERFACE; | ||
| } | ||
|
|
||
| modulePath = Marshal.StringToCoTaskMemUni(path); | ||
| Trace.TraceInformation($"RuntimeLibraryProvider: resolved {fileName} to {path}"); | ||
| return HResult.S_OK; |
noahfalk
left a comment
There was a problem hiding this comment.
LGTM modulo the policy handling
| // This also verifies the DAC signature before the DBI is passed the DAC path or handle. | ||
| CDacLoadPolicy policy = _runtime.RuntimeType == RuntimeType.Desktop | ||
| ? CDacLoadPolicy.UseLegacyDac | ||
| : _services.GetService<ISettingsService>()?.CDacLoadPolicy ?? CDacLoadPolicy.PreferCDac; |
There was a problem hiding this comment.
I don't think SOS should ever be changing the policy, we should insert some logic in the implementation of CreateCorDebugProcess so that it generates the expected result for each policy option on desktop.
cDacOnly -> loading fails
other policies -> load DAC as usual
|
|
||
| DbgShimCDacLoadPolicy loadPolicy = GetRuntimeConfiguration() == IRuntime::WindowsDesktop | ||
| ? DbgShimCDacLoadPolicy::LegacyDacOnly | ||
| : (DbgShimCDacLoadPolicy)GetCDacLoadPolicy(); |
There was a problem hiding this comment.
Same as above. We should handle the policy we are given rather than changing it which implies cDacOnly on desktop is expected to fail.
There was a problem hiding this comment.
yeah - I had the same change locally. Trying to clean up this change.
Teach dbgshim to recognize Desktop CLR through the standard ICLRDebugging path and apply the configured cDAC policy consistently to data access and DBI activation. Verify provider-resolved DAC and DBI binaries with WinTrust, Microsoft root policy, and the .NET DAC OID before loading them. Keep bundled universal DBI on the tool-asset trust path, preserve DAC-before-DBI ordering, and contain provider callback failures.
| public static bool ShouldTryCDac(CDacLoadPolicy policy) | ||
| /// <param name="policy">The configured activation policy.</param> | ||
| /// <returns>The policy to use for activation.</returns> | ||
| public static CDacLoadPolicy GetEffectiveLoadPolicy(CDacLoadPolicy policy) |
There was a problem hiding this comment.
Can we avoid this and instead have tests that set DOTNET_ENABLE_CDAC also change the SOS policy explicitly via command if they need to? If it isn't straightforward for the tests to set the policy via commands we could also have some SOS_CDAC_LOAD_POLICY env var that overrides the default policy that we initialize at startup.
High level my aim is:
- Keep the SOS policy as simple as possible. Having both a "configured" policy and an "effective" policy makes it harder to reason about what SOS is going to do.
- Keep test env vars narrowly focused. Ideally any given test env var only modifies the behavior of one component.
| # resolves the cDAC from its own native binaries directory, so this is the only spot it is picked up | ||
| # from. Used by the cdac DacMode to exercise the runtime-under-test's own cDAC instead of the copy | ||
| # restored from a referenced runtime package. | ||
| # Overlay an externally-provided cDAC transport next to the freshly built sos.dll. SOS resolves the |
There was a problem hiding this comment.
cDAC transport = cDAC transport package?
Assuming cdacPath refers to the binary and not the package then I'd just say 'cDAC'
| usage_list+=("-classfilter: pass class filter to xunit runner (Namespace.ClassName)") | ||
| usage_list+=("-dacmode: which DAC/cDAC the SOS tests load: cdac, cdacverify, or dac.") | ||
| usage_list+=("-cdacpath: path to an mscordaccore_universal to overlay next to sos.dll (only with -dacmode cdac).") | ||
| usage_list+=("-cdacpath: path to an mscordaccore_universal whose sibling universal DBI is overlaid next to SOS (only with -dacmode cdac).") |
There was a problem hiding this comment.
The new comment suggests only DBI is overlayed but I think want to say that both cDAC and universal DBI are overlayed.
| # Overlay an externally-provided cDAC (libmscordaccore_universal) next to the freshly built sos so | ||
| # SOS resolves it from its own native binaries directory. Used by the cdac DacMode to exercise the | ||
| # runtime-under-test's own cDAC instead of the copy restored from a referenced runtime package. | ||
| # Overlay an externally-provided cDAC transport next to the freshly built sos. SOS resolves the cDAC |
There was a problem hiding this comment.
| # Overlay an externally-provided cDAC transport next to the freshly built sos. SOS resolves the cDAC | |
| # Overlay an externally-provided cDAC next to the freshly built sos. SOS resolves the cDAC |
binary or package?
| // The signature needs to match m_skuId exactly, except for m_skuId=CLR_ID_ONECORE_CLR which is | ||
| // also compatible with the older CLR_ID_PHONE_CLR signature. | ||
| if (SUCCEEDED(hr) && (debugResource.signature != m_skuId) && !( (debugResource.signature == CLR_ID_PHONE_CLR) && (m_skuId == CLR_ID_ONECORE_CLR) )) | ||
| // The OneCore CLR debugging object supports CoreCLR and Desktop CLR targets. Other debugging |
There was a problem hiding this comment.
When we chatted earlier I'm worried I didn't think it through very well.
I'm worried this might be a breaking change. Debuggers could previously rely on CLRDebugging from dbgshim to only bind to CoreCLR binaries and now its going to bind to desktop binaries too. Although both runtimes provide ICorDebug as output the behavior of the APIs isn't perfectly identical. I'm pretty sure VS has various places in their code which special case how they interact with the API depending on CoreCLR vs. Desktop.
Seperate from the back-compat issue it also means now we'd have a testing/compat burden for dbgshim to work with desktop that would be difficult to unwind. Ideally we want new stuff to be migrating away from desktop coupling rather than towards it. For example at some point in the future we'll probably want to have a version of SOS that stops supporting desktop runtime.
| VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.F2(\(.*\))?\+0x<HEXVAL>\s+ | ||
| VERIFY:\[.*[\\|/]Debuggees[\\|/].*DivZero[\\|/]DivZero\.cs @ 36\s*\]\s* | ||
| VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.Main(\(.*\))?\+0x<HEXVAL>\s+ | ||
| IFDEF:DESKTOP |
There was a problem hiding this comment.
Were desktop tests not previously running on these scripts or does this represent a change in SOS behavior when running against desktop?
Depends on #5966.
Route CoreCLR
ICorDebugProcessactivation through dbgshim so the bundled universal DBI and cDAC are tried first, with SOS's existing DAC/DBI resolver retained as the provider fallback. Keep desktop CLR on its existing directmscordbipath because the public dbgshim factory is CoreCLR-SKU-specific.Ship
mscordbi_universalfrom the cDAC transport package beside dbgshim andmscordaccore_universalin the shared SOS packaging used by dotnet-sos, dotnet-dump, and the WinDbg SOS package.Validation:
clrstack -iwith forced cDAC used the bundled DBIclrstack -iused the matching runtime DAC/DBI