diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index be25e4cba9787d..356baef6a80850 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -61,6 +61,7 @@ TargetPointer GetModule(ModuleHandle handle); TargetPointer GetAssembly(ModuleHandle handle); TargetPointer GetPEAssembly(ModuleHandle handle); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags); +TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size); IEnumerable GetAvailableTypeParams(ModuleHandle handle); IEnumerable GetInstantiatedMethods(ModuleHandle handle); @@ -136,6 +137,16 @@ TargetPointer GetStubHeap(TargetPointer loaderAllocatorPointer); | `ArrayListBlock` | `Next` | Next ArrayListBlock in chain | | `ArrayListBlock` | `Size` | Size of data section in block | | `ArrayListBlock` | `ArrayStart` | Start of data section in block | +| `SystemDomain` | `GlobalLoaderAllocator` | global LoaderAllocator | +| `ImageDosHeader` | `Lfanew` | Offset to NT headers | +| `ImageNTHeaders` | `OptionalHeader` | Optional header | +| `ImageNTHeaders` | `FileHeader` | File header | +| `ImageOptionalHeader` | `SectionAlignment` | Alignment of sections in memory | +| `ImageFileHeader` | `NumberOfSections` | Number of sections in the PE file | +| `ImageFileHeader` | `SizeOfOptionalHeader` | Size of optional header on disk | +| `ImageSectionHeader` | `VirtualAddress` | Virtual address of the section | +| `ImageSectionHeader` | `VirtualSize` | Virtual size of the section | +| `ImageSectionHeader` | `PointerToRawData` | Offset to section data | | `EETypeHashTable` | `Buckets` | Pointer to hash table buckets | | `EETypeHashTable` | `Count` | Count of elements in the hash table | | `EETypeHashTable` | `VolatileEntryValue` | The data stored in the hash table entry | @@ -170,6 +181,11 @@ private enum ModuleFlags_1 : uint EditAndContinue = 0x00000008, // Edit and Continue is enabled for this module ReflectionEmit = 0x00000040, // Reflection.Emit was used to create this module } + +private enum PEImageFlags : uint +{ + FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout) +}; ``` ### Method Implementations @@ -333,6 +349,79 @@ bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddres return true; } +TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva) +{ + TargetPointer peImage = target.ReadPointer(peAssemblyPtr + /* PEAssembly::PEImage offset */); + if(peImage == TargetPointer.Null) + throw new InvalidOperationException("PEAssembly does not have a PEImage associated with it."); + + TargetPointer peImageLayout = target.ReadPointer(peImage + /* PEImage::LoadedImageLayout offset */); + if(peImageLayout == TargetPointer.Null) + throw new InvalidOperationException("PEImage does not have a LoadedImageLayout associated with it."); + + // Get base address and flags from PEImageLayout + TargetPointer baseAddress = target.ReadPointer(peImageLayout + /* PEImageLayout::Base offset */); + uint imageFlags = target.Read(peImageLayout + /* PEImageLayout::Flags offset */); + + bool isMapped = (imageFlags & (uint)PEImageFlags.FLAG_MAPPED) != 0; + + uint offset; + if (isMapped) + { + offset = (uint)rva; + } + else + { + // find NT headers using DOS header + uint dosHeaderLfanew = target.Read(baseAddress + /* ImageDosHeader::Lfanew offset */); + TargetPointer ntHeadersPtr = baseAddress + dosHeaderLfanew; + + TargetPointer optionalHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeader offset */; + uint sectionAlignment = target.Read(optionalHeaderPtr + /* ImageOptionalHeader::SectionAlignment offset */); + + // Get number of sections from file header + TargetPointer fileHeaderPtr = ntHeadersPtr + /* ImageNTHeaders::FileHeader offset */; + uint numberOfSections = target.Read(fileHeaderPtr + /* ImageFileHeader::NumberOfSections offset */); + + // Calculate first section address (after NT headers and optional header) + uint imageFileHeaderSize = target.Read(fileHeaderPtr + /* ImageFileHeader::SizeOfOptionalHeader offset */); + TargetPointer firstSectionPtr = ntHeadersPtr + /* ImageNTHeaders::OptionalHeader offset */ + imageFileHeaderSize; + + // Find the section containing this RVA + TargetPointer sectionPtr = TargetPointer.Null; + uint sectionHeaderSize = /* sizeof(ImageSectionHeader native struct) */; + + for (uint i = 0; i < numberOfSections; i++) + { + TargetPointer currentSectionPtr = firstSectionPtr + (i * sectionHeaderSize); + uint virtualAddress = target.Read(currentSectionPtr + /* ImageSectionHeader::VirtualAddress offset */); + uint virtualSize = target.Read(currentSectionPtr + /* ImageSectionHeader::VirtualSize offset */); + + uint alignedVirtualSize = (virtualSize + sectionAlignment - 1) & ~(sectionAlignment - 1); + if (rva < VirtualAddress + alignedVirtualSize) + { + if (rva < virtualAddress) + sectionPtr = TargetPointer.Null; + else + sectionPtr = currentSectionPtr; + break; + } + } + if (sectionPtr == TargetPointer.Null) + { + offset = (uint)rva; + } + else + { + // Convert RVA to file offset using section information + uint sectionVirtualAddress = target.Read(sectionPtr + /* ImageSectionHeader::VirtualAddress offset */); + uint sectionPointerToRawData = target.Read(sectionPtr + /* ImageSectionHeader::PointerToRawData offset */); + offset = ((rva - sectionVirtualAddress) + sectionPointerToRawData); + } + } + return baseAddress + offset; +} + bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size) { buffer = TargetPointer.Null; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.h b/src/coreclr/vm/datadescriptor/datadescriptor.h index 84adff2a49b4d3..49a52cdd0e23f3 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.h +++ b/src/coreclr/vm/datadescriptor/datadescriptor.h @@ -1,6 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#ifndef HOST_WINDOWS +#include "../pal/inc/pal.h" +#include "../pal/inc/rt/ntimage.h" +#endif // HOST_WINDOWS #include "common.h" #include diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 934bee1662b4d6..e1e7a8845bee86 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -196,6 +196,35 @@ CDAC_TYPE_FIELD(PEImageLayout, /*uint32*/, Size, cdac_data::Size) CDAC_TYPE_FIELD(PEImageLayout, /*uint32*/, Flags, cdac_data::Flags) CDAC_TYPE_END(PEImageLayout) +CDAC_TYPE_BEGIN(ImageNTHeaders) +CDAC_TYPE_INDETERMINATE(ImageNTHeaders) +CDAC_TYPE_FIELD(ImageNTHeaders, /*uint32*/, OptionalHeader, offsetof(IMAGE_NT_HEADERS, OptionalHeader)) +CDAC_TYPE_FIELD(ImageNTHeaders, /*uint16*/, FileHeader, offsetof(IMAGE_NT_HEADERS, FileHeader)) +CDAC_TYPE_END(ImageNTHeaders) + +CDAC_TYPE_BEGIN(ImageFileHeader) +CDAC_TYPE_INDETERMINATE(ImageFileHeader) +CDAC_TYPE_FIELD(ImageFileHeader, /*uint16*/, NumberOfSections, offsetof(IMAGE_FILE_HEADER, NumberOfSections)) +CDAC_TYPE_FIELD(ImageFileHeader, /*uint16*/, SizeOfOptionalHeader, offsetof(IMAGE_FILE_HEADER, SizeOfOptionalHeader)) +CDAC_TYPE_END(ImageFileHeader) + +CDAC_TYPE_BEGIN(ImageOptionalHeader) +CDAC_TYPE_INDETERMINATE(ImageOptionalHeader) +CDAC_TYPE_FIELD(ImageOptionalHeader, /*uint32*/, SectionAlignment, offsetof(IMAGE_OPTIONAL_HEADER, SectionAlignment)) +CDAC_TYPE_END(ImageOptionalHeader) + +CDAC_TYPE_BEGIN(ImageSectionHeader) +CDAC_TYPE_SIZE(sizeof(IMAGE_SECTION_HEADER)) +CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, VirtualAddress, offsetof(IMAGE_SECTION_HEADER, VirtualAddress)) +CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, VirtualSize, offsetof(IMAGE_SECTION_HEADER, Misc.VirtualSize)) +CDAC_TYPE_FIELD(ImageSectionHeader, /*uint32*/, PointerToRawData, offsetof(IMAGE_SECTION_HEADER, PointerToRawData)) +CDAC_TYPE_END(ImageSectionHeader) + +CDAC_TYPE_BEGIN(ImageDosHeader) +CDAC_TYPE_INDETERMINATE(ImageDosHeader) +CDAC_TYPE_FIELD(ImageDosHeader, /*uint32*/, Lfanew, offsetof(IMAGE_DOS_HEADER, e_lfanew)) +CDAC_TYPE_END(ImageDosHeader) + CDAC_TYPE_BEGIN(CGrowableSymbolStream) CDAC_TYPE_INDETERMINATE(CGrowableSymbolStream) CDAC_TYPE_FIELD(CGrowableSymbolStream, /*pointer*/, Buffer, cdac_data::Buffer) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 8822dfee7ba384..8151ebe20a65d7 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -84,6 +84,7 @@ public interface ILoader : IContract TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetPEAssembly(ModuleHandle handle) => throw new NotImplementedException(); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags) => throw new NotImplementedException(); + TargetPointer GetILAddr(TargetPointer peAssemblyPtr, int rva) => throw new NotImplementedException(); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size) => throw new NotImplementedException(); IEnumerable GetAvailableTypeParams(ModuleHandle handle) => throw new NotImplementedException(); IEnumerable GetInstantiatedMethods(ModuleHandle handle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 0a8ddc1b5cf24a..08e09ee8a89809 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -39,6 +39,11 @@ public enum DataType AssemblyBinder, PEImage, PEImageLayout, + ImageFileHeader, + ImageNTHeaders, + ImageOptionalHeader, + ImageSectionHeader, + ImageDosHeader, CGrowableSymbolStream, ProbeExtensionResult, MethodTable, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 2d2562625e4688..e856f61fac189e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -37,6 +37,10 @@ private enum ModuleFlags_1 : uint BeingUnloaded = 0x100000, } + private enum PEImageFlags : uint + { + FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout) + }; private readonly Target _target; internal Loader_1(Target target) @@ -196,6 +200,76 @@ bool ILoader.TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer ba return true; } + private static uint AlignUp(uint value, uint alignment) + { + if (alignment == 0) + throw new ArgumentException("Alignment must be greater than zero.", nameof(alignment)); + return (value + alignment - 1) & ~(alignment - 1); + } + + private static bool IsMapped(Data.PEImageLayout peImageLayout) + { + return (peImageLayout.Flags & (uint)PEImageFlags.FLAG_MAPPED) != 0; + } + + private TargetPointer FindNTHeaders(Data.PEImageLayout imageLayout) + { + Data.ImageDosHeader dosHeader = _target.ProcessedData.GetOrAdd(imageLayout.Base); + return imageLayout.Base + (uint)dosHeader.Lfanew; + } + + private TargetPointer RvaToSection(int rva, Data.PEImageLayout imageLayout) + { + TargetPointer ntHeadersPtr = FindNTHeaders(imageLayout); + Data.ImageNTHeaders ntHeaders = _target.ProcessedData.GetOrAdd(ntHeadersPtr); + Target.TypeInfo type = _target.GetTypeInfo(DataType.ImageNTHeaders); + int offset = type.Fields[nameof(Data.ImageNTHeaders.OptionalHeader)].Offset; + TargetPointer section = ntHeadersPtr + (uint)offset + ntHeaders.FileHeader.SizeOfOptionalHeader; + TargetPointer sectionEnd = section + _target.GetTypeInfo(DataType.ImageSectionHeader).Size!.Value * ntHeaders.FileHeader.NumberOfSections; + uint sectionAlignment = ntHeaders.OptionalHeader.SectionAlignment; + while (section < sectionEnd) + { + Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd(section); + if (rva < sectionHeader.VirtualAddress + AlignUp(sectionHeader.VirtualSize, sectionAlignment)) + { + if (rva < sectionHeader.VirtualAddress) + return TargetPointer.Null; + else + return section; + } + section += _target.GetTypeInfo(DataType.ImageSectionHeader).Size!.Value; + } + return TargetPointer.Null; + } + + private uint RvaToOffset(int rva, Data.PEImageLayout imageLayout) + { + TargetPointer section = RvaToSection(rva, imageLayout); + if (section == TargetPointer.Null) + return (uint)rva; + + Data.ImageSectionHeader sectionHeader = _target.ProcessedData.GetOrAdd(section); + uint offset = (uint)(rva - sectionHeader.VirtualAddress) + sectionHeader.PointerToRawData; + return offset; + } + + TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva) + { + Data.PEAssembly assembly = _target.ProcessedData.GetOrAdd(peAssemblyPtr); + if (assembly.PEImage == TargetPointer.Null) + throw new InvalidOperationException("PEAssembly does not have a PEImage associated with it."); + Data.PEImage peImage = _target.ProcessedData.GetOrAdd(assembly.PEImage); + if (peImage.LoadedImageLayout == TargetPointer.Null) + throw new InvalidOperationException("PEImage does not have a LoadedImageLayout associated with it."); + Data.PEImageLayout peImageLayout = _target.ProcessedData.GetOrAdd(peImage.LoadedImageLayout); + uint offset; + if (IsMapped(peImageLayout)) + offset = (uint)rva; + else + offset = RvaToOffset(rva, peImageLayout); + return peImageLayout.Base + offset; + } + bool ILoader.TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size) { buffer = TargetPointer.Null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageDosHeader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageDosHeader.cs new file mode 100644 index 00000000000000..f506ffa3685b29 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageDosHeader.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ImageDosHeader : IData +{ + static ImageDosHeader IData.Create(Target target, TargetPointer address) + => new ImageDosHeader(target, address); + + public ImageDosHeader(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ImageDosHeader); + Lfanew = target.Read(address + (ulong)type.Fields[nameof(Lfanew)].Offset); + } + public int Lfanew { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageFileHeader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageFileHeader.cs new file mode 100644 index 00000000000000..6c03dbac1166d1 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageFileHeader.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ImageFileHeader : IData +{ + static ImageFileHeader IData.Create(Target target, TargetPointer address) => new ImageFileHeader(target, address); + public ImageFileHeader(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ImageFileHeader); + NumberOfSections = target.Read(address + (ulong)type.Fields[nameof(NumberOfSections)].Offset); + SizeOfOptionalHeader = target.Read(address + (ulong)type.Fields[nameof(SizeOfOptionalHeader)].Offset); + } + public ushort NumberOfSections { get; init; } + public ushort SizeOfOptionalHeader { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageNTHeaders.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageNTHeaders.cs new file mode 100644 index 00000000000000..1985cfd8704601 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageNTHeaders.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ImageNTHeaders : IData +{ + static ImageNTHeaders IData.Create(Target target, TargetPointer address) => new ImageNTHeaders(target, address); + public ImageNTHeaders(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ImageNTHeaders); + OptionalHeader = target.ProcessedData.GetOrAdd(address + (ulong)type.Fields[nameof(OptionalHeader)].Offset); + FileHeader = target.ProcessedData.GetOrAdd(address + (ulong)type.Fields[nameof(FileHeader)].Offset); + } + + public ImageOptionalHeader OptionalHeader { get; init; } + public ImageFileHeader FileHeader { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageOptionalHeader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageOptionalHeader.cs new file mode 100644 index 00000000000000..9a82411dd3e820 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageOptionalHeader.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ImageOptionalHeader : IData +{ + static ImageOptionalHeader IData.Create(Target target, TargetPointer address) => new ImageOptionalHeader(target, address); + public ImageOptionalHeader(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ImageOptionalHeader); + SectionAlignment = target.Read(address + (ulong)type.Fields[nameof(SectionAlignment)].Offset); + } + public uint SectionAlignment { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageSectionHeader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageSectionHeader.cs new file mode 100644 index 00000000000000..af91d83a1e9b7b --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ImageSectionHeader.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class ImageSectionHeader : IData +{ + static ImageSectionHeader IData.Create(Target target, TargetPointer address) => new ImageSectionHeader(target, address); + public ImageSectionHeader(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.ImageSectionHeader); + + VirtualSize = target.Read(address + (ulong)type.Fields[nameof(VirtualSize)].Offset); + VirtualAddress = target.Read(address + (ulong)type.Fields[nameof(VirtualAddress)].Offset); + PointerToRawData = target.Read(address + (ulong)type.Fields[nameof(PointerToRawData)].Offset); + } + + public uint VirtualSize { get; init; } + public uint VirtualAddress { get; init; } + public uint PointerToRawData { get; init; } +} diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index b1cc4cc1ac9d24..ee1a092abd805a 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -663,7 +663,43 @@ int ISOSDacInterface.GetHillClimbingLogEntry(ClrDataAddress addr, void* data) return hr; } int ISOSDacInterface.GetILForModule(ClrDataAddress moduleAddr, int rva, ClrDataAddress* il) - => _legacyImpl is not null ? _legacyImpl.GetILForModule(moduleAddr, rva, il) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + if (moduleAddr == 0 || il == null) + { + hr = HResults.E_INVALIDARG; + } + else if (rva == 0) + *il = 0; + else + { + try + { + Contracts.ILoader loader = _target.Contracts.Loader; + TargetPointer module = moduleAddr.ToTargetPointer(_target); + Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(module); + TargetPointer peAssemblyPtr = loader.GetPEAssembly(moduleHandle); + *il = loader.GetILAddr(peAssemblyPtr, rva).ToClrDataAddress(_target); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } + } +#if DEBUG + if (_legacyImpl is not null) + { + ClrDataAddress ilLocal; + int hrLocal = _legacyImpl.GetILForModule(moduleAddr, rva, &ilLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK) + { + Debug.Assert(*il == ilLocal, $"cDAC: {*il:x}, DAC: {ilLocal:x}"); + } + } +#endif + return hr; + } int ISOSDacInterface.GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded) => _legacyImpl is not null ? _legacyImpl.GetJitHelperFunctionName(ip, count, name, pNeeded) : HResults.E_NOTIMPL; int ISOSDacInterface.GetJitManagerList(uint count, void* managers, uint* pNeeded)