Skip to content

Commit 29ccf6c

Browse files
Merge pull request #2944 from cshung/public/support-composite-mode
Support disassembling ReadyToRun binaries compiled using composite mode
2 parents 7514991 + cc87b00 commit 29ccf6c

File tree

4 files changed

+74
-23
lines changed

4 files changed

+74
-23
lines changed

ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

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

ILSpy.ReadyToRun/ReadyToRunDisassembler.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ public void Disassemble(PEFile currentFile, int bitness, ulong address, bool sho
137137
output.Write(tempOutput.ToStringAndReset());
138138
DecorateUnwindInfo(unwindInfo, baseInstrIP, instr);
139139
DecorateDebugInfo(instr, debugInfo, baseInstrIP);
140-
141140
DecorateCallSite(currentFile, showMetadataTokens, showMetadataTokensInBase10, instr);
141+
output.WriteLine();
142142
}
143143
output.WriteLine();
144144
}
@@ -451,16 +451,11 @@ private void DecorateCallSite(PEFile currentFile, bool showMetadataTokens, bool
451451
methodRefToken.WriteTo(currentFile, output, default);
452452
break;
453453
default:
454-
output.WriteLine(reader.ImportSignatures[importCellAddress].ToString(new SignatureFormattingOptions()));
454+
output.Write(reader.ImportSignatures[importCellAddress].ToString(new SignatureFormattingOptions()));
455455
break;
456456
}
457-
output.WriteLine();
458457
}
459458
}
460-
else
461-
{
462-
output.WriteLine();
463-
}
464459
}
465460
}
466461
}

ILSpy.ReadyToRun/ReadyToRunLanguage.cs

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Collections.Generic;
2323
using System.ComponentModel.Composition;
2424
using System.Diagnostics;
25+
using System.IO;
2526
using System.Linq;
2627
using System.Reflection.Metadata;
2728
using System.Reflection.PortableExecutable;
@@ -121,10 +122,13 @@ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput
121122
else
122123
{
123124
ReadyToRunReader reader = cacheEntry.readyToRunReader;
124-
WriteCommentLine(output, reader.Machine.ToString());
125-
WriteCommentLine(output, reader.OperatingSystem.ToString());
126-
WriteCommentLine(output, reader.CompilerIdentifier);
127-
WriteCommentLine(output, "TODO - display more header information");
125+
WriteCommentLine(output, $"Machine : {reader.Machine}");
126+
WriteCommentLine(output, $"OperatingSystem : {reader.OperatingSystem}");
127+
WriteCommentLine(output, $"CompilerIdentifier : {reader.CompilerIdentifier}");
128+
if (reader.OwnerCompositeExecutable != null)
129+
{
130+
WriteCommentLine(output, $"OwnerCompositeExecutable : {reader.OwnerCompositeExecutable}");
131+
}
128132
}
129133

