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
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public record X86GCInfo : IGCInfoDecoder
private readonly TargetPointer _gcInfoAddress;
private readonly uint _infoHdrSize;
private readonly uint _gcInfoVersion;
private readonly uint _stackSize;

public uint RelativeOffset { get; set; }
public uint MethodSize { get; set; }
Expand Down Expand Up @@ -166,6 +167,7 @@ public X86GCInfo(Target target, TargetPointer gcInfoAddress, uint gcInfoVersion,

SavedRegsCountExclFP = savedRegsCount;
SavedRegsMask = savedRegs;
_stackSize = RawStackSize + savedRegsCount * (uint)target.PointerSize;
if (Header.EbpFrame || Header.DoubleAlign)
{
Debug.Assert(Header.EbpSaved);
Expand Down Expand Up @@ -577,7 +579,7 @@ private TargetPointer GetOutermostBaseFP(TargetPointer ebp)
return _target.ReadPointer(pLocalloc);
}

return new TargetPointer(ebp.Value - RawStackSize + (uint)sizeof(int));
return new TargetPointer(ebp.Value - _stackSize + (uint)sizeof(int));
}

private ulong GetLocallocSPOffset()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

using System.Linq;
using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Contracts.GCInfoHelpers.X86;
using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
using Microsoft.Diagnostics.DataContractReader.Legacy;
using Microsoft.Diagnostics.DataContractReader.TestInfrastructure;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;

namespace Microsoft.Diagnostics.DataContractReader.DumpTests;
Expand Down Expand Up @@ -136,4 +138,83 @@ public unsafe void IsLeafFrame_FalseForNonLeafContext(TestConfiguration config)

Assert.Equal(Interop.BOOL.FALSE, result);
}

[ConditionalTheory]
[MemberData(nameof(TestConfigurations))]
[SkipOnVersion("net10.0", "x86 cDAC stack walking is not available in .NET 10")]
public unsafe void GetStackWalkCurrentFrameInfo_X86HandlerFrame_IncludesSavedRegistersInAmbientSP(TestConfiguration config)
{
InitializeDumpTest(config, DebuggeeName, dumpType: "heap");

if (Target.Contracts.RuntimeInfo.GetTargetArchitecture() != RuntimeInfoArchitecture.X86)
throw new SkipTestException("This regression test applies only to x86 dumps.");

DacDbiImpl dbi = CreateDacDbi();
IExecutionManager executionManager = Target.Contracts.ExecutionManager;
IGCInfo gcInfo = Target.Contracts.GCInfo;
ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target);
uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(Target).Size;
byte[] contextBuffer = new byte[contextSize];
nuint stackWalkHandle = 0;

fixed (byte* context = contextBuffer)
{
int hr = dbi.CreateStackWalk(crashingThread.ThreadAddress, context, &stackWalkHandle);
Assert.Equal(System.HResults.S_OK, hr);
}

try
{
while (true)
{
Debugger_STRData data = default;
FrameType frameType;
fixed (byte* context = contextBuffer)
{
data.ctx = (nuint)context;
int hr = dbi.GetStackWalkCurrentFrameInfo(stackWalkHandle, (nint)(&data), &frameType);
Assert.Equal(System.HResults.S_OK, hr);
}

if (frameType == FrameType.AtEndOfStack)
break;

TargetPointer methodDesc = new(data.v.jitFuncData.vmNativeCodeMethodDescToken);
if (frameType == FrameType.ManagedStackFrame &&
DumpTestHelpers.GetMethodName(Target, methodDesc) == "MethodB")
{
IPlatformAgnosticContext frameContext = IPlatformAgnosticContext.GetContextForPlatform(Target);
frameContext.FillFromBuffer(contextBuffer);

CodeBlockHandle? codeBlockHandle = executionManager.GetCodeBlockHandle(frameContext.InstructionPointer);
Assert.NotNull(codeBlockHandle);
executionManager.GetGCInfo(codeBlockHandle.Value, out TargetPointer gcInfoAddress, out uint gcInfoVersion);

var decoder = Assert.IsType<X86GCInfo>(gcInfo.DecodePlatformSpecificGCInfo(gcInfoAddress, gcInfoVersion));
Assert.True(decoder.Header.Handlers);
Assert.False(decoder.Header.LocalAlloc);

uint expectedStackSize = decoder.RawStackSize
+ uint.PopCount((uint)decoder.SavedRegsMask) * (uint)Target.PointerSize;
Assert.True(expectedStackSize > decoder.RawStackSize);

ulong expectedAmbientSP = (frameContext.FramePointer.Value - expectedStackSize + sizeof(int)) & ~3UL;
Assert.Equal(expectedAmbientSP, data.v.taAmbientESP);
return;
}

Interop.BOOL hasMoreFrames;
int unwindHr = dbi.UnwindStackWalkFrame(stackWalkHandle, &hasMoreFrames);
Assert.Equal(System.HResults.S_OK, unwindHr);
if (hasMoreFrames == Interop.BOOL.FALSE)
break;
}

Assert.Fail("MethodB was not found on the crashing thread's stack.");
}
finally
{
Assert.Equal(System.HResults.S_OK, dbi.DeleteStackWalk(stackWalkHandle));
}
}
}
Loading