Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions diagnostics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ extends:
architecture: arm64
artifactUploadPath: bin/Windows_NT.arm64.Release

- ${{ if ne(parameters.buildOnly, true) }}:
- template: /eng/pipelines/build.yml
parameters:
jobTemplate: ${{ variables.jobTemplate }}
name: Windows_cDAC
osGroup: Windows_NT
useCdac: true
buildConfigs:
- configuration: Release
architecture: x64

- template: /eng/pipelines/build.yml
parameters:
jobTemplate: ${{ variables.jobTemplate }}
Expand Down Expand Up @@ -234,6 +245,19 @@ extends:
- configuration: Debug
architecture: x64

- template: /eng/pipelines/build.yml
parameters:
jobTemplate: ${{ variables.jobTemplate }}
name: Ubuntu_22_04_cDAC
osGroup: Linux
container: test_ubuntu_22_04
dependsOn: Linux
testOnly: true
useCdac: true
buildConfigs:
- configuration: Release
architecture: x64

- template: /eng/pipelines/build.yml
parameters:
jobTemplate: ${{ variables.jobTemplate }}
Expand Down
11 changes: 11 additions & 0 deletions eng/pipelines/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ parameters:
type: boolean
default: false

# Optional: run tests with cDAC-only mode
- name: useCdac
type: boolean
default: false

# Optional: architecture cross build if true
- name: crossBuild
type: boolean
Expand Down Expand Up @@ -144,6 +149,12 @@ jobs:
- ${{ if eq(parameters.testOnly, 'true') }}:
- _TestArgs: '-test -skipnative'

- ${{ if and(eq(parameters.useCdac, 'true'), eq(parameters.testOnly, 'true')) }}:
- _TestArgs: '-test -skipnative -privatebuild -useCdac'

- ${{ if and(eq(parameters.useCdac, 'true'), ne(parameters.testOnly, 'true')) }}:
- _TestArgs: '-test -privatebuild -useCdac'

- ${{ if or(eq(parameters.buildOnly, 'true'), eq(parameters.isCodeQLRun, 'true')) }}:
- _TestArgs: ''

Expand Down
2 changes: 0 additions & 2 deletions eng/testsoscdac.cmd

This file was deleted.

18 changes: 0 additions & 18 deletions eng/testsoscdac.sh

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,21 @@ public ITarget OpenDump(string fileName)

try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && (targetPlatform != OSPlatform.OSX))
{
throw new NotSupportedException("Analyzing Windows or Linux dumps not supported when running on MacOS");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && (targetPlatform != OSPlatform.Linux))
// Cross-platform dump analysis is allowed when using cDAC-only mode (ForceUseContractReader)
// because the cDAC is a host-native NativeAOT binary that can analyze dumps from any platform.
ISettingsService settingsService = _host.Services.GetService<ISettingsService>();
bool allowCrossPlatform = settingsService?.ForceUseContractReader == true;

if (!allowCrossPlatform)
{
throw new NotSupportedException("Analyzing Windows or MacOS dumps not supported when running on Linux");
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && (targetPlatform != OSPlatform.OSX))
{
throw new NotSupportedException("Analyzing Windows or Linux dumps not supported when running on MacOS");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && (targetPlatform != OSPlatform.Linux))
{
throw new NotSupportedException("Analyzing Windows or MacOS dumps not supported when running on Linux");
}
}
return new TargetFromDataReader(dataTarget, targetPlatform, _host, fileName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ private string GetLibraryPath(DebugLibraryKind kind)

foreach (DebugLibraryInfo libraryInfo in _clrInfo.DebuggingLibraries)
{
if (libraryInfo.Kind == kind && RuntimeInformation.IsOSPlatform(libraryInfo.Platform) && libraryInfo.TargetArchitecture == currentArch)
// For cDAC, skip the platform filter — cDAC is a host-native NativeAOT binary
// that can analyze dumps from any target platform.
bool platformMatch = kind == DebugLibraryKind.CDac || RuntimeInformation.IsOSPlatform(libraryInfo.Platform);

if (libraryInfo.Kind == kind && platformMatch && libraryInfo.TargetArchitecture == currentArch)
{
libraryPath = GetLocalPath(libraryInfo);
if (libraryPath is not null)
Expand All @@ -206,7 +210,22 @@ private string GetLocalPath(DebugLibraryInfo libraryInfo)
string localFilePath;
if (libraryInfo.Kind == DebugLibraryKind.CDac)
{
// First try the absolute path from ClrMD (works for same-platform scenarios)
localFilePath = libraryInfo.FileName;
if (File.Exists(localFilePath))
{
return localFilePath;
}
// Fall back to RuntimeModuleDirectory if set (supports user-provided cDAC path via setclrpath)
if (!string.IsNullOrEmpty(RuntimeModuleDirectory))
{
localFilePath = Path.Combine(RuntimeModuleDirectory, Path.GetFileName(libraryInfo.FileName));
if (File.Exists(localFilePath))
{
return localFilePath;
}
}
return null;
}
else
{
Expand Down
17 changes: 14 additions & 3 deletions src/SOS/SOS.Hosting/RuntimeWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,13 @@ private int GetClrDataProcess(
return HResult.E_INVALIDARG;
}
*ppClrDataProcess = IntPtr.Zero;
if ((flags & ClrDataProcessFlags.UseCDac) != 0)

ISettingsService settingsService = _services.GetService<ISettingsService>();
bool forceUseCDac = settingsService?.ForceUseContractReader == true;

// Try cDAC if explicitly requested via flags, or if ForceUseContractReader is set
// (which overrides the caller's flags — callers like LoadClrDebugDll may not pass UseCDac).
if ((flags & ClrDataProcessFlags.UseCDac) != 0 || forceUseCDac)
{
if (_cdacDataProcess == IntPtr.Zero)
{
Expand All @@ -253,8 +259,9 @@ private int GetClrDataProcess(
}
*ppClrDataProcess = _cdacDataProcess;
}
// Fallback to regular DAC instance if CDac isn't enabled or there where errors creating the instance
if (*ppClrDataProcess == IntPtr.Zero)
// Skip legacy DAC fallback when cDAC-only mode is forced — there may not be a
// platform-matching legacy DAC available (e.g., analyzing a Linux dump on Windows).
if (*ppClrDataProcess == IntPtr.Zero && !forceUseCDac)
{
if (_clrDataProcess == IntPtr.Zero)
{
Expand All @@ -271,6 +278,10 @@ private int GetClrDataProcess(
}
if (*ppClrDataProcess == IntPtr.Zero)
{
if (forceUseCDac)
{
Trace.TraceError("cDAC-only mode (ForceUseContractReader): cDAC failed to load and legacy DAC fallback is disabled.");
}
return HResult.E_NOINTERFACE;
}
return HResult.S_OK;
Expand Down
4 changes: 4 additions & 0 deletions src/tests/SOS.UnitTests/SOSRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,10 @@ public static async Task<SOSRunner> StartDebugger(TestInformation information, D
&& !config.IsPrivateBuildTesting()
&& !config.IsNightlyBuild();
initialCommands.Add($"runtimes --DacSignatureVerification:{(shouldVerifyDacSignature ? "true" : "false")}");
if (config.TestCDAC)
{
initialCommands.Add("runtimes --forceusecdac");
}
arguments.Append(debuggerPath);
arguments.Append(@" analyze %DUMP_NAME%");
debuggerPath = config.DotNetDumpHost();
Expand Down
Loading