130134
return base.DecompileAssembly(assembly, output, options);
@@ -153,9 +157,22 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi
153157
}
154158
if (cacheEntry.methodMap == null)
155159
{
156-
cacheEntry.methodMap = reader.Methods.ToList()
157-
.GroupBy(m => m.MethodHandle)
158-
.ToDictionary(g => g.Key, g => g.ToArray());
160+
IEnumerable<ReadyToRunMethod> readyToRunMethods = null;
161+
if (cacheEntry.compositeReadyToRunReader == null)
162+
{
163+
readyToRunMethods = reader.Methods;
164+
}
165+
else
166+
{
167+
readyToRunMethods = cacheEntry.compositeReadyToRunReader.Methods
168+
.Where(m => {
169+
MetadataReader mr = m.ComponentReader.MetadataReader;
170+
return string.Equals(mr.GetString(mr.GetAssemblyDefinition().Name), method.ParentModule.Name, StringComparison.OrdinalIgnoreCase);
171+
});
172+
}
173+
cacheEntry.methodMap = readyToRunMethods.ToList()
174+
.GroupBy(m => m.MethodHandle)
175+
.ToDictionary(g => g.Key, g => g.ToArray());
159176
}
160177
var displaySettings = MainWindow.Instance.CurrentDisplaySettings;
161178
bool showMetadataTokens = displaySettings.ShowMetadataTokens;
@@ -174,7 +191,20 @@ public override void DecompileMethod(IMethod method, ITextOutput output, Decompi
174191
#endif
175192
foreach (RuntimeFunction runtimeFunction in readyToRunMethod.RuntimeFunctions)
176193
{
177-
new ReadyToRunDisassembler(output, reader, runtimeFunction).Disassemble(method.ParentModule.PEFile, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10);
194+
PEFile file = null;
195+
ReadyToRunReader disassemblingReader = null;
196+
if (cacheEntry.compositeReadyToRunReader == null)
197+
{
198+
disassemblingReader = reader;
199+
file = method.ParentModule.PEFile;
200+
}
201+
else
202+
{
203+
disassemblingReader = cacheEntry.compositeReadyToRunReader;
204+
file = ((IlSpyAssemblyMetadata)readyToRunMethod.ComponentReader).Module;
205+
}
206+
207+
new ReadyToRunDisassembler(output, disassemblingReader, runtimeFunction).Disassemble(file, bitness, (ulong)runtimeFunction.StartAddress, showMetadataTokens, showMetadataTokensInBase10);
178208
}
179209
}
180210
}
@@ -206,6 +236,11 @@ private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, PEFile mod
206236
result.failureReason = $"Architecture {result.readyToRunReader.Machine} is not currently supported.";
207237
result.readyToRunReader = null;
208238
}
239+
else if (result.readyToRunReader.OwnerCompositeExecutable != null)
240+
{
241+
string compositePath = Path.Combine(Path.GetDirectoryName(module.FileName), result.readyToRunReader.OwnerCompositeExecutable);
242+
result.compositeReadyToRunReader = new ReadyToRunReader(new ReadyToRunAssemblyResolver(assembly), compositePath);
243+
}
209244
}
210245
catch (BadImageFormatException e)
211246
{
@@ -219,31 +254,52 @@ private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, PEFile mod
219254

220255
private class ReadyToRunAssemblyResolver : ILCompiler.Reflection.ReadyToRun.IAssemblyResolver
221256
{
257+
private LoadedAssembly loadedAssembly;
222258
private Decompiler.Metadata.IAssemblyResolver assemblyResolver;
223259

224260
public ReadyToRunAssemblyResolver(LoadedAssembly loadedAssembly)
225261
{
262+
this.loadedAssembly = loadedAssembly;
226263
assemblyResolver = loadedAssembly.GetAssemblyResolver();
227264
}
228265

229266
public IAssemblyMetadata FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile)
230267
{
231-
PEFile module = assemblyResolver.Resolve(new Decompiler.Metadata.AssemblyReference(metadataReader, assemblyReferenceHandle));
232-
PEReader reader = module?.Reader;
233-
return reader == null ? null : new StandaloneAssemblyMetadata(reader);
268+
return GetAssemblyMetadata(assemblyResolver.Resolve(new Decompiler.Metadata.AssemblyReference(metadataReader, assemblyReferenceHandle)));
234269
}
235270

236271
public IAssemblyMetadata FindAssembly(string simpleName, string parentFile)
237272
{
238-
// This is called only for the composite R2R scenario,
239-
// So it will never be called before the feature is released.
240-
throw new NotSupportedException("Composite R2R format is not currently supported");
273+
return GetAssemblyMetadata(assemblyResolver.ResolveModule(loadedAssembly.GetPEFileOrNull(), simpleName + ".dll"));
274+
}
275+
276+
private IAssemblyMetadata GetAssemblyMetadata(PEFile module)
277+
{
278+
if (module.Reader == null)
279+
{
280+
return null;
281+
}
282+
else
283+
{
284+
return new IlSpyAssemblyMetadata(module);
285+
}
286+
}
287+
}
288+
289+
private class IlSpyAssemblyMetadata : StandaloneAssemblyMetadata
290+
{
291+
public PEFile Module { get; private set; }
292+
293+
public IlSpyAssemblyMetadata(PEFile module) : base(module.Reader)
294+
{
295+
Module = module;
241296
}
242297
}
243298

244299
private class ReadyToRunReaderCacheEntry
245300
{
246301
public ReadyToRunReader readyToRunReader;
302+
public ReadyToRunReader compositeReadyToRunReader;
247303
public string failureReason;
248304
public Dictionary<EntityHandle, ReadyToRunMethod[]> methodMap;
249305
}

NuGet.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
<packageSources>
44
<add key="Nuget Official" value="https://api.nuget.org/v3/index.json" />
55
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
6-
<add key="dotnet7-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7-transport/nuget/v3/index.json" />
6+
<add key="dotnet8-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json" />
77
</packageSources>
88
</configuration>

0 commit comments

Comments
 (0)