summaryrefslogtreecommitdiff
path: root/src/tools/r2rdump/R2RReader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/r2rdump/R2RReader.cs')
-rw-r--r--src/tools/r2rdump/R2RReader.cs271
1 files changed, 181 insertions, 90 deletions
diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs
index 62bf8a1f7b..2574f4d988 100644
--- a/src/tools/r2rdump/R2RReader.cs
+++ b/src/tools/r2rdump/R2RReader.cs
@@ -75,7 +75,7 @@ namespace R2RDump
}
}
- public class R2RReader
+ public class EcmaMetadataReader
{
/// <summary>
/// Option are used to specify details of signature formatting.
@@ -94,6 +94,18 @@ namespace R2RDump
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;
+
+ /// <summary>
/// Byte array containing the ReadyToRun image
/// </summary>
public byte[] Image { get; }
@@ -104,6 +116,82 @@ namespace R2RDump
public string Filename { get; set; }
/// <summary>
+ /// The default constructor initializes an empty metadata reader.
+ /// </summary>
+ public EcmaMetadataReader()
+ {
+ }
+
+ /// <summary>
+ /// Open an MSIL binary and locate the metadata blob.
+ /// </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(DumpOptions options, string filename, List<string> manifestReferenceAssemblies)
+ {
+ Options = options;
+ Filename = filename;
+ ManifestReferenceAssemblies = manifestReferenceAssemblies;
+ 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();
+ }
+ }
+
+ /// <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 (!Options.AssemblyCache.TryGetValue(name, out ecmaReader))
+ {
+ string assemblyPath = Options.FindAssembly(name, Filename);
+ if (assemblyPath == null)
+ {
+ throw new Exception($"Missing reference assembly: {name}");
+ }
+ ecmaReader = new EcmaMetadataReader(Options, assemblyPath, ManifestReferenceAssemblies);
+ Options.AssemblyCache.Add(name, ecmaReader);
+ }
+ return ecmaReader;
+ }
+ }
+
+ public class R2RReader : EcmaMetadataReader
+ {
+ /// <summary>
/// True if the image is ReadyToRun
/// </summary>
public bool IsR2R { get; set; }
@@ -176,7 +264,7 @@ namespace R2RDump
private Dictionary<int, DebugInfo> _runtimeFunctionToDebugInfo = new Dictionary<int, DebugInfo>();
- public unsafe R2RReader() { }
+ public R2RReader() { }
/// <summary>
/// Initializes the fields of the R2RHeader and R2RMethods
@@ -184,118 +272,121 @@ namespace R2RDump
/// <param name="filename">PE image</param>
/// <exception cref="BadImageFormatException">The Cor header flag must be ILLibrary</exception>
public unsafe R2RReader(DumpOptions options, string filename)
+ : base(options, filename, new List<string>())
{
- Options = options;
- Filename = filename;
- Image = File.ReadAllBytes(filename);
-
- fixed (byte* p = Image)
+ IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0);
+ if (!IsR2R)
{
- IntPtr ptr = (IntPtr)p;
- PEReader = new PEReader(p, Image.Length);
+ throw new BadImageFormatException("The file is not a ReadyToRun image");
+ }
- IsR2R = ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) != 0);
- if (!IsR2R)
+ uint machine = (uint)PEReader.PEHeaders.CoffHeader.Machine;
+ OS = OperatingSystem.Unknown;
+ foreach (OperatingSystem os in Enum.GetValues(typeof(OperatingSystem)))
+ {
+ Machine = (Machine)(machine ^ (uint)os);
+ if (Enum.IsDefined(typeof(Machine), Machine))
{
- throw new BadImageFormatException("The file is not a ReadyToRun image");
+ OS = os;
+ break;
}
+ }
+ if (OS == OperatingSystem.Unknown)
+ {
+ throw new BadImageFormatException($"Invalid Machine: {machine}");
+ }
- uint machine = (uint)PEReader.PEHeaders.CoffHeader.Machine;
- OS = OperatingSystem.Unknown;
- foreach(OperatingSystem os in Enum.GetValues(typeof(OperatingSystem)))
- {
- Machine = (Machine)(machine ^ (uint)os);
- if (Enum.IsDefined(typeof(Machine), Machine))
- {
- OS = os;
- break;
- }
- }
- if (OS == OperatingSystem.Unknown)
- {
- throw new BadImageFormatException($"Invalid Machine: {machine}");
- }
+ switch (Machine)
+ {
+ case Machine.I386:
+ Architecture = Architecture.X86;
+ PointerSize = 4;
+ break;
- switch (Machine)
- {
- case Machine.I386:
- Architecture = Architecture.X86;
- PointerSize = 4;
- break;
+ case Machine.Amd64:
+ Architecture = Architecture.X64;
+ PointerSize = 8;
+ break;
- case Machine.Amd64:
- Architecture = Architecture.X64;
- PointerSize = 8;
- break;
+ case Machine.Arm:
+ case Machine.Thumb:
+ case Machine.ArmThumb2:
+ Architecture = Architecture.Arm;
+ PointerSize = 4;
+ break;
- case Machine.Arm:
- case Machine.Thumb:
- case Machine.ArmThumb2:
- Architecture = Architecture.Arm;
- PointerSize = 4;
- break;
+ case Machine.Arm64:
+ Architecture = Architecture.Arm64;
+ PointerSize = 8;
+ break;
- case Machine.Arm64:
- Architecture = Architecture.Arm64;
- PointerSize = 8;
- break;
+ default:
+ throw new NotImplementedException(Machine.ToString());
+ }
- default:
- throw new NotImplementedException(Machine.ToString());
- }
+ ImageBase = PEReader.PEHeaders.PEHeader.ImageBase;
- ImageBase = PEReader.PEHeaders.PEHeader.ImageBase;
+ // initialize R2RHeader
+ DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory;
+ int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress);
+ R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset);
+ if (r2rHeaderDirectory.Size != R2RHeader.Size)
+ {
+ throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory");
+ }
- // initialize R2RHeader
- DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory;
- int r2rHeaderOffset = GetOffset(r2rHeaderDirectory.RelativeVirtualAddress);
- R2RHeader = new R2RHeader(Image, r2rHeaderDirectory.RelativeVirtualAddress, r2rHeaderOffset);
- if (r2rHeaderDirectory.Size != R2RHeader.Size)
- {
- throw new BadImageFormatException("The calculated size of the R2RHeader doesn't match the size saved in the ManagedNativeHeaderDirectory");
- }
+ ParseDebugInfo();
- if (PEReader.HasMetadata)
+ 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 = PEReader.GetMetadataReader();
-
- ParseDebugInfo();
-
- if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO))
+ MetadataReader manifestReader = new MetadataReader(image + GetOffset(manifestMetadata.RelativeVirtualAddress), manifestMetadata.Size);
+ int assemblyRefCount = manifestReader.GetTableRowCount(TableIndex.AssemblyRef);
+ for (int assemblyRefIndex = 1; assemblyRefIndex <= assemblyRefCount; assemblyRefIndex++)
{
- R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
- EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
+ AssemblyReferenceHandle asmRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
+ AssemblyReference asmRef = manifestReader.GetAssemblyReference(asmRefHandle);
+ string asmRefName = manifestReader.GetString(asmRef.Name);
+ ManifestReferenceAssemblies.Add(asmRefName);
}
+ }
+ }
- 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_EXCEPTION_INFO))
+ {
+ R2RSection exceptionInfoSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_EXCEPTION_INFO];
+ EHLookupTable = new EHLookupTable(Image, GetOffset(exceptionInfoSection.RelativeVirtualAddress), exceptionInfoSection.Size);
+ }
- if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
- {
- int runtimeFunctionSize = CalculateRuntimeFunctionSize();
- R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
+ ImportSections = new List<R2RImportSection>();
+ ImportCellNames = new Dictionary<int, string>();
+ ParseImportSections();
- uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
- int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
- bool[] isEntryPoint = new bool[nRuntimeFunctions];
+ R2RMethods = new List<R2RMethod>();
+ InstanceMethods = new List<InstanceMethod>();
- // initialize R2RMethods
- ParseMethodDefEntrypoints(isEntryPoint);
- ParseInstanceMethodEntrypoints(isEntryPoint);
- ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
- }
+ if (R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS))
+ {
+ int runtimeFunctionSize = CalculateRuntimeFunctionSize();
+ R2RSection runtimeFunctionSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS];
- AvailableTypes = new List<string>();
- ParseAvailableTypes();
+ uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
+ int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
+ bool[] isEntryPoint = new bool[nRuntimeFunctions];
- CompilerIdentifier = ParseCompilerIdentifier();
- }
+ // initialize R2RMethods
+ ParseMethodDefEntrypoints(isEntryPoint);
+ ParseInstanceMethodEntrypoints(isEntryPoint);
+ ParseRuntimeFunctions(isEntryPoint, runtimeFunctionOffset, runtimeFunctionSize);
}
+
+ AvailableTypes = new List<string>();
+ ParseAvailableTypes();
+
+ CompilerIdentifier = ParseCompilerIdentifier();
}
public bool InputArchitectureSupported()
@@ -470,7 +561,7 @@ namespace R2RDump
{
Console.WriteLine($"Warning: Could not parse GC Info for method: {method.SignatureString}");
}
-
+
}
}
else if (Machine == Machine.I386)