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: 4 additions & 0 deletions docs/design/datacontracts/DebugInfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ public enum DebugVarLocKind
RegisterStack,
StackRegister,
DoubleStack,
FloatingPointStack,
FixedVarArg,
}

public readonly struct DebugVarInfo
Expand All @@ -344,6 +346,8 @@ public readonly struct DebugVarInfo
public int StackOffset { get; init; }
public uint BaseRegister2 { get; init; }
public int StackOffset2 { get; init; }
public uint FloatingPointStackRegister { get; init; }
public uint FixedVarArgOffset { get; init; }
public uint CallReturnValueILOffset { get; init; }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public enum DebugVarLocKind
RegisterStack,
StackRegister,
DoubleStack,
FloatingPointStack,
FixedVarArg,
}
Comment thread
max-charlamb marked this conversation as resolved.

/// <summary>
Expand Down Expand Up @@ -73,6 +75,10 @@ public readonly struct DebugVarInfo
public uint BaseRegister2 { get; init; }
/// <summary>Second stack offset (RegisterStack).</summary>
public int StackOffset2 { get; init; }
/// <summary>Floating-point stack register number (FloatingPointStack).</summary>
public uint FloatingPointStackRegister { get; init; }
/// <summary>Offset of a fixed argument in a varargs function (FixedVarArg).</summary>
public uint FixedVarArgOffset { get; init; }
/// <summary>
/// For <see cref="VarNumber"/> == <c>ICorDebugInfo::CALL_RETURN_ILNUM</c> entries, the IL offset of
/// the call site whose return value this entry describes. Zero for all other entries.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,16 @@ internal static IEnumerable<DebugVarInfo> DoVars(NativeReader nativeReader, bool
StartOffset = startOffset, EndOffset = endOffset, VarNumber = varNumber, CallReturnValueILOffset = callReturnValueILOffset,
Kind = DebugVarLocKind.DoubleStack, BaseRegister = reader.ReadUInt(), StackOffset = ReadEncodedStackOffset(reader, isX86),
},
// FPSTK and FIXED_VA: consume stream data to keep reader aligned, but no public
// DebugVarLocKind exists for these rarely-used location types.
VarLocType.VLT_FPSTK => ConsumeAndDefault(reader.ReadUInt(), startOffset, endOffset, varNumber, callReturnValueILOffset),
VarLocType.VLT_FIXED_VA => ConsumeAndDefault(reader.ReadUInt(), startOffset, endOffset, varNumber, callReturnValueILOffset),
VarLocType.VLT_FPSTK => new DebugVarInfo
{
StartOffset = startOffset, EndOffset = endOffset, VarNumber = varNumber, CallReturnValueILOffset = callReturnValueILOffset,
Kind = DebugVarLocKind.FloatingPointStack, IsFloatingPoint = true, FloatingPointStackRegister = reader.ReadUInt(),
},
VarLocType.VLT_FIXED_VA => new DebugVarInfo
{
StartOffset = startOffset, EndOffset = endOffset, VarNumber = varNumber, CallReturnValueILOffset = callReturnValueILOffset,
Kind = DebugVarLocKind.FixedVarArg, FixedVarArgOffset = reader.ReadUInt(),
},
_ => new DebugVarInfo
{
StartOffset = startOffset, EndOffset = endOffset, VarNumber = varNumber, CallReturnValueILOffset = callReturnValueILOffset,
Expand All @@ -196,11 +202,6 @@ internal static IEnumerable<DebugVarInfo> DoVars(NativeReader nativeReader, bool
}
}

private static DebugVarInfo ConsumeAndDefault(uint _, uint startOffset, uint endOffset, uint varNumber, uint callReturnValueILOffset) => new()
{
StartOffset = startOffset, EndOffset = endOffset, VarNumber = varNumber, CallReturnValueILOffset = callReturnValueILOffset,
};

private static int ReadEncodedStackOffset(NibbleReader reader, bool isX86)
{
int value = reader.ReadInt();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ internal static VarLoc ConvertToVarLoc(DebugVarInfo varInfo)
(DebugVarLocKind.RegisterStack, _, _) => VarLocType.VLT_REG_STK,
(DebugVarLocKind.StackRegister, _, _) => VarLocType.VLT_STK_REG,
(DebugVarLocKind.DoubleStack, _, _) => VarLocType.VLT_STK2,
(DebugVarLocKind.FloatingPointStack, _, _) => VarLocType.VLT_FPSTK,
(DebugVarLocKind.FixedVarArg, _, _) => VarLocType.VLT_FIXED_VA,
_ => VarLocType.VLT_INVALID,
};

Expand Down Expand Up @@ -90,6 +92,12 @@ internal static VarLoc ConvertToVarLoc(DebugVarInfo varInfo)
loc.vlsBaseReg = varInfo.BaseRegister;
loc.vlsOffset = varInfo.StackOffset;
break;
case DebugVarLocKind.FloatingPointStack:
loc.vlfReg = varInfo.FloatingPointStackRegister;
break;
case DebugVarLocKind.FixedVarArg:
loc.vlfvOffset = varInfo.FixedVarArgOffset;
break;
}

