Skip to content

Commit

Permalink
Merge pull request #3149 from icsharpcode/pdb+dmeta
Browse files Browse the repository at this point in the history
Support reading raw metadata blobs and Portable PDBs
  • Loading branch information
siegfriedpammer authored Jan 4, 2024
2 parents b5d2fd1 + c821063 commit 47ac132
Show file tree
Hide file tree
Showing 99 changed files with 1,276 additions and 1,361 deletions.
5 changes: 1 addition & 4 deletions ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
Expand All @@ -26,8 +25,6 @@
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;

using SRM = System.Reflection.Metadata;

namespace ICSharpCode.Decompiler.Disassembler
{
public enum ILNameSyntax
Expand Down Expand Up @@ -72,7 +69,7 @@ public static void WriteOffsetReference(ITextOutput writer, int? offset)
writer.WriteLocalReference(OffsetToString(offset.Value), offset);
}

public static void WriteTo(this SRM.ExceptionRegion exceptionHandler, Metadata.PEFile module, MetadataGenericContext context, ITextOutput writer)
public static void WriteTo(this ExceptionRegion exceptionHandler, MetadataFile module, MetadataGenericContext context, ITextOutput writer)
{
writer.Write(".try ");
WriteOffsetReference(writer, exceptionHandler.TryOffset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ namespace ICSharpCode.Decompiler.Disassembler
{
public class DisassemblerSignatureTypeProvider : ISignatureTypeProvider<Action<ILNameSyntax>, MetadataGenericContext>
{
readonly PEFile module;
readonly MetadataFile module;
readonly MetadataReader metadata;
readonly ITextOutput output;

public DisassemblerSignatureTypeProvider(PEFile module, ITextOutput output)
public DisassemblerSignatureTypeProvider(MetadataFile module, ITextOutput output)
{
this.module = module ?? throw new ArgumentNullException(nameof(module));
this.output = output ?? throw new ArgumentNullException(nameof(output));
Expand Down
14 changes: 7 additions & 7 deletions ICSharpCode.Decompiler/Disassembler/IEntityProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ namespace ICSharpCode.Decompiler.Disassembler
{
public interface IEntityProcessor
{
IReadOnlyCollection<InterfaceImplementationHandle> Process(PEFile module, IReadOnlyCollection<InterfaceImplementationHandle> items);
IReadOnlyCollection<InterfaceImplementationHandle> Process(MetadataFile module, IReadOnlyCollection<InterfaceImplementationHandle> items);

IReadOnlyCollection<TypeDefinitionHandle> Process(PEFile module, IReadOnlyCollection<TypeDefinitionHandle> items);
IReadOnlyCollection<TypeDefinitionHandle> Process(MetadataFile module, IReadOnlyCollection<TypeDefinitionHandle> items);

IReadOnlyCollection<MethodDefinitionHandle> Process(PEFile module, IReadOnlyCollection<MethodDefinitionHandle> items);
IReadOnlyCollection<MethodDefinitionHandle> Process(MetadataFile module, IReadOnlyCollection<MethodDefinitionHandle> items);

IReadOnlyCollection<PropertyDefinitionHandle> Process(PEFile module, IReadOnlyCollection<PropertyDefinitionHandle> items);
IReadOnlyCollection<PropertyDefinitionHandle> Process(MetadataFile module, IReadOnlyCollection<PropertyDefinitionHandle> items);

IReadOnlyCollection<EventDefinitionHandle> Process(PEFile module, IReadOnlyCollection<EventDefinitionHandle> items);
IReadOnlyCollection<EventDefinitionHandle> Process(MetadataFile module, IReadOnlyCollection<EventDefinitionHandle> items);

IReadOnlyCollection<FieldDefinitionHandle> Process(PEFile module, IReadOnlyCollection<FieldDefinitionHandle> items);
IReadOnlyCollection<FieldDefinitionHandle> Process(MetadataFile module, IReadOnlyCollection<FieldDefinitionHandle> items);

IReadOnlyCollection<CustomAttributeHandle> Process(PEFile module, IReadOnlyCollection<CustomAttributeHandle> items);
IReadOnlyCollection<CustomAttributeHandle> Process(MetadataFile module, IReadOnlyCollection<CustomAttributeHandle> items);
}
}
28 changes: 14 additions & 14 deletions ICSharpCode.Decompiler/Disassembler/SortByNameProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,52 +30,52 @@ namespace ICSharpCode.Decompiler.Disassembler
{
public class SortByNameProcessor : IEntityProcessor
{
public IReadOnlyCollection<InterfaceImplementationHandle> Process(PEFile module,
public IReadOnlyCollection<InterfaceImplementationHandle> Process(MetadataFile module,
IReadOnlyCollection<InterfaceImplementationHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<TypeDefinitionHandle> Process(PEFile module,
public IReadOnlyCollection<TypeDefinitionHandle> Process(MetadataFile module,
IReadOnlyCollection<TypeDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<MethodDefinitionHandle> Process(PEFile module,
public IReadOnlyCollection<MethodDefinitionHandle> Process(MetadataFile module,
IReadOnlyCollection<MethodDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<PropertyDefinitionHandle> Process(PEFile module,
public IReadOnlyCollection<PropertyDefinitionHandle> Process(MetadataFile module,
IReadOnlyCollection<PropertyDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<EventDefinitionHandle> Process(PEFile module,
public IReadOnlyCollection<EventDefinitionHandle> Process(MetadataFile module,
IReadOnlyCollection<EventDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<FieldDefinitionHandle> Process(PEFile module,
public IReadOnlyCollection<FieldDefinitionHandle> Process(MetadataFile module,
IReadOnlyCollection<FieldDefinitionHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

public IReadOnlyCollection<CustomAttributeHandle> Process(PEFile module,
public IReadOnlyCollection<CustomAttributeHandle> Process(MetadataFile module,
IReadOnlyCollection<CustomAttributeHandle> items)
{
return items.OrderBy(item => GetSortKey(item, module)).ToArray();
}

private static string GetSortKey(TypeDefinitionHandle handle, PEFile module) =>
private static string GetSortKey(TypeDefinitionHandle handle, MetadataFile module) =>
handle.GetFullTypeName(module.Metadata).ToILNameString();

private static string GetSortKey(MethodDefinitionHandle handle, PEFile module)
private static string GetSortKey(MethodDefinitionHandle handle, MetadataFile module)
{
PlainTextOutput output = new PlainTextOutput();
MethodDefinition definition = module.Metadata.GetMethodDefinition(handle);
Expand All @@ -97,22 +97,22 @@ private static string GetSortKey(MethodDefinitionHandle handle, PEFile module)
return output.ToString();
}

private static string GetSortKey(InterfaceImplementationHandle handle, PEFile module) =>
private static string GetSortKey(InterfaceImplementationHandle handle, MetadataFile module) =>
module.Metadata.GetInterfaceImplementation(handle)
.Interface
.GetFullTypeName(module.Metadata)
.ToILNameString();

private static string GetSortKey(FieldDefinitionHandle handle, PEFile module) =>
private static string GetSortKey(FieldDefinitionHandle handle, MetadataFile module) =>
module.Metadata.GetString(module.Metadata.GetFieldDefinition(handle).Name);

private static string GetSortKey(PropertyDefinitionHandle handle, PEFile module) =>
private static string GetSortKey(PropertyDefinitionHandle handle, MetadataFile module) =>
module.Metadata.GetString(module.Metadata.GetPropertyDefinition(handle).Name);

private static string GetSortKey(EventDefinitionHandle handle, PEFile module) =>
private static string GetSortKey(EventDefinitionHandle handle, MetadataFile module) =>
module.Metadata.GetString(module.Metadata.GetEventDefinition(handle).Name);

private static string GetSortKey(CustomAttributeHandle handle, PEFile module) =>
private static string GetSortKey(CustomAttributeHandle handle, MetadataFile module) =>
module.Metadata.GetCustomAttribute(handle)
.Constructor
.GetDeclaringType(module.Metadata)
Expand Down
26 changes: 13 additions & 13 deletions ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static void WriteTo(this Interval interval, ITextOutput output, ILAstWrit
output.Write($"[{interval.Start:x4}..{interval.InclusiveEnd:x4}] ");
}

public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput output, Metadata.MetadataGenericContext genericContext, ILNameSyntax syntax = ILNameSyntax.Signature)
public static void WriteTo(this EntityHandle entity, MetadataFile module, ITextOutput output, Metadata.MetadataGenericContext genericContext, ILNameSyntax syntax = ILNameSyntax.Signature)
{
if (entity.IsNil)
{
Expand Down Expand Up @@ -138,7 +138,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
case HandleKind.FieldDefinition:
{
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)entity);
signature = fd.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new Metadata.MetadataGenericContext(fd.GetDeclaringType(), module));
signature = fd.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new Metadata.MetadataGenericContext(fd.GetDeclaringType(), metadata));
signature(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
((EntityHandle)fd.GetDeclaringType()).WriteTo(module, output, default, ILNameSyntax.TypeName);
Expand All @@ -149,7 +149,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
case HandleKind.MethodDefinition:
{
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity);
methodSignature = md.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new Metadata.MetadataGenericContext((MethodDefinitionHandle)entity, module));
methodSignature = md.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new Metadata.MetadataGenericContext((MethodDefinitionHandle)entity, metadata));
methodSignature.Header.WriteTo(output);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
Expand Down Expand Up @@ -198,7 +198,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
if (j > 0)
output.Write(", ");
var constraint = metadata.GetGenericParameterConstraint(constraints[j]);
constraint.Type.WriteTo(module, output, new Metadata.MetadataGenericContext((MethodDefinitionHandle)entity, module), ILNameSyntax.TypeName);
constraint.Type.WriteTo(module, output, new Metadata.MetadataGenericContext((MethodDefinitionHandle)entity, metadata), ILNameSyntax.TypeName);
}
output.Write(") ");
}
Expand Down Expand Up @@ -227,7 +227,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
methodSignature.Header.WriteTo(output);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
WriteParent(output, module, mr.Parent, genericContext, syntax);
output.Write("::");
output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName));
WriteParameterList(output, methodSignature);
Expand All @@ -236,7 +236,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
var fieldSignature = mr.DecodeFieldSignature(new DisassemblerSignatureTypeProvider(module, output), genericContext);
fieldSignature(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
WriteParent(output, module, mr.Parent, genericContext, syntax);
output.Write("::");
output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName));
break;
Expand Down Expand Up @@ -279,7 +279,7 @@ public static void WriteTo(this EntityHandle entity, PEFile module, ITextOutput
methodSignature.Header.WriteTo(output);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
WriteParent(output, module, metadata, memberReference.Parent, genericContext, syntax);
WriteParent(output, module, memberReference.Parent, genericContext, syntax);
output.Write("::");
output.Write(DisassemblerHelpers.Escape(memberName));
WriteTypeParameterList(output, syntax, substitution);
Expand Down Expand Up @@ -352,24 +352,24 @@ internal static void WriteTo(this in SignatureHeader header, ITextOutput output)
}
}

static void WriteParent(ITextOutput output, PEFile module, MetadataReader metadata, EntityHandle parentHandle, Metadata.MetadataGenericContext genericContext, ILNameSyntax syntax)
static void WriteParent(ITextOutput output, MetadataFile metadataFile, EntityHandle parentHandle, Metadata.MetadataGenericContext genericContext, ILNameSyntax syntax)
{
switch (parentHandle.Kind)
{
case HandleKind.MethodDefinition:
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)parentHandle);
((EntityHandle)methodDef.GetDeclaringType()).WriteTo(module, output, genericContext, syntax);
var methodDef = metadataFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)parentHandle);
((EntityHandle)methodDef.GetDeclaringType()).WriteTo(metadataFile, output, genericContext, syntax);
break;
case HandleKind.ModuleReference:
output.Write('[');
var moduleRef = metadata.GetModuleReference((ModuleReferenceHandle)parentHandle);
output.Write(metadata.GetString(moduleRef.Name));
var moduleRef = metadataFile.Metadata.GetModuleReference((ModuleReferenceHandle)parentHandle);
output.Write(metadataFile.Metadata.GetString(moduleRef.Name));
output.Write(']');
break;
case HandleKind.TypeDefinition:
case HandleKind.TypeReference:
case HandleKind.TypeSpecification:
parentHandle.WriteTo(module, output, genericContext, syntax);
parentHandle.WriteTo(metadataFile, output, genericContext, syntax);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion ICSharpCode.Decompiler/Metadata/MetadataGenericContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public readonly struct MetadataGenericContext
readonly TypeDefinitionHandle declaringType;
readonly MethodDefinitionHandle method;

public MetadataGenericContext(MethodDefinitionHandle method, PEFile module)
public MetadataGenericContext(MethodDefinitionHandle method, MetadataFile module)
{
this.metadata = module.Metadata;
this.method = method;
Expand Down
51 changes: 43 additions & 8 deletions ICSharpCode.Decompiler/Metadata/PEFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,43 @@

namespace ICSharpCode.Decompiler.Metadata
{
public class MetadataFile
{
public enum MetadataFileKind
{
PortableExecutable,
ProgramDebugDatabase,
Metadata
}

public string FileName { get; }
public MetadataFileKind Kind { get; }
public MetadataReader Metadata { get; }

public virtual int MetadataOffset { get; }
public virtual bool IsEmbedded { get; }

public MetadataFile(string fileName, MetadataReaderProvider metadata, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default, int metadataOffset = 0, bool isEmbedded = false)
{
this.FileName = fileName;
this.Metadata = metadata.GetMetadataReader(metadataOptions);
this.MetadataOffset = metadataOffset;
this.IsEmbedded = isEmbedded;
this.Kind = isEmbedded || Path.GetExtension(fileName).Equals(".pdb", StringComparison.OrdinalIgnoreCase) ? MetadataFileKind.ProgramDebugDatabase : MetadataFileKind.Metadata;
}

private protected MetadataFile(string fileName, PEReader reader, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
{
this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
_ = reader ?? throw new ArgumentNullException(nameof(reader));
if (!reader.HasMetadata)
throw new PEFileNotSupportedException("PE file does not contain any managed metadata.");
this.Metadata = reader.GetMetadataReader(metadataOptions);
this.Kind = MetadataFileKind.PortableExecutable;
}
}


/// <summary>
/// PEFile is the main class the decompiler uses to represent a metadata assembly/module.
/// Every file on disk can be loaded into a standalone PEFile instance.
Expand All @@ -46,11 +83,9 @@ namespace ICSharpCode.Decompiler.Metadata
/// decompiled type systems.
/// </remarks>
[DebuggerDisplay("{FileName}")]
public class PEFile : IDisposable, TypeSystem.IModuleReference
public class PEFile : MetadataFile, IDisposable, TypeSystem.IModuleReference
{
public string FileName { get; }
public PEReader Reader { get; }
public MetadataReader Metadata { get; }

public PEFile(string fileName, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
: this(fileName, new PEReader(new FileStream(fileName, FileMode.Open, FileAccess.Read), streamOptions), metadataOptions)
Expand All @@ -63,16 +98,16 @@ public PEFile(string fileName, Stream stream, PEStreamOptions streamOptions = PE
}

public PEFile(string fileName, PEReader reader, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
: base(fileName, reader, metadataOptions)
{
this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
this.Reader = reader ?? throw new ArgumentNullException(nameof(reader));
if (!reader.HasMetadata)
throw new PEFileNotSupportedException("PE file does not contain any managed metadata.");
this.Metadata = reader.GetMetadataReader(metadataOptions);
this.Reader = reader;
}

public bool IsAssembly => Metadata.IsAssembly;

public override bool IsEmbedded => false;
public override int MetadataOffset => Reader.PEHeaders.MetadataStartOffset;

string? name;

public string Name {
Expand Down
2 changes: 1 addition & 1 deletion ICSharpCode.Decompiler/Output/ITextOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface ITextOutput
void Write(string text);
void WriteLine();
void WriteReference(OpCodeInfo opCode, bool omitSuffix = false);
void WriteReference(PEFile module, Handle handle, string text, string protocol = "decompile", bool isDefinition = false);
void WriteReference(MetadataFile metadata, Handle handle, string text, string protocol = "decompile", bool isDefinition = false);
void WriteReference(IType type, string text, bool isDefinition = false);
void WriteReference(IMember member, string text, bool isDefinition = false);
void WriteLocalReference(string text, object reference, bool isDefinition = false);
Expand Down
4 changes: 2 additions & 2 deletions ICSharpCode.Decompiler/Output/PlainTextOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void WriteReference(Disassembler.OpCodeInfo opCode, bool omitSuffix = fal
}
}

public void WriteReference(PEFile module, Handle handle, string text, string protocol = "decompile", bool isDefinition = false)
public void WriteReference(MetadataFile module, Handle handle, string text, string protocol = "decompile", bool isDefinition = false)
{
Write(text);
}
Expand Down Expand Up @@ -225,7 +225,7 @@ public void WriteReference(OpCodeInfo opCode, bool omitSuffix = false)
actions.Add(target => target.WriteReference(opCode));
}

public void WriteReference(PEFile module, Handle handle, string text, string protocol = "decompile", bool isDefinition = false)
public void WriteReference(MetadataFile module, Handle handle, string text, string protocol = "decompile", bool isDefinition = false)
{
actions.Add(target => target.WriteReference(module, handle, text, protocol, isDefinition));
}
Expand Down
Loading

0 comments on commit 47ac132

Please sign in to comment.