mirror of https://github.com/icsharpcode/ILSpy.git
129 changed files with 1427 additions and 862 deletions
@ -0,0 +1,332 @@ |
|||||||
|
// Copyright (c) 2024 Siegfried Pammer
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#nullable enable |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection.Metadata; |
||||||
|
using System.Reflection.PortableExecutable; |
||||||
|
|
||||||
|
using ICSharpCode.Decompiler.TypeSystem; |
||||||
|
using ICSharpCode.Decompiler.Util; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Metadata |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// MetadataFile is the main class the decompiler uses to represent a metadata assembly/module.
|
||||||
|
/// Every file on disk can be loaded into a standalone MetadataFile instance.
|
||||||
|
///
|
||||||
|
/// A MetadataFile can be combined with its referenced assemblies/modules to form a type system,
|
||||||
|
/// in that case the <see cref="MetadataModule"/> class is used instead.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In addition to wrapping a <c>System.Reflection.Metadata.MetadataReader</c>, this class
|
||||||
|
/// contains a few decompiler-specific caches to allow efficiently constructing a type
|
||||||
|
/// system from multiple MetadataFiles. This allows the caches to be shared across multiple
|
||||||
|
/// decompiled type systems.
|
||||||
|
/// </remarks>
|
||||||
|
[DebuggerDisplay("{Kind}: {FileName}")] |
||||||
|
public class MetadataFile |
||||||
|
{ |
||||||
|
public enum MetadataFileKind |
||||||
|
{ |
||||||
|
PortableExecutable, |
||||||
|
ProgramDebugDatabase, |
||||||
|
WebCIL, |
||||||
|
Metadata |
||||||
|
} |
||||||
|
|
||||||
|
public string FileName { get; } |
||||||
|
public MetadataFileKind Kind { get; } |
||||||
|
public MetadataReader Metadata { get; } |
||||||
|
|
||||||
|
public virtual int MetadataOffset { get; } |
||||||
|
public virtual bool IsEmbedded { get; } |
||||||
|
|
||||||
|
public bool IsAssembly => Metadata.IsAssembly; |
||||||
|
|
||||||
|
string? name; |
||||||
|
|
||||||
|
public string Name { |
||||||
|
get { |
||||||
|
var value = LazyInit.VolatileRead(ref name); |
||||||
|
if (value == null) |
||||||
|
{ |
||||||
|
var metadata = Metadata; |
||||||
|
value = metadata.IsAssembly |
||||||
|
? metadata.GetString(metadata.GetAssemblyDefinition().Name) |
||||||
|
: metadata.GetString(metadata.GetModuleDefinition().Name); |
||||||
|
value = LazyInit.GetOrSet(ref name, value); |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
string? fullName; |
||||||
|
|
||||||
|
public string FullName { |
||||||
|
get { |
||||||
|
var value = LazyInit.VolatileRead(ref fullName); |
||||||
|
if (value == null) |
||||||
|
{ |
||||||
|
var metadata = Metadata; |
||||||
|
value = metadata.IsAssembly ? metadata.GetFullAssemblyName() : Name; |
||||||
|
value = LazyInit.GetOrSet(ref fullName, value); |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public TargetRuntime GetRuntime() |
||||||
|
{ |
||||||
|
string version = Metadata.MetadataVersion; |
||||||
|
if (version == null || version.Length <= 1) |
||||||
|
return TargetRuntime.Unknown; |
||||||
|
switch (version[1]) |
||||||
|
{ |
||||||
|
case '1': |
||||||
|
if (version.Length <= 3) |
||||||
|
return TargetRuntime.Unknown; |
||||||
|
if (version[3] == 1) |
||||||
|
return TargetRuntime.Net_1_0; |
||||||
|
else |
||||||
|
return TargetRuntime.Net_1_1; |
||||||
|
case '2': |
||||||
|
return TargetRuntime.Net_2_0; |
||||||
|
case '4': |
||||||
|
return TargetRuntime.Net_4_0; |
||||||
|
default: |
||||||
|
return TargetRuntime.Unknown; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ImmutableArray<AssemblyReference> assemblyReferences; |
||||||
|
public ImmutableArray<AssemblyReference> AssemblyReferences { |
||||||
|
get { |
||||||
|
var value = assemblyReferences; |
||||||
|
if (value.IsDefault) |
||||||
|
{ |
||||||
|
value = Metadata.AssemblyReferences.Select(r => new AssemblyReference(this.Metadata, r)).ToImmutableArray(); |
||||||
|
assemblyReferences = value; |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ImmutableArray<ModuleReferenceMetadata> moduleReferences; |
||||||
|
public ImmutableArray<ModuleReferenceMetadata> ModuleReferences { |
||||||
|
get { |
||||||
|
var value = moduleReferences; |
||||||
|
if (value.IsDefault) |
||||||
|
{ |
||||||
|
value = Metadata.GetModuleReferences() |
||||||
|
.Select(m => new ModuleReferenceMetadata(this.Metadata, m)) |
||||||
|
.ToImmutableArray(); |
||||||
|
|
||||||
|
moduleReferences = value; |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public ImmutableArray<Resource> Resources => GetResources().ToImmutableArray(); |
||||||
|
|
||||||
|
IEnumerable<Resource> GetResources() |
||||||
|
{ |
||||||
|
var metadata = Metadata; |
||||||
|
foreach (var h in metadata.ManifestResources) |
||||||
|
{ |
||||||
|
yield return new MetadataResource(this, h); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Dictionary<TopLevelTypeName, TypeDefinitionHandle>? typeLookup; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the top-level-type with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
public TypeDefinitionHandle GetTypeDefinition(TopLevelTypeName typeName) |
||||||
|
{ |
||||||
|
var lookup = LazyInit.VolatileRead(ref typeLookup); |
||||||
|
if (lookup == null) |
||||||
|
{ |
||||||
|
lookup = new Dictionary<TopLevelTypeName, TypeDefinitionHandle>(); |
||||||
|
foreach (var handle in Metadata.TypeDefinitions) |
||||||
|
{ |
||||||
|
var td = Metadata.GetTypeDefinition(handle); |
||||||
|
if (!td.GetDeclaringType().IsNil) |
||||||
|
{ |
||||||
|
continue; // nested type
|
||||||
|
} |
||||||
|
var nsHandle = td.Namespace; |
||||||
|
string ns = nsHandle.IsNil ? string.Empty : Metadata.GetString(nsHandle); |
||||||
|
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(Metadata.GetString(td.Name), out int typeParameterCount); |
||||||
|
lookup[new TopLevelTypeName(ns, name, typeParameterCount)] = handle; |
||||||
|
} |
||||||
|
lookup = LazyInit.GetOrSet(ref typeLookup, lookup); |
||||||
|
} |
||||||
|
if (lookup.TryGetValue(typeName, out var resultHandle)) |
||||||
|
return resultHandle; |
||||||
|
else |
||||||
|
return default; |
||||||
|
} |
||||||
|
|
||||||
|
Dictionary<FullTypeName, ExportedTypeHandle>? typeForwarderLookup; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the type forwarder with the specified name.
|
||||||
|
/// </summary>
|
||||||
|
public ExportedTypeHandle GetTypeForwarder(FullTypeName typeName) |
||||||
|
{ |
||||||
|
var lookup = LazyInit.VolatileRead(ref typeForwarderLookup); |
||||||
|
if (lookup == null) |
||||||
|
{ |
||||||
|
lookup = new Dictionary<FullTypeName, ExportedTypeHandle>(); |
||||||
|
foreach (var handle in Metadata.ExportedTypes) |
||||||
|
{ |
||||||
|
var td = Metadata.GetExportedType(handle); |
||||||
|
lookup[td.GetFullTypeName(Metadata)] = handle; |
||||||
|
} |
||||||
|
lookup = LazyInit.GetOrSet(ref typeForwarderLookup, lookup); |
||||||
|
} |
||||||
|
if (lookup.TryGetValue(typeName, out var resultHandle)) |
||||||
|
return resultHandle; |
||||||
|
else |
||||||
|
return default; |
||||||
|
} |
||||||
|
|
||||||
|
MethodSemanticsLookup? methodSemanticsLookup; |
||||||
|
|
||||||
|
internal MethodSemanticsLookup MethodSemanticsLookup { |
||||||
|
get { |
||||||
|
var r = LazyInit.VolatileRead(ref methodSemanticsLookup); |
||||||
|
if (r != null) |
||||||
|
return r; |
||||||
|
else |
||||||
|
return LazyInit.GetOrSet(ref methodSemanticsLookup, new MethodSemanticsLookup(Metadata)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public MetadataFile(MetadataFileKind kind, string fileName, MetadataReaderProvider metadata, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default, int metadataOffset = 0, bool isEmbedded = false) |
||||||
|
{ |
||||||
|
this.Kind = kind; |
||||||
|
this.FileName = fileName; |
||||||
|
this.Metadata = metadata.GetMetadataReader(metadataOptions); |
||||||
|
this.MetadataOffset = metadataOffset; |
||||||
|
this.IsEmbedded = isEmbedded; |
||||||
|
} |
||||||
|
|
||||||
|
private protected MetadataFile(MetadataFileKind kind, string fileName, PEReader reader, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) |
||||||
|
{ |
||||||
|
this.Kind = kind; |
||||||
|
this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); |
||||||
|
_ = reader ?? throw new ArgumentNullException(nameof(reader)); |
||||||
|
if (!reader.HasMetadata) |
||||||
|
throw new MetadataFileNotSupportedException("PE file does not contain any managed metadata."); |
||||||
|
this.Metadata = reader.GetMetadataReader(metadataOptions); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual MethodBodyBlock GetMethodBody(int rva) |
||||||
|
{ |
||||||
|
throw new BadImageFormatException("This metadata file does not contain method bodies."); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual SectionData GetSectionData(int rva) |
||||||
|
{ |
||||||
|
throw new BadImageFormatException("This metadata file does not support sections."); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual int GetContainingSectionIndex(int rva) |
||||||
|
{ |
||||||
|
throw new BadImageFormatException("This metadata file does not support sections."); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual ImmutableArray<SectionHeader> SectionHeaders => throw new BadImageFormatException("This metadata file does not support sections."); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the CLI header or null if the image does not have one.
|
||||||
|
/// </summary>
|
||||||
|
public virtual CorHeader? CorHeader => null; |
||||||
|
|
||||||
|
public IModuleReference WithOptions(TypeSystemOptions options) |
||||||
|
{ |
||||||
|
return new MetadataFileWithOptions(this, options); |
||||||
|
} |
||||||
|
|
||||||
|
private class MetadataFileWithOptions : IModuleReference |
||||||
|
{ |
||||||
|
readonly MetadataFile peFile; |
||||||
|
readonly TypeSystemOptions options; |
||||||
|
|
||||||
|
public MetadataFileWithOptions(MetadataFile peFile, TypeSystemOptions options) |
||||||
|
{ |
||||||
|
this.peFile = peFile; |
||||||
|
this.options = options; |
||||||
|
} |
||||||
|
|
||||||
|
IModule IModuleReference.Resolve(ITypeResolveContext context) |
||||||
|
{ |
||||||
|
return new MetadataModule(context.Compilation, peFile, options); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstraction over PEMemoryBlock
|
||||||
|
/// </summary>
|
||||||
|
public readonly unsafe struct SectionData |
||||||
|
{ |
||||||
|
public byte* Pointer { get; } |
||||||
|
public int Length { get; } |
||||||
|
|
||||||
|
public SectionData(PEMemoryBlock block) |
||||||
|
{ |
||||||
|
Pointer = block.Pointer; |
||||||
|
Length = block.Length; |
||||||
|
} |
||||||
|
|
||||||
|
public SectionData(byte* startPointer, int length) |
||||||
|
{ |
||||||
|
Pointer = startPointer; |
||||||
|
Length = length; |
||||||
|
} |
||||||
|
|
||||||
|
public BlobReader GetReader() |
||||||
|
{ |
||||||
|
return new BlobReader(Pointer, Length); |
||||||
|
} |
||||||
|
|
||||||
|
internal BlobReader GetReader(int offset, int size) |
||||||
|
{ |
||||||
|
return new BlobReader(Pointer + offset, size); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public struct SectionHeader |
||||||
|
{ |
||||||
|
public string Name; |
||||||
|
public uint VirtualSize; |
||||||
|
public uint VirtualAddress; |
||||||
|
public uint RawDataSize; |
||||||
|
public uint RawDataPtr; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,284 @@ |
|||||||
|
// Copyright (c) 2024 Siegfried Pammer
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.Diagnostics.CodeAnalysis; |
||||||
|
using System.IO; |
||||||
|
using System.IO.MemoryMappedFiles; |
||||||
|
using System.Reflection.Metadata; |
||||||
|
using System.Text; |
||||||
|
|
||||||
|
using ICSharpCode.Decompiler.TypeSystem; |
||||||
|
|
||||||
|
#nullable enable |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Metadata |
||||||
|
{ |
||||||
|
public class WebCilFile : MetadataFile, IDisposable, IModuleReference |
||||||
|
{ |
||||||
|
readonly MemoryMappedViewAccessor view; |
||||||
|
readonly long webcilOffset; |
||||||
|
|
||||||
|
private WebCilFile(string fileName, long webcilOffset, long metadataOffset, MemoryMappedViewAccessor view, ImmutableArray<SectionHeader> sectionHeaders, ImmutableArray<WasmSection> wasmSections, MetadataReaderProvider provider, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) |
||||||
|
: base(MetadataFileKind.WebCIL, fileName, provider, metadataOptions, 0) |
||||||
|
{ |
||||||
|
this.webcilOffset = webcilOffset; |
||||||
|
this.MetadataOffset = (int)metadataOffset; |
||||||
|
this.view = view; |
||||||
|
this.SectionHeaders = sectionHeaders; |
||||||
|
this.WasmSections = wasmSections; |
||||||
|
} |
||||||
|
|
||||||
|
public static WebCilFile? FromStream(string fileName, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) |
||||||
|
{ |
||||||
|
using var memoryMappedFile = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, null, 0, MemoryMappedFileAccess.Read); |
||||||
|
var view = memoryMappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); |
||||||
|
try |
||||||
|
{ |
||||||
|
// read magic "\0asm"
|
||||||
|
if (view.ReadUInt32(0) != WASM_MAGIC) |
||||||
|
return null; |
||||||
|
|
||||||
|
// read version
|
||||||
|
if (view.ReadUInt32(4) != 1) |
||||||
|
return null; |
||||||
|
|
||||||
|
using var stream = view.AsStream(); |
||||||
|
using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true); |
||||||
|
|
||||||
|
stream.Position += 8; |
||||||
|
|
||||||
|
long metadataOffset = -1; |
||||||
|
List<WasmSection> sections = new List<WasmSection>(); |
||||||
|
|
||||||
|
while (stream.Position < stream.Length) |
||||||
|
{ |
||||||
|
WasmSectionId id = (WasmSectionId)reader.ReadByte(); |
||||||
|
uint size = reader.ReadULEB128(); |
||||||
|
sections.Add(new WasmSection(id, stream.Position, size, view)); |
||||||
|
|
||||||
|
if (id == WasmSectionId.Custom && size == 0) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
stream.Seek(size, SeekOrigin.Current); |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var section in sections) |
||||||
|
{ |
||||||
|
if (section.Id != WasmSectionId.Data || metadataOffset > -1) |
||||||
|
continue; |
||||||
|
|
||||||
|
stream.Seek(section.Offset, SeekOrigin.Begin); |
||||||
|
|
||||||
|
uint numSegments = reader.ReadULEB128(); |
||||||
|
if (numSegments != 2) |
||||||
|
continue; |
||||||
|
|
||||||
|
// skip the first segment
|
||||||
|
if (reader.ReadByte() != 1) |
||||||
|
continue; |
||||||
|
|
||||||
|
long segmentLength = reader.ReadULEB128(); |
||||||
|
long segmentStart = reader.BaseStream.Position; |
||||||
|
|
||||||
|
reader.BaseStream.Seek(segmentLength, SeekOrigin.Current); |
||||||
|
|
||||||
|
if (reader.ReadByte() != 1) |
||||||
|
continue; |
||||||
|
|
||||||
|
segmentLength = reader.ReadULEB128(); |
||||||
|
if (TryReadWebCilSegment(reader, out var header, out metadataOffset, out var webcilOffset, out var sectionHeaders)) |
||||||
|
{ |
||||||
|
stream.Seek(metadataOffset, SeekOrigin.Begin); |
||||||
|
var metadata = MetadataReaderProvider.FromMetadataStream(stream, MetadataStreamOptions.LeaveOpen | MetadataStreamOptions.PrefetchMetadata); |
||||||
|
|
||||||
|
var result = new WebCilFile(fileName, webcilOffset, metadataOffset, view, ImmutableArray.Create(sectionHeaders), sections.ToImmutableArray(), metadata, metadataOptions); |
||||||
|
|
||||||
|
view = null; // don't dispose the view, we're still using it in the sections
|
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
finally |
||||||
|
{ |
||||||
|
view?.Dispose(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static unsafe bool TryReadWebCilSegment(BinaryReader reader, out WebcilHeader webcilHeader, out long metadataOffset, out long webcilOffset, [NotNullWhen(true)] out SectionHeader[]? sectionHeaders) |
||||||
|
{ |
||||||
|
webcilHeader = default; |
||||||
|
metadataOffset = -1; |
||||||
|
sectionHeaders = null; |
||||||
|
|
||||||
|
webcilOffset = reader.BaseStream.Position; |
||||||
|
|
||||||
|
if (reader.ReadUInt32() != WEBCIL_MAGIC) |
||||||
|
return false; |
||||||
|
|
||||||
|
webcilHeader.VersionMajor = reader.ReadUInt16(); |
||||||
|
webcilHeader.VersionMinor = reader.ReadUInt16(); |
||||||
|
webcilHeader.CoffSections = reader.ReadUInt16(); |
||||||
|
_ = reader.ReadUInt16(); // reserved0
|
||||||
|
webcilHeader.PECliHeaderRVA = reader.ReadUInt32(); |
||||||
|
webcilHeader.PECliHeaderSize = reader.ReadUInt32(); |
||||||
|
webcilHeader.PEDebugRVA = reader.ReadUInt32(); |
||||||
|
webcilHeader.PEDebugSize = reader.ReadUInt32(); |
||||||
|
|
||||||
|
sectionHeaders = new SectionHeader[webcilHeader.CoffSections]; |
||||||
|
for (int i = 0; i < webcilHeader.CoffSections; i++) |
||||||
|
{ |
||||||
|
sectionHeaders[i].VirtualSize = reader.ReadUInt32(); |
||||||
|
sectionHeaders[i].VirtualAddress = reader.ReadUInt32(); |
||||||
|
sectionHeaders[i].RawDataSize = reader.ReadUInt32(); |
||||||
|
sectionHeaders[i].RawDataPtr = reader.ReadUInt32(); |
||||||
|
} |
||||||
|
|
||||||
|
long corHeaderStart = TranslateRVA(sectionHeaders, webcilOffset, webcilHeader.PECliHeaderRVA); |
||||||
|
if (reader.BaseStream.Seek(corHeaderStart, SeekOrigin.Begin) != corHeaderStart) |
||||||
|
return false; |
||||||
|
int byteCount = reader.ReadInt32(); |
||||||
|
int majorVersion = reader.ReadUInt16(); |
||||||
|
int minorVersion = reader.ReadUInt16(); |
||||||
|
metadataOffset = TranslateRVA(sectionHeaders, webcilOffset, (uint)reader.ReadInt32()); |
||||||
|
return reader.BaseStream.Seek(metadataOffset, SeekOrigin.Begin) == metadataOffset; |
||||||
|
} |
||||||
|
|
||||||
|
public override int MetadataOffset { get; } |
||||||
|
|
||||||
|
private static int GetContainingSectionIndex(IEnumerable<SectionHeader> sections, int rva) |
||||||
|
{ |
||||||
|
int i = 0; |
||||||
|
foreach (var section in sections) |
||||||
|
{ |
||||||
|
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize) |
||||||
|
{ |
||||||
|
return i; |
||||||
|
} |
||||||
|
i++; |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
private static long TranslateRVA(IEnumerable<SectionHeader> sections, long webcilOffset, uint rva) |
||||||
|
{ |
||||||
|
foreach (var section in sections) |
||||||
|
{ |
||||||
|
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize) |
||||||
|
{ |
||||||
|
return section.RawDataPtr + (rva - section.VirtualAddress) + webcilOffset; |
||||||
|
} |
||||||
|
} |
||||||
|
throw new BadImageFormatException("RVA not found in any section"); |
||||||
|
} |
||||||
|
|
||||||
|
public override MethodBodyBlock GetMethodBody(int rva) |
||||||
|
{ |
||||||
|
var reader = GetSectionData(rva).GetReader(); |
||||||
|
return MethodBodyBlock.Create(reader); |
||||||
|
} |
||||||
|
|
||||||
|
public override int GetContainingSectionIndex(int rva) |
||||||
|
{ |
||||||
|
return GetContainingSectionIndex(SectionHeaders, rva); |
||||||
|
} |
||||||
|
|
||||||
|
public override unsafe SectionData GetSectionData(int rva) |
||||||
|
{ |
||||||
|
foreach (var section in SectionHeaders) |
||||||
|
{ |
||||||
|
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize) |
||||||
|
{ |
||||||
|
byte* ptr = (byte*)0; |
||||||
|
view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr); |
||||||
|
return new SectionData(ptr + section.RawDataPtr + webcilOffset + (rva - section.VirtualAddress), (int)section.RawDataSize); |
||||||
|
} |
||||||
|
} |
||||||
|
throw new BadImageFormatException("RVA not found in any section"); |
||||||
|
} |
||||||
|
|
||||||
|
public override ImmutableArray<SectionHeader> SectionHeaders { get; } |
||||||
|
|
||||||
|
public ImmutableArray<WasmSection> WasmSections { get; } |
||||||
|
|
||||||
|
IModule? IModuleReference.Resolve(ITypeResolveContext context) |
||||||
|
{ |
||||||
|
return new MetadataModule(context.Compilation, this, TypeSystemOptions.Default); |
||||||
|
} |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
view.Dispose(); |
||||||
|
} |
||||||
|
|
||||||
|
public struct WebcilHeader |
||||||
|
{ |
||||||
|
public ushort VersionMajor; |
||||||
|
public ushort VersionMinor; |
||||||
|
public ushort CoffSections; |
||||||
|
public uint PECliHeaderRVA; |
||||||
|
public uint PECliHeaderSize; |
||||||
|
public uint PEDebugRVA; |
||||||
|
public uint PEDebugSize; |
||||||
|
} |
||||||
|
|
||||||
|
const uint WASM_MAGIC = 0x6d736100u; // "\0asm"
|
||||||
|
const uint WEBCIL_MAGIC = 0x4c496257u; // "WbIL"
|
||||||
|
|
||||||
|
[DebuggerDisplay("WasmSection {Id}: {Offset} {Size}")] |
||||||
|
public class WasmSection |
||||||
|
{ |
||||||
|
public WasmSectionId Id; |
||||||
|
public long Offset; |
||||||
|
public uint Size; |
||||||
|
private MemoryMappedViewAccessor view; |
||||||
|
|
||||||
|
public WasmSection(WasmSectionId id, long offset, uint size, MemoryMappedViewAccessor view) |
||||||
|
{ |
||||||
|
this.Id = id; |
||||||
|
this.Size = size; |
||||||
|
this.Offset = offset; |
||||||
|
this.view = view; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public enum WasmSectionId : byte |
||||||
|
{ |
||||||
|
// order matters: enum values must match the WebAssembly spec
|
||||||
|
Custom = 0, |
||||||
|
Type = 1, |
||||||
|
Import = 2, |
||||||
|
Function = 3, |
||||||
|
Table = 4, |
||||||
|
Memory = 5, |
||||||
|
Global = 6, |
||||||
|
Export = 7, |
||||||
|
Start = 8, |
||||||
|
Element = 9, |
||||||
|
Code = 10, |
||||||
|
Data = 11, |
||||||
|
DataCount = 12, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,18 +1,30 @@ |
|||||||
using System; |
// Copyright (c) 2018 Siegfried Pammer
|
||||||
using System.Collections.Generic; |
//
|
||||||
using System.Linq; |
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
using System.Reflection.Metadata; |
using System.Reflection.Metadata; |
||||||
using System.Text; |
|
||||||
using System.Threading.Tasks; |
|
||||||
|
|
||||||
using ICSharpCode.Decompiler.Metadata; |
using ICSharpCode.Decompiler.Metadata; |
||||||
using ICSharpCode.ILSpy.TreeNodes; |
using ICSharpCode.ILSpy.TreeNodes; |
||||||
using ICSharpCode.TreeView; |
|
||||||
|
|
||||||
namespace ICSharpCode.ILSpy |
namespace ICSharpCode.ILSpy |
||||||
{ |
{ |
||||||
public interface IProtocolHandler |
public interface IProtocolHandler |
||||||
{ |
{ |
||||||
ILSpyTreeNode Resolve(string protocol, PEFile module, Handle handle, out bool newTabPage); |
ILSpyTreeNode Resolve(string protocol, MetadataFile module, Handle handle, out bool newTabPage); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue