4037 lines
131 KiB
C#
4037 lines
131 KiB
C#
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// Copyright (c) 2008 - 2015 Jb Evain
|
|
// Copyright (c) 2008 - 2011 Novell, Inc.
|
|
//
|
|
// Licensed under the MIT/X11 license.
|
|
//
|
|
|
|
using MonoFN.Cecil.Cil;
|
|
using MonoFN.Cecil.Metadata;
|
|
using MonoFN.Cecil.PE;
|
|
using MonoFN.Collections.Generic;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Text;
|
|
using RVA = System.UInt32;
|
|
|
|
namespace MonoFN.Cecil
|
|
{
|
|
internal abstract class ModuleReader
|
|
{
|
|
protected readonly ModuleDefinition module;
|
|
|
|
protected ModuleReader(Image image, ReadingMode mode)
|
|
{
|
|
module = new(image);
|
|
module.ReadingMode = mode;
|
|
}
|
|
|
|
protected abstract void ReadModule();
|
|
public abstract void ReadSymbols(ModuleDefinition module);
|
|
|
|
protected void ReadModuleManifest(MetadataReader reader)
|
|
{
|
|
reader.Populate(module);
|
|
|
|
ReadAssembly(reader);
|
|
}
|
|
|
|
private void ReadAssembly(MetadataReader reader)
|
|
{
|
|
AssemblyNameDefinition name = reader.ReadAssemblyNameDefinition();
|
|
if (name == null)
|
|
{
|
|
module.kind = ModuleKind.NetModule;
|
|
return;
|
|
}
|
|
|
|
AssemblyDefinition assembly = new();
|
|
assembly.Name = name;
|
|
|
|
module.assembly = assembly;
|
|
assembly.main_module = module;
|
|
}
|
|
|
|
public static ModuleDefinition CreateModule(Image image, ReaderParameters parameters)
|
|
{
|
|
ModuleReader reader = CreateModuleReader(image, parameters.ReadingMode);
|
|
ModuleDefinition module = reader.module;
|
|
|
|
if (parameters.assembly_resolver != null)
|
|
module.assembly_resolver = Disposable.NotOwned(parameters.assembly_resolver);
|
|
|
|
if (parameters.metadata_resolver != null)
|
|
module.metadata_resolver = parameters.metadata_resolver;
|
|
|
|
if (parameters.metadata_importer_provider != null)
|
|
module.metadata_importer = parameters.metadata_importer_provider.GetMetadataImporter(module);
|
|
|
|
if (parameters.reflection_importer_provider != null)
|
|
module.reflection_importer = parameters.reflection_importer_provider.GetReflectionImporter(module);
|
|
|
|
GetMetadataKind(module, parameters);
|
|
|
|
reader.ReadModule();
|
|
|
|
ReadSymbols(module, parameters);
|
|
|
|
reader.ReadSymbols(module);
|
|
|
|
if (parameters.ReadingMode == ReadingMode.Immediate)
|
|
module.MetadataSystem.Clear();
|
|
|
|
return module;
|
|
}
|
|
|
|
private static void ReadSymbols(ModuleDefinition module, ReaderParameters parameters)
|
|
{
|
|
ISymbolReaderProvider symbol_reader_provider = parameters.SymbolReaderProvider;
|
|
|
|
if (symbol_reader_provider == null && parameters.ReadSymbols)
|
|
symbol_reader_provider = new DefaultSymbolReaderProvider();
|
|
|
|
if (symbol_reader_provider != null)
|
|
{
|
|
module.SymbolReaderProvider = symbol_reader_provider;
|
|
|
|
ISymbolReader reader = parameters.SymbolStream != null ? symbol_reader_provider.GetSymbolReader(module, parameters.SymbolStream) : symbol_reader_provider.GetSymbolReader(module, module.FileName);
|
|
|
|
if (reader != null)
|
|
{
|
|
try
|
|
{
|
|
module.ReadSymbols(reader, parameters.ThrowIfSymbolsAreNotMatching);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
reader.Dispose();
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (module.Image.HasDebugTables())
|
|
module.ReadSymbols(new PortablePdbReader(module.Image, module));
|
|
}
|
|
|
|
private static void GetMetadataKind(ModuleDefinition module, ReaderParameters parameters)
|
|
{
|
|
if (!parameters.ApplyWindowsRuntimeProjections)
|
|
{
|
|
module.MetadataKind = MetadataKind.Ecma335;
|
|
return;
|
|
}
|
|
|
|
string runtime_version = module.RuntimeVersion;
|
|
|
|
if (!runtime_version.Contains("WindowsRuntime"))
|
|
module.MetadataKind = MetadataKind.Ecma335;
|
|
else if (runtime_version.Contains("CLR"))
|
|
module.MetadataKind = MetadataKind.ManagedWindowsMetadata;
|
|
else
|
|
module.MetadataKind = MetadataKind.WindowsMetadata;
|
|
}
|
|
|
|
private static ModuleReader CreateModuleReader(Image image, ReadingMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case ReadingMode.Immediate:
|
|
return new ImmediateModuleReader(image);
|
|
case ReadingMode.Deferred:
|
|
return new DeferredModuleReader(image);
|
|
default:
|
|
throw new ArgumentException();
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class ImmediateModuleReader : ModuleReader
|
|
{
|
|
private bool resolve_attributes;
|
|
public ImmediateModuleReader(Image image) : base(image, ReadingMode.Immediate) { }
|
|
|
|
protected override void ReadModule()
|
|
{
|
|
this.module.Read(this.module, (module, reader) =>
|
|
{
|
|
ReadModuleManifest(reader);
|
|
ReadModule(module, resolve_attributes: true);
|
|
});
|
|
}
|
|
|
|
public void ReadModule(ModuleDefinition module, bool resolve_attributes)
|
|
{
|
|
this.resolve_attributes = resolve_attributes;
|
|
|
|
if (module.HasAssemblyReferences)
|
|
Mixin.Read(module.AssemblyReferences);
|
|
if (module.HasResources)
|
|
Mixin.Read(module.Resources);
|
|
if (module.HasModuleReferences)
|
|
Mixin.Read(module.ModuleReferences);
|
|
if (module.HasTypes)
|
|
ReadTypes(module.Types);
|
|
if (module.HasExportedTypes)
|
|
Mixin.Read(module.ExportedTypes);
|
|
|
|
ReadCustomAttributes(module);
|
|
|
|
AssemblyDefinition assembly = module.Assembly;
|
|
if (module.kind == ModuleKind.NetModule || assembly == null)
|
|
return;
|
|
|
|
ReadCustomAttributes(assembly);
|
|
ReadSecurityDeclarations(assembly);
|
|
}
|
|
|
|
private void ReadTypes(Collection<TypeDefinition> types)
|
|
{
|
|
for (int i = 0; i < types.Count; i++)
|
|
ReadType(types[i]);
|
|
}
|
|
|
|
private void ReadType(TypeDefinition type)
|
|
{
|
|
ReadGenericParameters(type);
|
|
|
|
if (type.HasInterfaces)
|
|
ReadInterfaces(type);
|
|
|
|
if (type.HasNestedTypes)
|
|
ReadTypes(type.NestedTypes);
|
|
|
|
if (type.HasLayoutInfo)
|
|
Mixin.Read(type.ClassSize);
|
|
|
|
if (type.HasFields)
|
|
ReadFields(type);
|
|
|
|
if (type.HasMethods)
|
|
ReadMethods(type);
|
|
|
|
if (type.HasProperties)
|
|
ReadProperties(type);
|
|
|
|
if (type.HasEvents)
|
|
ReadEvents(type);
|
|
|
|
ReadSecurityDeclarations(type);
|
|
ReadCustomAttributes(type);
|
|
}
|
|
|
|
private void ReadInterfaces(TypeDefinition type)
|
|
{
|
|
Collection<InterfaceImplementation> interfaces = type.Interfaces;
|
|
|
|
for (int i = 0; i < interfaces.Count; i++)
|
|
ReadCustomAttributes(interfaces[i]);
|
|
}
|
|
|
|
private void ReadGenericParameters(IGenericParameterProvider provider)
|
|
{
|
|
if (!provider.HasGenericParameters)
|
|
return;
|
|
|
|
Collection<GenericParameter> parameters = provider.GenericParameters;
|
|
|
|
for (int i = 0; i < parameters.Count; i++)
|
|
{
|
|
GenericParameter parameter = parameters[i];
|
|
|
|
if (parameter.HasConstraints)
|
|
ReadGenericParameterConstraints(parameter);
|
|
|
|
ReadCustomAttributes(parameter);
|
|
}
|
|
}
|
|
|
|
private void ReadGenericParameterConstraints(GenericParameter parameter)
|
|
{
|
|
Collection<GenericParameterConstraint> constraints = parameter.Constraints;
|
|
|
|
for (int i = 0; i < constraints.Count; i++)
|
|
ReadCustomAttributes(constraints[i]);
|
|
}
|
|
|
|
private void ReadSecurityDeclarations(ISecurityDeclarationProvider provider)
|
|
{
|
|
if (!provider.HasSecurityDeclarations)
|
|
return;
|
|
|
|
Collection<SecurityDeclaration> security_declarations = provider.SecurityDeclarations;
|
|
|
|
if (!resolve_attributes)
|
|
return;
|
|
|
|
for (int i = 0; i < security_declarations.Count; i++)
|
|
{
|
|
SecurityDeclaration security_declaration = security_declarations[i];
|
|
|
|
Mixin.Read(security_declaration.SecurityAttributes);
|
|
}
|
|
}
|
|
|
|
private void ReadCustomAttributes(ICustomAttributeProvider provider)
|
|
{
|
|
if (!provider.HasCustomAttributes)
|
|
return;
|
|
|
|
Collection<CustomAttribute> custom_attributes = provider.CustomAttributes;
|
|
|
|
if (!resolve_attributes)
|
|
return;
|
|
|
|
for (int i = 0; i < custom_attributes.Count; i++)
|
|
{
|
|
CustomAttribute custom_attribute = custom_attributes[i];
|
|
|
|
Mixin.Read(custom_attribute.ConstructorArguments);
|
|
}
|
|
}
|
|
|
|
private void ReadFields(TypeDefinition type)
|
|
{
|
|
Collection<FieldDefinition> fields = type.Fields;
|
|
|
|
for (int i = 0; i < fields.Count; i++)
|
|
{
|
|
FieldDefinition field = fields[i];
|
|
|
|
if (field.HasConstant)
|
|
Mixin.Read(field.Constant);
|
|
|
|
if (field.HasLayoutInfo)
|
|
Mixin.Read(field.Offset);
|
|
|
|
if (field.RVA > 0)
|
|
Mixin.Read(field.InitialValue);
|
|
|
|
if (field.HasMarshalInfo)
|
|
Mixin.Read(field.MarshalInfo);
|
|
|
|
ReadCustomAttributes(field);
|
|
}
|
|
}
|
|
|
|
private void ReadMethods(TypeDefinition type)
|
|
{
|
|
Collection<MethodDefinition> methods = type.Methods;
|
|
|
|
for (int i = 0; i < methods.Count; i++)
|
|
{
|
|
MethodDefinition method = methods[i];
|
|
|
|
ReadGenericParameters(method);
|
|
|
|
if (method.HasParameters)
|
|
ReadParameters(method);
|
|
|
|
if (method.HasOverrides)
|
|
Mixin.Read(method.Overrides);
|
|
|
|
if (method.IsPInvokeImpl)
|
|
Mixin.Read(method.PInvokeInfo);
|
|
|
|
ReadSecurityDeclarations(method);
|
|
ReadCustomAttributes(method);
|
|
|
|
MethodReturnType return_type = method.MethodReturnType;
|
|
if (return_type.HasConstant)
|
|
Mixin.Read(return_type.Constant);
|
|
|
|
if (return_type.HasMarshalInfo)
|
|
Mixin.Read(return_type.MarshalInfo);
|
|
|
|
ReadCustomAttributes(return_type);
|
|
}
|
|
}
|
|
|
|
private void ReadParameters(MethodDefinition method)
|
|
{
|
|
Collection<ParameterDefinition> parameters = method.Parameters;
|
|
|
|
for (int i = 0; i < parameters.Count; i++)
|
|
{
|
|
ParameterDefinition parameter = parameters[i];
|
|
|
|
if (parameter.HasConstant)
|
|
Mixin.Read(parameter.Constant);
|
|
|
|
if (parameter.HasMarshalInfo)
|
|
Mixin.Read(parameter.MarshalInfo);
|
|
|
|
ReadCustomAttributes(parameter);
|
|
}
|
|
}
|
|
|
|
private void ReadProperties(TypeDefinition type)
|
|
{
|
|
Collection<PropertyDefinition> properties = type.Properties;
|
|
|
|
for (int i = 0; i < properties.Count; i++)
|
|
{
|
|
PropertyDefinition property = properties[i];
|
|
|
|
Mixin.Read(property.GetMethod);
|
|
|
|
if (property.HasConstant)
|
|
Mixin.Read(property.Constant);
|
|
|
|
ReadCustomAttributes(property);
|
|
}
|
|
}
|
|
|
|
private void ReadEvents(TypeDefinition type)
|
|
{
|
|
Collection<EventDefinition> events = type.Events;
|
|
|
|
for (int i = 0; i < events.Count; i++)
|
|
{
|
|
EventDefinition @event = events[i];
|
|
|
|
Mixin.Read(@event.AddMethod);
|
|
|
|
ReadCustomAttributes(@event);
|
|
}
|
|
}
|
|
|
|
public override void ReadSymbols(ModuleDefinition module)
|
|
{
|
|
if (module.symbol_reader == null)
|
|
return;
|
|
|
|
ReadTypesSymbols(module.Types, module.symbol_reader);
|
|
}
|
|
|
|
private void ReadTypesSymbols(Collection<TypeDefinition> types, ISymbolReader symbol_reader)
|
|
{
|
|
for (int i = 0; i < types.Count; i++)
|
|
{
|
|
TypeDefinition type = types[i];
|
|
|
|
if (type.HasNestedTypes)
|
|
ReadTypesSymbols(type.NestedTypes, symbol_reader);
|
|
|
|
if (type.HasMethods)
|
|
ReadMethodsSymbols(type, symbol_reader);
|
|
}
|
|
}
|
|
|
|
private void ReadMethodsSymbols(TypeDefinition type, ISymbolReader symbol_reader)
|
|
{
|
|
Collection<MethodDefinition> methods = type.Methods;
|
|
for (int i = 0; i < methods.Count; i++)
|
|
{
|
|
MethodDefinition method = methods[i];
|
|
|
|
if (method.HasBody && method.token.RID != 0 && method.debug_info == null)
|
|
method.debug_info = symbol_reader.Read(method);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class DeferredModuleReader : ModuleReader
|
|
{
|
|
public DeferredModuleReader(Image image) : base(image, ReadingMode.Deferred) { }
|
|
|
|
protected override void ReadModule()
|
|
{
|
|
module.Read(module, (_, reader) => ReadModuleManifest(reader));
|
|
}
|
|
|
|
public override void ReadSymbols(ModuleDefinition module) { }
|
|
}
|
|
|
|
internal sealed class MetadataReader : ByteBuffer
|
|
{
|
|
internal readonly Image image;
|
|
internal readonly ModuleDefinition module;
|
|
internal readonly MetadataSystem metadata;
|
|
internal CodeReader code;
|
|
internal IGenericContext context;
|
|
private readonly MetadataReader metadata_reader;
|
|
|
|
public MetadataReader(ModuleDefinition module) : base(module.Image.TableHeap.data)
|
|
{
|
|
image = module.Image;
|
|
this.module = module;
|
|
metadata = module.MetadataSystem;
|
|
code = new(this);
|
|
}
|
|
|
|
public MetadataReader(Image image, ModuleDefinition module, MetadataReader metadata_reader) : base(image.TableHeap.data)
|
|
{
|
|
this.image = image;
|
|
this.module = module;
|
|
metadata = module.MetadataSystem;
|
|
this.metadata_reader = metadata_reader;
|
|
}
|
|
|
|
private int GetCodedIndexSize(CodedIndex index)
|
|
{
|
|
return image.GetCodedIndexSize(index);
|
|
}
|
|
|
|
private uint ReadByIndexSize(int size)
|
|
{
|
|
if (size == 4)
|
|
return ReadUInt32();
|
|
else
|
|
return ReadUInt16();
|
|
}
|
|
|
|
private byte[] ReadBlob()
|
|
{
|
|
BlobHeap blob_heap = image.BlobHeap;
|
|
if (blob_heap == null)
|
|
{
|
|
position += 2;
|
|
return Empty<byte>.Array;
|
|
}
|
|
|
|
return blob_heap.Read(ReadBlobIndex());
|
|
}
|
|
|
|
private byte[] ReadBlob(uint signature)
|
|
{
|
|
BlobHeap blob_heap = image.BlobHeap;
|
|
if (blob_heap == null)
|
|
return Empty<byte>.Array;
|
|
|
|
return blob_heap.Read(signature);
|
|
}
|
|
|
|
private uint ReadBlobIndex()
|
|
{
|
|
BlobHeap blob_heap = image.BlobHeap;
|
|
return ReadByIndexSize(blob_heap != null ? blob_heap.IndexSize : 2);
|
|
}
|
|
|
|
private void GetBlobView(uint signature, out byte[] blob, out int index, out int count)
|
|
{
|
|
BlobHeap blob_heap = image.BlobHeap;
|
|
if (blob_heap == null)
|
|
{
|
|
blob = null;
|
|
index = count = 0;
|
|
return;
|
|
}
|
|
|
|
blob_heap.GetView(signature, out blob, out index, out count);
|
|
}
|
|
|
|
private string ReadString()
|
|
{
|
|
return image.StringHeap.Read(ReadByIndexSize(image.StringHeap.IndexSize));
|
|
}
|
|
|
|
private uint ReadStringIndex()
|
|
{
|
|
return ReadByIndexSize(image.StringHeap.IndexSize);
|
|
}
|
|
|
|
private Guid ReadGuid()
|
|
{
|
|
return image.GuidHeap.Read(ReadByIndexSize(image.GuidHeap.IndexSize));
|
|
}
|
|
|
|
private uint ReadTableIndex(Table table)
|
|
{
|
|
return ReadByIndexSize(image.GetTableIndexSize(table));
|
|
}
|
|
|
|
private MetadataToken ReadMetadataToken(CodedIndex index)
|
|
{
|
|
return index.GetMetadataToken(ReadByIndexSize(GetCodedIndexSize(index)));
|
|
}
|
|
|
|
private int MoveTo(Table table)
|
|
{
|
|
TableInformation info = image.TableHeap[table];
|
|
if (info.Length != 0)
|
|
position = (int)info.Offset;
|
|
|
|
return (int)info.Length;
|
|
}
|
|
|
|
private bool MoveTo(Table table, uint row)
|
|
{
|
|
TableInformation info = image.TableHeap[table];
|
|
uint length = info.Length;
|
|
if (length == 0 || row > length)
|
|
return false;
|
|
|
|
position = (int)(info.Offset + info.RowSize * (row - 1));
|
|
return true;
|
|
}
|
|
|
|
public AssemblyNameDefinition ReadAssemblyNameDefinition()
|
|
{
|
|
if (MoveTo(Table.Assembly) == 0)
|
|
return null;
|
|
|
|
AssemblyNameDefinition name = new();
|
|
|
|
name.HashAlgorithm = (AssemblyHashAlgorithm)ReadUInt32();
|
|
|
|
PopulateVersionAndFlags(name);
|
|
|
|
name.PublicKey = ReadBlob();
|
|
|
|
PopulateNameAndCulture(name);
|
|
|
|
return name;
|
|
}
|
|
|
|
public ModuleDefinition Populate(ModuleDefinition module)
|
|
{
|
|
if (MoveTo(Table.Module) == 0)
|
|
return module;
|
|
|
|
Advance(2); // Generation
|
|
|
|
module.Name = ReadString();
|
|
module.Mvid = ReadGuid();
|
|
|
|
return module;
|
|
}
|
|
|
|
private void InitializeAssemblyReferences()
|
|
{
|
|
if (metadata.AssemblyReferences != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.AssemblyRef);
|
|
AssemblyNameReference[] references = metadata.AssemblyReferences = new AssemblyNameReference [length];
|
|
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
AssemblyNameReference reference = new();
|
|
reference.token = new(TokenType.AssemblyRef, i + 1);
|
|
|
|
PopulateVersionAndFlags(reference);
|
|
|
|
byte[] key_or_token = ReadBlob();
|
|
|
|
if (reference.HasPublicKey)
|
|
reference.PublicKey = key_or_token;
|
|
else
|
|
reference.PublicKeyToken = key_or_token;
|
|
|
|
PopulateNameAndCulture(reference);
|
|
|
|
reference.Hash = ReadBlob();
|
|
|
|
references[i] = reference;
|
|
}
|
|
}
|
|
|
|
public Collection<AssemblyNameReference> ReadAssemblyReferences()
|
|
{
|
|
InitializeAssemblyReferences();
|
|
|
|
Collection<AssemblyNameReference> references = new(metadata.AssemblyReferences);
|
|
if (module.IsWindowsMetadata())
|
|
module.Projections.AddVirtualReferences(references);
|
|
|
|
return references;
|
|
}
|
|
|
|
public MethodDefinition ReadEntryPoint()
|
|
{
|
|
if (module.Image.EntryPointToken == 0)
|
|
return null;
|
|
|
|
MetadataToken token = new(module.Image.EntryPointToken);
|
|
return GetMethodDefinition(token.RID);
|
|
}
|
|
|
|
public Collection<ModuleDefinition> ReadModules()
|
|
{
|
|
Collection<ModuleDefinition> modules = new(1);
|
|
modules.Add(module);
|
|
|
|
int length = MoveTo(Table.File);
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
FileAttributes attributes = (FileAttributes)ReadUInt32();
|
|
string name = ReadString();
|
|
ReadBlobIndex();
|
|
|
|
if (attributes != FileAttributes.ContainsMetaData)
|
|
continue;
|
|
|
|
ReaderParameters parameters = new()
|
|
{
|
|
ReadingMode = module.ReadingMode,
|
|
SymbolReaderProvider = module.SymbolReaderProvider,
|
|
AssemblyResolver = module.AssemblyResolver
|
|
};
|
|
|
|
ModuleDefinition netmodule = ModuleDefinition.ReadModule(GetModuleFileName(name), parameters);
|
|
netmodule.assembly = module.assembly;
|
|
|
|
modules.Add(netmodule);
|
|
}
|
|
|
|
return modules;
|
|
}
|
|
|
|
private string GetModuleFileName(string name)
|
|
{
|
|
if (module.FileName == null)
|
|
throw new NotSupportedException();
|
|
|
|
string path = Path.GetDirectoryName(module.FileName);
|
|
return Path.Combine(path, name);
|
|
}
|
|
|
|
private void InitializeModuleReferences()
|
|
{
|
|
if (metadata.ModuleReferences != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.ModuleRef);
|
|
ModuleReference[] references = metadata.ModuleReferences = new ModuleReference [length];
|
|
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
ModuleReference reference = new(ReadString());
|
|
reference.token = new(TokenType.ModuleRef, i + 1);
|
|
|
|
references[i] = reference;
|
|
}
|
|
}
|
|
|
|
public Collection<ModuleReference> ReadModuleReferences()
|
|
{
|
|
InitializeModuleReferences();
|
|
|
|
return new(metadata.ModuleReferences);
|
|
}
|
|
|
|
public bool HasFileResource()
|
|
{
|
|
int length = MoveTo(Table.File);
|
|
if (length == 0)
|
|
return false;
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
if (ReadFileRecord(i).Col1 == FileAttributes.ContainsNoMetaData)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public Collection<Resource> ReadResources()
|
|
{
|
|
int length = MoveTo(Table.ManifestResource);
|
|
Collection<Resource> resources = new(length);
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
uint offset = ReadUInt32();
|
|
ManifestResourceAttributes flags = (ManifestResourceAttributes)ReadUInt32();
|
|
string name = ReadString();
|
|
MetadataToken implementation = ReadMetadataToken(CodedIndex.Implementation);
|
|
|
|
Resource resource;
|
|
|
|
if (implementation.RID == 0)
|
|
{
|
|
resource = new EmbeddedResource(name, flags, offset, this);
|
|
}
|
|
else if (implementation.TokenType == TokenType.AssemblyRef)
|
|
{
|
|
resource = new AssemblyLinkedResource(name, flags)
|
|
{
|
|
Assembly = (AssemblyNameReference)GetTypeReferenceScope(implementation)
|
|
};
|
|
}
|
|
else if (implementation.TokenType == TokenType.File)
|
|
{
|
|
Row<FileAttributes, string, uint> file_record = ReadFileRecord(implementation.RID);
|
|
|
|
resource = new LinkedResource(name, flags)
|
|
{
|
|
File = file_record.Col2,
|
|
hash = ReadBlob(file_record.Col3)
|
|
};
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
resources.Add(resource);
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
|
|
private Row<FileAttributes, string, uint> ReadFileRecord(uint rid)
|
|
{
|
|
int position = this.position;
|
|
|
|
if (!MoveTo(Table.File, rid))
|
|
throw new ArgumentException();
|
|
|
|
Row<FileAttributes, string, uint> record = new((FileAttributes)ReadUInt32(), ReadString(), ReadBlobIndex());
|
|
|
|
this.position = position;
|
|
|
|
return record;
|
|
}
|
|
|
|
public byte[] GetManagedResource(uint offset)
|
|
{
|
|
return image.GetReaderAt(image.Resources.VirtualAddress, offset, (o, reader) =>
|
|
{
|
|
reader.Advance((int)o);
|
|
return reader.ReadBytes(reader.ReadInt32());
|
|
}) ?? Empty<byte>.Array;
|
|
}
|
|
|
|
private void PopulateVersionAndFlags(AssemblyNameReference name)
|
|
{
|
|
name.Version = new(ReadUInt16(), ReadUInt16(), ReadUInt16(), ReadUInt16());
|
|
|
|
name.Attributes = (AssemblyAttributes)ReadUInt32();
|
|
}
|
|
|
|
private void PopulateNameAndCulture(AssemblyNameReference name)
|
|
{
|
|
name.Name = ReadString();
|
|
name.Culture = ReadString();
|
|
}
|
|
|
|
public TypeDefinitionCollection ReadTypes()
|
|
{
|
|
InitializeTypeDefinitions();
|
|
TypeDefinition[] mtypes = metadata.Types;
|
|
int type_count = mtypes.Length - metadata.NestedTypes.Count;
|
|
TypeDefinitionCollection types = new(module, type_count);
|
|
|
|
for (int i = 0; i < mtypes.Length; i++)
|
|
{
|
|
TypeDefinition type = mtypes[i];
|
|
if (IsNested(type.Attributes))
|
|
continue;
|
|
|
|
types.Add(type);
|
|
}
|
|
|
|
if (image.HasTable(Table.MethodPtr) || image.HasTable(Table.FieldPtr))
|
|
CompleteTypes();
|
|
|
|
return types;
|
|
}
|
|
|
|
private void CompleteTypes()
|
|
{
|
|
TypeDefinition[] types = metadata.Types;
|
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
TypeDefinition type = types[i];
|
|
|
|
Mixin.Read(type.Fields);
|
|
Mixin.Read(type.Methods);
|
|
}
|
|
}
|
|
|
|
private void InitializeTypeDefinitions()
|
|
{
|
|
if (metadata.Types != null)
|
|
return;
|
|
|
|
InitializeNestedTypes();
|
|
InitializeFields();
|
|
InitializeMethods();
|
|
|
|
int length = MoveTo(Table.TypeDef);
|
|
TypeDefinition[] types = metadata.Types = new TypeDefinition [length];
|
|
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
if (types[i] != null)
|
|
continue;
|
|
|
|
types[i] = ReadType(i + 1);
|
|
}
|
|
|
|
if (module.IsWindowsMetadata())
|
|
{
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
WindowsRuntimeProjections.Project(types[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool IsNested(TypeAttributes attributes)
|
|
{
|
|
switch (attributes & TypeAttributes.VisibilityMask)
|
|
{
|
|
case TypeAttributes.NestedAssembly:
|
|
case TypeAttributes.NestedFamANDAssem:
|
|
case TypeAttributes.NestedFamily:
|
|
case TypeAttributes.NestedFamORAssem:
|
|
case TypeAttributes.NestedPrivate:
|
|
case TypeAttributes.NestedPublic:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool HasNestedTypes(TypeDefinition type)
|
|
{
|
|
Collection<uint> mapping;
|
|
InitializeNestedTypes();
|
|
|
|
if (!metadata.TryGetNestedTypeMapping(type, out mapping))
|
|
return false;
|
|
|
|
return mapping.Count > 0;
|
|
}
|
|
|
|
public Collection<TypeDefinition> ReadNestedTypes(TypeDefinition type)
|
|
{
|
|
InitializeNestedTypes();
|
|
Collection<uint> mapping;
|
|
if (!metadata.TryGetNestedTypeMapping(type, out mapping))
|
|
return new MemberDefinitionCollection<TypeDefinition>(type);
|
|
|
|
MemberDefinitionCollection<TypeDefinition> nested_types = new(type, mapping.Count);
|
|
|
|
for (int i = 0; i < mapping.Count; i++)
|
|
{
|
|
TypeDefinition nested_type = GetTypeDefinition(mapping[i]);
|
|
|
|
if (nested_type != null)
|
|
nested_types.Add(nested_type);
|
|
}
|
|
|
|
metadata.RemoveNestedTypeMapping(type);
|
|
|
|
return nested_types;
|
|
}
|
|
|
|
private void InitializeNestedTypes()
|
|
{
|
|
if (metadata.NestedTypes != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.NestedClass);
|
|
|
|
metadata.NestedTypes = new(length);
|
|
metadata.ReverseNestedTypes = new(length);
|
|
|
|
if (length == 0)
|
|
return;
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
uint nested = ReadTableIndex(Table.TypeDef);
|
|
uint declaring = ReadTableIndex(Table.TypeDef);
|
|
|
|
AddNestedMapping(declaring, nested);
|
|
}
|
|
}
|
|
|
|
private void AddNestedMapping(uint declaring, uint nested)
|
|
{
|
|
metadata.SetNestedTypeMapping(declaring, AddMapping(metadata.NestedTypes, declaring, nested));
|
|
metadata.SetReverseNestedTypeMapping(nested, declaring);
|
|
}
|
|
|
|
private static Collection<TValue> AddMapping<TKey, TValue>(Dictionary<TKey, Collection<TValue>> cache, TKey key, TValue value)
|
|
{
|
|
Collection<TValue> mapped;
|
|
if (!cache.TryGetValue(key, out mapped))
|
|
{
|
|
mapped = new();
|
|
}
|
|
mapped.Add(value);
|
|
return mapped;
|
|
}
|
|
|
|
private TypeDefinition ReadType(uint rid)
|
|
{
|
|
if (!MoveTo(Table.TypeDef, rid))
|
|
return null;
|
|
|
|
TypeAttributes attributes = (TypeAttributes)ReadUInt32();
|
|
string name = ReadString();
|
|
string @namespace = ReadString();
|
|
TypeDefinition type = new(@namespace, name, attributes);
|
|
type.token = new(TokenType.TypeDef, rid);
|
|
type.scope = module;
|
|
type.module = module;
|
|
|
|
metadata.AddTypeDefinition(type);
|
|
|
|
context = type;
|
|
|
|
type.BaseType = GetTypeDefOrRef(ReadMetadataToken(CodedIndex.TypeDefOrRef));
|
|
|
|
type.fields_range = ReadListRange(rid, Table.TypeDef, Table.Field);
|
|
type.methods_range = ReadListRange(rid, Table.TypeDef, Table.Method);
|
|
|
|
if (IsNested(attributes))
|
|
type.DeclaringType = GetNestedTypeDeclaringType(type);
|
|
|
|
return type;
|
|
}
|
|
|
|
private TypeDefinition GetNestedTypeDeclaringType(TypeDefinition type)
|
|
{
|
|
uint declaring_rid;
|
|
if (!metadata.TryGetReverseNestedTypeMapping(type, out declaring_rid))
|
|
return null;
|
|
|
|
metadata.RemoveReverseNestedTypeMapping(type);
|
|
return GetTypeDefinition(declaring_rid);
|
|
}
|
|
|
|
private Range ReadListRange(uint current_index, Table current, Table target)
|
|
{
|
|
Range list = new();
|
|
|
|
uint start = ReadTableIndex(target);
|
|
if (start == 0)
|
|
return list;
|
|
|
|
uint next_index;
|
|
TableInformation current_table = image.TableHeap[current];
|
|
|
|
if (current_index == current_table.Length)
|
|
{
|
|
next_index = image.TableHeap[target].Length + 1;
|
|
}
|
|
else
|
|
{
|
|
int position = this.position;
|
|
this.position += (int)(current_table.RowSize - image.GetTableIndexSize(target));
|
|
next_index = ReadTableIndex(target);
|
|
this.position = position;
|
|
}
|
|
|
|
list.Start = start;
|
|
list.Length = next_index - start;
|
|
|
|
return list;
|
|
}
|
|
|
|
public Row<short, int> ReadTypeLayout(TypeDefinition type)
|
|
{
|
|
InitializeTypeLayouts();
|
|
Row<ushort, uint> class_layout;
|
|
uint rid = type.token.RID;
|
|
if (!metadata.ClassLayouts.TryGetValue(rid, out class_layout))
|
|
return new(Mixin.NoDataMarker, Mixin.NoDataMarker);
|
|
|
|
type.PackingSize = (short)class_layout.Col1;
|
|
type.ClassSize = (int)class_layout.Col2;
|
|
|
|
metadata.ClassLayouts.Remove(rid);
|
|
|
|
return new((short)class_layout.Col1, (int)class_layout.Col2);
|
|
}
|
|
|
|
private void InitializeTypeLayouts()
|
|
{
|
|
if (metadata.ClassLayouts != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.ClassLayout);
|
|
|
|
Dictionary<uint, Row<ushort, uint>> class_layouts = metadata.ClassLayouts = new(length);
|
|
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
ushort packing_size = ReadUInt16();
|
|
uint class_size = ReadUInt32();
|
|
|
|
uint parent = ReadTableIndex(Table.TypeDef);
|
|
|
|
class_layouts.Add(parent, new(packing_size, class_size));
|
|
}
|
|
}
|
|
|
|
public TypeReference GetTypeDefOrRef(MetadataToken token)
|
|
{
|
|
return (TypeReference)LookupToken(token);
|
|
}
|
|
|
|
public TypeDefinition GetTypeDefinition(uint rid)
|
|
{
|
|
InitializeTypeDefinitions();
|
|
|
|
TypeDefinition type = metadata.GetTypeDefinition(rid);
|
|
if (type != null)
|
|
return type;
|
|
|
|
type = ReadTypeDefinition(rid);
|
|
|
|
if (module.IsWindowsMetadata())
|
|
WindowsRuntimeProjections.Project(type);
|
|
|
|
return type;
|
|
}
|
|
|
|
private TypeDefinition ReadTypeDefinition(uint rid)
|
|
{
|
|
if (!MoveTo(Table.TypeDef, rid))
|
|
return null;
|
|
|
|
return ReadType(rid);
|
|
}
|
|
|
|
private void InitializeTypeReferences()
|
|
{
|
|
if (metadata.TypeReferences != null)
|
|
return;
|
|
|
|
metadata.TypeReferences = new TypeReference [image.GetTableLength(Table.TypeRef)];
|
|
}
|
|
|
|
public TypeReference GetTypeReference(string scope, string full_name)
|
|
{
|
|
InitializeTypeReferences();
|
|
|
|
int length = metadata.TypeReferences.Length;
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
TypeReference type = GetTypeReference(i);
|
|
|
|
if (type.FullName != full_name)
|
|
continue;
|
|
|
|
if (string.IsNullOrEmpty(scope))
|
|
return type;
|
|
|
|
if (type.Scope.Name == scope)
|
|
return type;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private TypeReference GetTypeReference(uint rid)
|
|
{
|
|
InitializeTypeReferences();
|
|
|
|
TypeReference type = metadata.GetTypeReference(rid);
|
|
if (type != null)
|
|
return type;
|
|
|
|
return ReadTypeReference(rid);
|
|
}
|
|
|
|
private TypeReference ReadTypeReference(uint rid)
|
|
{
|
|
if (!MoveTo(Table.TypeRef, rid))
|
|
return null;
|
|
|
|
TypeReference declaring_type = null;
|
|
IMetadataScope scope;
|
|
|
|
MetadataToken scope_token = ReadMetadataToken(CodedIndex.ResolutionScope);
|
|
|
|
string name = ReadString();
|
|
string @namespace = ReadString();
|
|
|
|
TypeReference type = new(@namespace, name, module, null);
|
|
|
|
type.token = new(TokenType.TypeRef, rid);
|
|
|
|
metadata.AddTypeReference(type);
|
|
|
|
if (scope_token.TokenType == TokenType.TypeRef)
|
|
{
|
|
if (scope_token.RID != rid)
|
|
{
|
|
declaring_type = GetTypeDefOrRef(scope_token);
|
|
|
|
scope = declaring_type != null ? declaring_type.Scope : module;
|
|
}
|
|
else // obfuscated typeref row pointing to self
|
|
{
|
|
scope = module;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
scope = GetTypeReferenceScope(scope_token);
|
|
}
|
|
|
|
type.scope = scope;
|
|
type.DeclaringType = declaring_type;
|
|
|
|
MetadataSystem.TryProcessPrimitiveTypeReference(type);
|
|
|
|
if (type.Module.IsWindowsMetadata())
|
|
WindowsRuntimeProjections.Project(type);
|
|
|
|
return type;
|
|
}
|
|
|
|
private IMetadataScope GetTypeReferenceScope(MetadataToken scope)
|
|
{
|
|
if (scope.TokenType == TokenType.Module)
|
|
return module;
|
|
|
|
IMetadataScope[] scopes;
|
|
|
|
switch (scope.TokenType)
|
|
{
|
|
case TokenType.AssemblyRef:
|
|
InitializeAssemblyReferences();
|
|
scopes = metadata.AssemblyReferences;
|
|
break;
|
|
case TokenType.ModuleRef:
|
|
InitializeModuleReferences();
|
|
scopes = metadata.ModuleReferences;
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
uint index = scope.RID - 1;
|
|
if (index < 0 || index >= scopes.Length)
|
|
return null;
|
|
|
|
return scopes[index];
|
|
}
|
|
|
|
public IEnumerable<TypeReference> GetTypeReferences()
|
|
{
|
|
InitializeTypeReferences();
|
|
|
|
int length = image.GetTableLength(Table.TypeRef);
|
|
|
|
TypeReference[] type_references = new TypeReference [length];
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
type_references[i - 1] = GetTypeReference(i);
|
|
|
|
return type_references;
|
|
}
|
|
|
|
private TypeReference GetTypeSpecification(uint rid)
|
|
{
|
|
if (!MoveTo(Table.TypeSpec, rid))
|
|
return null;
|
|
|
|
SignatureReader reader = ReadSignature(ReadBlobIndex());
|
|
TypeReference type = reader.ReadTypeSignature();
|
|
if (type.token.RID == 0)
|
|
type.token = new(TokenType.TypeSpec, rid);
|
|
|
|
return type;
|
|
}
|
|
|
|
private SignatureReader ReadSignature(uint signature)
|
|
{
|
|
return new(signature, this);
|
|
}
|
|
|
|
public bool HasInterfaces(TypeDefinition type)
|
|
{
|
|
InitializeInterfaces();
|
|
Collection<Row<uint, MetadataToken>> mapping;
|
|
|
|
return metadata.TryGetInterfaceMapping(type, out mapping);
|
|
}
|
|
|
|
public InterfaceImplementationCollection ReadInterfaces(TypeDefinition type)
|
|
{
|
|
InitializeInterfaces();
|
|
Collection<Row<uint, MetadataToken>> mapping;
|
|
|
|
if (!metadata.TryGetInterfaceMapping(type, out mapping))
|
|
return new(type);
|
|
|
|
InterfaceImplementationCollection interfaces = new(type, mapping.Count);
|
|
|
|
context = type;
|
|
|
|
for (int i = 0; i < mapping.Count; i++)
|
|
{
|
|
interfaces.Add(new(GetTypeDefOrRef(mapping[i].Col2), new(TokenType.InterfaceImpl, mapping[i].Col1)));
|
|
}
|
|
|
|
metadata.RemoveInterfaceMapping(type);
|
|
|
|
return interfaces;
|
|
}
|
|
|
|
private void InitializeInterfaces()
|
|
{
|
|
if (metadata.Interfaces != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.InterfaceImpl);
|
|
|
|
metadata.Interfaces = new(length);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
uint type = ReadTableIndex(Table.TypeDef);
|
|
MetadataToken @interface = ReadMetadataToken(CodedIndex.TypeDefOrRef);
|
|
|
|
AddInterfaceMapping(type, new(i, @interface));
|
|
}
|
|
}
|
|
|
|
private void AddInterfaceMapping(uint type, Row<uint, MetadataToken> @interface)
|
|
{
|
|
metadata.SetInterfaceMapping(type, AddMapping(metadata.Interfaces, type, @interface));
|
|
}
|
|
|
|
public Collection<FieldDefinition> ReadFields(TypeDefinition type)
|
|
{
|
|
Range fields_range = type.fields_range;
|
|
if (fields_range.Length == 0)
|
|
return new MemberDefinitionCollection<FieldDefinition>(type);
|
|
|
|
MemberDefinitionCollection<FieldDefinition> fields = new(type, (int)fields_range.Length);
|
|
context = type;
|
|
|
|
if (!MoveTo(Table.FieldPtr, fields_range.Start))
|
|
{
|
|
if (!MoveTo(Table.Field, fields_range.Start))
|
|
return fields;
|
|
|
|
for (uint i = 0; i < fields_range.Length; i++)
|
|
ReadField(fields_range.Start + i, fields);
|
|
}
|
|
else
|
|
{
|
|
ReadPointers(Table.FieldPtr, Table.Field, fields_range, fields, ReadField);
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
private void ReadField(uint field_rid, Collection<FieldDefinition> fields)
|
|
{
|
|
FieldAttributes attributes = (FieldAttributes)ReadUInt16();
|
|
string name = ReadString();
|
|
uint signature = ReadBlobIndex();
|
|
|
|
FieldDefinition field = new(name, attributes, ReadFieldType(signature));
|
|
field.token = new(TokenType.Field, field_rid);
|
|
metadata.AddFieldDefinition(field);
|
|
|
|
if (IsDeleted(field))
|
|
return;
|
|
|
|
fields.Add(field);
|
|
|
|
if (module.IsWindowsMetadata())
|
|
WindowsRuntimeProjections.Project(field);
|
|
}
|
|
|
|
private void InitializeFields()
|
|
{
|
|
if (metadata.Fields != null)
|
|
return;
|
|
|
|
metadata.Fields = new FieldDefinition [image.GetTableLength(Table.Field)];
|
|
}
|
|
|
|
private TypeReference ReadFieldType(uint signature)
|
|
{
|
|
SignatureReader reader = ReadSignature(signature);
|
|
|
|
const byte field_sig = 0x6;
|
|
|
|
if (reader.ReadByte() != field_sig)
|
|
throw new NotSupportedException();
|
|
|
|
return reader.ReadTypeSignature();
|
|
}
|
|
|
|
public int ReadFieldRVA(FieldDefinition field)
|
|
{
|
|
InitializeFieldRVAs();
|
|
uint rid = field.token.RID;
|
|
|
|
RVA rva;
|
|
if (!metadata.FieldRVAs.TryGetValue(rid, out rva))
|
|
return 0;
|
|
|
|
int size = GetFieldTypeSize(field.FieldType);
|
|
|
|
if (size == 0 || rva == 0)
|
|
return 0;
|
|
|
|
metadata.FieldRVAs.Remove(rid);
|
|
|
|
field.InitialValue = GetFieldInitializeValue(size, rva);
|
|
|
|
return (int)rva;
|
|
}
|
|
|
|
private byte[] GetFieldInitializeValue(int size, RVA rva)
|
|
{
|
|
return image.GetReaderAt(rva, size, (s, reader) => reader.ReadBytes(s)) ?? Empty<byte>.Array;
|
|
}
|
|
|
|
private static int GetFieldTypeSize(TypeReference type)
|
|
{
|
|
int size = 0;
|
|
|
|
switch (type.etype)
|
|
{
|
|
case ElementType.Boolean:
|
|
case ElementType.U1:
|
|
case ElementType.I1:
|
|
size = 1;
|
|
break;
|
|
case ElementType.U2:
|
|
case ElementType.I2:
|
|
case ElementType.Char:
|
|
size = 2;
|
|
break;
|
|
case ElementType.U4:
|
|
case ElementType.I4:
|
|
case ElementType.R4:
|
|
size = 4;
|
|
break;
|
|
case ElementType.U8:
|
|
case ElementType.I8:
|
|
case ElementType.R8:
|
|
size = 8;
|
|
break;
|
|
case ElementType.Ptr:
|
|
case ElementType.FnPtr:
|
|
size = IntPtr.Size;
|
|
break;
|
|
case ElementType.CModOpt:
|
|
case ElementType.CModReqD:
|
|
return GetFieldTypeSize(((IModifierType)type).ElementType);
|
|
default:
|
|
TypeDefinition field_type = type.Resolve();
|
|
if (field_type != null && field_type.HasLayoutInfo)
|
|
size = field_type.ClassSize;
|
|
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
private void InitializeFieldRVAs()
|
|
{
|
|
if (metadata.FieldRVAs != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.FieldRVA);
|
|
|
|
Dictionary<uint, uint> field_rvas = metadata.FieldRVAs = new(length);
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
uint rva = ReadUInt32();
|
|
uint field = ReadTableIndex(Table.Field);
|
|
|
|
field_rvas.Add(field, rva);
|
|
}
|
|
}
|
|
|
|
public int ReadFieldLayout(FieldDefinition field)
|
|
{
|
|
InitializeFieldLayouts();
|
|
uint rid = field.token.RID;
|
|
uint offset;
|
|
if (!metadata.FieldLayouts.TryGetValue(rid, out offset))
|
|
return Mixin.NoDataMarker;
|
|
|
|
metadata.FieldLayouts.Remove(rid);
|
|
|
|
return (int)offset;
|
|
}
|
|
|
|
private void InitializeFieldLayouts()
|
|
{
|
|
if (metadata.FieldLayouts != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.FieldLayout);
|
|
|
|
Dictionary<uint, uint> field_layouts = metadata.FieldLayouts = new(length);
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
uint offset = ReadUInt32();
|
|
uint field = ReadTableIndex(Table.Field);
|
|
|
|
field_layouts.Add(field, offset);
|
|
}
|
|
}
|
|
|
|
public bool HasEvents(TypeDefinition type)
|
|
{
|
|
InitializeEvents();
|
|
|
|
Range range;
|
|
if (!metadata.TryGetEventsRange(type, out range))
|
|
return false;
|
|
|
|
return range.Length > 0;
|
|
}
|
|
|
|
public Collection<EventDefinition> ReadEvents(TypeDefinition type)
|
|
{
|
|
InitializeEvents();
|
|
Range range;
|
|
|
|
if (!metadata.TryGetEventsRange(type, out range))
|
|
return new MemberDefinitionCollection<EventDefinition>(type);
|
|
|
|
MemberDefinitionCollection<EventDefinition> events = new(type, (int)range.Length);
|
|
|
|
metadata.RemoveEventsRange(type);
|
|
|
|
if (range.Length == 0)
|
|
return events;
|
|
|
|
context = type;
|
|
|
|
if (!MoveTo(Table.EventPtr, range.Start))
|
|
{
|
|
if (!MoveTo(Table.Event, range.Start))
|
|
return events;
|
|
|
|
for (uint i = 0; i < range.Length; i++)
|
|
ReadEvent(range.Start + i, events);
|
|
}
|
|
else
|
|
{
|
|
ReadPointers(Table.EventPtr, Table.Event, range, events, ReadEvent);
|
|
}
|
|
|
|
return events;
|
|
}
|
|
|
|
private void ReadEvent(uint event_rid, Collection<EventDefinition> events)
|
|
{
|
|
EventAttributes attributes = (EventAttributes)ReadUInt16();
|
|
string name = ReadString();
|
|
TypeReference event_type = GetTypeDefOrRef(ReadMetadataToken(CodedIndex.TypeDefOrRef));
|
|
|
|
EventDefinition @event = new(name, attributes, event_type);
|
|
@event.token = new(TokenType.Event, event_rid);
|
|
|
|
if (IsDeleted(@event))
|
|
return;
|
|
|
|
events.Add(@event);
|
|
}
|
|
|
|
private void InitializeEvents()
|
|
{
|
|
if (metadata.Events != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.EventMap);
|
|
|
|
metadata.Events = new(length);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
uint type_rid = ReadTableIndex(Table.TypeDef);
|
|
Range events_range = ReadListRange(i, Table.EventMap, Table.Event);
|
|
metadata.AddEventsRange(type_rid, events_range);
|
|
}
|
|
}
|
|
|
|
public bool HasProperties(TypeDefinition type)
|
|
{
|
|
InitializeProperties();
|
|
|
|
Range range;
|
|
if (!metadata.TryGetPropertiesRange(type, out range))
|
|
return false;
|
|
|
|
return range.Length > 0;
|
|
}
|
|
|
|
public Collection<PropertyDefinition> ReadProperties(TypeDefinition type)
|
|
{
|
|
InitializeProperties();
|
|
|
|
Range range;
|
|
|
|
if (!metadata.TryGetPropertiesRange(type, out range))
|
|
return new MemberDefinitionCollection<PropertyDefinition>(type);
|
|
|
|
metadata.RemovePropertiesRange(type);
|
|
|
|
MemberDefinitionCollection<PropertyDefinition> properties = new(type, (int)range.Length);
|
|
|
|
if (range.Length == 0)
|
|
return properties;
|
|
|
|
context = type;
|
|
|
|
if (!MoveTo(Table.PropertyPtr, range.Start))
|
|
{
|
|
if (!MoveTo(Table.Property, range.Start))
|
|
return properties;
|
|
for (uint i = 0; i < range.Length; i++)
|
|
ReadProperty(range.Start + i, properties);
|
|
}
|
|
else
|
|
{
|
|
ReadPointers(Table.PropertyPtr, Table.Property, range, properties, ReadProperty);
|
|
}
|
|
|
|
return properties;
|
|
}
|
|
|
|
private void ReadProperty(uint property_rid, Collection<PropertyDefinition> properties)
|
|
{
|
|
PropertyAttributes attributes = (PropertyAttributes)ReadUInt16();
|
|
string name = ReadString();
|
|
uint signature = ReadBlobIndex();
|
|
|
|
SignatureReader reader = ReadSignature(signature);
|
|
const byte property_signature = 0x8;
|
|
|
|
byte calling_convention = reader.ReadByte();
|
|
|
|
if ((calling_convention & property_signature) == 0)
|
|
throw new NotSupportedException();
|
|
|
|
bool has_this = (calling_convention & 0x20) != 0;
|
|
|
|
reader.ReadCompressedUInt32(); // count
|
|
|
|
PropertyDefinition property = new(name, attributes, reader.ReadTypeSignature());
|
|
property.HasThis = has_this;
|
|
property.token = new(TokenType.Property, property_rid);
|
|
|
|
if (IsDeleted(property))
|
|
return;
|
|
|
|
properties.Add(property);
|
|
}
|
|
|
|
private void InitializeProperties()
|
|
{
|
|
if (metadata.Properties != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.PropertyMap);
|
|
|
|
metadata.Properties = new(length);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
uint type_rid = ReadTableIndex(Table.TypeDef);
|
|
Range properties_range = ReadListRange(i, Table.PropertyMap, Table.Property);
|
|
metadata.AddPropertiesRange(type_rid, properties_range);
|
|
}
|
|
}
|
|
|
|
private MethodSemanticsAttributes ReadMethodSemantics(MethodDefinition method)
|
|
{
|
|
InitializeMethodSemantics();
|
|
Row<MethodSemanticsAttributes, MetadataToken> row;
|
|
if (!metadata.Semantics.TryGetValue(method.token.RID, out row))
|
|
return MethodSemanticsAttributes.None;
|
|
|
|
TypeDefinition type = method.DeclaringType;
|
|
|
|
switch (row.Col1)
|
|
{
|
|
case MethodSemanticsAttributes.AddOn:
|
|
GetEvent(type, row.Col2).add_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Fire:
|
|
GetEvent(type, row.Col2).invoke_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.RemoveOn:
|
|
GetEvent(type, row.Col2).remove_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Getter:
|
|
GetProperty(type, row.Col2).get_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Setter:
|
|
GetProperty(type, row.Col2).set_method = method;
|
|
break;
|
|
case MethodSemanticsAttributes.Other:
|
|
switch (row.Col2.TokenType)
|
|
{
|
|
case TokenType.Event:
|
|
{
|
|
EventDefinition @event = GetEvent(type, row.Col2);
|
|
if (@event.other_methods == null)
|
|
@event.other_methods = new();
|
|
|
|
@event.other_methods.Add(method);
|
|
break;
|
|
}
|
|
case TokenType.Property:
|
|
{
|
|
PropertyDefinition property = GetProperty(type, row.Col2);
|
|
if (property.other_methods == null)
|
|
property.other_methods = new();
|
|
|
|
property.other_methods.Add(method);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
metadata.Semantics.Remove(method.token.RID);
|
|
|
|
return row.Col1;
|
|
}
|
|
|
|
private static EventDefinition GetEvent(TypeDefinition type, MetadataToken token)
|
|
{
|
|
if (token.TokenType != TokenType.Event)
|
|
throw new ArgumentException();
|
|
|
|
return GetMember(type.Events, token);
|
|
}
|
|
|
|
private static PropertyDefinition GetProperty(TypeDefinition type, MetadataToken token)
|
|
{
|
|
if (token.TokenType != TokenType.Property)
|
|
throw new ArgumentException();
|
|
|
|
return GetMember(type.Properties, token);
|
|
}
|
|
|
|
private static TMember GetMember<TMember>(Collection<TMember> members, MetadataToken token) where TMember : IMemberDefinition
|
|
{
|
|
for (int i = 0; i < members.Count; i++)
|
|
{
|
|
TMember member = members[i];
|
|
if (member.MetadataToken == token)
|
|
return member;
|
|
}
|
|
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
private void InitializeMethodSemantics()
|
|
{
|
|
if (metadata.Semantics != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.MethodSemantics);
|
|
|
|
Dictionary<uint, Row<MethodSemanticsAttributes, MetadataToken>> semantics = metadata.Semantics = new(0);
|
|
|
|
for (uint i = 0; i < length; i++)
|
|
{
|
|
MethodSemanticsAttributes attributes = (MethodSemanticsAttributes)ReadUInt16();
|
|
uint method_rid = ReadTableIndex(Table.Method);
|
|
MetadataToken association = ReadMetadataToken(CodedIndex.HasSemantics);
|
|
|
|
semantics[method_rid] = new(attributes, association);
|
|
}
|
|
}
|
|
|
|
public void ReadMethods(PropertyDefinition property)
|
|
{
|
|
ReadAllSemantics(property.DeclaringType);
|
|
}
|
|
|
|
public void ReadMethods(EventDefinition @event)
|
|
{
|
|
ReadAllSemantics(@event.DeclaringType);
|
|
}
|
|
|
|
public void ReadAllSemantics(MethodDefinition method)
|
|
{
|
|
ReadAllSemantics(method.DeclaringType);
|
|
}
|
|
|
|
private void ReadAllSemantics(TypeDefinition type)
|
|
{
|
|
Collection<MethodDefinition> methods = type.Methods;
|
|
for (int i = 0; i < methods.Count; i++)
|
|
{
|
|
MethodDefinition method = methods[i];
|
|
if (method.sem_attrs_ready)
|
|
continue;
|
|
|
|
method.sem_attrs = ReadMethodSemantics(method);
|
|
method.sem_attrs_ready = true;
|
|
}
|
|
}
|
|
|
|
public Collection<MethodDefinition> ReadMethods(TypeDefinition type)
|
|
{
|
|
Range methods_range = type.methods_range;
|
|
if (methods_range.Length == 0)
|
|
return new MemberDefinitionCollection<MethodDefinition>(type);
|
|
|
|
MemberDefinitionCollection<MethodDefinition> methods = new(type, (int)methods_range.Length);
|
|
if (!MoveTo(Table.MethodPtr, methods_range.Start))
|
|
{
|
|
if (!MoveTo(Table.Method, methods_range.Start))
|
|
return methods;
|
|
|
|
for (uint i = 0; i < methods_range.Length; i++)
|
|
ReadMethod(methods_range.Start + i, methods);
|
|
}
|
|
else
|
|
{
|
|
ReadPointers(Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod);
|
|
}
|
|
|
|
return methods;
|
|
}
|
|
|
|
private void ReadPointers<TMember>(Table ptr, Table table, Range range, Collection<TMember> members, Action<uint, Collection<TMember>> reader) where TMember : IMemberDefinition
|
|
{
|
|
for (uint i = 0; i < range.Length; i++)
|
|
{
|
|
MoveTo(ptr, range.Start + i);
|
|
|
|
uint rid = ReadTableIndex(table);
|
|
MoveTo(table, rid);
|
|
|
|
reader(rid, members);
|
|
}
|
|
}
|
|
|
|
private static bool IsDeleted(IMemberDefinition member)
|
|
{
|
|
return member.IsSpecialName && member.Name == "_Deleted";
|
|
}
|
|
|
|
private void InitializeMethods()
|
|
{
|
|
if (metadata.Methods != null)
|
|
return;
|
|
|
|
metadata.Methods = new MethodDefinition [image.GetTableLength(Table.Method)];
|
|
}
|
|
|
|
private void ReadMethod(uint method_rid, Collection<MethodDefinition> methods)
|
|
{
|
|
MethodDefinition method = new();
|
|
method.rva = ReadUInt32();
|
|
method.ImplAttributes = (MethodImplAttributes)ReadUInt16();
|
|
method.Attributes = (MethodAttributes)ReadUInt16();
|
|
method.Name = ReadString();
|
|
method.token = new(TokenType.Method, method_rid);
|
|
|
|
if (IsDeleted(method))
|
|
return;
|
|
|
|
methods.Add(method); // attach method
|
|
|
|
uint signature = ReadBlobIndex();
|
|
Range param_range = ReadListRange(method_rid, Table.Method, Table.Param);
|
|
|
|
context = method;
|
|
|
|
ReadMethodSignature(signature, method);
|
|
metadata.AddMethodDefinition(method);
|
|
|
|
if (param_range.Length != 0)
|
|
{
|
|
int position = this.position;
|
|
ReadParameters(method, param_range);
|
|
this.position = position;
|
|
}
|
|
|
|
if (module.IsWindowsMetadata())
|
|
WindowsRuntimeProjections.Project(method);
|
|
}
|
|
|
|
private void ReadParameters(MethodDefinition method, Range param_range)
|
|
{
|
|
if (!MoveTo(Table.ParamPtr, param_range.Start))
|
|
{
|
|
if (!MoveTo(Table.Param, param_range.Start))
|
|
return;
|
|
|
|
for (uint i = 0; i < param_range.Length; i++)
|
|
ReadParameter(param_range.Start + i, method);
|
|
}
|
|
else
|
|
{
|
|
ReadParameterPointers(method, param_range);
|
|
}
|
|
}
|
|
|
|
private void ReadParameterPointers(MethodDefinition method, Range range)
|
|
{
|
|
for (uint i = 0; i < range.Length; i++)
|
|
{
|
|
MoveTo(Table.ParamPtr, range.Start + i);
|
|
|
|
uint rid = ReadTableIndex(Table.Param);
|
|
|
|
MoveTo(Table.Param, rid);
|
|
|
|
ReadParameter(rid, method);
|
|
}
|
|
}
|
|
|
|
private void ReadParameter(uint param_rid, MethodDefinition method)
|
|
{
|
|
ParameterAttributes attributes = (ParameterAttributes)ReadUInt16();
|
|
ushort sequence = ReadUInt16();
|
|
string name = ReadString();
|
|
|
|
ParameterDefinition parameter = sequence == 0 ? method.MethodReturnType.Parameter : method.Parameters[sequence - 1];
|
|
|
|
parameter.token = new(TokenType.Param, param_rid);
|
|
parameter.Name = name;
|
|
parameter.Attributes = attributes;
|
|
}
|
|
|
|
private void ReadMethodSignature(uint signature, IMethodSignature method)
|
|
{
|
|
SignatureReader reader = ReadSignature(signature);
|
|
reader.ReadMethodSignature(method);
|
|
}
|
|
|
|
public PInvokeInfo ReadPInvokeInfo(MethodDefinition method)
|
|
{
|
|
InitializePInvokes();
|
|
Row<PInvokeAttributes, uint, uint> row;
|
|
|
|
uint rid = method.token.RID;
|
|
|
|
if (!metadata.PInvokes.TryGetValue(rid, out row))
|
|
return null;
|
|
|
|
metadata.PInvokes.Remove(rid);
|
|
|
|
return new(row.Col1, image.StringHeap.Read(row.Col2), module.ModuleReferences[(int)row.Col3 - 1]);
|
|
}
|
|
|
|
private void InitializePInvokes()
|
|
{
|
|
if (metadata.PInvokes != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.ImplMap);
|
|
|
|
Dictionary<uint, Row<PInvokeAttributes, uint, uint>> pinvokes = metadata.PInvokes = new(length);
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
PInvokeAttributes attributes = (PInvokeAttributes)ReadUInt16();
|
|
MetadataToken method = ReadMetadataToken(CodedIndex.MemberForwarded);
|
|
uint name = ReadStringIndex();
|
|
uint scope = ReadTableIndex(Table.File);
|
|
|
|
if (method.TokenType != TokenType.Method)
|
|
continue;
|
|
|
|
pinvokes.Add(method.RID, new(attributes, name, scope));
|
|
}
|
|
}
|
|
|
|
public bool HasGenericParameters(IGenericParameterProvider provider)
|
|
{
|
|
InitializeGenericParameters();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetGenericParameterRanges(provider, out ranges))
|
|
return false;
|
|
|
|
return RangesSize(ranges) > 0;
|
|
}
|
|
|
|
public Collection<GenericParameter> ReadGenericParameters(IGenericParameterProvider provider)
|
|
{
|
|
InitializeGenericParameters();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetGenericParameterRanges(provider, out ranges))
|
|
return new GenericParameterCollection(provider);
|
|
|
|
metadata.RemoveGenericParameterRange(provider);
|
|
|
|
GenericParameterCollection generic_parameters = new(provider, RangesSize(ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadGenericParametersRange(ranges[i], provider, generic_parameters);
|
|
|
|
return generic_parameters;
|
|
}
|
|
|
|
private void ReadGenericParametersRange(Range range, IGenericParameterProvider provider, GenericParameterCollection generic_parameters)
|
|
{
|
|
if (!MoveTo(Table.GenericParam, range.Start))
|
|
return;
|
|
|
|
for (uint i = 0; i < range.Length; i++)
|
|
{
|
|
ReadUInt16(); // index
|
|
GenericParameterAttributes flags = (GenericParameterAttributes)ReadUInt16();
|
|
ReadMetadataToken(CodedIndex.TypeOrMethodDef);
|
|
string name = ReadString();
|
|
|
|
GenericParameter parameter = new(name, provider);
|
|
parameter.token = new(TokenType.GenericParam, range.Start + i);
|
|
parameter.Attributes = flags;
|
|
|
|
generic_parameters.Add(parameter);
|
|
}
|
|
}
|
|
|
|
private void InitializeGenericParameters()
|
|
{
|
|
if (metadata.GenericParameters != null)
|
|
return;
|
|
|
|
metadata.GenericParameters = InitializeRanges(Table.GenericParam, () =>
|
|
{
|
|
Advance(4);
|
|
MetadataToken next = ReadMetadataToken(CodedIndex.TypeOrMethodDef);
|
|
ReadStringIndex();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
private Dictionary<MetadataToken, Range[]> InitializeRanges(Table table, Func<MetadataToken> get_next)
|
|
{
|
|
int length = MoveTo(table);
|
|
Dictionary<MetadataToken, Range[]> ranges = new(length);
|
|
|
|
if (length == 0)
|
|
return ranges;
|
|
|
|
MetadataToken owner = MetadataToken.Zero;
|
|
Range range = new(1, 0);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
MetadataToken next = get_next();
|
|
|
|
if (i == 1)
|
|
{
|
|
owner = next;
|
|
range.Length++;
|
|
}
|
|
else if (next != owner)
|
|
{
|
|
AddRange(ranges, owner, range);
|
|
range = new(i, 1);
|
|
owner = next;
|
|
}
|
|
else
|
|
{
|
|
range.Length++;
|
|
}
|
|
}
|
|
|
|
AddRange(ranges, owner, range);
|
|
|
|
return ranges;
|
|
}
|
|
|
|
private static void AddRange(Dictionary<MetadataToken, Range[]> ranges, MetadataToken owner, Range range)
|
|
{
|
|
if (owner.RID == 0)
|
|
return;
|
|
|
|
Range[] slots;
|
|
if (!ranges.TryGetValue(owner, out slots))
|
|
{
|
|
ranges.Add(owner, new[] { range });
|
|
return;
|
|
}
|
|
|
|
ranges[owner] = slots.Add(range);
|
|
}
|
|
|
|
public bool HasGenericConstraints(GenericParameter generic_parameter)
|
|
{
|
|
InitializeGenericConstraints();
|
|
|
|
Collection<Row<uint, MetadataToken>> mapping;
|
|
if (!metadata.TryGetGenericConstraintMapping(generic_parameter, out mapping))
|
|
return false;
|
|
|
|
return mapping.Count > 0;
|
|
}
|
|
|
|
public GenericParameterConstraintCollection ReadGenericConstraints(GenericParameter generic_parameter)
|
|
{
|
|
InitializeGenericConstraints();
|
|
|
|
Collection<Row<uint, MetadataToken>> mapping;
|
|
if (!metadata.TryGetGenericConstraintMapping(generic_parameter, out mapping))
|
|
return new(generic_parameter);
|
|
|
|
GenericParameterConstraintCollection constraints = new(generic_parameter, mapping.Count);
|
|
|
|
context = (IGenericContext)generic_parameter.Owner;
|
|
|
|
for (int i = 0; i < mapping.Count; i++)
|
|
{
|
|
constraints.Add(new(GetTypeDefOrRef(mapping[i].Col2), new(TokenType.GenericParamConstraint, mapping[i].Col1)));
|
|
}
|
|
|
|
metadata.RemoveGenericConstraintMapping(generic_parameter);
|
|
|
|
return constraints;
|
|
}
|
|
|
|
private void InitializeGenericConstraints()
|
|
{
|
|
if (metadata.GenericConstraints != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.GenericParamConstraint);
|
|
|
|
metadata.GenericConstraints = new(length);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
AddGenericConstraintMapping(ReadTableIndex(Table.GenericParam), new(i, ReadMetadataToken(CodedIndex.TypeDefOrRef)));
|
|
}
|
|
}
|
|
|
|
private void AddGenericConstraintMapping(uint generic_parameter, Row<uint, MetadataToken> constraint)
|
|
{
|
|
metadata.SetGenericConstraintMapping(generic_parameter, AddMapping(metadata.GenericConstraints, generic_parameter, constraint));
|
|
}
|
|
|
|
public bool HasOverrides(MethodDefinition method)
|
|
{
|
|
InitializeOverrides();
|
|
Collection<MetadataToken> mapping;
|
|
|
|
if (!metadata.TryGetOverrideMapping(method, out mapping))
|
|
return false;
|
|
|
|
return mapping.Count > 0;
|
|
}
|
|
|
|
public Collection<MethodReference> ReadOverrides(MethodDefinition method)
|
|
{
|
|
InitializeOverrides();
|
|
|
|
Collection<MetadataToken> mapping;
|
|
if (!metadata.TryGetOverrideMapping(method, out mapping))
|
|
return new();
|
|
|
|
Collection<MethodReference> overrides = new(mapping.Count);
|
|
|
|
context = method;
|
|
|
|
for (int i = 0; i < mapping.Count; i++)
|
|
overrides.Add((MethodReference)LookupToken(mapping[i]));
|
|
|
|
metadata.RemoveOverrideMapping(method);
|
|
|
|
return overrides;
|
|
}
|
|
|
|
private void InitializeOverrides()
|
|
{
|
|
if (metadata.Overrides != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.MethodImpl);
|
|
|
|
metadata.Overrides = new(length);
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
ReadTableIndex(Table.TypeDef);
|
|
|
|
MetadataToken method = ReadMetadataToken(CodedIndex.MethodDefOrRef);
|
|
if (method.TokenType != TokenType.Method)
|
|
throw new NotSupportedException();
|
|
|
|
MetadataToken @override = ReadMetadataToken(CodedIndex.MethodDefOrRef);
|
|
|
|
AddOverrideMapping(method.RID, @override);
|
|
}
|
|
}
|
|
|
|
private void AddOverrideMapping(uint method_rid, MetadataToken @override)
|
|
{
|
|
metadata.SetOverrideMapping(method_rid, AddMapping(metadata.Overrides, method_rid, @override));
|
|
}
|
|
|
|
public MethodBody ReadMethodBody(MethodDefinition method)
|
|
{
|
|
return code.ReadMethodBody(method);
|
|
}
|
|
|
|
public int ReadCodeSize(MethodDefinition method)
|
|
{
|
|
return code.ReadCodeSize(method);
|
|
}
|
|
|
|
public CallSite ReadCallSite(MetadataToken token)
|
|
{
|
|
if (!MoveTo(Table.StandAloneSig, token.RID))
|
|
return null;
|
|
|
|
uint signature = ReadBlobIndex();
|
|
|
|
CallSite call_site = new();
|
|
|
|
ReadMethodSignature(signature, call_site);
|
|
|
|
call_site.MetadataToken = token;
|
|
|
|
return call_site;
|
|
}
|
|
|
|
public VariableDefinitionCollection ReadVariables(MetadataToken local_var_token, MethodDefinition method = null)
|
|
{
|
|
if (!MoveTo(Table.StandAloneSig, local_var_token.RID))
|
|
return null;
|
|
|
|
SignatureReader reader = ReadSignature(ReadBlobIndex());
|
|
const byte local_sig = 0x7;
|
|
|
|
if (reader.ReadByte() != local_sig)
|
|
throw new NotSupportedException();
|
|
|
|
uint count = reader.ReadCompressedUInt32();
|
|
if (count == 0)
|
|
return null;
|
|
|
|
VariableDefinitionCollection variables = new(method, (int)count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
variables.Add(new(reader.ReadTypeSignature()));
|
|
|
|
return variables;
|
|
}
|
|
|
|
public IMetadataTokenProvider LookupToken(MetadataToken token)
|
|
{
|
|
uint rid = token.RID;
|
|
|
|
if (rid == 0)
|
|
return null;
|
|
|
|
if (metadata_reader != null)
|
|
return metadata_reader.LookupToken(token);
|
|
|
|
IMetadataTokenProvider element;
|
|
int position = this.position;
|
|
IGenericContext context = this.context;
|
|
|
|
switch (token.TokenType)
|
|
{
|
|
case TokenType.TypeDef:
|
|
element = GetTypeDefinition(rid);
|
|
break;
|
|
case TokenType.TypeRef:
|
|
element = GetTypeReference(rid);
|
|
break;
|
|
case TokenType.TypeSpec:
|
|
element = GetTypeSpecification(rid);
|
|
break;
|
|
case TokenType.Field:
|
|
element = GetFieldDefinition(rid);
|
|
break;
|
|
case TokenType.Method:
|
|
element = GetMethodDefinition(rid);
|
|
break;
|
|
case TokenType.MemberRef:
|
|
element = GetMemberReference(rid);
|
|
break;
|
|
case TokenType.MethodSpec:
|
|
element = GetMethodSpecification(rid);
|
|
break;
|
|
default:
|
|
return null;
|
|
}
|
|
|
|
this.position = position;
|
|
this.context = context;
|
|
|
|
return element;
|
|
}
|
|
|
|
public FieldDefinition GetFieldDefinition(uint rid)
|
|
{
|
|
InitializeTypeDefinitions();
|
|
|
|
FieldDefinition field = metadata.GetFieldDefinition(rid);
|
|
if (field != null)
|
|
return field;
|
|
|
|
return LookupField(rid);
|
|
}
|
|
|
|
private FieldDefinition LookupField(uint rid)
|
|
{
|
|
TypeDefinition type = metadata.GetFieldDeclaringType(rid);
|
|
if (type == null)
|
|
return null;
|
|
|
|
Mixin.Read(type.Fields);
|
|
|
|
return metadata.GetFieldDefinition(rid);
|
|
}
|
|
|
|
public MethodDefinition GetMethodDefinition(uint rid)
|
|
{
|
|
InitializeTypeDefinitions();
|
|
|
|
MethodDefinition method = metadata.GetMethodDefinition(rid);
|
|
if (method != null)
|
|
return method;
|
|
|
|
return LookupMethod(rid);
|
|
}
|
|
|
|
private MethodDefinition LookupMethod(uint rid)
|
|
{
|
|
TypeDefinition type = metadata.GetMethodDeclaringType(rid);
|
|
if (type == null)
|
|
return null;
|
|
|
|
Mixin.Read(type.Methods);
|
|
|
|
return metadata.GetMethodDefinition(rid);
|
|
}
|
|
|
|
private MethodSpecification GetMethodSpecification(uint rid)
|
|
{
|
|
if (!MoveTo(Table.MethodSpec, rid))
|
|
return null;
|
|
|
|
MethodReference element_method = (MethodReference)LookupToken(ReadMetadataToken(CodedIndex.MethodDefOrRef));
|
|
uint signature = ReadBlobIndex();
|
|
|
|
MethodSpecification method_spec = ReadMethodSpecSignature(signature, element_method);
|
|
method_spec.token = new(TokenType.MethodSpec, rid);
|
|
return method_spec;
|
|
}
|
|
|
|
private MethodSpecification ReadMethodSpecSignature(uint signature, MethodReference method)
|
|
{
|
|
SignatureReader reader = ReadSignature(signature);
|
|
const byte methodspec_sig = 0x0a;
|
|
|
|
byte call_conv = reader.ReadByte();
|
|
|
|
if (call_conv != methodspec_sig)
|
|
throw new NotSupportedException();
|
|
|
|
uint arity = reader.ReadCompressedUInt32();
|
|
|
|
GenericInstanceMethod instance = new(method, (int)arity);
|
|
|
|
reader.ReadGenericInstanceSignature(method, instance, arity);
|
|
|
|
return instance;
|
|
}
|
|
|
|
private MemberReference GetMemberReference(uint rid)
|
|
{
|
|
InitializeMemberReferences();
|
|
|
|
MemberReference member = metadata.GetMemberReference(rid);
|
|
if (member != null)
|
|
return member;
|
|
|
|
member = ReadMemberReference(rid);
|
|
if (member != null && !member.ContainsGenericParameter)
|
|
metadata.AddMemberReference(member);
|
|
return member;
|
|
}
|
|
|
|
private MemberReference ReadMemberReference(uint rid)
|
|
{
|
|
if (!MoveTo(Table.MemberRef, rid))
|
|
return null;
|
|
|
|
MetadataToken token = ReadMetadataToken(CodedIndex.MemberRefParent);
|
|
string name = ReadString();
|
|
uint signature = ReadBlobIndex();
|
|
|
|
MemberReference member;
|
|
|
|
switch (token.TokenType)
|
|
{
|
|
case TokenType.TypeDef:
|
|
case TokenType.TypeRef:
|
|
case TokenType.TypeSpec:
|
|
member = ReadTypeMemberReference(token, name, signature);
|
|
break;
|
|
case TokenType.Method:
|
|
member = ReadMethodMemberReference(token, name, signature);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
member.token = new(TokenType.MemberRef, rid);
|
|
return member;
|
|
}
|
|
|
|
private MemberReference ReadTypeMemberReference(MetadataToken type, string name, uint signature)
|
|
{
|
|
TypeReference declaring_type = GetTypeDefOrRef(type);
|
|
|
|
if (!declaring_type.IsArray)
|
|
context = declaring_type;
|
|
|
|
MemberReference member = ReadMemberReferenceSignature(signature, declaring_type);
|
|
member.Name = name;
|
|
|
|
return member;
|
|
}
|
|
|
|
private MemberReference ReadMemberReferenceSignature(uint signature, TypeReference declaring_type)
|
|
{
|
|
SignatureReader reader = ReadSignature(signature);
|
|
const byte field_sig = 0x6;
|
|
|
|
if (reader.buffer[reader.position] == field_sig)
|
|
{
|
|
reader.position++;
|
|
FieldReference field = new();
|
|
field.DeclaringType = declaring_type;
|
|
field.FieldType = reader.ReadTypeSignature();
|
|
return field;
|
|
}
|
|
else
|
|
{
|
|
MethodReference method = new();
|
|
method.DeclaringType = declaring_type;
|
|
reader.ReadMethodSignature(method);
|
|
return method;
|
|
}
|
|
}
|
|
|
|
private MemberReference ReadMethodMemberReference(MetadataToken token, string name, uint signature)
|
|
{
|
|
MethodDefinition method = GetMethodDefinition(token.RID);
|
|
|
|
context = method;
|
|
|
|
MemberReference member = ReadMemberReferenceSignature(signature, method.DeclaringType);
|
|
member.Name = name;
|
|
|
|
return member;
|
|
}
|
|
|
|
private void InitializeMemberReferences()
|
|
{
|
|
if (metadata.MemberReferences != null)
|
|
return;
|
|
|
|
metadata.MemberReferences = new MemberReference [image.GetTableLength(Table.MemberRef)];
|
|
}
|
|
|
|
public IEnumerable<MemberReference> GetMemberReferences()
|
|
{
|
|
InitializeMemberReferences();
|
|
|
|
int length = image.GetTableLength(Table.MemberRef);
|
|
|
|
TypeSystem type_system = module.TypeSystem;
|
|
|
|
MethodDefinition context = new(string.Empty, MethodAttributes.Static, type_system.Void);
|
|
context.DeclaringType = new(string.Empty, string.Empty, TypeAttributes.Public);
|
|
|
|
MemberReference[] member_references = new MemberReference [length];
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
this.context = context;
|
|
member_references[i - 1] = GetMemberReference(i);
|
|
}
|
|
|
|
return member_references;
|
|
}
|
|
|
|
private void InitializeConstants()
|
|
{
|
|
if (metadata.Constants != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.Constant);
|
|
|
|
Dictionary<MetadataToken, Row<ElementType, uint>> constants = metadata.Constants = new(length);
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
ElementType type = (ElementType)ReadUInt16();
|
|
MetadataToken owner = ReadMetadataToken(CodedIndex.HasConstant);
|
|
uint signature = ReadBlobIndex();
|
|
|
|
constants.Add(owner, new(type, signature));
|
|
}
|
|
}
|
|
|
|
public TypeReference ReadConstantSignature(MetadataToken token)
|
|
{
|
|
if (token.TokenType != TokenType.Signature)
|
|
throw new NotSupportedException();
|
|
|
|
if (token.RID == 0)
|
|
return null;
|
|
|
|
if (!MoveTo(Table.StandAloneSig, token.RID))
|
|
return null;
|
|
|
|
return ReadFieldType(ReadBlobIndex());
|
|
}
|
|
|
|
public object ReadConstant(IConstantProvider owner)
|
|
{
|
|
InitializeConstants();
|
|
|
|
Row<ElementType, uint> row;
|
|
if (!metadata.Constants.TryGetValue(owner.MetadataToken, out row))
|
|
return Mixin.NoValue;
|
|
|
|
metadata.Constants.Remove(owner.MetadataToken);
|
|
|
|
return ReadConstantValue(row.Col1, row.Col2);
|
|
}
|
|
|
|
private object ReadConstantValue(ElementType etype, uint signature)
|
|
{
|
|
switch (etype)
|
|
{
|
|
case ElementType.Class:
|
|
case ElementType.Object:
|
|
return null;
|
|
case ElementType.String:
|
|
return ReadConstantString(signature);
|
|
default:
|
|
return ReadConstantPrimitive(etype, signature);
|
|
}
|
|
}
|
|
|
|
private string ReadConstantString(uint signature)
|
|
{
|
|
byte[] blob;
|
|
int index, count;
|
|
|
|
GetBlobView(signature, out blob, out index, out count);
|
|
if (count == 0)
|
|
return string.Empty;
|
|
|
|
if ((count & 1) == 1)
|
|
count--;
|
|
|
|
return Encoding.Unicode.GetString(blob, index, count);
|
|
}
|
|
|
|
private object ReadConstantPrimitive(ElementType type, uint signature)
|
|
{
|
|
SignatureReader reader = ReadSignature(signature);
|
|
return reader.ReadConstantSignature(type);
|
|
}
|
|
|
|
internal void InitializeCustomAttributes()
|
|
{
|
|
if (metadata.CustomAttributes != null)
|
|
return;
|
|
|
|
metadata.CustomAttributes = InitializeRanges(Table.CustomAttribute, () =>
|
|
{
|
|
MetadataToken next = ReadMetadataToken(CodedIndex.HasCustomAttribute);
|
|
ReadMetadataToken(CodedIndex.CustomAttributeType);
|
|
ReadBlobIndex();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
public bool HasCustomAttributes(ICustomAttributeProvider owner)
|
|
{
|
|
InitializeCustomAttributes();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetCustomAttributeRanges(owner, out ranges))
|
|
return false;
|
|
|
|
return RangesSize(ranges) > 0;
|
|
}
|
|
|
|
public Collection<CustomAttribute> ReadCustomAttributes(ICustomAttributeProvider owner)
|
|
{
|
|
InitializeCustomAttributes();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetCustomAttributeRanges(owner, out ranges))
|
|
return new();
|
|
|
|
Collection<CustomAttribute> custom_attributes = new(RangesSize(ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadCustomAttributeRange(ranges[i], custom_attributes);
|
|
|
|
metadata.RemoveCustomAttributeRange(owner);
|
|
|
|
if (module.IsWindowsMetadata())
|
|
foreach (CustomAttribute custom_attribute in custom_attributes)
|
|
WindowsRuntimeProjections.Project(owner, custom_attribute);
|
|
|
|
return custom_attributes;
|
|
}
|
|
|
|
private void ReadCustomAttributeRange(Range range, Collection<CustomAttribute> custom_attributes)
|
|
{
|
|
if (!MoveTo(Table.CustomAttribute, range.Start))
|
|
return;
|
|
|
|
for (int i = 0; i < range.Length; i++)
|
|
{
|
|
ReadMetadataToken(CodedIndex.HasCustomAttribute);
|
|
|
|
MethodReference constructor = (MethodReference)LookupToken(ReadMetadataToken(CodedIndex.CustomAttributeType));
|
|
|
|
uint signature = ReadBlobIndex();
|
|
|
|
custom_attributes.Add(new(signature, constructor));
|
|
}
|
|
}
|
|
|
|
private static int RangesSize(Range[] ranges)
|
|
{
|
|
uint size = 0;
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
size += ranges[i].Length;
|
|
|
|
return (int)size;
|
|
}
|
|
|
|
public IEnumerable<CustomAttribute> GetCustomAttributes()
|
|
{
|
|
InitializeTypeDefinitions();
|
|
|
|
uint length = image.TableHeap[Table.CustomAttribute].Length;
|
|
Collection<CustomAttribute> custom_attributes = new((int)length);
|
|
ReadCustomAttributeRange(new(1, length), custom_attributes);
|
|
|
|
return custom_attributes;
|
|
}
|
|
|
|
public byte[] ReadCustomAttributeBlob(uint signature)
|
|
{
|
|
return ReadBlob(signature);
|
|
}
|
|
|
|
public void ReadCustomAttributeSignature(CustomAttribute attribute)
|
|
{
|
|
SignatureReader reader = ReadSignature(attribute.signature);
|
|
|
|
if (!reader.CanReadMore())
|
|
return;
|
|
|
|
if (reader.ReadUInt16() != 0x0001)
|
|
throw new InvalidOperationException();
|
|
|
|
MethodReference constructor = attribute.Constructor;
|
|
if (constructor.HasParameters)
|
|
reader.ReadCustomAttributeConstructorArguments(attribute, constructor.Parameters);
|
|
|
|
if (!reader.CanReadMore())
|
|
return;
|
|
|
|
ushort named = reader.ReadUInt16();
|
|
|
|
if (named == 0)
|
|
return;
|
|
|
|
reader.ReadCustomAttributeNamedArguments(named, ref attribute.fields, ref attribute.properties);
|
|
}
|
|
|
|
private void InitializeMarshalInfos()
|
|
{
|
|
if (metadata.FieldMarshals != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.FieldMarshal);
|
|
|
|
Dictionary<MetadataToken, uint> marshals = metadata.FieldMarshals = new(length);
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
MetadataToken token = ReadMetadataToken(CodedIndex.HasFieldMarshal);
|
|
uint signature = ReadBlobIndex();
|
|
if (token.RID == 0)
|
|
continue;
|
|
|
|
marshals.Add(token, signature);
|
|
}
|
|
}
|
|
|
|
public bool HasMarshalInfo(IMarshalInfoProvider owner)
|
|
{
|
|
InitializeMarshalInfos();
|
|
|
|
return metadata.FieldMarshals.ContainsKey(owner.MetadataToken);
|
|
}
|
|
|
|
public MarshalInfo ReadMarshalInfo(IMarshalInfoProvider owner)
|
|
{
|
|
InitializeMarshalInfos();
|
|
|
|
uint signature;
|
|
if (!metadata.FieldMarshals.TryGetValue(owner.MetadataToken, out signature))
|
|
return null;
|
|
|
|
SignatureReader reader = ReadSignature(signature);
|
|
|
|
metadata.FieldMarshals.Remove(owner.MetadataToken);
|
|
|
|
return reader.ReadMarshalInfo();
|
|
}
|
|
|
|
private void InitializeSecurityDeclarations()
|
|
{
|
|
if (metadata.SecurityDeclarations != null)
|
|
return;
|
|
|
|
metadata.SecurityDeclarations = InitializeRanges(Table.DeclSecurity, () =>
|
|
{
|
|
ReadUInt16();
|
|
MetadataToken next = ReadMetadataToken(CodedIndex.HasDeclSecurity);
|
|
ReadBlobIndex();
|
|
return next;
|
|
});
|
|
}
|
|
|
|
public bool HasSecurityDeclarations(ISecurityDeclarationProvider owner)
|
|
{
|
|
InitializeSecurityDeclarations();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetSecurityDeclarationRanges(owner, out ranges))
|
|
return false;
|
|
|
|
return RangesSize(ranges) > 0;
|
|
}
|
|
|
|
public Collection<SecurityDeclaration> ReadSecurityDeclarations(ISecurityDeclarationProvider owner)
|
|
{
|
|
InitializeSecurityDeclarations();
|
|
|
|
Range[] ranges;
|
|
if (!metadata.TryGetSecurityDeclarationRanges(owner, out ranges))
|
|
return new();
|
|
|
|
Collection<SecurityDeclaration> security_declarations = new(RangesSize(ranges));
|
|
|
|
for (int i = 0; i < ranges.Length; i++)
|
|
ReadSecurityDeclarationRange(ranges[i], security_declarations);
|
|
|
|
metadata.RemoveSecurityDeclarationRange(owner);
|
|
|
|
return security_declarations;
|
|
}
|
|
|
|
private void ReadSecurityDeclarationRange(Range range, Collection<SecurityDeclaration> security_declarations)
|
|
{
|
|
if (!MoveTo(Table.DeclSecurity, range.Start))
|
|
return;
|
|
|
|
for (int i = 0; i < range.Length; i++)
|
|
{
|
|
SecurityAction action = (SecurityAction)ReadUInt16();
|
|
ReadMetadataToken(CodedIndex.HasDeclSecurity);
|
|
uint signature = ReadBlobIndex();
|
|
|
|
security_declarations.Add(new(action, signature, module));
|
|
}
|
|
}
|
|
|
|
public byte[] ReadSecurityDeclarationBlob(uint signature)
|
|
{
|
|
return ReadBlob(signature);
|
|
}
|
|
|
|
public void ReadSecurityDeclarationSignature(SecurityDeclaration declaration)
|
|
{
|
|
uint signature = declaration.signature;
|
|
SignatureReader reader = ReadSignature(signature);
|
|
|
|
if (reader.buffer[reader.position] != '.')
|
|
{
|
|
ReadXmlSecurityDeclaration(signature, declaration);
|
|
return;
|
|
}
|
|
|
|
reader.position++;
|
|
uint count = reader.ReadCompressedUInt32();
|
|
Collection<SecurityAttribute> attributes = new((int)count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
attributes.Add(reader.ReadSecurityAttribute());
|
|
|
|
declaration.security_attributes = attributes;
|
|
}
|
|
|
|
private void ReadXmlSecurityDeclaration(uint signature, SecurityDeclaration declaration)
|
|
{
|
|
Collection<SecurityAttribute> attributes = new(1);
|
|
|
|
SecurityAttribute attribute = new(module.TypeSystem.LookupType("System.Security.Permissions", "PermissionSetAttribute"));
|
|
|
|
attribute.properties = new(1);
|
|
attribute.properties.Add(new("XML", new(module.TypeSystem.String, ReadUnicodeStringBlob(signature))));
|
|
|
|
attributes.Add(attribute);
|
|
|
|
declaration.security_attributes = attributes;
|
|
}
|
|
|
|
public Collection<ExportedType> ReadExportedTypes()
|
|
{
|
|
int length = MoveTo(Table.ExportedType);
|
|
if (length == 0)
|
|
return new();
|
|
|
|
Collection<ExportedType> exported_types = new(length);
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
TypeAttributes attributes = (TypeAttributes)ReadUInt32();
|
|
uint identifier = ReadUInt32();
|
|
string name = ReadString();
|
|
string @namespace = ReadString();
|
|
MetadataToken implementation = ReadMetadataToken(CodedIndex.Implementation);
|
|
|
|
ExportedType declaring_type = null;
|
|
IMetadataScope scope = null;
|
|
|
|
switch (implementation.TokenType)
|
|
{
|
|
case TokenType.AssemblyRef:
|
|
case TokenType.File:
|
|
scope = GetExportedTypeScope(implementation);
|
|
break;
|
|
case TokenType.ExportedType:
|
|
// FIXME: if the table is not properly sorted
|
|
declaring_type = exported_types[(int)implementation.RID - 1];
|
|
break;
|
|
}
|
|
|
|
ExportedType exported_type = new(@namespace, name, module, scope)
|
|
{
|
|
Attributes = attributes,
|
|
Identifier = (int)identifier,
|
|
DeclaringType = declaring_type
|
|
};
|
|
exported_type.token = new(TokenType.ExportedType, i);
|
|
|
|
exported_types.Add(exported_type);
|
|
}
|
|
|
|
return exported_types;
|
|
}
|
|
|
|
private IMetadataScope GetExportedTypeScope(MetadataToken token)
|
|
{
|
|
int position = this.position;
|
|
IMetadataScope scope;
|
|
|
|
switch (token.TokenType)
|
|
{
|
|
case TokenType.AssemblyRef:
|
|
InitializeAssemblyReferences();
|
|
scope = metadata.GetAssemblyNameReference(token.RID);
|
|
break;
|
|
case TokenType.File:
|
|
InitializeModuleReferences();
|
|
scope = GetModuleReferenceFromFile(token);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
this.position = position;
|
|
return scope;
|
|
}
|
|
|
|
private ModuleReference GetModuleReferenceFromFile(MetadataToken token)
|
|
{
|
|
if (!MoveTo(Table.File, token.RID))
|
|
return null;
|
|
|
|
ReadUInt32();
|
|
string file_name = ReadString();
|
|
Collection<ModuleReference> modules = module.ModuleReferences;
|
|
|
|
ModuleReference reference;
|
|
for (int i = 0; i < modules.Count; i++)
|
|
{
|
|
reference = modules[i];
|
|
if (reference.Name == file_name)
|
|
return reference;
|
|
}
|
|
|
|
reference = new(file_name);
|
|
modules.Add(reference);
|
|
return reference;
|
|
}
|
|
|
|
private void InitializeDocuments()
|
|
{
|
|
if (metadata.Documents != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.Document);
|
|
|
|
Document[] documents = metadata.Documents = new Document [length];
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
uint name_index = ReadBlobIndex();
|
|
Guid hash_algorithm = ReadGuid();
|
|
byte[] hash = ReadBlob();
|
|
Guid language = ReadGuid();
|
|
|
|
SignatureReader signature = ReadSignature(name_index);
|
|
string name = signature.ReadDocumentName();
|
|
|
|
documents[i - 1] = new(name)
|
|
{
|
|
HashAlgorithmGuid = hash_algorithm,
|
|
Hash = hash,
|
|
LanguageGuid = language,
|
|
token = new(TokenType.Document, i)
|
|
};
|
|
}
|
|
}
|
|
|
|
public Collection<SequencePoint> ReadSequencePoints(MethodDefinition method)
|
|
{
|
|
InitializeDocuments();
|
|
|
|
if (!MoveTo(Table.MethodDebugInformation, method.MetadataToken.RID))
|
|
return new(0);
|
|
|
|
uint document_index = ReadTableIndex(Table.Document);
|
|
uint signature = ReadBlobIndex();
|
|
if (signature == 0)
|
|
return new(0);
|
|
|
|
Document document = GetDocument(document_index);
|
|
SignatureReader reader = ReadSignature(signature);
|
|
|
|
return reader.ReadSequencePoints(document);
|
|
}
|
|
|
|
public Document GetDocument(uint rid)
|
|
{
|
|
Document document = metadata.GetDocument(rid);
|
|
if (document == null)
|
|
return null;
|
|
|
|
document.custom_infos = GetCustomDebugInformation(document);
|
|
return document;
|
|
}
|
|
|
|
private void InitializeLocalScopes()
|
|
{
|
|
if (metadata.LocalScopes != null)
|
|
return;
|
|
|
|
InitializeMethods();
|
|
|
|
int length = MoveTo(Table.LocalScope);
|
|
|
|
metadata.LocalScopes = new();
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
uint method = ReadTableIndex(Table.Method);
|
|
uint import = ReadTableIndex(Table.ImportScope);
|
|
Range variables = ReadListRange(i, Table.LocalScope, Table.LocalVariable);
|
|
Range constants = ReadListRange(i, Table.LocalScope, Table.LocalConstant);
|
|
uint scope_start = ReadUInt32();
|
|
uint scope_length = ReadUInt32();
|
|
|
|
metadata.SetLocalScopes(method, AddMapping(metadata.LocalScopes, method, new(import, variables, constants, scope_start, scope_length, i)));
|
|
}
|
|
}
|
|
|
|
public ScopeDebugInformation ReadScope(MethodDefinition method)
|
|
{
|
|
InitializeLocalScopes();
|
|
InitializeImportScopes();
|
|
|
|
Collection<Row<uint, Range, Range, uint, uint, uint>> records;
|
|
if (!metadata.TryGetLocalScopes(method, out records))
|
|
return null;
|
|
|
|
ScopeDebugInformation method_scope = null as ScopeDebugInformation;
|
|
|
|
for (int i = 0; i < records.Count; i++)
|
|
{
|
|
ScopeDebugInformation scope = ReadLocalScope(records[i]);
|
|
|
|
if (i == 0)
|
|
{
|
|
method_scope = scope;
|
|
continue;
|
|
}
|
|
|
|
if (!AddScope(method_scope.scopes, scope))
|
|
method_scope.Scopes.Add(scope);
|
|
}
|
|
|
|
return method_scope;
|
|
}
|
|
|
|
private static bool AddScope(Collection<ScopeDebugInformation> scopes, ScopeDebugInformation scope)
|
|
{
|
|
if (scopes.IsNullOrEmpty())
|
|
return false;
|
|
|
|
foreach (ScopeDebugInformation sub_scope in scopes)
|
|
{
|
|
if (sub_scope.HasScopes && AddScope(sub_scope.Scopes, scope))
|
|
return true;
|
|
|
|
if (scope.Start.Offset >= sub_scope.Start.Offset && scope.End.Offset <= sub_scope.End.Offset)
|
|
{
|
|
sub_scope.Scopes.Add(scope);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private ScopeDebugInformation ReadLocalScope(Row<uint, Range, Range, uint, uint, uint> record)
|
|
{
|
|
ScopeDebugInformation scope = new()
|
|
{
|
|
start = new((int)record.Col4),
|
|
end = new((int)(record.Col4 + record.Col5)),
|
|
token = new(TokenType.LocalScope, record.Col6)
|
|
};
|
|
|
|
if (record.Col1 > 0)
|
|
scope.import = metadata.GetImportScope(record.Col1);
|
|
|
|
if (record.Col2.Length > 0)
|
|
{
|
|
scope.variables = new((int)record.Col2.Length);
|
|
for (uint i = 0; i < record.Col2.Length; i++)
|
|
{
|
|
VariableDebugInformation variable = ReadLocalVariable(record.Col2.Start + i);
|
|
if (variable != null)
|
|
scope.variables.Add(variable);
|
|
}
|
|
}
|
|
|
|
if (record.Col3.Length > 0)
|
|
{
|
|
scope.constants = new((int)record.Col3.Length);
|
|
for (uint i = 0; i < record.Col3.Length; i++)
|
|
{
|
|
ConstantDebugInformation constant = ReadLocalConstant(record.Col3.Start + i);
|
|
if (constant != null)
|
|
scope.constants.Add(constant);
|
|
}
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
private VariableDebugInformation ReadLocalVariable(uint rid)
|
|
{
|
|
if (!MoveTo(Table.LocalVariable, rid))
|
|
return null;
|
|
|
|
VariableAttributes attributes = (VariableAttributes)ReadUInt16();
|
|
ushort index = ReadUInt16();
|
|
string name = ReadString();
|
|
|
|
VariableDebugInformation variable = new(index, name) { Attributes = attributes, token = new(TokenType.LocalVariable, rid) };
|
|
variable.custom_infos = GetCustomDebugInformation(variable);
|
|
return variable;
|
|
}
|
|
|
|
private ConstantDebugInformation ReadLocalConstant(uint rid)
|
|
{
|
|
if (!MoveTo(Table.LocalConstant, rid))
|
|
return null;
|
|
|
|
string name = ReadString();
|
|
SignatureReader signature = ReadSignature(ReadBlobIndex());
|
|
TypeReference type = signature.ReadTypeSignature();
|
|
|
|
object value;
|
|
if (type.etype == ElementType.String)
|
|
{
|
|
if (signature.CanReadMore() && signature.buffer[signature.position] != 0xff)
|
|
{
|
|
byte[] bytes = signature.ReadBytes((int)(signature.sig_length - (signature.position - signature.start)));
|
|
value = Encoding.Unicode.GetString(bytes, 0, bytes.Length);
|
|
}
|
|
else
|
|
{
|
|
value = null;
|
|
}
|
|
}
|
|
else if (type.IsTypeOf("System", "Decimal"))
|
|
{
|
|
byte b = signature.ReadByte();
|
|
value = new decimal(signature.ReadInt32(), signature.ReadInt32(), signature.ReadInt32(), (b & 0x80) != 0, (byte)(b & 0x7f));
|
|
}
|
|
else if (type.IsTypeOf("System", "DateTime"))
|
|
{
|
|
value = new DateTime(signature.ReadInt64());
|
|
}
|
|
else if (type.etype == ElementType.Object || type.etype == ElementType.None || type.etype == ElementType.Class || type.etype == ElementType.Array || type.etype == ElementType.GenericInst)
|
|
{
|
|
value = null;
|
|
}
|
|
else
|
|
{
|
|
value = signature.ReadConstantSignature(type.etype);
|
|
}
|
|
|
|
ConstantDebugInformation constant = new(name, type, value) { token = new(TokenType.LocalConstant, rid) };
|
|
constant.custom_infos = GetCustomDebugInformation(constant);
|
|
return constant;
|
|
}
|
|
|
|
private void InitializeImportScopes()
|
|
{
|
|
if (metadata.ImportScopes != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.ImportScope);
|
|
|
|
metadata.ImportScopes = new ImportDebugInformation [length];
|
|
|
|
for (int i = 1; i <= length; i++)
|
|
{
|
|
ReadTableIndex(Table.ImportScope);
|
|
|
|
ImportDebugInformation import = new();
|
|
import.token = new(TokenType.ImportScope, i);
|
|
|
|
SignatureReader signature = ReadSignature(ReadBlobIndex());
|
|
while (signature.CanReadMore())
|
|
import.Targets.Add(ReadImportTarget(signature));
|
|
|
|
metadata.ImportScopes[i - 1] = import;
|
|
}
|
|
|
|
MoveTo(Table.ImportScope);
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
uint parent = ReadTableIndex(Table.ImportScope);
|
|
|
|
ReadBlobIndex();
|
|
|
|
if (parent != 0)
|
|
metadata.ImportScopes[i].Parent = metadata.GetImportScope(parent);
|
|
}
|
|
}
|
|
|
|
public string ReadUTF8StringBlob(uint signature)
|
|
{
|
|
return ReadStringBlob(signature, Encoding.UTF8);
|
|
}
|
|
|
|
private string ReadUnicodeStringBlob(uint signature)
|
|
{
|
|
return ReadStringBlob(signature, Encoding.Unicode);
|
|
}
|
|
|
|
private string ReadStringBlob(uint signature, Encoding encoding)
|
|
{
|
|
byte[] blob;
|
|
int index, count;
|
|
|
|
GetBlobView(signature, out blob, out index, out count);
|
|
if (count == 0)
|
|
return string.Empty;
|
|
|
|
return encoding.GetString(blob, index, count);
|
|
}
|
|
|
|
private ImportTarget ReadImportTarget(SignatureReader signature)
|
|
{
|
|
AssemblyNameReference reference = null;
|
|
string @namespace = null;
|
|
string alias = null;
|
|
TypeReference type = null;
|
|
|
|
ImportTargetKind kind = (ImportTargetKind)signature.ReadCompressedUInt32();
|
|
switch (kind)
|
|
{
|
|
case ImportTargetKind.ImportNamespace:
|
|
@namespace = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.ImportNamespaceInAssembly:
|
|
reference = metadata.GetAssemblyNameReference(signature.ReadCompressedUInt32());
|
|
@namespace = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.ImportType:
|
|
type = signature.ReadTypeToken();
|
|
break;
|
|
case ImportTargetKind.ImportXmlNamespaceWithAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
@namespace = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.ImportAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.DefineAssemblyAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
reference = metadata.GetAssemblyNameReference(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.DefineNamespaceAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
@namespace = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.DefineNamespaceInAssemblyAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
reference = metadata.GetAssemblyNameReference(signature.ReadCompressedUInt32());
|
|
@namespace = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
break;
|
|
case ImportTargetKind.DefineTypeAlias:
|
|
alias = ReadUTF8StringBlob(signature.ReadCompressedUInt32());
|
|
type = signature.ReadTypeToken();
|
|
break;
|
|
}
|
|
|
|
return new(kind)
|
|
{
|
|
alias = alias,
|
|
type = type,
|
|
@namespace = @namespace,
|
|
reference = reference
|
|
};
|
|
}
|
|
|
|
private void InitializeStateMachineMethods()
|
|
{
|
|
if (metadata.StateMachineMethods != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.StateMachineMethod);
|
|
|
|
metadata.StateMachineMethods = new(length);
|
|
|
|
for (int i = 0; i < length; i++)
|
|
metadata.StateMachineMethods.Add(ReadTableIndex(Table.Method), ReadTableIndex(Table.Method));
|
|
}
|
|
|
|
public MethodDefinition ReadStateMachineKickoffMethod(MethodDefinition method)
|
|
{
|
|
InitializeStateMachineMethods();
|
|
|
|
uint rid;
|
|
if (!metadata.TryGetStateMachineKickOffMethod(method, out rid))
|
|
return null;
|
|
|
|
return GetMethodDefinition(rid);
|
|
}
|
|
|
|
private void InitializeCustomDebugInformations()
|
|
{
|
|
if (metadata.CustomDebugInformations != null)
|
|
return;
|
|
|
|
int length = MoveTo(Table.CustomDebugInformation);
|
|
|
|
metadata.CustomDebugInformations = new();
|
|
|
|
for (uint i = 1; i <= length; i++)
|
|
{
|
|
MetadataToken token = ReadMetadataToken(CodedIndex.HasCustomDebugInformation);
|
|
Row<Guid, uint, uint> info = new(ReadGuid(), ReadBlobIndex(), i);
|
|
|
|
Row<Guid, uint, uint>[] infos;
|
|
metadata.CustomDebugInformations.TryGetValue(token, out infos);
|
|
metadata.CustomDebugInformations[token] = infos.Add(info);
|
|
}
|
|
}
|
|
|
|
public Collection<CustomDebugInformation> GetCustomDebugInformation(ICustomDebugInformationProvider provider)
|
|
{
|
|
InitializeCustomDebugInformations();
|
|
|
|
Row<Guid, uint, uint>[] rows;
|
|
if (!metadata.CustomDebugInformations.TryGetValue(provider.MetadataToken, out rows))
|
|
return null;
|
|
|
|
Collection<CustomDebugInformation> infos = new(rows.Length);
|
|
|
|
for (int i = 0; i < rows.Length; i++)
|
|
{
|
|
if (rows[i].Col1 == StateMachineScopeDebugInformation.KindIdentifier)
|
|
{
|
|
SignatureReader signature = ReadSignature(rows[i].Col2);
|
|
Collection<StateMachineScope> scopes = new();
|
|
|
|
while (signature.CanReadMore())
|
|
{
|
|
int start = signature.ReadInt32();
|
|
int end = start + signature.ReadInt32();
|
|
scopes.Add(new(start, end));
|
|
}
|
|
|
|
StateMachineScopeDebugInformation state_machine = new();
|
|
state_machine.scopes = scopes;
|
|
|
|
infos.Add(state_machine);
|
|
}
|
|
else if (rows[i].Col1 == AsyncMethodBodyDebugInformation.KindIdentifier)
|
|
{
|
|
SignatureReader signature = ReadSignature(rows[i].Col2);
|
|
|
|
int catch_offset = signature.ReadInt32() - 1;
|
|
Collection<InstructionOffset> yields = new();
|
|
Collection<InstructionOffset> resumes = new();
|
|
Collection<MethodDefinition> resume_methods = new();
|
|
|
|
while (signature.CanReadMore())
|
|
{
|
|
yields.Add(new(signature.ReadInt32()));
|
|
resumes.Add(new(signature.ReadInt32()));
|
|
resume_methods.Add(GetMethodDefinition(signature.ReadCompressedUInt32()));
|
|
}
|
|
|
|
AsyncMethodBodyDebugInformation async_body = new(catch_offset);
|
|
async_body.yields = yields;
|
|
async_body.resumes = resumes;
|
|
async_body.resume_methods = resume_methods;
|
|
|
|
infos.Add(async_body);
|
|
}
|
|
else if (rows[i].Col1 == EmbeddedSourceDebugInformation.KindIdentifier)
|
|
{
|
|
infos.Add(new EmbeddedSourceDebugInformation(rows[i].Col2, this));
|
|
}
|
|
else if (rows[i].Col1 == SourceLinkDebugInformation.KindIdentifier)
|
|
{
|
|
infos.Add(new SourceLinkDebugInformation(Encoding.UTF8.GetString(ReadBlob(rows[i].Col2))));
|
|
}
|
|
else
|
|
{
|
|
infos.Add(new BinaryCustomDebugInformation(rows[i].Col1, ReadBlob(rows[i].Col2)));
|
|
}
|
|
|
|
infos[i].token = new(TokenType.CustomDebugInformation, rows[i].Col3);
|
|
}
|
|
|
|
return infos;
|
|
}
|
|
|
|
public byte[] ReadRawEmbeddedSourceDebugInformation(uint index)
|
|
{
|
|
SignatureReader signature = ReadSignature(index);
|
|
return signature.ReadBytes((int)signature.sig_length);
|
|
}
|
|
|
|
public Row<byte[], bool> ReadEmbeddedSourceDebugInformation(uint index)
|
|
{
|
|
SignatureReader signature = ReadSignature(index);
|
|
int format = signature.ReadInt32();
|
|
uint length = signature.sig_length - 4;
|
|
|
|
if (format == 0)
|
|
{
|
|
return new(signature.ReadBytes((int)length), false);
|
|
}
|
|
else if (format > 0)
|
|
{
|
|
MemoryStream compressed_stream = new(signature.ReadBytes((int)length));
|
|
byte[] decompressed_document = new byte [format]; // if positive, format is the decompressed length of the document
|
|
MemoryStream decompressed_stream = new(decompressed_document);
|
|
|
|
using (DeflateStream deflate_stream = new(compressed_stream, CompressionMode.Decompress, leaveOpen: true))
|
|
{
|
|
deflate_stream.CopyTo(decompressed_stream);
|
|
}
|
|
|
|
return new(decompressed_document, true);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class SignatureReader : ByteBuffer
|
|
{
|
|
private readonly MetadataReader reader;
|
|
internal readonly uint start, sig_length;
|
|
private TypeSystem TypeSystem
|
|
{
|
|
get { return reader.module.TypeSystem; }
|
|
}
|
|
|
|
public SignatureReader(uint blob, MetadataReader reader) : base(reader.image.BlobHeap.data)
|
|
{
|
|
this.reader = reader;
|
|
position = (int)blob;
|
|
sig_length = ReadCompressedUInt32();
|
|
start = (uint)position;
|
|
}
|
|
|
|
private MetadataToken ReadTypeTokenSignature()
|
|
{
|
|
return CodedIndex.TypeDefOrRef.GetMetadataToken(ReadCompressedUInt32());
|
|
}
|
|
|
|
private GenericParameter GetGenericParameter(GenericParameterType type, uint var)
|
|
{
|
|
IGenericContext context = reader.context;
|
|
int index = (int)var;
|
|
|
|
if (context == null)
|
|
return GetUnboundGenericParameter(type, index);
|
|
|
|
IGenericParameterProvider provider;
|
|
|
|
switch (type)
|
|
{
|
|
case GenericParameterType.Type:
|
|
provider = context.Type;
|
|
break;
|
|
case GenericParameterType.Method:
|
|
provider = context.Method;
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
if (!context.IsDefinition)
|
|
CheckGenericContext(provider, index);
|
|
|
|
if (index >= provider.GenericParameters.Count)
|
|
return GetUnboundGenericParameter(type, index);
|
|
|
|
return provider.GenericParameters[index];
|
|
}
|
|
|
|
private GenericParameter GetUnboundGenericParameter(GenericParameterType type, int index)
|
|
{
|
|
return new(index, type, reader.module);
|
|
}
|
|
|
|
private static void CheckGenericContext(IGenericParameterProvider owner, int index)
|
|
{
|
|
Collection<GenericParameter> owner_parameters = owner.GenericParameters;
|
|
|
|
for (int i = owner_parameters.Count; i <= index; i++)
|
|
owner_parameters.Add(new(owner));
|
|
}
|
|
|
|
public void ReadGenericInstanceSignature(IGenericParameterProvider provider, IGenericInstance instance, uint arity)
|
|
{
|
|
if (!provider.IsDefinition)
|
|
CheckGenericContext(provider, (int)arity - 1);
|
|
|
|
Collection<TypeReference> instance_arguments = instance.GenericArguments;
|
|
|
|
for (int i = 0; i < arity; i++)
|
|
instance_arguments.Add(ReadTypeSignature());
|
|
}
|
|
|
|
private ArrayType ReadArrayTypeSignature()
|
|
{
|
|
ArrayType array = new(ReadTypeSignature());
|
|
|
|
uint rank = ReadCompressedUInt32();
|
|
|
|
uint[] sizes = new uint [ReadCompressedUInt32()];
|
|
for (int i = 0; i < sizes.Length; i++)
|
|
sizes[i] = ReadCompressedUInt32();
|
|
|
|
int[] low_bounds = new int [ReadCompressedUInt32()];
|
|
for (int i = 0; i < low_bounds.Length; i++)
|
|
low_bounds[i] = ReadCompressedInt32();
|
|
|
|
array.Dimensions.Clear();
|
|
|
|
for (int i = 0; i < rank; i++)
|
|
{
|
|
int? lower = null, upper = null;
|
|
|
|
if (i < low_bounds.Length)
|
|
lower = low_bounds[i];
|
|
|
|
if (i < sizes.Length)
|
|
upper = lower + (int)sizes[i] - 1;
|
|
|
|
array.Dimensions.Add(new(lower, upper));
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
private TypeReference GetTypeDefOrRef(MetadataToken token)
|
|
{
|
|
return reader.GetTypeDefOrRef(token);
|
|
}
|
|
|
|
public TypeReference ReadTypeSignature()
|
|
{
|
|
return ReadTypeSignature((ElementType)ReadByte());
|
|
}
|
|
|
|
public TypeReference ReadTypeToken()
|
|
{
|
|
return GetTypeDefOrRef(ReadTypeTokenSignature());
|
|
}
|
|
|
|
private TypeReference ReadTypeSignature(ElementType etype)
|
|
{
|
|
switch (etype)
|
|
{
|
|
case ElementType.ValueType:
|
|
{
|
|
TypeReference value_type = GetTypeDefOrRef(ReadTypeTokenSignature());
|
|
value_type.KnownValueType();
|
|
return value_type;
|
|
}
|
|
case ElementType.Class:
|
|
return GetTypeDefOrRef(ReadTypeTokenSignature());
|
|
case ElementType.Ptr:
|
|
return new PointerType(ReadTypeSignature());
|
|
case ElementType.FnPtr:
|
|
{
|
|
FunctionPointerType fptr = new();
|
|
ReadMethodSignature(fptr);
|
|
return fptr;
|
|
}
|
|
case ElementType.ByRef:
|
|
return new ByReferenceType(ReadTypeSignature());
|
|
case ElementType.Pinned:
|
|
return new PinnedType(ReadTypeSignature());
|
|
case ElementType.SzArray:
|
|
return new ArrayType(ReadTypeSignature());
|
|
case ElementType.Array:
|
|
return ReadArrayTypeSignature();
|
|
case ElementType.CModOpt:
|
|
return new OptionalModifierType(GetTypeDefOrRef(ReadTypeTokenSignature()), ReadTypeSignature());
|
|
case ElementType.CModReqD:
|
|
return new RequiredModifierType(GetTypeDefOrRef(ReadTypeTokenSignature()), ReadTypeSignature());
|
|
case ElementType.Sentinel:
|
|
return new SentinelType(ReadTypeSignature());
|
|
case ElementType.Var:
|
|
return GetGenericParameter(GenericParameterType.Type, ReadCompressedUInt32());
|
|
case ElementType.MVar:
|
|
return GetGenericParameter(GenericParameterType.Method, ReadCompressedUInt32());
|
|
case ElementType.GenericInst:
|
|
{
|
|
bool is_value_type = ReadByte() == (byte)ElementType.ValueType;
|
|
TypeReference element_type = GetTypeDefOrRef(ReadTypeTokenSignature());
|
|
|
|
uint arity = ReadCompressedUInt32();
|
|
GenericInstanceType generic_instance = new(element_type, (int)arity);
|
|
|
|
ReadGenericInstanceSignature(element_type, generic_instance, arity);
|
|
|
|
if (is_value_type)
|
|
{
|
|
generic_instance.KnownValueType();
|
|
element_type.GetElementType().KnownValueType();
|
|
}
|
|
|
|
return generic_instance;
|
|
}
|
|
case ElementType.Object:
|
|
return TypeSystem.Object;
|
|
case ElementType.Void:
|
|
return TypeSystem.Void;
|
|
case ElementType.TypedByRef:
|
|
return TypeSystem.TypedReference;
|
|
case ElementType.I:
|
|
return TypeSystem.IntPtr;
|
|
case ElementType.U:
|
|
return TypeSystem.UIntPtr;
|
|
default:
|
|
return GetPrimitiveType(etype);
|
|
}
|
|
}
|
|
|
|
public void ReadMethodSignature(IMethodSignature method)
|
|
{
|
|
byte calling_convention = ReadByte();
|
|
|
|
const byte has_this = 0x20;
|
|
const byte explicit_this = 0x40;
|
|
|
|
if ((calling_convention & has_this) != 0)
|
|
{
|
|
method.HasThis = true;
|
|
calling_convention = (byte)(calling_convention & ~has_this);
|
|
}
|
|
|
|
if ((calling_convention & explicit_this) != 0)
|
|
{
|
|
method.ExplicitThis = true;
|
|
calling_convention = (byte)(calling_convention & ~explicit_this);
|
|
}
|
|
|
|
method.CallingConvention = (MethodCallingConvention)calling_convention;
|
|
|
|
MethodReference generic_context = method as MethodReference;
|
|
if (generic_context != null && !generic_context.DeclaringType.IsArray)
|
|
reader.context = generic_context;
|
|
|
|
if ((calling_convention & 0x10) != 0)
|
|
{
|
|
uint arity = ReadCompressedUInt32();
|
|
|
|
if (generic_context != null && !generic_context.IsDefinition)
|
|
CheckGenericContext(generic_context, (int)arity - 1);
|
|
}
|
|
|
|
uint param_count = ReadCompressedUInt32();
|
|
|
|
method.MethodReturnType.ReturnType = ReadTypeSignature();
|
|
|
|
if (param_count == 0)
|
|
return;
|
|
|
|
Collection<ParameterDefinition> parameters;
|
|
|
|
MethodReference method_ref = method as MethodReference;
|
|
if (method_ref != null)
|
|
parameters = method_ref.parameters = new(method, (int)param_count);
|
|
else
|
|
parameters = method.Parameters;
|
|
|
|
for (int i = 0; i < param_count; i++)
|
|
parameters.Add(new(ReadTypeSignature()));
|
|
}
|
|
|
|
public object ReadConstantSignature(ElementType type)
|
|
{
|
|
return ReadPrimitiveValue(type);
|
|
}
|
|
|
|
public void ReadCustomAttributeConstructorArguments(CustomAttribute attribute, Collection<ParameterDefinition> parameters)
|
|
{
|
|
int count = parameters.Count;
|
|
if (count == 0)
|
|
return;
|
|
|
|
attribute.arguments = new(count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
attribute.arguments.Add(ReadCustomAttributeFixedArgument(parameters[i].ParameterType));
|
|
}
|
|
|
|
private CustomAttributeArgument ReadCustomAttributeFixedArgument(TypeReference type)
|
|
{
|
|
if (type.IsArray)
|
|
return ReadCustomAttributeFixedArrayArgument((ArrayType)type);
|
|
|
|
return ReadCustomAttributeElement(type);
|
|
}
|
|
|
|
public void ReadCustomAttributeNamedArguments(ushort count, ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (!CanReadMore())
|
|
return;
|
|
ReadCustomAttributeNamedArgument(ref fields, ref properties);
|
|
}
|
|
}
|
|
|
|
private void ReadCustomAttributeNamedArgument(ref Collection<CustomAttributeNamedArgument> fields, ref Collection<CustomAttributeNamedArgument> properties)
|
|
{
|
|
byte kind = ReadByte();
|
|
TypeReference type = ReadCustomAttributeFieldOrPropType();
|
|
string name = ReadUTF8String();
|
|
|
|
Collection<CustomAttributeNamedArgument> container;
|
|
switch (kind)
|
|
{
|
|
case 0x53:
|
|
container = GetCustomAttributeNamedArgumentCollection(ref fields);
|
|
break;
|
|
case 0x54:
|
|
container = GetCustomAttributeNamedArgumentCollection(ref properties);
|
|
break;
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
container.Add(new(name, ReadCustomAttributeFixedArgument(type)));
|
|
}
|
|
|
|
private static Collection<CustomAttributeNamedArgument> GetCustomAttributeNamedArgumentCollection(ref Collection<CustomAttributeNamedArgument> collection)
|
|
{
|
|
if (collection != null)
|
|
return collection;
|
|
|
|
return collection = new();
|
|
}
|
|
|
|
private CustomAttributeArgument ReadCustomAttributeFixedArrayArgument(ArrayType type)
|
|
{
|
|
uint length = ReadUInt32();
|
|
|
|
if (length == 0xffffffff)
|
|
return new(type, null);
|
|
|
|
if (length == 0)
|
|
return new(type, Empty<CustomAttributeArgument>.Array);
|
|
|
|
CustomAttributeArgument[] arguments = new CustomAttributeArgument [length];
|
|
TypeReference element_type = type.ElementType;
|
|
|
|
for (int i = 0; i < length; i++)
|
|
arguments[i] = ReadCustomAttributeElement(element_type);
|
|
|
|
return new(type, arguments);
|
|
}
|
|
|
|
private CustomAttributeArgument ReadCustomAttributeElement(TypeReference type)
|
|
{
|
|
if (type.IsArray)
|
|
return ReadCustomAttributeFixedArrayArgument((ArrayType)type);
|
|
|
|
return new(type, type.etype == ElementType.Object ? ReadCustomAttributeElement(ReadCustomAttributeFieldOrPropType()) : ReadCustomAttributeElementValue(type));
|
|
}
|
|
|
|
private object ReadCustomAttributeElementValue(TypeReference type)
|
|
{
|
|
ElementType etype = type.etype;
|
|
|
|
switch (etype)
|
|
{
|
|
case ElementType.String:
|
|
return ReadUTF8String();
|
|
case ElementType.None:
|
|
if (type.IsTypeOf("System", "Type"))
|
|
return ReadTypeReference();
|
|
|
|
return ReadCustomAttributeEnum(type);
|
|
default:
|
|
return ReadPrimitiveValue(etype);
|
|
}
|
|
}
|
|
|
|
private object ReadPrimitiveValue(ElementType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ElementType.Boolean:
|
|
return ReadByte() == 1;
|
|
case ElementType.I1:
|
|
return (sbyte)ReadByte();
|
|
case ElementType.U1:
|
|
return ReadByte();
|
|
case ElementType.Char:
|
|
return (char)ReadUInt16();
|
|
case ElementType.I2:
|
|
return ReadInt16();
|
|
case ElementType.U2:
|
|
return ReadUInt16();
|
|
case ElementType.I4:
|
|
return ReadInt32();
|
|
case ElementType.U4:
|
|
return ReadUInt32();
|
|
case ElementType.I8:
|
|
return ReadInt64();
|
|
case ElementType.U8:
|
|
return ReadUInt64();
|
|
case ElementType.R4:
|
|
return ReadSingle();
|
|
case ElementType.R8:
|
|
return ReadDouble();
|
|
default:
|
|
throw new NotImplementedException(type.ToString());
|
|
}
|
|
}
|
|
|
|
private TypeReference GetPrimitiveType(ElementType etype)
|
|
{
|
|
switch (etype)
|
|
{
|
|
case ElementType.Boolean:
|
|
return TypeSystem.Boolean;
|
|
case ElementType.Char:
|
|
return TypeSystem.Char;
|
|
case ElementType.I1:
|
|
return TypeSystem.SByte;
|
|
case ElementType.U1:
|
|
return TypeSystem.Byte;
|
|
case ElementType.I2:
|
|
return TypeSystem.Int16;
|
|
case ElementType.U2:
|
|
return TypeSystem.UInt16;
|
|
case ElementType.I4:
|
|
return TypeSystem.Int32;
|
|
case ElementType.U4:
|
|
return TypeSystem.UInt32;
|
|
case ElementType.I8:
|
|
return TypeSystem.Int64;
|
|
case ElementType.U8:
|
|
return TypeSystem.UInt64;
|
|
case ElementType.R4:
|
|
return TypeSystem.Single;
|
|
case ElementType.R8:
|
|
return TypeSystem.Double;
|
|
case ElementType.String:
|
|
return TypeSystem.String;
|
|
default:
|
|
throw new NotImplementedException(etype.ToString());
|
|
}
|
|
}
|
|
|
|
private TypeReference ReadCustomAttributeFieldOrPropType()
|
|
{
|
|
ElementType etype = (ElementType)ReadByte();
|
|
|
|
switch (etype)
|
|
{
|
|
case ElementType.Boxed:
|
|
return TypeSystem.Object;
|
|
case ElementType.SzArray:
|
|
return new ArrayType(ReadCustomAttributeFieldOrPropType());
|
|
case ElementType.Enum:
|
|
return ReadTypeReference();
|
|
case ElementType.Type:
|
|
return TypeSystem.LookupType("System", "Type");
|
|
default:
|
|
return GetPrimitiveType(etype);
|
|
}
|
|
}
|
|
|
|
public TypeReference ReadTypeReference()
|
|
{
|
|
return TypeParser.ParseType(reader.module, ReadUTF8String());
|
|
}
|
|
|
|
private object ReadCustomAttributeEnum(TypeReference enum_type)
|
|
{
|
|
TypeDefinition type = enum_type.CheckedResolve();
|
|
if (!type.IsEnum)
|
|
throw new ArgumentException();
|
|
|
|
return ReadCustomAttributeElementValue(type.GetEnumUnderlyingType());
|
|
}
|
|
|
|
public SecurityAttribute ReadSecurityAttribute()
|
|
{
|
|
SecurityAttribute attribute = new(ReadTypeReference());
|
|
|
|
ReadCompressedUInt32();
|
|
|
|
ReadCustomAttributeNamedArguments((ushort)ReadCompressedUInt32(), ref attribute.fields, ref attribute.properties);
|
|
|
|
return attribute;
|
|
}
|
|
|
|
public MarshalInfo ReadMarshalInfo()
|
|
{
|
|
NativeType native = ReadNativeType();
|
|
switch (native)
|
|
{
|
|
case NativeType.Array:
|
|
{
|
|
ArrayMarshalInfo array = new();
|
|
if (CanReadMore())
|
|
array.element_type = ReadNativeType();
|
|
if (CanReadMore())
|
|
array.size_parameter_index = (int)ReadCompressedUInt32();
|
|
if (CanReadMore())
|
|
array.size = (int)ReadCompressedUInt32();
|
|
if (CanReadMore())
|
|
array.size_parameter_multiplier = (int)ReadCompressedUInt32();
|
|
return array;
|
|
}
|
|
case NativeType.SafeArray:
|
|
{
|
|
SafeArrayMarshalInfo array = new();
|
|
if (CanReadMore())
|
|
array.element_type = ReadVariantType();
|
|
return array;
|
|
}
|
|
case NativeType.FixedArray:
|
|
{
|
|
FixedArrayMarshalInfo array = new();
|
|
if (CanReadMore())
|
|
array.size = (int)ReadCompressedUInt32();
|
|
if (CanReadMore())
|
|
array.element_type = ReadNativeType();
|
|
return array;
|
|
}
|
|
case NativeType.FixedSysString:
|
|
{
|
|
FixedSysStringMarshalInfo sys_string = new();
|
|
if (CanReadMore())
|
|
sys_string.size = (int)ReadCompressedUInt32();
|
|
return sys_string;
|
|
}
|
|
case NativeType.CustomMarshaler:
|
|
{
|
|
CustomMarshalInfo marshaler = new();
|
|
string guid_value = ReadUTF8String();
|
|
marshaler.guid = !string.IsNullOrEmpty(guid_value) ? new(guid_value) : Guid.Empty;
|
|
marshaler.unmanaged_type = ReadUTF8String();
|
|
marshaler.managed_type = ReadTypeReference();
|
|
marshaler.cookie = ReadUTF8String();
|
|
return marshaler;
|
|
}
|
|
default:
|
|
return new(native);
|
|
}
|
|
}
|
|
|
|
private NativeType ReadNativeType()
|
|
{
|
|
return (NativeType)ReadByte();
|
|
}
|
|
|
|
private VariantType ReadVariantType()
|
|
{
|
|
return (VariantType)ReadByte();
|
|
}
|
|
|
|
private string ReadUTF8String()
|
|
{
|
|
if (buffer[position] == 0xff)
|
|
{
|
|
position++;
|
|
return null;
|
|
}
|
|
|
|
int length = (int)ReadCompressedUInt32();
|
|
if (length == 0)
|
|
return string.Empty;
|
|
|
|
if (position + length > buffer.Length)
|
|
return string.Empty;
|
|
|
|
string @string = Encoding.UTF8.GetString(buffer, position, length);
|
|
|
|
position += length;
|
|
return @string;
|
|
}
|
|
|
|
public string ReadDocumentName()
|
|
{
|
|
char separator = (char)buffer[position];
|
|
position++;
|
|
|
|
StringBuilder builder = new();
|
|
for (int i = 0; CanReadMore(); i++)
|
|
{
|
|
if (i > 0 && separator != 0)
|
|
builder.Append(separator);
|
|
|
|
uint part = ReadCompressedUInt32();
|
|
if (part != 0)
|
|
builder.Append(reader.ReadUTF8StringBlob(part));
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
public Collection<SequencePoint> ReadSequencePoints(Document document)
|
|
{
|
|
ReadCompressedUInt32(); // local_sig_token
|
|
|
|
if (document == null)
|
|
document = reader.GetDocument(ReadCompressedUInt32());
|
|
|
|
int offset = 0;
|
|
int start_line = 0;
|
|
int start_column = 0;
|
|
bool first_non_hidden = true;
|
|
|
|
// there's about 5 compressed int32's per sequenec points. we don't know exactly how many
|
|
// but let's take a conservative guess so we dont end up reallocating the sequence_points collection
|
|
// as it grows.
|
|
long bytes_remaining_for_sequencepoints = sig_length - (position - start);
|
|
int estimated_sequencepoint_amount = (int)bytes_remaining_for_sequencepoints / 5;
|
|
Collection<SequencePoint> sequence_points = new(estimated_sequencepoint_amount);
|
|
|
|
for (int i = 0; CanReadMore(); i++)
|
|
{
|
|
int delta_il = (int)ReadCompressedUInt32();
|
|
if (i > 0 && delta_il == 0)
|
|
{
|
|
document = reader.GetDocument(ReadCompressedUInt32());
|
|
continue;
|
|
}
|
|
|
|
offset += delta_il;
|
|
|
|
int delta_lines = (int)ReadCompressedUInt32();
|
|
int delta_columns = delta_lines == 0 ? (int)ReadCompressedUInt32() : ReadCompressedInt32();
|
|
|
|
if (delta_lines == 0 && delta_columns == 0)
|
|
{
|
|
sequence_points.Add(new(offset, document)
|
|
{
|
|
StartLine = 0xfeefee,
|
|
EndLine = 0xfeefee,
|
|
StartColumn = 0,
|
|
EndColumn = 0
|
|
});
|
|
continue;
|
|
}
|
|
|
|
if (first_non_hidden)
|
|
{
|
|
start_line = (int)ReadCompressedUInt32();
|
|
start_column = (int)ReadCompressedUInt32();
|
|
}
|
|
else
|
|
{
|
|
start_line += ReadCompressedInt32();
|
|
start_column += ReadCompressedInt32();
|
|
}
|
|
|
|
sequence_points.Add(new(offset, document)
|
|
{
|
|
StartLine = start_line,
|
|
StartColumn = start_column,
|
|
EndLine = start_line + delta_lines,
|
|
EndColumn = start_column + delta_columns
|
|
});
|
|
first_non_hidden = false;
|
|
}
|
|
|
|
return sequence_points;
|
|
}
|
|
|
|
public bool CanReadMore()
|
|
{
|
|
return position - start < sig_length;
|
|
}
|
|
}
|
|
} |