diff --git a/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/MiniDumpLocalVarLookup.csproj b/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/MiniDumpLocalVarLookup.csproj new file mode 100644 index 0000000000..644ea7fa32 --- /dev/null +++ b/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/MiniDumpLocalVarLookup.csproj @@ -0,0 +1,7 @@ + + + Exe + $(BuildProjectFramework) + $(SupportedSubProcessTargetFrameworks) + + diff --git a/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/Program.cs b/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/Program.cs new file mode 100644 index 0000000000..cbea65ad93 --- /dev/null +++ b/src/SOS/SOS.UnitTests/Debuggees/MiniDumpLocalVarLookup/Program.cs @@ -0,0 +1,26 @@ +// 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.Diagnostics; + +namespace MiniDumpLocalVarLookup; + +internal class Program +{ + static public void Main() + { + int intValue = 42; + string stringValue = "Hello, World!"; + + PrintValues(intValue, stringValue); + } + + static void PrintValues(int intValue, string stringValue) + { + int length = stringValue.Length; + Debugger.Break(); + Console.WriteLine($"intValue: {intValue}"); + Console.WriteLine($"stringValue: {stringValue} (length = {length})"); + } +} diff --git a/src/SOS/SOS.UnitTests/SOS.cs b/src/SOS/SOS.UnitTests/SOS.cs index 3a66a4046f..ebf4e0deda 100644 --- a/src/SOS/SOS.UnitTests/SOS.cs +++ b/src/SOS/SOS.UnitTests/SOS.cs @@ -139,7 +139,9 @@ internal static async Task RunTest( string testName = null, bool testLive = true, bool testDump = true, - bool testTriage = false) + bool testTriage = false, + bool testMini = false, + SOSRunner.DumpGenerator dumpGenerator = SOSRunner.DumpGenerator.CreateDump) { await RunTest(scriptName, new SOSRunner.TestInformation @@ -149,7 +151,8 @@ await RunTest(scriptName, TestLive = testLive, TestDump = testDump, DebuggeeName = debuggeeName, - DumpType = SOSRunner.DumpType.Heap + DumpType = SOSRunner.DumpType.Heap, + DumpGenerator = dumpGenerator, }, output); @@ -165,7 +168,23 @@ await RunTest(scriptName, TestLive = false, TestDump = testDump, DebuggeeName = debuggeeName, - DumpType = SOSRunner.DumpType.Triage + DumpType = SOSRunner.DumpType.Triage, + DumpGenerator = dumpGenerator, + }, + output); + } + if (testMini && !config.PublishSingleFile) + { + await RunTest(scriptName, + new SOSRunner.TestInformation + { + TestConfiguration = config, + TestName = testName, + TestLive = false, + TestDump = testDump, + DebuggeeName = debuggeeName, + DumpType = SOSRunner.DumpType.Mini, + DumpGenerator = dumpGenerator, }, output); } @@ -234,6 +253,31 @@ public SOS(ITestOutputHelper output) public static IEnumerable Configurations => SOSTestHelpers.GetConfigurations("TestName", value: null); + [SkippableTheory, MemberData(nameof(SOSTestHelpers.GetNetCoreConfigurations), MemberType = typeof(SOSTestHelpers))] + public async Task MiniDumpLocalVarLookup(TestConfiguration config) + { + if (OS.Kind != OSKind.Windows) + { + throw new SkipTestException("Test only supports CDB and therefore only runs on Windows"); + } + + if (config.PublishSingleFile) + { + throw new SkipTestException("Single file does not support mini dumps"); + } + + // The default dumpGenerator, CreateDump, only supports taking dumps at exceptions. + // DotnetDump could support taking a dump at a breakpoint, but this SOS test framework doesn't currently support this operation. + // Therefore we use the NativeDebugger to take a dump at the DebugBreak() call in the debuggee. + await SOSTestHelpers.RunTest( + config, + debuggeeName: "MiniDumpLocalVarLookup", + scriptName: "MiniDumpLocalVarLookup.script", + Output, + testName: "SOS.MiniDumpLocalVarLookup", + testMini: true, + dumpGenerator: SOSRunner.DumpGenerator.NativeDebugger); + } [SkippableTheory, MemberData(nameof(SOSTestHelpers.GetNetCoreConfigurations), MemberType = typeof(SOSTestHelpers))] public async Task VarargPInvokeInteropMD(TestConfiguration config) diff --git a/src/SOS/SOS.UnitTests/SOSRunner.cs b/src/SOS/SOS.UnitTests/SOSRunner.cs index 382a66bfe9..80fed0eb5e 100644 --- a/src/SOS/SOS.UnitTests/SOSRunner.cs +++ b/src/SOS/SOS.UnitTests/SOSRunner.cs @@ -34,6 +34,7 @@ public enum DumpGenerator public enum DumpType { Triage, + Mini, Heap, Full } @@ -235,6 +236,9 @@ public static async Task CreateDump(TestInformation information) await runner.ContinueExecution(); switch (information.DumpType) { + case DumpType.Mini: + command = ".dump /o /m %DUMP_NAME%"; + break; case DumpType.Heap: command = ".dump /o /mw %DUMP_NAME%"; break; @@ -349,6 +353,9 @@ public static async Task CreateDump(TestInformation information) } switch (dumpType) { + case DumpType.Mini: + processRunner.WithRuntimeConfiguration("DbgMiniDumpType", "1"); + break; case DumpType.Heap: processRunner.WithRuntimeConfiguration("DbgMiniDumpType", "2"); break; @@ -1498,6 +1505,9 @@ private HashSet GetEnabledDefines() { switch (_dumpType.Value) { + case DumpType.Mini: + defines.Add("MINI_DUMP"); + break; case DumpType.Triage: defines.Add("TRIAGE_DUMP"); break; diff --git a/src/SOS/SOS.UnitTests/Scripts/MiniDumpLocalVarLookup.script b/src/SOS/SOS.UnitTests/Scripts/MiniDumpLocalVarLookup.script new file mode 100644 index 0000000000..8ce9245019 --- /dev/null +++ b/src/SOS/SOS.UnitTests/Scripts/MiniDumpLocalVarLookup.script @@ -0,0 +1,15 @@ +# +# Verifies that local stack value variables are able to be parsed by the debugger in mini/triage dumps +# Utilizes the ICorDebug stackwalk with -i +# + +CONTINUE + +LOADSOS + +# stackwalk with locals +SOSCOMMAND:clrstack -l + +# stackwalk through ICorDebug with locals +SOSCOMMAND:clrstack -i -l +VERIFY:int\s+length\s+=\s+13