Skip to content
Draft
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
22 changes: 19 additions & 3 deletions docs/design/datacontracts/Object.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ TargetPointer GetMethodTableAddress(TargetPointer address);
// Get the string corresponding to a managed string object. Error if address does not represent a string.
string GetStringValue(TargetPointer address);

// Get the pointer to the data corresponding to a managed array object. Error if address does not represent a array.
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds);
// Get the pointer to the data and shape information corresponding to a managed array object.
// Error if address does not represent an array.
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds, out uint[] dimensionLengths, out int[] lowerBoundsValues);

// Get the length (in chars) and the offset from the object base to the first character
// for a managed string object. Error if address does not represent a string.
Expand Down Expand Up @@ -142,7 +143,7 @@ void GetStringData(TargetPointer address, out uint length, out uint offsetToFirs
offsetToFirstChar = /* String::m_FirstChar offset */;
}

TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds)
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds, out uint[] dimensionLengths, out int[] lowerBoundsValues)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
Expand Down Expand Up @@ -173,6 +174,21 @@ TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPoin
lowerBounds = target.ReadGlobalPointer("ArrayBoundsZero");
}

dimensionLengths = new uint[rank];
lowerBoundsValues = new int[rank];
if (corType == CorElementType.Array)
{
for (int i = 0; i < rank; i++)
{
dimensionLengths[i] = target.Read<uint>(boundsStart + i * sizeof(int));
lowerBoundsValues[i] = target.Read<int>(lowerBounds + i * sizeof(int));
}
}
else
{
dimensionLengths[0] = count;
}

// Sync block is before `this` pointer, so substract the object header size
ulong dataOffset = typeSystemContract.GetBaseSize(typeHandle) - target.ReadGlobal<uint>("ObjectHeaderSize");
return address + dataOffset;
Expand Down
2 changes: 1 addition & 1 deletion docs/design/datacontracts/RuntimeMutableTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ TargetPointer GetEnCInstanceFieldAddress(TargetPointer objectAddress, TargetPoin
// Primitive stored in a 1-element array. Return the address of the first element.
if (fieldObject == TargetPointer.Null)
return TargetPointer.Null;
return target.Contracts.Object.GetArrayData(fieldObject, out _, out _, out _);
return target.Contracts.Object.GetArrayData(fieldObject, out _, out _, out _, out _, out _);
}
}
entryPtr = target.ReadPointer(entryPtr + /* EnCAddedField::Next offset */);
Expand Down
2 changes: 1 addition & 1 deletion docs/design/datacontracts/WindowsErrorReporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ byte[] GetWatsonBuckets(TargetPointer threadPointer)
Data.Exception exception = target.ProcessedData.GetOrAdd<Data.Exception>(thrownObject);
if (exception.WatsonBuckets != TargetPointer.Null)
{
readFrom = target.Contracts.Object.GetArrayData(exception.WatsonBuckets, out _, out _, out _);
readFrom = target.Contracts.Object.GetArrayData(exception.WatsonBuckets, out _, out _, out _, out _, out _);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface IObject : IContract
static string IContract.Name { get; } = nameof(Object);
TargetPointer GetMethodTableAddress(TargetPointer address) => throw new NotImplementedException();
string GetStringValue(TargetPointer address) => throw new NotImplementedException();
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds) => throw new NotImplementedException();
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds, out uint[] dimensionLengths, out int[] lowerBoundsValues) => throw new NotImplementedException();
bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw, out TargetPointer ccf) => throw new NotImplementedException();
int TryGetHashCode(TargetPointer address) => throw new NotImplementedException();
// Returns the SyncBlock address for the object, or TargetPointer.Null if no sync block is associated with it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ string IObject.GetStringValue(TargetPointer address)
if (str.StringLength == 0)
return string.Empty;

Span<byte> span = stackalloc byte[(int)str.StringLength * sizeof(char)];
byte[] bytes = new byte[checked((int)str.StringLength * sizeof(char))];
Span<byte> span = bytes;
_target.ReadBuffer(str.FirstChar, span);
return new string(MemoryMarshal.Cast<byte, char>(span));
}
Expand All @@ -68,7 +69,7 @@ public void GetStringData(TargetPointer address, out uint length, out uint offse
offsetToFirstChar = (uint)(str.FirstChar.Value - address.Value);
}

public TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds)
public TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds, out uint[] dimensionLengths, out int[] lowerBoundsValues)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
Expand Down Expand Up @@ -101,6 +102,24 @@ public TargetPointer GetArrayData(TargetPointer address, out uint count, out Tar
lowerBounds = _target.ReadGlobalPointer(Constants.Globals.ArrayBoundsZero);
}

int rankValue = checked((int)rank);
dimensionLengths = new uint[rankValue];
lowerBoundsValues = new int[rankValue];
if (corType == CorElementType.Array)
{
for (int i = 0; i < rankValue; i++)
{
ulong offset = (ulong)(i * sizeof(int));
dimensionLengths[i] = _target.Read<uint>(boundsStart + offset);
lowerBoundsValues[i] = _target.Read<int>(lowerBounds + offset);
}
}
else
{
Debug.Assert(rankValue == 1);
dimensionLengths[0] = count;
}

// Sync block is before `this` pointer, so substract the object header size
ulong dataOffset = typeSystemContract.GetBaseSize(typeHandle) - Data.ObjectHeader.GetSize(_target);
return address + dataOffset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ TargetPointer IRuntimeMutableTypeSystem.GetEnCInstanceFieldAddress(TargetPointer
// Primitive stored in a 1-element array. Get pointer to first element.
if (fieldObject == TargetPointer.Null)
return TargetPointer.Null;
return objectContract.GetArrayData(fieldObject, out _, out _, out _);
return objectContract.GetArrayData(fieldObject, out _, out _, out _, out _, out _);
}
}
entryPtr = entry.Next;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public SignatureTypeProvider(Target target, Contracts.ModuleHandle moduleHandle)
return null;
return _runtimeTypeSystem.GetInstantiation(typeContext)[index];
}
if (typeof(T) == typeof(MethodDescHandle))
{
MethodDescHandle methodContext = (MethodDescHandle)(object)context!;
ITypeHandle declaringType = _runtimeTypeSystem.GetTypeHandle(_runtimeTypeSystem.GetMethodTable(methodContext));
return _runtimeTypeSystem.GetInstantiation(declaringType)[index];
}
throw new NotImplementedException();
}
public ITypeHandle? GetModifiedType(ITypeHandle? modifier, ITypeHandle? unmodifiedType, bool isRequired)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ byte[] IWindowsErrorReporting.GetWatsonBuckets(TargetPointer threadPointer)
Data.Exception exception = _target.ProcessedData.GetOrAdd<Data.Exception>(thrownObject);
if (exception.WatsonBuckets != TargetPointer.Null)
{
readFrom = _target.Contracts.Object.GetArrayData(exception.WatsonBuckets, out _, out _, out _);
readFrom = _target.Contracts.Object.GetArrayData(exception.WatsonBuckets, out _, out _, out _, out _, out _);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,16 @@ int IXCLRDataExceptionState.GetManagedObject(DacComNullableByRef<IXCLRDataValue>
throw new ArgumentException();
}

ulong objectSize = _target.Contracts.Object.GetSize(exceptionObject);
IObject objectContract = _target.Contracts.Object;
ulong objectSize = objectContract.GetSize(exceptionObject);
ITypeHandle typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(
objectContract.GetMethodTableAddress(exceptionObject));
value.Interface = new ClrDataValue(
_target,
_threadAddress,
(uint)ClrDataValueFlag.DEFAULT,
typeHandle,
exceptionObject,
[
new NativeVarLocation
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@
using System.Runtime.InteropServices.Marshalling;
using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
using Microsoft.Diagnostics.DataContractReader.SignatureHelpers;

namespace Microsoft.Diagnostics.DataContractReader.Legacy;

[GeneratedComClass]
public sealed unsafe partial class ClrDataFrame : IXCLRDataFrame, IXCLRDataFrame2
{
private readonly Target _target;
private readonly TargetPointer _threadAddress;
private readonly IXCLRDataFrame? _legacyImpl;

private readonly IStackDataFrameHandle _dataFrame;

public ClrDataFrame(Target target, IStackDataFrameHandle dataFrame, IXCLRDataFrame? legacyImpl)
public ClrDataFrame(Target target, TargetPointer threadAddress, IStackDataFrameHandle dataFrame, IXCLRDataFrame? legacyImpl)
{
_target = target;
_threadAddress = threadAddress;
_legacyImpl = legacyImpl;

_dataFrame = dataFrame;
Expand Down Expand Up @@ -463,14 +466,24 @@ private ClrDataValue CreateValueFromDebugInfo(
// Only VAR/MVAR (generic parameters) require runtime type system resolution.
uint valueFlags;
int typeSize = -1;
ITypeHandle? typeHandle;
if (isArg && sigIndex == 0 && methodHeader.IsInstance)
{
// 'this' parameter is always a reference
valueFlags = (uint)ClrDataValueFlag.IS_REFERENCE;
typeHandle = _target.Contracts.RuntimeTypeSystem.GetTypeHandle(
_target.Contracts.RuntimeTypeSystem.GetMethodTable(mdh));
}
else
{
(valueFlags, typeSize) = ComputeFlagsFromSignature(isArg, sigIndex, methodHeader, mdh, moduleHandle);
typeHandle = GetTypeHandleFromSignature(isArg, sigIndex, methodHeader, mdh, moduleHandle);
if (typeHandle is null)
{
typeHandle = _target.Contracts.RuntimeTypeSystem.GetPrimitiveType(CorElementType.U8);
valueFlags = (uint)ClrDataValueFlag.DEFAULT;
typeSize = -1;
}
}

// Match native DAC (ValueFromDebugInfo in stack.cpp): for primitives with a
Expand All @@ -497,7 +510,10 @@ private ClrDataValue CreateValueFromDebugInfo(
];
}

return new ClrDataValue(_target, valueFlags, locations, legacyImpl);
ulong baseAddress = locations.Length == 1 && !locations[0].IsRegisterValue
? locations[0].AddressOrValue
: 0;
return new ClrDataValue(_target, _threadAddress, valueFlags, typeHandle, baseAddress, locations, legacyImpl);
}

// ========== Signature-based flag computation ==========
Expand Down Expand Up @@ -607,6 +623,40 @@ private uint GetLocalVariableCount(MethodDescHandle mdh, Contracts.ModuleHandle
}
}

private ITypeHandle? GetTypeHandleFromSignature(
bool isArg, uint sigIndex, SignatureHeader methodHeader,
MethodDescHandle mdh, Contracts.ModuleHandle moduleHandle)
{
try
{
MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle) ?? throw new NotImplementedException();
uint token = _target.Contracts.RuntimeTypeSystem.GetMethodToken(mdh);
MethodDefinition methodDef = mdReader.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle((int)EcmaMetadataUtils.GetRowId(token)));
SignatureTypeProvider<MethodDescHandle> provider = new(_target, moduleHandle);
SignatureDecoder<ITypeHandle?, MethodDescHandle> decoder = new(provider, mdReader, mdh);

if (isArg)
{
BlobReader sigReader = mdReader.GetBlobReader(methodDef.Signature);
MethodSignature<ITypeHandle?> methodSig = decoder.DecodeMethodSignature(ref sigReader);
int paramIndex = methodHeader.IsInstance ? (int)sigIndex - 1 : (int)sigIndex;
return methodSig.ParameterTypes[paramIndex];
}

BlobReader? localReader = GetLocalSignatureReader(mdh, moduleHandle, out _);
if (localReader is null)
return null;

BlobReader localSigReader = localReader.Value;
ImmutableArray<ITypeHandle?> localTypes = decoder.DecodeLocalSignature(ref localSigReader);
return localTypes[(int)sigIndex];
}
catch (System.Exception)
{
return null;
}
}

/// <summary>
/// Maps a CorElementType to ClrDataValueFlag and primitive type size.
/// Used for generic parameter resolution (VAR/MVAR) where we get the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ int IXCLRDataStackWalk.GetFrame(DacComNullableByRef<IXCLRDataFrame> frame)
if (!_currentFrameIsValid)
throw new ArgumentException();

frame.Interface = new ClrDataFrame(_target, _dataFrames.Current, legacyFrame);
frame.Interface = new ClrDataFrame(_target, _threadAddr, _dataFrames.Current, legacyFrame);
}
catch (System.Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public sealed unsafe partial class ClrDataTypeInstance : IXCLRDataTypeInstance
private readonly ITypeHandle _typeHandle;
private readonly IXCLRDataTypeInstance? _legacyImpl;

internal ITypeHandle TypeHandle => _typeHandle;
internal IXCLRDataTypeInstance? LegacyImpl => _legacyImpl;

public ClrDataTypeInstance(Target target, ITypeHandle typeHandle, IXCLRDataTypeInstance? legacyImpl)
{
_target = target;
Expand Down
Loading
Loading