Browse Source

Support disassembling ReadyToRun binaries compiled using composite mode

pull/2944/head
Andrew Au 2 years ago
parent
commit
cc87b00109
  1. 2
      ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
  2. 9
      ILSpy.ReadyToRun/ReadyToRunDisassembler.cs
  3. 84
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs
  4. 2
      NuGet.config

2
ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

@ -38,7 +38,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Iced" Version="1.18.0" /> <PackageReference Include="Iced" Version="1.18.0" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun.Experimental" Version="7.0.4-servicing.23115.8" /> <PackageReference Include="ILCompiler.Reflection.ReadyToRun.Experimental" Version="8.0.0-preview.4.23202.2" />
<!-- ILCompiler.Reflection.ReadyToRun has dependencies on System.Reflection.Metadata and <!-- ILCompiler.Reflection.ReadyToRun has dependencies on System.Reflection.Metadata and
System.Runtime.CompilerServices.Unsafe. Because the AddIn compiles into ILSpy's output System.Runtime.CompilerServices.Unsafe. Because the AddIn compiles into ILSpy's output
directory, we're at risk of overwriting our dependencies with different versions. directory, we're at risk of overwriting our dependencies with different versions.

9
ILSpy.ReadyToRun/ReadyToRunDisassembler.cs

@ -137,8 +137,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
output.Write(tempOutput.ToStringAndReset()); output.Write(tempOutput.ToStringAndReset());
DecorateUnwindInfo(unwindInfo, baseInstrIP, instr); DecorateUnwindInfo(unwindInfo, baseInstrIP, instr);
DecorateDebugInfo(instr, debugInfo, baseInstrIP); DecorateDebugInfo(instr, debugInfo, baseInstrIP);
DecorateCallSite(currentFile, showMetadataTokens, showMetadataTokensInBase10, instr); DecorateCallSite(currentFile, showMetadataTokens, showMetadataTokensInBase10, instr);
output.WriteLine();
} }
output.WriteLine(); output.WriteLine();
} }
@ -451,16 +451,11 @@ namespace ICSharpCode.ILSpy.ReadyToRun
methodRefToken.WriteTo(currentFile, output, default); methodRefToken.WriteTo(currentFile, output, default);
break; break;
default: default:
output.WriteLine(reader.ImportSignatures[importCellAddress].ToString(new SignatureFormattingOptions())); output.Write(reader.ImportSignatures[importCellAddress].ToString(new SignatureFormattingOptions()));
break; break;
} }
output.WriteLine();
} }
} }
else
{
output.WriteLine();
}
} }
} }
} }

