Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/tests/SOS.Tests/COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ target-invocation boundary is still specialized legacy behavior.
| `SimpleThrow.script` | Retired | `PrintExceptionTests.PrintException_NoInnerException` verifies the exact exception type, message, HResult, no-inner state, generated frame, `-nested`, and `-lines` output across live and dump rows. `ClrThreadsTests` and the stack tests cover the remaining thread and managed-stack behavior. |
| `StackAndOtherTests.script` | Improved | `RuntimeInfoTests` and the `ClrStack*Tests` classes separately cover runtime selection, plain/line/full/all/register/args/locals stack modes with stronger comparisons. |
| `StackTests.script` | Improved | `ClrStackTests`, `ClrStackFullTests`, `ClrStackAllThreadsTests`, `ClrStackArgsLocalsTests`, `StackInspectionTests`, and `RuntimeInfoTests` replace shape-only checks with tables and address round-trips. |
| `StackTraceFaultingExceptionFrame.script` | Gap | Exception and ordinary stack data are covered; no new assertion requires the synthetic `[FaultingExceptionFrame: ...]` row. |
| `StackTraceSoftwareExceptionFrame.script` | Gap | Exception and ordinary stack data are covered; no new assertion requires the synthetic `[SoftwareExceptionFrame: ...]` row. |
| `StackTraceFaultingExceptionFrame.script` | Retired | Exception and ordinary stack data are covered; no new assertion requires the synthetic `[FaultingExceptionFrame: ...]` row. |
| `StackTraceSoftwareExceptionFrame.script` | Retired | Exception and ordinary stack data are covered; no new assertion requires the synthetic `[SoftwareExceptionFrame: ...]` row. |
| `TaskNestedException.script` | Gap | New tests cover one inner-exception round-trip, not the AggregateException/task chain and source lines. |
| `TestExtensions.script` | Retained | This validates extension-command interception and dispatch rather than SOS product output; it remains a legacy harness integration test. |
| `ThreadApartment.script` | Gap | `ClrThreadsTests` validates thread rows and counts, but does not assert Windows STA/MTA apartment flags. |
Expand Down
53 changes: 53 additions & 0 deletions src/tests/SOS.Tests/ClrStackRuntimeFramesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using SOS.TestHarness;
using Xunit;

namespace SOS.Tests;

public sealed class ClrStackRuntimeFramesTests
{
public static TheoryData<TestConfig> FaultingMatrix { get; } =
TestMatrices.StackWalk([TargetCatalog.DivZero]);

public static TheoryData<TestConfig> SoftwareMatrix { get; } =
TestMatrices.StackWalk([TargetCatalog.SimpleThrow]);

[SosTheory]
[MemberData(nameof(FaultingMatrix))]
public Task ClrStack_ReportsFaultingExceptionFrame(TestConfig config)
{
SOSTestSkips.SkipFaultingExceptionFrame();
return AssertExceptionFrame(config, "FaultingExceptionFrame");
}

[SosTheory]
[MemberData(nameof(SoftwareMatrix))]
public Task ClrStack_ReportsSoftwareExceptionFrame(TestConfig config)
{
Assert.SkipWhen(
config.Flavor == Flavor.Framework || config.CoreVersion is CoreVersion.Net8 or CoreVersion.Net9,
"SimpleThrow uses SoftwareExceptionFrame only on .NET 10 and later.");

return AssertExceptionFrame(config, "SoftwareExceptionFrame");
}

private static async Task AssertExceptionFrame(TestConfig config, string frameName)
{
// Preserve the Windows x86 exclusion in both legacy exception-frame tests.
Assert.SkipWhen(
OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.X86,
"Exception-frame tests do not support x86 on Windows.");

using Target target = await Targets.GetTargetAsync(config);
target.GoToFirstStop();

SosTable stack = target.Clrstack();
SosToken expected = new(frameName, $@"\[{frameName}: {Sos.Addr.Pattern}\]");
stack.AssertContainsRow(
row => row["InternalFrame"].AsBoolean() && expected.Matches(row["Call Site"]),
$"a {frameName} row with a frame address");
}
}
8 changes: 8 additions & 0 deletions src/tests/SOS.Tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ The ICorDebug frame-limit test excludes Framework, as the legacy test did.
Temporary, narrowly scoped ICorDebug skips for .NET 10 Windows x86 NestedException
and .NET 11 macOS ARM64 SingleFile/cDAC are defined in
[SOSTestSkips.cs](SOSTestSkips.cs), with inline investigation notes and removal criteria.
`ClrStackRuntimeFramesTests` adds dump-only checks for `FaultingExceptionFrame`
on DivZero and `SoftwareExceptionFrame` on SimpleThrow. The latter runs on .NET 10+
Core/SingleFile; both preserve the legacy Windows x86 exclusion.
The DivZero faulting-frame check also skips ARM/ARM64 via `SOSTestSkips`: division by
zero uses a software throw there, and the legacy test did not run on those platforms.
The software-frame check remains enabled on ARM/ARM64.
`StackTraceFaultingExceptionFrame.script` and `StackTraceSoftwareExceptionFrame.script`
are retired; their shared debuggees remain.
`GCTests.script` and `GCPOH.script` are retired using existing heap coverage plus
known POH object location and roots, Core static reference fields, and native
`dumpobj -refs` coverage using the existing Scenarios target. These additions use dump-only
Expand Down
11 changes: 11 additions & 0 deletions src/tests/SOS.Tests/SOSTestSkips.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ namespace SOS.Tests;

