Skip to content

Commit 2d6b8e4

Browse files
max-charlambMax Charlambsteveisok
authored
[cDAC] Add support to run SOS tests against the cDAC (#5350)
dotnet/runtime#110758 Given the cDAC only supports a small subset of the DAC apis, I have created some pared down tests that are `CDACCompatible`. Steps to run tests with cDAC: 1. Build diagnostics repo. 2. Build runtime repo. 3. Run `eng\privatebuild.cmd` in the diagnostics repo 4. Copy over relevant files from runtime repo to `.\dotnet-test`. See https://github.com/dotnet/diagnostics/blob/main/documentation/privatebuildtesting.md for example. Note, with the addition of the cDAC, `cdacreader.dll` and all of the dll's under `cdaclibs` must be copied over as well. 5. Run `eng\testsoscdac.cmd` in the diagnostics repo. The cDAC can be debugged in these tests by running the tests script with `$env:VSTEST_HOST_DEBUG=1` which waits for a debugger to attach to the test host. Use VS with the [Child Process Debugging Power Tool](https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool2022) to selectively debug `cdb.exe` child process. Note this requires using mixed mode debugging. --------- Co-authored-by: Max Charlamb <[email protected]> Co-authored-by: Steve Pfister <[email protected]>
1 parent 822db0e commit 2d6b8e4

File tree

10 files changed

+203
-5
lines changed

10 files changed

+203
-5
lines changed

eng/InstallRuntimes.proj

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<PropertyGroup>
2121
<BuildArch Condition="'$(BuildArch)' == ''">$(Platform)</BuildArch>
2222
<BuildArch Condition="'$(BuildArch)' == 'AnyCpu'">$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant)</BuildArch>
23+
<LiveRuntimeDir Condition="'$(LiveRuntimeDir)' != ''">$([MSBuild]::NormalizePath('$(LiveRuntimeDir)'))</LiveRuntimeDir>
2324
</PropertyGroup>
2425

2526
<PropertyGroup Condition="'$(BuildArch)' != 'x86'">
@@ -57,7 +58,7 @@
5758
-->
5859

5960
<Target Name="InstallTestRuntimes"
60-
DependsOnTargets="CleanupVersionManifest;InstallRuntimesWindows;InstallRuntimesUnix;WriteTestVersionManifest;" />
61+
DependsOnTargets="CleanupVersionManifest;InstallRuntimesWindows;InstallRuntimesUnix;OverrideLatestRuntime;WriteTestVersionManifest" />
6162

6263
<!--
6364
Installs the test runtimes on Windows
@@ -95,7 +96,21 @@
9596
<Exec Command="bash $(DotnetInstallScriptCmd) $(CommonInstallArgs) %(RuntimeTestVersions.ExtraInstallArgs) -Version %(RuntimeTestVersions.AspNetDownload) -Runtime aspnetcore"
9697
IgnoreStandardErrorWarningFormat="true"
9798
Condition="'%(RuntimeTestVersions.AspNetDownload)' != ''" />
98-
</Target>
99+
</Target>
100+
101+
<!-- Overrides the latest runtime shared framework with local shared framework artifacts -->
102+
<Target Name="OverrideLatestRuntime"
103+
Condition="'$(LiveRuntimeDir)' != ''"
104+
Inputs="$(VersionsPropsPath)"
105+
Outputs="$(TestConfigFileName)">
106+
107+
<ItemGroup>
108+
<_LiveRuntimeFiles Include="$(LiveRuntimeDir)\**\*.*" />
109+
</ItemGroup>
110+
<Copy SourceFiles="@(_LiveRuntimeFiles)"
111+
DestinationFolder="$(DotNetInstallDir)"
112+
OverwriteReadOnlyFiles="true" />
113+
</Target>
99114

100115
<!--
101116
Writes the Debugger.Tests.Versions.txt file used by the SOS test harness

eng/build.ps1

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ Param(
1010
[switch] $skipmanaged,
1111
[switch] $skipnative,
1212
[switch] $bundletools,
13+
[switch] $useCdac,
1314
[ValidatePattern("(default|\d+\.\d+.\d+(-[a-z0-9\.]+)?)")][string] $dotnetruntimeversion = 'default',
1415
[ValidatePattern("(default|\d+\.\d+.\d+(-[a-z0-9\.]+)?)")][string] $dotnetruntimedownloadversion= 'default',
1516
[string] $runtimesourcefeed = '',
1617
[string] $runtimesourcefeedkey = '',
18+
[string] $liveRuntimeDir = '',
1719
[Parameter(ValueFromRemainingArguments=$true)][String[]] $remainingargs
1820
)
1921

