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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
Expand All @@ -15,6 +17,17 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy;
[GeneratedComClass]
public sealed unsafe partial class ClrDataMethodDefinition : IXCLRDataMethodDefinition
{
private sealed class EnumMethodDefinitionExtents : IEnum<ClrDataMethodDefinitionExtent>
{
public IEnumerator<ClrDataMethodDefinitionExtent> Enumerator { get; }
public nuint LegacyHandle { get; set; }

public EnumMethodDefinitionExtents(ClrDataMethodDefinitionExtent extent)
{
Enumerator = Enumerable.Repeat(extent, 1).GetEnumerator();
}
}

private readonly Target _target;
private readonly TargetPointer _module;
private readonly uint _token;
Expand All @@ -41,6 +54,22 @@ private TargetPointer TryResolveMethodDesc()
return methodDescAddr;
}

private TargetPointer GetILExtentStart(out uint codeSize)
{
ILoader loader = _target.Contracts.Loader;
Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(_module);
TargetPointer ilHeader = loader.GetILHeader(moduleHandle, _token);
if (ilHeader == TargetPointer.Null)
{
codeSize = 0;
return TargetPointer.Null;
}

int headerSize = HeaderReaderHelpers.GetHeaderSize(_target, ilHeader);
codeSize = (uint)HeaderReaderHelpers.GetCodeSize(_target, ilHeader);
return headerSize == sizeof(byte) ? ilHeader : ilHeader + (uint)headerSize;
}

private static bool HasClassInstantiation(Target target, MethodDescHandle md)
{
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
Expand Down Expand Up @@ -384,13 +413,155 @@ int IXCLRDataMethodDefinition.GetLatestEnCVersion(uint* version)
=> HResults.E_NOTIMPL;

int IXCLRDataMethodDefinition.StartEnumExtents(ulong* handle)
=> LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumExtents(handle) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;
try
{
if (handle is null)
throw new ArgumentNullException(nameof(handle));

*handle = 0;
TargetPointer code = GetILExtentStart(out uint codeSize);
if (code == TargetPointer.Null)
{
hr = HResults.S_FALSE;
}
else
{
ClrDataAddress startAddress = code.ToClrDataAddress(_target);
ClrDataMethodDefinitionExtent extent = new()
{
startAddress = startAddress,
endAddress = startAddress + codeSize - 1,
enCVersion = 0,
type = 0,
};
EnumMethodDefinitionExtents extents = new(extent);
*handle = (ulong)((IEnum<ClrDataMethodDefinitionExtent>)extents).GetHandle();
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (LegacyFallbackHelper.CanFallback() && _legacyImpl is not null)
{
ulong legacyHandle = 0;
int hrLocal = _legacyImpl.StartEnumExtents(handle is null ? null : &legacyHandle);
Debug.ValidateHResult(hr, hrLocal);

if (hr == HResults.S_OK && hrLocal == HResults.S_OK)
{
GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle));
((EnumMethodDefinitionExtents)gcHandle.Target!).LegacyHandle = (nuint)legacyHandle;
}
else if (hrLocal == HResults.S_OK)
{
_legacyImpl.EndEnumExtents(legacyHandle);
}
}
#endif

return hr;
}

int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionExtent* extent)
=> LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumExtent(handle, extent) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;
EnumMethodDefinitionExtents? extents = null;
bool completed = false;
try
{
if (handle is null)
throw new ArgumentNullException(nameof(handle));
if (extent is null)
throw new ArgumentNullException(nameof(extent));
if (*handle == 0)
throw new ArgumentException("Extent enumeration has not been started or has already ended.", nameof(handle));

GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle));
if (gcHandle.Target is not EnumMethodDefinitionExtents methodExtents)
throw new ArgumentException("Handle does not reference a method definition extent enumeration.", nameof(handle));