internal static class SOSTestSkips
{
internal static void SkipFaultingExceptionFrame()
{
// The legacy exception-frame script did not run on ARM/ARM64 in CI.
// Integer division by zero uses a software throw on these architectures, not a hardware fault.
// ARM64 stacks show HelperMethodFrame on .NET 8/9 and SoftwareExceptionFrame on .NET 10/11.
// https://dev.azure.com/dnceng-public/public/_build/results?buildId=1616829
Assert.SkipWhen(
RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64,
"DivZero does not produce a FaultingExceptionFrame on ARM/ARM64; the legacy test did not run on these platforms.");
}

internal static void SkipICorDebugFrameCount(TestConfig config)
{
string? reason = GetICorDebugFrameCountSkipReason(config, OperatingSystem.IsWindows(), OperatingSystem.IsMacOS(), RuntimeInformation.ProcessArchitecture);
Expand Down
33 changes: 0 additions & 33 deletions src/tests/SOS.UnitTests/SOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,39 +290,6 @@ public SOSStackTraceTests(ITestOutputHelper output)

private ITestOutputHelper Output { get; set; }

[Theory, MemberData(nameof(SOSTestHelpers.Configurations), MemberType = typeof(SOSTestHelpers))]
public async Task StackTraceSoftwareExceptionFrame(TestConfiguration config)
{
if (config.RuntimeFrameworkVersionMajor < 10)
{
Assert.Skip("This test validates SoftwareExceptionFrame handling, before .NET10, these aren't used in this debuggee scenario.");
}

SOSTestHelpers.SkipIfWinX86(config);

await SOSTestHelpers.RunTest(
config,
debuggeeName: "SimpleThrow",
scriptName: "StackTraceSoftwareExceptionFrame.script",
Output,
testName: "SOS.StackTraceSoftwareExceptionFrame",
testTriage: true);
}

[Theory, MemberData(nameof(SOSTestHelpers.Configurations), MemberType = typeof(SOSTestHelpers))]
public async Task StackTraceFaultingExceptionFrame(TestConfiguration config)
{
SOSTestHelpers.SkipIfWinX86(config);

await SOSTestHelpers.RunTest(
config,
debuggeeName: "DivZero",
scriptName: "StackTraceFaultingExceptionFrame.script",
Output,
testName: "SOS.StackTraceFaultingExceptionFrame",
testTriage: true);
}

[Theory, MemberData(nameof(SOSTestHelpers.Configurations), MemberType = typeof(SOSTestHelpers))]
public async Task StackTests(TestConfiguration config)
{
Expand Down

This file was deleted.

This file was deleted.

Loading