From 0ee188a427dc7af333659bd82af460b9297633b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Jul 2026 02:50:38 +0000 Subject: [PATCH 1/4] Implement CLRDataMethodDefinition IL extents Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- .../ClrDataMethodDefinition.cs | 202 +++++++++++++++++- .../tests/UnitTests/IXCLRDataProcessTests.cs | 76 +++++++ 2 files changed, 274 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs index 737dbeb2c36290..ddd31641d8edf3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs @@ -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; @@ -15,6 +17,17 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataMethodDefinition : IXCLRDataMethodDefinition { + private sealed class EnumMethodDefinitionExtents : IEnum + { + public IEnumerator 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; @@ -41,6 +54,22 @@ private TargetPointer TryResolveMethodDesc() return methodDescAddr; } + private TargetPointer GetILCode(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 ilHeader + (uint)headerSize; + } + private static bool HasClassInstantiation(Target target, MethodDescHandle md) { IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; @@ -384,13 +413,145 @@ 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 = GetILCode(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)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; + 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("Invalid extent handle.", nameof(handle)); + + GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle)); + if (gcHandle.Target is not EnumMethodDefinitionExtents methodExtents) + throw new ArgumentException("Invalid extent handle.", nameof(handle)); + + extents = methodExtents; + if (extents.Enumerator.MoveNext()) + { + *extent = extents.Enumerator.Current; + } + 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 + + 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("Invalid extent handle.", nameof(handle)); + + legacyHandle = extents.LegacyHandle; + ((IEnum)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) { @@ -484,7 +645,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 = GetILCode(out _); + if (code == TargetPointer.Null) + throw new COMException("Method does not have IL.", 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) { diff --git a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs index c5e702d8809dc1..e091f171a17088 100644 --- a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs @@ -231,6 +231,7 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) Mock loader = new(MockBehavior.Strict); loader.Setup(l => l.GetAppDomain()).Returns(new TargetPointer(AppDomainAddress)); + loader.Setup(l => l.GetModuleHandleFromModulePtr(new TargetPointer(ModuleAddress))).Returns(module); loader.Setup(l => l.GetModuleHandles( new TargetPointer(AppDomainAddress), AssemblyIterationFlags.IncludeLoaded | AssemblyIterationFlags.IncludeExecution)).Returns([module]); @@ -238,6 +239,8 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) loader.Setup(l => l.GetPEAssembly(module)).Returns(new TargetPointer(PeAssemblyAddress)); loader.Setup(l => l.GetILAddr(new TargetPointer(PeAssemblyAddress), 0x10)).Returns(new TargetPointer(FirstHeaderAddress)); loader.Setup(l => l.GetILAddr(new TargetPointer(PeAssemblyAddress), 0x20)).Returns(new TargetPointer(SecondHeaderAddress)); + loader.Setup(l => l.GetILHeader(module, FirstToken)).Returns(new TargetPointer(FirstHeaderAddress)); + loader.Setup(l => l.GetILHeader(module, SecondToken)).Returns(new TargetPointer(SecondHeaderAddress)); Mock ecmaMetadata = new(MockBehavior.Strict); ecmaMetadata.Setup(e => e.GetMetadata(module)).Returns(reader); @@ -292,6 +295,10 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) DacComNullableByRef nullModule = new(isNullRef: true); Assert.Equal(HResults.S_OK, method.GetTokenAndScope(&token, nullModule)); Assert.Equal(FirstToken, token); + AssertMethodDefinitionExtent( + method, + FirstHeaderAddress + TinyHeaderSize, + FirstHeaderAddress + TinyHeaderSize + TinyCodeSize - 1); DacComNullableByRef endOut = new(isNullRef: false); Assert.Equal(HResults.S_FALSE, process.EnumMethodDefinitionByAddress(&handle, endOut)); @@ -314,6 +321,10 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) DacComNullableByRef nullModule = new(isNullRef: true); Assert.Equal(HResults.S_OK, method.GetTokenAndScope(&token, nullModule)); Assert.Equal(SecondToken, token); + AssertMethodDefinitionExtent( + method, + SecondHeaderAddress + 12, + SecondHeaderAddress + 12 + FatCodeSize - 1); } finally { @@ -339,6 +350,71 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) } } + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void MethodDefinitionWithoutIL(MockTarget.Architecture arch) + { + const ulong ModuleAddress = 0x2000; + const uint Token = 0x06000001; + const int EUnexpected = unchecked((int)0x8000FFFF); + ModuleHandle module = new(new TargetPointer(ModuleAddress)); + Mock loader = new(MockBehavior.Strict); + loader.Setup(l => l.GetModuleHandleFromModulePtr(new TargetPointer(ModuleAddress))).Returns(module); + loader.Setup(l => l.GetILHeader(module, Token)).Returns(TargetPointer.Null); + TestPlaceholderTarget.Builder builder = new(arch); + builder.AddMockContract(loader.Object); + IXCLRDataMethodDefinition method = new ClrDataMethodDefinition( + builder.Build(), + new TargetPointer(ModuleAddress), + Token, + legacyImpl: null); + + ulong handle; + Assert.Equal(HResults.S_FALSE, method.StartEnumExtents(&handle)); + Assert.Equal(0ul, handle); + + ClrDataAddress address; + Assert.Equal(EUnexpected, method.GetRepresentativeEntryAddress(&address)); + } + + private static void AssertMethodDefinitionExtent( + IXCLRDataMethodDefinition method, + ClrDataAddress expectedStart, + ClrDataAddress expectedEnd) + { + Assert.Equal(HResults.E_POINTER, method.StartEnumExtents(null)); + Assert.Equal(HResults.E_POINTER, method.GetRepresentativeEntryAddress(null)); + + ulong invalidHandle = 0; + ClrDataMethodDefinitionExtent extent; + Assert.Equal(HResults.E_INVALIDARG, method.EnumExtent(&invalidHandle, &extent)); + + ulong handle; + Assert.Equal(HResults.S_OK, method.StartEnumExtents(&handle)); + Assert.NotEqual(0ul, handle); + try + { + Assert.Equal(HResults.E_POINTER, method.EnumExtent(null, &extent)); + Assert.Equal(HResults.E_POINTER, method.EnumExtent(&handle, null)); + Assert.Equal(HResults.S_OK, method.EnumExtent(&handle, &extent)); + Assert.Equal(expectedStart, extent.startAddress); + Assert.Equal(expectedEnd, extent.endAddress); + Assert.Equal(0u, extent.enCVersion); + Assert.Equal(0u, extent.type); + Assert.Equal(HResults.S_FALSE, method.EnumExtent(&handle, &extent)); + } + finally + { + Assert.Equal(HResults.S_OK, method.EndEnumExtents(handle)); + } + + Assert.Equal(HResults.S_OK, method.EndEnumExtents(0)); + + ClrDataAddress address; + Assert.Equal(HResults.S_OK, method.GetRepresentativeEntryAddress(&address)); + Assert.Equal(expectedStart, address); + } + private static byte[] BuildMethodDefinitionMetadata() { MetadataBuilder builder = new(); From 3132cd280c9dc2f10612db36d2e0b23f26529416 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Jul 2026 03:00:00 +0000 Subject: [PATCH 2/4] Match legacy method definition extent behavior Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- .../ClrDataMethodDefinition.cs | 18 ++++++++++++++---- .../HeaderReaderHelpers.cs | 2 +- .../tests/UnitTests/IXCLRDataProcessTests.cs | 18 ++++++++++-------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs index ddd31641d8edf3..4246f14a7ab1b0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs @@ -54,7 +54,7 @@ private TargetPointer TryResolveMethodDesc() return methodDescAddr; } - private TargetPointer GetILCode(out uint codeSize) + private TargetPointer GetILExtentStart(out uint codeSize) { ILoader loader = _target.Contracts.Loader; Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(_module); @@ -67,7 +67,7 @@ private TargetPointer GetILCode(out uint codeSize) int headerSize = HeaderReaderHelpers.GetHeaderSize(_target, ilHeader); codeSize = (uint)HeaderReaderHelpers.GetCodeSize(_target, ilHeader); - return ilHeader + (uint)headerSize; + return headerSize == sizeof(byte) ? ilHeader : ilHeader + (uint)headerSize; } private static bool HasClassInstantiation(Target target, MethodDescHandle md) @@ -421,7 +421,7 @@ int IXCLRDataMethodDefinition.StartEnumExtents(ulong* handle) throw new ArgumentNullException(nameof(handle)); *handle = 0; - TargetPointer code = GetILCode(out uint codeSize); + TargetPointer code = GetILExtentStart(out uint codeSize); if (code == TargetPointer.Null) { hr = HResults.S_FALSE; @@ -471,6 +471,7 @@ int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionE { int hr = HResults.S_OK; EnumMethodDefinitionExtents? extents = null; + bool completed = false; try { if (handle is null) @@ -488,6 +489,7 @@ int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionE if (extents.Enumerator.MoveNext()) { *extent = extents.Enumerator.Current; + completed = true; } else { @@ -517,6 +519,14 @@ int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionE } #endif + if (completed && extents is not null) + { + ((IEnum)extents).Dispose(); + GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle)); + gcHandle.Free(); + *handle = 0; + } + return hr; } @@ -653,7 +663,7 @@ int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr if (addr is null) throw new ArgumentNullException(nameof(addr)); - TargetPointer code = GetILCode(out _); + TargetPointer code = GetILExtentStart(out _); if (code == TargetPointer.Null) throw new COMException("Method does not have IL.", unchecked((int)0x8000FFFF)); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs index 950eef6f46577b..b7ac20d14d9140 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs @@ -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(ilHeader + 1) >> 4) * sizeof(uint); throw new BadImageFormatException("Invalid IL method header."); } diff --git a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs index e091f171a17088..fe675ec3c5dedb 100644 --- a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs @@ -214,9 +214,10 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) const uint SecondToken = 0x06000003; const byte TinyFormat = 0x2; const byte FatFormat = 0x3; - const byte FatHeaderDwords = 3; + const byte FatHeaderDwords = 4; const int TinyHeaderSize = sizeof(byte); const int TinyCodeSize = 3; + const int FatHeaderSize = FatHeaderDwords * sizeof(uint); const int FatCodeSize = 2; const int FatCodeSizeOffset = 4; @@ -245,7 +246,7 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) Mock ecmaMetadata = new(MockBehavior.Strict); ecmaMetadata.Setup(e => e.GetMetadata(module)).Returns(reader); - byte[] secondHeader = new byte[14]; + byte[] secondHeader = new byte[FatHeaderSize + FatCodeSize]; secondHeader[0] = FatFormat; secondHeader[1] = FatHeaderDwords << 4; int codeSizeByteOffset = FatCodeSizeOffset + (arch.IsLittleEndian ? 0 : sizeof(uint) - 1); @@ -297,8 +298,8 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) Assert.Equal(FirstToken, token); AssertMethodDefinitionExtent( method, - FirstHeaderAddress + TinyHeaderSize, - FirstHeaderAddress + TinyHeaderSize + TinyCodeSize - 1); + FirstHeaderAddress, + FirstHeaderAddress + TinyCodeSize - 1); DacComNullableByRef endOut = new(isNullRef: false); Assert.Equal(HResults.S_FALSE, process.EnumMethodDefinitionByAddress(&handle, endOut)); @@ -308,7 +309,7 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) Assert.Equal(HResults.S_OK, process.EndEnumMethodDefinitionsByAddress(handle)); } - hr = process.StartEnumMethodDefinitionsByAddress(SecondHeaderAddress + 12, &handle); + hr = process.StartEnumMethodDefinitionsByAddress(SecondHeaderAddress + FatHeaderSize, &handle); Assert.Equal(HResults.S_OK, hr); try { @@ -323,8 +324,8 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) Assert.Equal(SecondToken, token); AssertMethodDefinitionExtent( method, - SecondHeaderAddress + 12, - SecondHeaderAddress + 12 + FatCodeSize - 1); + SecondHeaderAddress + FatHeaderSize, + SecondHeaderAddress + FatHeaderSize + FatCodeSize - 1); } finally { @@ -401,7 +402,8 @@ private static void AssertMethodDefinitionExtent( Assert.Equal(expectedEnd, extent.endAddress); Assert.Equal(0u, extent.enCVersion); Assert.Equal(0u, extent.type); - Assert.Equal(HResults.S_FALSE, method.EnumExtent(&handle, &extent)); + Assert.Equal(0ul, handle); + Assert.Equal(HResults.E_INVALIDARG, method.EnumExtent(&handle, &extent)); } finally { From 8df936c97dfa1c379a15af688bed190d0bcf6988 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Jul 2026 03:01:04 +0000 Subject: [PATCH 3/4] Clarify extent validation errors Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- .../ClrDataMethodDefinition.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs index 4246f14a7ab1b0..30318aeb4dd775 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs @@ -479,11 +479,11 @@ int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionE if (extent is null) throw new ArgumentNullException(nameof(extent)); if (*handle == 0) - throw new ArgumentException("Invalid extent handle.", nameof(handle)); + 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("Invalid extent handle.", nameof(handle)); + throw new ArgumentException("Handle does not reference a method definition extent enumeration.", nameof(handle)); extents = methodExtents; if (extents.Enumerator.MoveNext()) @@ -540,7 +540,7 @@ int IXCLRDataMethodDefinition.EndEnumExtents(ulong handle) { GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)handle); if (gcHandle.Target is not EnumMethodDefinitionExtents extents) - throw new ArgumentException("Invalid extent handle.", nameof(handle)); + throw new ArgumentException("Handle does not reference a method definition extent enumeration.", nameof(handle)); legacyHandle = extents.LegacyHandle; ((IEnum)extents).Dispose(); @@ -665,7 +665,7 @@ int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr TargetPointer code = GetILExtentStart(out _); if (code == TargetPointer.Null) - throw new COMException("Method does not have IL.", unchecked((int)0x8000FFFF)); + throw new COMException("Method definition does not have an IL header.", unchecked((int)0x8000FFFF)); *addr = code.ToClrDataAddress(_target); } From ac007d5f7c58dce79339c676182f1df500ec7c6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Jul 2026 03:06:24 +0000 Subject: [PATCH 4/4] Read IL headers as little endian Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- .../HeaderReaderHelpers.cs | 4 ++-- .../managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs index b7ac20d14d9140..2130c8f2c41e2f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/HeaderReaderHelpers.cs @@ -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(ilHeader + 4); + return (int)target.ReadLittleEndian(ilHeader + 4); throw new BadImageFormatException("Invalid IL method header."); } @@ -52,7 +52,7 @@ public static bool TryGetLocalVarSigToken(Target target, TargetPointer ilHeader, if (!IsFat(firstByte)) return false; - localVarSigToken = target.Read(ilHeader + 8); + localVarSigToken = target.ReadLittleEndian(ilHeader + 8); return true; } } diff --git a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs index fe675ec3c5dedb..674c2008152bb9 100644 --- a/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Collections.Generic; using System.Reflection; using System.Reflection.Metadata; @@ -249,8 +250,7 @@ public void MethodDefinitionsByAddress(MockTarget.Architecture arch) byte[] secondHeader = new byte[FatHeaderSize + FatCodeSize]; secondHeader[0] = FatFormat; secondHeader[1] = FatHeaderDwords << 4; - int codeSizeByteOffset = FatCodeSizeOffset + (arch.IsLittleEndian ? 0 : sizeof(uint) - 1); - secondHeader[codeSizeByteOffset] = FatCodeSize; + BinaryPrimitives.WriteUInt32LittleEndian(secondHeader.AsSpan(FatCodeSizeOffset), FatCodeSize); MockMemorySpace.HeapFragment[] memory = [ new()