return loc;
Expand Down Expand Up @@ -232,6 +240,14 @@ private static void AssertVarInfosEqual(List<NativeVarInfo> cdac, List<NativeVar
Debug.Assert(c.loc.vlsrReg == d.loc.vlsrReg,
$"VarInfo[{i}] vlsrReg mismatch - cDAC: {c.loc.vlsrReg}, DAC: {d.loc.vlsrReg}");
break;
case VarLocType.VLT_FPSTK:
Debug.Assert(c.loc.vlfReg == d.loc.vlfReg,
$"VarInfo[{i}] vlfReg mismatch - cDAC: {c.loc.vlfReg}, DAC: {d.loc.vlfReg}");
break;
case VarLocType.VLT_FIXED_VA:
Debug.Assert(c.loc.vlfvOffset == d.loc.vlfvOffset,
$"VarInfo[{i}] vlfvOffset mismatch - cDAC: {c.loc.vlfvOffset}, DAC: {d.loc.vlfvOffset}");
break;
}
}
}
Expand Down
77 changes: 77 additions & 0 deletions src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using ILCompiler.Reflection.ReadyToRun;
using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
using Microsoft.Diagnostics.DataContractReader.Legacy;
Expand Down Expand Up @@ -1219,6 +1221,8 @@ public void GetManagedStoppedContext_NoContextAvailable(MockTarget.Architecture
[InlineData(DebugVarLocKind.RegisterStack, false, false, VarLocType.VLT_REG_STK)]
[InlineData(DebugVarLocKind.StackRegister, false, false, VarLocType.VLT_STK_REG)]
[InlineData(DebugVarLocKind.DoubleStack, false, false, VarLocType.VLT_STK2)]
[InlineData(DebugVarLocKind.FloatingPointStack, false, false, VarLocType.VLT_FPSTK)]
[InlineData(DebugVarLocKind.FixedVarArg, false, false, VarLocType.VLT_FIXED_VA)]
public void ConvertToVarLoc_MapsVarLocTypeCorrectly(DebugVarLocKind kind, bool isByRef, bool isFloatingPoint, VarLocType expected)
{
var varInfo = new DebugVarInfo { Kind = kind, IsByRef = isByRef, IsFloatingPoint = isFloatingPoint };
Expand Down Expand Up @@ -1291,6 +1295,79 @@ public void ConvertToVarLoc_DoubleStack_SetsBaseRegAndOffset()
Assert.Equal(0x20, result.vlsOffset);
}

[Fact]
public void ConvertToVarLoc_FloatingPointStack_SetsRegister()
{
var varInfo = new DebugVarInfo { Kind = DebugVarLocKind.FloatingPointStack, FloatingPointStackRegister = 3 };
VarLoc result = DacDbiImpl.ConvertToVarLoc(varInfo);
Assert.Equal(VarLocType.VLT_FPSTK, result.vlType);
Assert.Equal(3u, result.vlfReg);
}

[Fact]
public void ConvertToVarLoc_FixedVarArg_SetsOffset()
{
var varInfo = new DebugVarInfo { Kind = DebugVarLocKind.FixedVarArg, FixedVarArgOffset = 0x28 };
VarLoc result = DacDbiImpl.ConvertToVarLoc(varInfo);
Assert.Equal(VarLocType.VLT_FIXED_VA, result.vlType);
Assert.Equal(0x28u, result.vlfvOffset);
}

[Fact]
public void DecodeVarInfo_PreservesFloatingPointStackAndFixedVarArgLocations()
{
const uint maxILNum = unchecked((uint)-6);
byte[] encoded = EncodeNibbleUInts(
2,
unchecked(0u - maxILNum), 1, 2, (uint)VarLocType.VLT_FPSTK, 3,
unchecked(1u - maxILNum), 4, 2, (uint)VarLocType.VLT_FIXED_VA, 0x28);

var reader = new NativeReader(new MemoryStream(encoded));
List<DebugVarInfo> result = new(DebugInfoHelpers.DoVars(reader, isX86: true));

Assert.Collection(
result,
varInfo =>
{
Assert.Equal(DebugVarLocKind.FloatingPointStack, varInfo.Kind);
Assert.True(varInfo.IsFloatingPoint);
Assert.Equal(3u, varInfo.FloatingPointStackRegister);
},
varInfo =>
{
Assert.Equal(DebugVarLocKind.FixedVarArg, varInfo.Kind);
Assert.Equal(0x28u, varInfo.FixedVarArgOffset);
});
}

private static byte[] EncodeNibbleUInts(params uint[] values)
{
List<byte> nibbles = new();
Span<byte> groups = stackalloc byte[11];
foreach (uint value in values)
{
int groupCount = 0;
uint remaining = value;
do
{
groups[groupCount++] = (byte)(remaining & 7);
remaining >>= 3;
}
while (remaining != 0);

for (int i = groupCount - 1; i >= 0; i--)
{
byte continuation = i == 0 ? (byte)0 : (byte)8;
nibbles.Add((byte)(groups[i] | continuation));
}
}

byte[] bytes = new byte[(nibbles.Count + 1) / 2];
for (int i = 0; i < nibbles.Count; i++)
bytes[i / 2] |= (byte)(nibbles[i] << (4 * (i & 1)));
return bytes;
}

[Theory]
[InlineData(SourceTypes.Default, 0x00u)]
[InlineData(SourceTypes.StackEmpty, 0x02u)]
Expand Down
Loading