extents = methodExtents;
if (extents.Enumerator.MoveNext())
{
*extent = extents.Enumerator.Current;
completed = true;
}
else
{
hr = HResults.S_FALSE;
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (LegacyFallbackHelper.CanFallback() && _legacyImpl is not null && extents is { LegacyHandle: not 0 })
{
ulong legacyHandle = (ulong)extents.LegacyHandle;
ClrDataMethodDefinitionExtent extentLocal = default;
int hrLocal = _legacyImpl.EnumExtent(&legacyHandle, &extentLocal);
extents.LegacyHandle = (nuint)legacyHandle;
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(extent->startAddress == extentLocal.startAddress, $"StartAddress - cDAC: {extent->startAddress:x}, DAC: {extentLocal.startAddress:x}");
Debug.Assert(extent->endAddress == extentLocal.endAddress, $"EndAddress - cDAC: {extent->endAddress:x}, DAC: {extentLocal.endAddress:x}");
Debug.Assert(extent->enCVersion == extentLocal.enCVersion, $"EnCVersion - cDAC: {extent->enCVersion:x}, DAC: {extentLocal.enCVersion:x}");
Debug.Assert(extent->type == extentLocal.type, $"Type - cDAC: {extent->type:x}, DAC: {extentLocal.type:x}");
}
}
#endif

if (completed && extents is not null)
{
((IEnum<ClrDataMethodDefinitionExtent>)extents).Dispose();
GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle));
gcHandle.Free();
*handle = 0;
}

return hr;
}

int IXCLRDataMethodDefinition.EndEnumExtents(ulong handle)
=> LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumExtents(handle) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;
nuint legacyHandle = 0;
try
{
if (handle != 0)
{
GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)handle);
if (gcHandle.Target is not EnumMethodDefinitionExtents extents)
throw new ArgumentException("Handle does not reference a method definition extent enumeration.", nameof(handle));

legacyHandle = extents.LegacyHandle;
((IEnum<ClrDataMethodDefinitionExtent>)extents).Dispose();
gcHandle.Free();
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (LegacyFallbackHelper.CanFallback() && _legacyImpl is not null && legacyHandle != 0)
{
int hrLocal = _legacyImpl.EndEnumExtents((ulong)legacyHandle);
Debug.ValidateHResult(hr, hrLocal);
}
#endif

return hr;
}

int IXCLRDataMethodDefinition.GetCodeNotification(uint* flags)
{
Expand Down Expand Up @@ -484,7 +655,40 @@ int IXCLRDataMethodDefinition.Request(uint reqCode, uint inBufferSize, byte* inB
}

int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr)
=> LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetRepresentativeEntryAddress(addr) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;

try
{
if (addr is null)
throw new ArgumentNullException(nameof(addr));

TargetPointer code = GetILExtentStart(out _);
if (code == TargetPointer.Null)
throw new COMException("Method definition does not have an IL header.", unchecked((int)0x8000FFFF));

*addr = code.ToClrDataAddress(_target);
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (LegacyFallbackHelper.CanFallback() && _legacyImpl is not null)
{
ClrDataAddress addrLocal = 0;
int hrLocal = _legacyImpl.GetRepresentativeEntryAddress(addr is null ? null : &addrLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(*addr == addrLocal, $"cDAC: {*addr:x}, DAC: {addrLocal:x}");
}
}
#endif

return hr;
}

int IXCLRDataMethodDefinition.HasClassOrMethodInstantiation(int* bGeneric)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static int GetHeaderSize(Target target, TargetPointer ilHeader)
if (IsTiny(firstByte))
return 1;
if (IsFat(firstByte))
return 12;
return (target.Read<byte>(ilHeader + 1) >> 4) * sizeof(uint);
throw new BadImageFormatException("Invalid IL method header.");
}

Expand All @@ -40,7 +40,7 @@ public static int GetCodeSize(Target target, TargetPointer ilHeader)
if (IsTiny(firstByte))
return firstByte >> 2;
if (IsFat(firstByte))
return (int)target.Read<uint>(ilHeader + 4);
return (int)target.ReadLittleEndian<uint>(ilHeader + 4);
throw new BadImageFormatException("Invalid IL method header.");
}

Expand All @@ -52,7 +52,7 @@ public static bool TryGetLocalVarSigToken(Target target, TargetPointer ilHeader,
if (!IsFat(firstByte))
return false;

localVarSigToken = target.Read<int>(ilHeader + 8);
localVarSigToken = target.ReadLittleEndian<int>(ilHeader + 8);
return true;
}
}
Loading
Loading