@@ -80,12 +82,17 @@ if ($installruntimes -or $privatebuild) {
8082
/bl:$logdir\InstallRuntimes.binlog `
8183
/p:PrivateBuildTesting=$privatebuildtesting `
8284
/p:BuildArch=$architecture `
83-
/p:TestArchitectures=$architecture
85+
/p:TestArchitectures=$architecture `
86+
/p:LiveRuntimeDir="$liveRuntimeDir"
8487
}
8588

8689
# Run the xunit tests
8790
if ($test) {
8891
if (-not $crossbuild) {
92+
if ($useCdac) {
93+
$env:SOS_TEST_CDAC="true"
94+
}
95+
8996
& "$engroot\common\build.ps1" `
9097
-test `
9198
-configuration $configuration `
@@ -97,7 +104,8 @@ if ($test) {
97104
/p:DotnetRuntimeVersion="$dotnetruntimeversion" `
98105
/p:DotnetRuntimeDownloadVersion="$dotnetruntimedownloadversion" `
99106
/p:RuntimeSourceFeed="$runtimesourcefeed" `
100-
/p:RuntimeSourceFeedKey="$runtimesourcefeedkey"
107+
/p:RuntimeSourceFeedKey="$runtimesourcefeedkey" `
108+
/p:LiveRuntimeDir="$liveRuntimeDir"
101109

102110
if ($lastExitCode -ne 0) {
103111
exit $lastExitCode

eng/testsoscdac.cmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
set SOS_TEST_CDAC=true
2+
%~dp0..\.dotnet\dotnet.exe test --no-build --logger "console;verbosity=detailed" %~dp0..\src\SOS\SOS.UnitTests\SOS.UnitTests.csproj --filter "Category=CDACCompatible"

eng/testsoscdac.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
source="${BASH_SOURCE[0]}"
4+
5+
# resolve $SOURCE until the file is no longer a symlink
6+
while [[ -h $source ]]; do
7+
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
8+
source="$(readlink "$source")"
9+
10+
# if $source was a relative symlink, we need to resolve it relative to the path where the
11+
# symlink file was located
12+
[[ $source != /* ]] && source="$scriptroot/$source"
13+
done
14+
15+
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
16+
export LLDB_PATH=/usr/bin/lldb
17+
export SOS_TEST_CDAC=true
18+
$scriptroot/../.dotnet/dotnet test --no-build --logger "console;verbosity=detailed" $scriptroot/../src/SOS/SOS.UnitTests/SOS.UnitTests.csproj --filter "Category=CDACCompatible"

src/Microsoft.Diagnostics.TestHelpers/TestConfiguration.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ private void ParseConfigFile(string path)
7979
["IsAlpine"] = OS.IsAlpine.ToString().ToLowerInvariant(),
8080
["TargetRid"] = GetRid(),
8181
["TargetArchitecture"] = OS.TargetArchitecture.ToString().ToLowerInvariant(),
82-
["NuGetPackageCacheDir"] = nugetPackages
82+
["NuGetPackageCacheDir"] = nugetPackages,
83+
["TestCDAC"] = Environment.GetEnvironmentVariable("SOS_TEST_CDAC")
8384
};
8485
if (OS.Kind == OSKind.Windows)
8586
{
@@ -461,6 +462,10 @@ private string GetStringViewWithVersion(string version)
461462
{
462463
sb.Append(".singlefile");
463464
}
465+
if (TestCDAC)
466+
{
467+
sb.Append(".cdac");
468+
}
464469
if (!string.IsNullOrEmpty(version))
465470
{
466471
sb.Append('.');
@@ -555,6 +560,14 @@ public bool IsDesktop
555560
get { return TestProduct.Equals("desktop"); }
556561
}
557562

563+
/// <summary>
564+
/// Returns true if test should use the cDAC.
565+
/// </summary>
566+
public bool TestCDAC
567+
{
568+
get { return string.Equals(GetValue("TestCDAC"), "true", StringComparison.InvariantCultureIgnoreCase); }
569+
}
570+
558571
/// <summary>
559572
/// The test runner script directory
560573
/// </summary>

src/SOS/SOS.UnitTests/SOS.UnitTests.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,13 @@
6262
</ItemGroup>
6363
</Target>
6464

65+
<Target Name="_ApplyTestCategoryFilter"
66+
Condition="'$(SOS_TEST_CDAC)' == 'true'"
67+
BeforeTargets="RunTests">
68+
<ItemGroup>
69+
<TestToRun Include="@(TestToRun)">
70+
<TestRunnerAdditionalArguments>-trait Category=CDACCompatible</TestRunnerAdditionalArguments>
71+
</TestToRun>
72+
</ItemGroup>
73+
</Target>
6574
</Project>

src/SOS/SOS.UnitTests/SOS.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ internal static void SkipIfArm(TestConfiguration config)
3232
}
3333
}
3434

35+
internal static void SkipIfWinX86(TestConfiguration config)
36+
{
37+
if (config.TargetArchitecture == "x86" && OS.Kind == OSKind.Windows)
38+
{
39+
throw new SkipTestException("Test does not support x86 on Windows");
40+
}
41+
}
42+
3543
internal static async Task RunTest(
3644
string scriptName,
3745
SOSRunner.TestInformation information,
@@ -192,6 +200,39 @@ public SOS(ITestOutputHelper output)
192200

193201
public static IEnumerable<object[]> Configurations => SOSTestHelpers.GetConfigurations("TestName", value: null);
194202

203+
[SkippableTheory, MemberData(nameof(Configurations)), Trait("Category", "CDACCompatible")]
204+
public async Task StackTraceSoftwareExceptionFrame(TestConfiguration config)
205+
{
206+
if (config.RuntimeFrameworkVersionMajor < 10)
207+
{
208+
throw new SkipTestException("This test validates SoftwareExceptionFrame handling, before .NET10, these aren't used in this debuggee scenario.");
209+
}
210+
211+
SOSTestHelpers.SkipIfWinX86(config);
212+
213+
await SOSTestHelpers.RunTest(
214+
config,
215+
debuggeeName: "SimpleThrow",
216+
scriptName: "StackTraceSoftwareExceptionFrame.script",
217+
Output,
218+
testName: "SOS.StackTraceSoftwareExceptionFrame",
219+
testTriage: true);
220+
}
221+
222+
[SkippableTheory, MemberData(nameof(Configurations)), Trait("Category", "CDACCompatible")]
223+
public async Task StackTraceFaultingExceptionFrame(TestConfiguration config)
224+
{
225+
SOSTestHelpers.SkipIfWinX86(config);
226+
227+
await SOSTestHelpers.RunTest(
228+
config,
229+
debuggeeName: "DivZero",
230+
scriptName: "StackTraceFaultingExceptionFrame.script",
231+
Output,
232+
testName: "SOS.StackTraceFaultingExceptionFrame",
233+
testTriage: true);
234+
}
235+
195236
[SkippableTheory, MemberData(nameof(Configurations))]
196237
public async Task DivZero(TestConfiguration config)
197238
{

src/SOS/SOS.UnitTests/SOSRunner.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,11 @@ public static async Task<SOSRunner> StartDebugger(TestInformation information, D
691691
WithLog(scriptLogger).
692692
WithTimeout(TimeSpan.FromMinutes(10));
693693

694+
if (config.TestCDAC)
695+
{
696+
processRunner.WithEnvironmentVariable("DOTNET_ENABLE_CDAC", "1");
697+
}
698+
694699
// Exit codes on Windows should always be 0, but not on Linux/OSX for the faulting debuggees.
695700
if (OS.Kind == OSKind.Windows)
696701
{
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Divide By Zero debugging scenario
2+
# 1) Load the executable
3+
# 2) Run the executable and wait for it to crash
4+
# 3) Take a dump of the executable.
5+
# 4) Open the dump and compare the output
6+
7+
CONTINUE
8+
9+
LOADSOS
10+
11+
# Verifying that PrintException gives us the right exception in the format above.
12+
SOSCOMMAND:PrintException
13+
VERIFY:Exception object:\s+<HEXVAL>\s+
14+
VERIFY:Exception type:\s+System\.DivideByZeroException\s+
15+
VERIFY:Message:\s+(<Invalid Object>|Attempted to divide by zero\.)\s+
16+
VERIFY:InnerException:\s+<none>\s+
17+
VERIFY:StackTrace \(generated\):\s+
18+
VERIFY:\s+SP\s+IP\s+\s+Function\s+
19+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.DivideByZero(\(.*\))?\+0x<HEXVAL>\s+
20+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.F3(\(.*\))?\+0x<HEXVAL>\s+
21+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.F2(\(.*\))?\+0x<HEXVAL>\s+
22+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[Dd]iv[Zz]ero.*!C\.Main(\(.*\))?\+0x<HEXVAL>\s+
23+
VERIFY:(StackTraceString: <none>\s+)?\s+
24+
VERIFY:HResult:\s+80020012\s+
25+
26+
# Verify that Threads (clrthreads) works
27+
SOSCOMMAND:clrthreads
28+
VERIFY:\s*ThreadCount:\s+<DECVAL>\s+
29+
VERIFY:\s+UnstartedThread:\s+<DECVAL>\s+
30+
VERIFY:\s+BackgroundThread:\s+<DECVAL>\s+
31+
VERIFY:\s+PendingThread:\s+<DECVAL>\s+
32+
VERIFY:\s+DeadThread:\s+<DECVAL>\s+
33+
VERIFY:\s+Hosted Runtime:\s+no\s+
34+
VERIFY:\s+ID\s+OSID\s+ThreadOBJ\s+State.*\s+
35+
VERIFY:\s+<DECVAL>\s+<DECVAL>\s+<HEXVAL>\s+<HEXVAL>.*\s+
36+
37+
# Verify that ClrStack with no options works
38+
SOSCOMMAND:ClrStack
39+
VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
40+
VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
41+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[FaultingExceptionFrame: <HEXVAL>]\s+
42+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+(\*\*\* WARNING: Unable to verify checksum for DivZero.exe\s*)?
43+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+C\.F3(\(.*\))?\s+
44+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+C\.F2(\(.*\))?\s+
45+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+C\.Main(\(.*\))?\s+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Simple Throw debugging scenario
2+
# 1) Load the executable
3+
# 2) Run the executable and wait for it to crash
4+
# 3) Take a dump of the executable.
5+
# 4) Open the dump and compare the output
6+
7+
CONTINUE
8+
9+
LOADSOS
10+
11+
# Verifying that PrintException gives us the right exception in the format above.
12+
SOSCOMMAND:PrintException
13+
VERIFY:Exception object:\s+<HEXVAL>\s+
14+
VERIFY:Exception type:\s+System\.InvalidOperationException\s+
15+
VERIFY:Message:\s+(<Invalid Object>|Throwing an invalid operation\.\.\.\.)\s+
16+
VERIFY:InnerException:\s+<none>\s+
17+
VERIFY:StackTrace \(generated\):\s+
18+
VERIFY:\s+SP\s+IP\s+\s+Function\s+
19+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+.*!UserObject\.UseObject(\(.*\))?\+0x<HEXVAL>\s+
20+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+.*!Simple\.Main(\(.*\))?\+0x<HEXVAL>\s+
21+
VERIFY:(StackTraceString: <none>\s+)?\s+
22+
VERIFY:HResult:\s+80131509\s+
23+
24+
# Verify that Threads (clrthreads) works
25+
SOSCOMMAND:clrthreads
26+
VERIFY:\s*ThreadCount:\s+<DECVAL>\s+
27+
VERIFY:\s+UnstartedThread:\s+<DECVAL>\s+
28+
VERIFY:\s+BackgroundThread:\s+<DECVAL>\s+
29+
VERIFY:\s+PendingThread:\s+<DECVAL>\s+
30+
VERIFY:\s+DeadThread:\s+<DECVAL>\s+
31+
VERIFY:\s+Hosted Runtime:\s+no\s+
32+
VERIFY:\s+ID\s+OSID\s+ThreadOBJ\s+State.*\s+
33+
VERIFY:\s+<DECVAL>\s+<DECVAL>\s+<HEXVAL>\s+<HEXVAL>.*\s+
34+
35+
# Verify that ClrStack with no options works
36+
SOSCOMMAND:ClrStack
37+
VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
38+
VERIFY:\s+Child\s+SP\s+IP\s+Call Site\s+
39+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[InlinedCallFrame: <HEXVAL>]\s+
40+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+[SoftwareExceptionFrame: <HEXVAL>]\s+
41+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+UserObject\.UseObject(\(.*\))?\s+
42+
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+Simple\.Main(\(.*\))?\s+

0 commit comments

Comments
 (0)