84
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -22,6 +22,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
@ -121,10 +122,13 @@ namespace ICSharpCode.ILSpy.ReadyToRun
else else
{ {
ReadyToRunReader reader = cacheEntry.readyToRunReader; ReadyToRunReader reader = cacheEntry.readyToRunReader;
WriteCommentLine(output, reader.Machine.ToString()); WriteCommentLine(output, $"Machine : {reader.Machine}");
WriteCommentLine(output, reader.OperatingSystem.ToString()); WriteCommentLine(output, $"OperatingSystem : {reader.OperatingSystem}");
WriteCommentLine(output, reader.CompilerIdentifier); WriteCommentLine(output, $"CompilerIdentifier : {reader.CompilerIdentifier}");
WriteCommentLine(output, "TODO - display more header information"); if (reader.OwnerCompositeExecutable != null)
{
WriteCommentLine(output, $"OwnerCompositeExecutable : {reader.OwnerCompositeExecutable}");
}
} }
return base.DecompileAssembly(assembly, output, options); return base.DecompileAssembly(assembly, output, options);
@ -153,9 +157,22 @@ namespace ICSharpCode.ILSpy.ReadyToRun
} }
if (cacheEntry.methodMap == null) if (cacheEntry.methodMap == null)
{ {
cacheEntry.methodMap = reader.Methods.ToList() IEnumerable<ReadyToRunMethod> readyToRunMethods = null;
.GroupBy(m => m.MethodHandle) if (cacheEntry.compositeReadyToRunReader == null)
.ToDictionary(g => g.Key, g => g.ToArray()); {
readyToRunMethods = reader.Methods;
}
else
{
readyToRunMethods = cacheEntry.compositeReadyToRunReader.Methods
.Where(m => {
MetadataReader mr = m.ComponentReader.MetadataReader;
return string.Equals(mr.GetString(mr.GetAssemblyDefinition().Name), method.ParentModule.Name, StringComparison.OrdinalIgnoreCase);
});
}
cacheEntry.methodMap = readyToRunMethods.ToList()
.GroupBy(m => m.MethodHandle)
.ToDictionary(g => g.Key, g => g.ToArray());
} }
var displaySettings = MainWindow.Instance.CurrentDisplaySettings; var displaySettings = MainWindow.Instance.CurrentDisplaySettings;
bool showMetadataTokens = displaySettings.ShowMetadataTokens; bool showMetadataTokens = displaySettings.ShowMetadataTokens;
@ -174,7 +191,20 @@ namespace ICSharpCode.ILSpy.ReadyToRun
#endif #endif
foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions) foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions)
{ {
new ReadyToRunDisassembler(output, reader, runtimeFunction).Disassemble(method.ParentModule.PEFile, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10); PEFile file = null;
ReadyToRunReader disassemblingReader = null;
if (cacheEntry.compositeReadyToRunReader == null)
{
disassemblingReader = reader;
file = method.ParentModule.PEFile;
}
else
{
disassemblingReader = cacheEntry.compositeReadyToRunReader;
file = ((IlSpyAssemblyMetadata)readyToRunMethod.ComponentReader).Module;
}
new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10);
} }
} }
} }
@ -206,6 +236,11 @@ namespace ICSharpCode.ILSpy.ReadyToRun
result.failureReason = $"Architecture {result.readyToRunReader.Machine} is not currently supported."; result.failureReason = $"Architecture {result.readyToRunReader.Machine} is not currently supported.";
result.readyToRunReader = null; result.readyToRunReader = null;
} }
else if (result.readyToRunReader.OwnerCompositeExecutable != null)
{
string compositePath = Path.Combine(Path.GetDirectoryName(module.FileName), result.readyToRunReader.OwnerCompositeExecutable);
result.compositeReadyToRunReader = new ReadyToRunReader(new ReadyToRunAssemblyResolver(assembly), compositePath);
}
} }
catch (BadImageFormatException e) catch (BadImageFormatException e)
{ {
@ -219,31 +254,52 @@ namespace ICSharpCode.ILSpy.ReadyToRun
private class ReadyToRunAssemblyResolver : ILCompiler.Reflection.ReadyToRun.IAssemblyResolver private class ReadyToRunAssemblyResolver : ILCompiler.Reflection.ReadyToRun.IAssemblyResolver
{ {
private LoadedAssembly loadedAssembly;
private Decompiler.Metadata.IAssemblyResolver assemblyResolver; private Decompiler.Metadata.IAssemblyResolver assemblyResolver;
public ReadyToRunAssemblyResolver(LoadedAssembly loadedAssembly) public ReadyToRunAssemblyResolver(LoadedAssembly loadedAssembly)
{ {
this.loadedAssembly = loadedAssembly;
assemblyResolver = loadedAssembly.GetAssemblyResolver(); assemblyResolver = loadedAssembly.GetAssemblyResolver();
} }
public IAssemblyMetadata FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile) public IAssemblyMetadata FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile)
{ {
PEFile module = assemblyResolver.Resolve(new Decompiler.Metadata.AssemblyReference(metadataReader, assemblyReferenceHandle)); return GetAssemblyMetadata(assemblyResolver.Resolve(new Decompiler.Metadata.AssemblyReference(metadataReader, assemblyReferenceHandle)));
PEReader reader = module?.Reader;
return reader == null ? null : new StandaloneAssemblyMetadata(reader);
} }
public IAssemblyMetadata FindAssembly(string simpleName, string parentFile) public IAssemblyMetadata FindAssembly(string simpleName, string parentFile)
{ {
// This is called only for the composite R2R scenario, return GetAssemblyMetadata(assemblyResolver.ResolveModule(loadedAssembly.GetPEFileOrNull(), simpleName + ".dll"));
// So it will never be called before the feature is released. }
throw new NotSupportedException("Composite R2R format is not currently supported");
private IAssemblyMetadata GetAssemblyMetadata(PEFile module)
{
if (module.Reader == null)
{
return null;
}
else
{
return new IlSpyAssemblyMetadata(module);
}
}
}
private class IlSpyAssemblyMetadata : StandaloneAssemblyMetadata
{
public PEFile Module { get; private set; }
public IlSpyAssemblyMetadata(PEFile module) : base(module.Reader)
{
Module = module;
} }
} }
private class ReadyToRunReaderCacheEntry private class ReadyToRunReaderCacheEntry
{ {
public ReadyToRunReader readyToRunReader; public ReadyToRunReader readyToRunReader;
public ReadyToRunReader compositeReadyToRunReader;
public string failureReason; public string failureReason;
public Dictionary<EntityHandle, ReadyToRunMethod[]> methodMap; public Dictionary<EntityHandle, ReadyToRunMethod[]> methodMap;
} }

2
NuGet.config

@ -3,6 +3,6 @@
<packageSources> <packageSources>
<add key="Nuget Official" value="https://api.nuget.org/v3/index.json" /> <add key="Nuget Official" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" /> <add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="dotnet7-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7-transport/nuget/v3/index.json" /> <add key="dotnet8-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json" />
</packageSources> </packageSources>
</configuration> </configuration>

Loading…
Cancel
Save