}
}
- public class EcmaMetadataReader
+ public sealed class R2RReader
{
- protected IAssemblyResolver _assemblyResolver;
- protected Dictionary<string, EcmaMetadataReader> _assemblyCache;
-
+ private IAssemblyResolver _assemblyResolver;
+ private Dictionary<int, MetadataReader> _assemblyCache;
+ private Dictionary<int, DebugInfo> _runtimeFunctionToDebugInfo;
+ private MetadataReader _manifestReader;
+ private List<AssemblyReferenceHandle> _manifestReferences;
/// <summary>
/// Underlying PE image reader is used to access raw PE structures like header
/// or section list.
/// </summary>
- public readonly PEReader PEReader;
+ public PEReader PEReader { get; private set; }
/// <summary>
/// MetadataReader is used to access the MSIL metadata in the R2R file.
/// </summary>
- public readonly MetadataReader MetadataReader;
-
- /// <summary>
- /// Extra reference assemblies parsed from the manifest metadata.
- /// Only used by R2R assemblies with larger version bubble.
- /// The manifest contains extra assembly references created by resolved
- /// inlines and facades (non-existent in the source MSIL).
- /// In module overrides, these assembly references are represented
- /// by indices larger than the number of AssemblyRef rows in MetadataReader.
- /// The list originates in the top-level R2R image and is copied
- /// to all reference assemblies for the sake of simplicity.
- /// </summary>
- public readonly List<string> ManifestReferenceAssemblies;
+ public MetadataReader MetadataReader { get; private set; }
/// <summary>
/// Byte array containing the ReadyToRun image
/// </summary>
- public byte[] Image { get; }
+ public byte[] Image { get; private set; }
/// <summary>
/// Name of the image file
/// </summary>
- public string Filename { get; set; }
+ public string Filename { get; private set; }
/// <summary>
- /// The default constructor initializes an empty metadata reader.
- /// </summary>
- public EcmaMetadataReader()
- {
- }
-
- public EcmaMetadataReader(IAssemblyResolver assemblyResolver, MetadataReader metadata, PEReader peReader, string filename, List<string> manifestReferenceAssemblies)
- {
- _assemblyResolver = assemblyResolver;
- _assemblyCache = new Dictionary<string, EcmaMetadataReader>();
- MetadataReader = metadata;
- PEReader = peReader;
- ImmutableArray<byte> content = peReader.GetEntireImage().GetContent();
- // TODO: Avoid copying
- Image = new byte[content.Length];
- content.CopyTo(Image);
- Filename = filename;
- ManifestReferenceAssemblies = manifestReferenceAssemblies;
- }
-
- /// <summary>
- /// Open an MSIL binary and locate the metadata blob.
+ /// Extra reference assemblies parsed from the manifest metadata.
+ /// Only used by R2R assemblies with larger version bubble.
+ /// The manifest contains extra assembly references created by resolved
+ /// inlines and facades (non-existent in the source MSIL).
+ /// In module overrides, these assembly references are represented
+ /// by indices larger than the number of AssemblyRef rows in MetadataReader.
+ /// The list originates in the top-level R2R image and is copied
+ /// to all reference assemblies for the sake of simplicity.
/// </summary>
- /// <param name="options">Ambient options to use</param>
- /// <param name="filename">PE image</param>
- /// <param name="manifestReferenceAssemblies">List of reference assemblies from the R2R metadata manifest</param>
- /// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
- public unsafe EcmaMetadataReader(IAssemblyResolver assemblyResolver, string filename, List<string> manifestReferenceAssemblies)
+ public IEnumerable<string> ManifestReferenceAssemblies
{
- _assemblyResolver = assemblyResolver;
- _assemblyCache = new Dictionary<string, EcmaMetadataReader>();
- Filename = filename;
- ManifestReferenceAssemblies = manifestReferenceAssemblies;
- Image = File.ReadAllBytes(filename);
-
- fixed (byte* p = Image)
+ get
{
- IntPtr ptr = (IntPtr)p;
- PEReader = new PEReader(p, Image.Length);
-
- if (!PEReader.HasMetadata)
+ foreach (AssemblyReferenceHandle _manifestReference in _manifestReferences)
{
- throw new Exception($"ECMA metadata not found in file '{filename}'");
+ yield return _manifestReader.GetString(_manifestReader.GetAssemblyReference(_manifestReference).Name);
}
-
- MetadataReader = PEReader.GetMetadataReader();
}
}
/// <summary>
- /// Open a given reference assembly (relative to this ECMA metadata file).
- /// </summary>
- /// <param name="refAsmIndex">Reference assembly index</param>
- /// <returns>EcmaMetadataReader instance representing the reference assembly</returns>
- public EcmaMetadataReader OpenReferenceAssembly(int refAsmIndex)
- {
- if (refAsmIndex == 0)
- {
- return this;
- }
-
- int assemblyRefCount = MetadataReader.GetTableRowCount(TableIndex.AssemblyRef);
- string name;
- if (refAsmIndex <= assemblyRefCount)
- {
- AssemblyReference asmRef = MetadataReader.GetAssemblyReference(MetadataTokens.AssemblyReferenceHandle(refAsmIndex));
- name = MetadataReader.GetString(asmRef.Name);
- }
- else
- {
- name = ManifestReferenceAssemblies[refAsmIndex - assemblyRefCount - 2];
- }
-
- EcmaMetadataReader ecmaReader;
- if (!_assemblyCache.TryGetValue(name, out ecmaReader))
- {
- string assemblyPath = _assemblyResolver.FindAssembly(name, Filename);
- if (assemblyPath == null)
- {
- throw new Exception($"Missing reference assembly: {name}");
- }
- ecmaReader = new EcmaMetadataReader(_assemblyResolver, assemblyPath, ManifestReferenceAssemblies);
- _assemblyCache.Add(name, ecmaReader);
- }
- return ecmaReader;
- }
- }
-
- public class R2RReader : EcmaMetadataReader
- {
- /// <summary>
- /// True if the image is ReadyToRun
- /// </summary>
- public bool IsR2R { get; set; }
-
- /// <summary>
/// The type of target machine
/// </summary>
public Machine Machine { get; set; }
/// </summary>
public Dictionary<int, string> ImportCellNames { get; private set; }
- private Dictionary<int, DebugInfo> _runtimeFunctionToDebugInfo = new Dictionary<int, DebugInfo>();
-
- public R2RReader() { }
-
/// <summary>
/// Initializes the fields of the R2RHeader and R2RMethods
/// </summary>
/// <param name="filename">PE image</param>
/// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
public R2RReader(IAssemblyResolver assemblyResolver, MetadataReader metadata, PEReader peReader, string filename)
- : base(assemblyResolver, metadata, peReader, filename, new List<string>())
{
+ _assemblyResolver = assemblyResolver;
+ MetadataReader = metadata;
+ PEReader = peReader;
+ Filename = filename;
Initialize();
}
/// </summary>
/// <param name="filename">PE image</param>
/// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
- public R2RReader(IAssemblyResolver assemblyResolver, string filename)
- : base(assemblyResolver, filename, new List<string>())
+ public unsafe R2RReader(IAssemblyResolver assemblyResolver, string filename)
{
+ _assemblyResolver = assemblyResolver;
+ Filename = filename;
Initialize();
}
private unsafe void Initialize()
{
- IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0);
- if (!IsR2R)
+ _assemblyCache = new Dictionary<int, MetadataReader>();
+ this._manifestReferences = new List<AssemblyReferenceHandle>();
+
+ if (MetadataReader == null)
+ {
+ Image = File.ReadAllBytes(Filename);
+
+ fixed (byte* p = Image)
+ {
+ IntPtr ptr = (IntPtr)p;
+ PEReader = new PEReader(p, Image.Length);
+
+ if (!PEReader.HasMetadata)
+ {
+ throw new Exception($"ECMA metadata not found in file '{Filename}'");
+ }
+
+ MetadataReader = PEReader.GetMetadataReader();
+ }
+ }
+ else
+ {
+ ImmutableArray<byte> content = PEReader.GetEntireImage().GetContent();
+ // TODO: Avoid copying
+ Image = new byte[content.Length];
+ content.CopyTo(Image);
+ }
+
+ ParseHeader();
+
+ ParseDebugInfo();
+
+ if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA))
+ {
+ R2RSection manifestMetadata = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA];
+ fixed (byte* image = Image)
+ {
+ _manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size);
+ int assemblyRefCount = _manifestReader.GetTableRowCount(TableIndex.AssemblyRef);
+ for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++)
+ {
+ AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
+ _manifestReferences.Add(asmRefHandle);
+ }
+ }
+ }
+
+ if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO))
+ {
+ R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
+ EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
+ }
+
+ ImportSections = new List<R2RImportSection>();
+ ImportCellNames = new Dictionary<int, string>();
+ ParseImportSections();
+
+ R2RMethods = new List<R2RMethod>();
+ InstanceMethods = new List<InstanceMethod>();
+
+ if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
+ {
+ int runtimeFunctionSize = CalculateRuntimeFunctionSize();
+ R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
+
+ uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
+ int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
+ bool[] isEntryPoint = new bool[nRuntimeFunctions];
+
+ // initialize R2RMethods
+ ParseMethodDefEntrypoints(isEntryPoint);
+ ParseInstanceMethodEntrypoints(isEntryPoint);
+ ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
+ }
+
+ AvailableTypes = new List<string>();
+ ParseAvailableTypes();
+
+ CompilerIdentifier = ParseCompilerIdentifier();
+ }
+
+ private unsafe void ParseHeader()
+ {
+ if ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) == 0)
{
throw new BadImageFormatException("The file is not a ReadyToRun image");
}
{
throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory");
}
-
- ParseDebugInfo();
-
- if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA))
- {
- R2RSection manifestMetadata = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_MANIFEST_METADATA];
- fixed (byte* image = Image)
- {
- MetadataReader manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size);
- int assemblyRefCount = manifestReader.GetTableRowCount(TableIndex.AssemblyRef);
- for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++)
- {
- AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
- AssemblyReference asmRef = manifestReader.GetAssemblyReference(asmRefHandle);
- string asmRefName = manifestReader.GetString(asmRef.Name);
- ManifestReferenceAssemblies.Add(asmRefName);
- }
- }
- }
-
- if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO))
- {
- R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
- EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
- }
-
- ImportSections = new List<R2RImportSection>();
- ImportCellNames = new Dictionary<int, string>();
- ParseImportSections();
-
- R2RMethods = new List<R2RMethod>();
- InstanceMethods = new List<InstanceMethod>();
-
- if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
- {
- int runtimeFunctionSize = CalculateRuntimeFunctionSize();
- R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
-
- uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
- int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
- bool[] isEntryPoint = new bool[nRuntimeFunctions];
-
- // initialize R2RMethods
- ParseMethodDefEntrypoints(isEntryPoint);
- ParseInstanceMethodEntrypoints(isEntryPoint);
- ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
- }
-
- AvailableTypes = new List<string>();
- ParseAvailableTypes();
-
- CompilerIdentifier = ParseCompilerIdentifier();
}
public bool InputArchitectureSupported()
private void ParseDebugInfo()
{
+ _runtimeFunctionToDebugInfo = new Dictionary<int, DebugInfo>();
if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_DEBUG_INFO))
{
return;
/// <summary>
/// Get the full name of an ExportedType, including namespace
/// </summary>
- public static string GetExportedTypeFullName(MetadataReader mdReader, ExportedTypeHandle handle)
+ private static string GetExportedTypeFullName(MetadataReader mdReader, ExportedTypeHandle handle)
{
string typeNamespace = "";
string typeStr = "";
return cells.ToArray();
}
+
+ /// <summary>
+ /// Open a given reference assembly (relative to this ECMA metadata file).
+ /// </summary>
+ /// <param name="refAsmIndex">Reference assembly index</param>
+ /// <returns>MetadataReader instance representing the reference assembly</returns>
+ internal MetadataReader OpenReferenceAssembly(int refAsmIndex)
+ {
+ if (refAsmIndex == 0)
+ {
+ return this.MetadataReader;
+ }
+
+ int assemblyRefCount = MetadataReader.GetTableRowCount(TableIndex.AssemblyRef);
+ MetadataReader metadataReader;
+ AssemblyReferenceHandle assemblyReferenceHandle;
+ if (refAsmIndex <= assemblyRefCount)
+ {
+ metadataReader = MetadataReader;
+ assemblyReferenceHandle = MetadataTokens.AssemblyReferenceHandle(refAsmIndex);
+ }
+ else
+ {
+ metadataReader = _manifestReader;
+ assemblyReferenceHandle = _manifestReferences[refAsmIndex - assemblyRefCount - 2];
+ }
+
+
+ MetadataReader result;
+ if (!_assemblyCache.TryGetValue(refAsmIndex, out result))
+ {
+ result = _assemblyResolver.FindAssembly(metadataReader, assemblyReferenceHandle, Filename);
+ if (result == null)
+ {
+ string name = metadataReader.GetString(metadataReader.GetAssemblyReference(assemblyReferenceHandle).Name);
+ throw new Exception($"Missing reference assembly: {name}");
+ }
+ _assemblyCache.Add(refAsmIndex, result);
+ }
+ return result;
+ }
}
}
return formatter.EmitHandleName(handle, namespaceQualified, owningTypeOverride, signaturePrefix);
}
- public static string FormatSignature(IAssemblyResolver assemblyResolver, EcmaMetadataReader ecmaReader, int imageOffset)
+ public static string FormatSignature(IAssemblyResolver assemblyResolver, R2RReader r2rReader, int imageOffset)
{
- SignatureDecoder decoder = new SignatureDecoder(assemblyResolver, ecmaReader, imageOffset);
+ SignatureDecoder decoder = new SignatureDecoder(assemblyResolver, r2rReader, imageOffset);
string result = decoder.ReadR2RSignature();
return result;
}
/// <summary>
/// ECMA reader is used to access the embedded MSIL metadata blob in the R2R file.
/// </summary>
- private readonly EcmaMetadataReader _ecmaReader;
+ private readonly MetadataReader _metadataReader;
/// <summary>
/// ECMA reader representing the top-level signature context.
/// </summary>
- private readonly EcmaMetadataReader _contextReader;
+ private readonly R2RReader _contextReader;
/// <summary>
/// Dump options are used to specify details of signature formatting.
/// Construct the signature decoder by storing the image byte array and offset within the array.
/// </summary>
/// <param name="options">Dump options and paths</param>
- /// <param name="ecmaReader">EcmaMetadataReader object representing the PE file containing the ECMA metadata</param>
+ /// <param name="r2rReader">R2RReader object representing the PE file containing the ECMA metadata</param>
/// <param name="offset">Signature offset within the PE file byte array</param>
- public SignatureDecoder(IAssemblyResolver options, EcmaMetadataReader ecmaReader, int offset)
+ public SignatureDecoder(IAssemblyResolver options, R2RReader r2rReader, int offset)
{
- _ecmaReader = ecmaReader;
+ _metadataReader = r2rReader.MetadataReader;
_options = options;
- _image = ecmaReader.Image;
+ _image = r2rReader.Image;
_offset = offset;
- _contextReader = ecmaReader;
+ _contextReader = r2rReader;
}
/// <summary>
/// Construct the signature decoder by storing the image byte array and offset within the array.
/// </summary>
/// <param name="options">Dump options and paths</param>
- /// <param name="ecmaReader">Metadata reader for the R2R image</param>
+ /// <param name="metadataReader">Metadata reader for the R2R image</param>
/// <param name="signature">Signature to parse</param>
/// <param name="offset">Signature offset within the signature byte array</param>
/// <param name="contextReader">Top-level signature context reader</param>
- public SignatureDecoder(IAssemblyResolver options, EcmaMetadataReader ecmaReader, byte[] signature, int offset, EcmaMetadataReader contextReader)
+ private SignatureDecoder(IAssemblyResolver options, MetadataReader metadataReader, byte[] signature, int offset, R2RReader contextReader)
{
- _ecmaReader = ecmaReader;
+ _metadataReader = metadataReader;
_options = options;
_image = signature;
_offset = offset;
{
fixupType &= ~(uint)ReadyToRunFixupKind.ModuleOverride;
int moduleIndex = (int)ReadUIntAndEmitInlineSignatureBinary(builder);
- EcmaMetadataReader refAsmEcmaReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+ MetadataReader refAsmEcmaReader = _contextReader.OpenReferenceAssembly(moduleIndex);
moduleDecoder = new SignatureDecoder(_options, refAsmEcmaReader, _image, _offset, _contextReader);
}
case CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG:
{
int moduleIndex = (int)ReadUIntAndEmitInlineSignatureBinary(builder);
- EcmaMetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+ MetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
SignatureDecoder refAsmDecoder = new SignatureDecoder(_options, refAsmReader, _image, _offset, _contextReader);
refAsmDecoder.ParseType(builder);
_offset = refAsmDecoder.Offset;
ReadElementType();
int moduleIndex = (int)ReadUInt();
- EcmaMetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
+ MetadataReader refAsmReader = _contextReader.OpenReferenceAssembly(moduleIndex);
_offset = currentOffset;
- return refAsmReader.MetadataReader;
+ return refAsmReader;
}
return null;
}
StringBuilder signaturePrefixBuilder = new StringBuilder();
uint token = ReadTokenAndEmitInlineSignatureBinary(signaturePrefixBuilder);
builder.Append(MetadataNameFormatter.FormatHandle(
- _ecmaReader.MetadataReader,
+ _metadataReader,
MetadataTokens.Handle((int)token),
owningTypeOverride: null,
signaturePrefix: signaturePrefixBuilder.ToString()));
string owningTypeOverride = null;
if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0)
{
- SignatureDecoder owningTypeDecoder = new SignatureDecoder(_options, _ecmaReader, _image, _offset, _contextReader);
+ SignatureDecoder owningTypeDecoder = new SignatureDecoder(_options, _metadataReader, _image, _offset, _contextReader);
owningTypeOverride = owningTypeDecoder.ReadTypeSignatureNoEmit();
_offset = owningTypeDecoder._offset;
}
StringBuilder signaturePrefixBuilder = new StringBuilder();
uint methodDefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMethodDef;
builder.Append(MetadataNameFormatter.FormatHandle(
- _ecmaReader.MetadataReader,
+ _metadataReader,
MetadataTokens.Handle((int)methodDefToken),
namespaceQualified: true,
owningTypeOverride: owningTypeOverride,
StringBuilder signaturePrefixBuilder = new StringBuilder();
uint methodRefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMemberRef;
builder.Append(MetadataNameFormatter.FormatHandle(
- _ecmaReader.MetadataReader,
+ _metadataReader,
MetadataTokens.Handle((int)methodRefToken),
namespaceQualified: false,
owningTypeOverride: owningTypeOverride,
fieldToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtFieldDef;
}
builder.Append(MetadataNameFormatter.FormatHandle(
- _ecmaReader.MetadataReader,
+ _metadataReader,
MetadataTokens.Handle((int)fieldToken),
namespaceQualified: false,
owningTypeOverride: owningTypeOverride,
{
uint rid = ReadUIntAndEmitInlineSignatureBinary(builder);
UserStringHandle stringHandle = MetadataTokens.UserStringHandle((int)rid);
- builder.Append(_ecmaReader.MetadataReader.GetUserString(stringHandle));
+ builder.Append(_metadataReader.GetUserString(stringHandle));
}
}
}