1225 lines
38 KiB
C#
1225 lines
38 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.Threading;
|
|
using SR = System.Reflection;
|
|
|
|
namespace MonoFN.Cecil
|
|
{
|
|
public enum ReadingMode
|
|
{
|
|
Immediate = 1,
|
|
Deferred = 2
|
|
}
|
|
|
|
public sealed class ReaderParameters
|
|
{
|
|
internal IAssemblyResolver assembly_resolver;
|
|
internal IMetadataResolver metadata_resolver;
|
|
internal IMetadataImporterProvider metadata_importer_provider;
|
|
internal IReflectionImporterProvider reflection_importer_provider;
|
|
public ReadingMode ReadingMode { get; set; }
|
|
public bool InMemory { get; set; }
|
|
public IAssemblyResolver AssemblyResolver
|
|
{
|
|
get { return assembly_resolver; }
|
|
set { assembly_resolver = value; }
|
|
}
|
|
public IMetadataResolver MetadataResolver
|
|
{
|
|
get { return metadata_resolver; }
|
|
set { metadata_resolver = value; }
|
|
}
|
|
public IMetadataImporterProvider MetadataImporterProvider
|
|
{
|
|
get { return metadata_importer_provider; }
|
|
set { metadata_importer_provider = value; }
|
|
}
|
|
public IReflectionImporterProvider ReflectionImporterProvider
|
|
{
|
|
get { return reflection_importer_provider; }
|
|
set { reflection_importer_provider = value; }
|
|
}
|
|
public Stream SymbolStream { get; set; }
|
|
public ISymbolReaderProvider SymbolReaderProvider { get; set; }
|
|
public bool ReadSymbols { get; set; }
|
|
public bool ThrowIfSymbolsAreNotMatching { get; set; }
|
|
public bool ReadWrite { get; set; }
|
|
public bool ApplyWindowsRuntimeProjections { get; set; }
|
|
public ReaderParameters() : this(ReadingMode.Deferred) { }
|
|
|
|
public ReaderParameters(ReadingMode readingMode)
|
|
{
|
|
ReadingMode = readingMode;
|
|
ThrowIfSymbolsAreNotMatching = true;
|
|
}
|
|
}
|
|
|
|
public sealed class ModuleParameters
|
|
{
|
|
public ModuleKind Kind { get; set; }
|
|
public TargetRuntime Runtime { get; set; }
|
|
public uint? Timestamp { get; set; }
|
|
public TargetArchitecture Architecture { get; set; }
|
|
public IAssemblyResolver AssemblyResolver { get; set; }
|
|
public IMetadataResolver MetadataResolver { get; set; }
|
|
public IMetadataImporterProvider MetadataImporterProvider { get; set; }
|
|
public IReflectionImporterProvider ReflectionImporterProvider { get; set; }
|
|
|
|
public ModuleParameters()
|
|
{
|
|
Kind = ModuleKind.Dll;
|
|
Runtime = GetCurrentRuntime();
|
|
Architecture = TargetArchitecture.I386;
|
|
}
|
|
|
|
private static TargetRuntime GetCurrentRuntime()
|
|
{
|
|
return typeof(object).Assembly.ImageRuntimeVersion.ParseRuntime();
|
|
}
|
|
}
|
|
|
|
public sealed class WriterParameters
|
|
{
|
|
public uint? Timestamp { get; set; }
|
|
public Stream SymbolStream { get; set; }
|
|
public ISymbolWriterProvider SymbolWriterProvider { get; set; }
|
|
public bool WriteSymbols { get; set; }
|
|
public bool HasStrongNameKey
|
|
{
|
|
get { return StrongNameKeyPair != null || StrongNameKeyBlob != null || StrongNameKeyContainer != null; }
|
|
}
|
|
public byte[] StrongNameKeyBlob { get; set; }
|
|
public string StrongNameKeyContainer { get; set; }
|
|
public SR.StrongNameKeyPair StrongNameKeyPair { get; set; }
|
|
public bool DeterministicMvid { get; set; }
|
|
}
|
|
|
|
public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider, ICustomDebugInformationProvider, IDisposable
|
|
{
|
|
internal Image Image;
|
|
internal MetadataSystem MetadataSystem;
|
|
internal ReadingMode ReadingMode;
|
|
internal ISymbolReaderProvider SymbolReaderProvider;
|
|
internal ISymbolReader symbol_reader;
|
|
internal Disposable<IAssemblyResolver> assembly_resolver;
|
|
internal IMetadataResolver metadata_resolver;
|
|
internal TypeSystem type_system;
|
|
internal readonly MetadataReader reader;
|
|
internal string runtime_version;
|
|
internal ModuleKind kind;
|
|
private WindowsRuntimeProjections projections;
|
|
private TargetRuntime runtime;
|
|
internal ushort linker_version = 8;
|
|
internal ushort subsystem_major = 4;
|
|
internal ushort subsystem_minor = 0;
|
|
internal uint timestamp;
|
|
internal AssemblyDefinition assembly;
|
|
private MethodDefinition entry_point;
|
|
private bool entry_point_set;
|
|
internal IReflectionImporter reflection_importer;
|
|
internal IMetadataImporter metadata_importer;
|
|
private Collection<CustomAttribute> custom_attributes;
|
|
private Collection<AssemblyNameReference> references;
|
|
private Collection<ModuleReference> modules;
|
|
private Collection<Resource> resources;
|
|
private Collection<ExportedType> exported_types;
|
|
private TypeDefinitionCollection types;
|
|
internal Collection<CustomDebugInformation> custom_infos;
|
|
internal MetadataBuilder metadata_builder;
|
|
public bool IsMain
|
|
{
|
|
get { return kind != ModuleKind.NetModule; }
|
|
}
|
|
public ModuleKind Kind
|
|
{
|
|
get { return kind; }
|
|
set { kind = value; }
|
|
}
|
|
public MetadataKind MetadataKind { get; set; }
|
|
internal WindowsRuntimeProjections Projections
|
|
{
|
|
get
|
|
{
|
|
if (projections == null)
|
|
Interlocked.CompareExchange(ref projections, new(this), null);
|
|
|
|
return projections;
|
|
}
|
|
}
|
|
public TargetRuntime Runtime
|
|
{
|
|
get { return runtime; }
|
|
set
|
|
{
|
|
runtime = value;
|
|
runtime_version = runtime.RuntimeVersionString();
|
|
}
|
|
}
|
|
public string RuntimeVersion
|
|
{
|
|
get { return runtime_version; }
|
|
set
|
|
{
|
|
runtime_version = value;
|
|
runtime = runtime_version.ParseRuntime();
|
|
}
|
|
}
|
|
public TargetArchitecture Architecture { get; set; }
|
|
public ModuleAttributes Attributes { get; set; }
|
|
public ModuleCharacteristics Characteristics { get; set; }
|
|
[Obsolete("Use FileName")]
|
|
public string FullyQualifiedName
|
|
{
|
|
get { return FileName; }
|
|
}
|
|
public string FileName { get; }
|
|
public Guid Mvid { get; set; }
|
|
internal bool HasImage
|
|
{
|
|
get { return Image != null; }
|
|
}
|
|
public bool HasSymbols
|
|
{
|
|
get { return symbol_reader != null; }
|
|
}
|
|
public ISymbolReader SymbolReader
|
|
{
|
|
get { return symbol_reader; }
|
|
}
|
|
public override MetadataScopeType MetadataScopeType
|
|
{
|
|
get { return MetadataScopeType.ModuleDefinition; }
|
|
}
|
|
public AssemblyDefinition Assembly
|
|
{
|
|
get { return assembly; }
|
|
}
|
|
internal IReflectionImporter ReflectionImporter
|
|
{
|
|
get
|
|
{
|
|
if (reflection_importer == null)
|
|
Interlocked.CompareExchange(ref reflection_importer, new DefaultReflectionImporter(this), null);
|
|
|
|
return reflection_importer;
|
|
}
|
|
}
|
|
internal IMetadataImporter MetadataImporter
|
|
{
|
|
get
|
|
{
|
|
if (metadata_importer == null)
|
|
Interlocked.CompareExchange(ref metadata_importer, new DefaultMetadataImporter(this), null);
|
|
|
|
return metadata_importer;
|
|
}
|
|
}
|
|
public IAssemblyResolver AssemblyResolver
|
|
{
|
|
get
|
|
{
|
|
if (assembly_resolver.value == null)
|
|
{
|
|
lock (SyncRoot)
|
|
{
|
|
assembly_resolver = Disposable.Owned(new DefaultAssemblyResolver() as IAssemblyResolver);
|
|
}
|
|
}
|
|
|
|
return assembly_resolver.value;
|
|
}
|
|
}
|
|
public IMetadataResolver MetadataResolver
|
|
{
|
|
get
|
|
{
|
|
if (metadata_resolver == null)
|
|
Interlocked.CompareExchange(ref metadata_resolver, new MetadataResolver(AssemblyResolver), null);
|
|
|
|
return metadata_resolver;
|
|
}
|
|
}
|
|
public TypeSystem TypeSystem
|
|
{
|
|
get
|
|
{
|
|
if (type_system == null)
|
|
Interlocked.CompareExchange(ref type_system, TypeSystem.CreateTypeSystem(this), null);
|
|
|
|
return type_system;
|
|
}
|
|
}
|
|
public bool HasAssemblyReferences
|
|
{
|
|
get
|
|
{
|
|
if (references != null)
|
|
return references.Count > 0;
|
|
|
|
return HasImage && Image.HasTable(Table.AssemblyRef);
|
|
}
|
|
}
|
|
public Collection<AssemblyNameReference> AssemblyReferences
|
|
{
|
|
get
|
|
{
|
|
if (references != null)
|
|
return references;
|
|
|
|
if (HasImage)
|
|
return Read(ref references, this, (_, reader) => reader.ReadAssemblyReferences());
|
|
|
|
Interlocked.CompareExchange(ref references, new(), null);
|
|
return references;
|
|
}
|
|
}
|
|
public bool HasModuleReferences
|
|
{
|
|
get
|
|
{
|
|
if (modules != null)
|
|
return modules.Count > 0;
|
|
|
|
return HasImage && Image.HasTable(Table.ModuleRef);
|
|
}
|
|
}
|
|
public Collection<ModuleReference> ModuleReferences
|
|
{
|
|
get
|
|
{
|
|
if (modules != null)
|
|
return modules;
|
|
|
|
if (HasImage)
|
|
return Read(ref modules, this, (_, reader) => reader.ReadModuleReferences());
|
|
|
|
Interlocked.CompareExchange(ref modules, new(), null);
|
|
return modules;
|
|
}
|
|
}
|
|
public bool HasResources
|
|
{
|
|
get
|
|
{
|
|
if (resources != null)
|
|
return resources.Count > 0;
|
|
|
|
if (HasImage)
|
|
return Image.HasTable(Table.ManifestResource) || Read(this, (_, reader) => reader.HasFileResource());
|
|
|
|
return false;
|
|
}
|
|
}
|
|
public Collection<Resource> Resources
|
|
{
|
|
get
|
|
{
|
|
if (resources != null)
|
|
return resources;
|
|
|
|
if (HasImage)
|
|
return Read(ref resources, this, (_, reader) => reader.ReadResources());
|
|
|
|
Interlocked.CompareExchange(ref resources, new(), null);
|
|
return resources;
|
|
}
|
|
}
|
|
public bool HasCustomAttributes
|
|
{
|
|
get
|
|
{
|
|
if (custom_attributes != null)
|
|
return custom_attributes.Count > 0;
|
|
|
|
return this.GetHasCustomAttributes(this);
|
|
}
|
|
}
|
|
public Collection<CustomAttribute> CustomAttributes
|
|
{
|
|
get { return custom_attributes ?? this.GetCustomAttributes(ref custom_attributes, this); }
|
|
}
|
|
public bool HasTypes
|
|
{
|
|
get
|
|
{
|
|
if (types != null)
|
|
return types.Count > 0;
|
|
|
|
return HasImage && Image.HasTable(Table.TypeDef);
|
|
}
|
|
}
|
|
public Collection<TypeDefinition> Types
|
|
{
|
|
get
|
|
{
|
|
if (types != null)
|
|
return types;
|
|
|
|
if (HasImage)
|
|
return Read(ref types, this, (_, reader) => reader.ReadTypes());
|
|
|
|
Interlocked.CompareExchange(ref types, new(this), null);
|
|
return types;
|
|
}
|
|
}
|
|
public bool HasExportedTypes
|
|
{
|
|
get
|
|
{
|
|
if (exported_types != null)
|
|
return exported_types.Count > 0;
|
|
|
|
return HasImage && Image.HasTable(Table.ExportedType);
|
|
}
|
|
}
|
|
public Collection<ExportedType> ExportedTypes
|
|
{
|
|
get
|
|
{
|
|
if (exported_types != null)
|
|
return exported_types;
|
|
|
|
if (HasImage)
|
|
return Read(ref exported_types, this, (_, reader) => reader.ReadExportedTypes());
|
|
|
|
Interlocked.CompareExchange(ref exported_types, new(), null);
|
|
return exported_types;
|
|
}
|
|
}
|
|
public MethodDefinition EntryPoint
|
|
{
|
|
get
|
|
{
|
|
if (entry_point_set)
|
|
return entry_point;
|
|
|
|
if (HasImage)
|
|
Read(ref entry_point, this, (_, reader) => reader.ReadEntryPoint());
|
|
else
|
|
entry_point = null;
|
|
|
|
entry_point_set = true;
|
|
return entry_point;
|
|
}
|
|
set
|
|
{
|
|
entry_point = value;
|
|
entry_point_set = true;
|
|
}
|
|
}
|
|
public bool HasCustomDebugInformations
|
|
{
|
|
get { return custom_infos != null && custom_infos.Count > 0; }
|
|
}
|
|
public Collection<CustomDebugInformation> CustomDebugInformations
|
|
{
|
|
get
|
|
{
|
|
if (custom_infos == null)
|
|
Interlocked.CompareExchange(ref custom_infos, new(), null);
|
|
|
|
return custom_infos;
|
|
}
|
|
}
|
|
|
|
internal ModuleDefinition()
|
|
{
|
|
MetadataSystem = new();
|
|
token = new(TokenType.Module, 1);
|
|
}
|
|
|
|
internal ModuleDefinition(Image image) : this()
|
|
{
|
|
Image = image;
|
|
kind = image.Kind;
|
|
RuntimeVersion = image.RuntimeVersion;
|
|
Architecture = image.Architecture;
|
|
Attributes = image.Attributes;
|
|
Characteristics = image.DllCharacteristics;
|
|
linker_version = image.LinkerVersion;
|
|
subsystem_major = image.SubSystemMajor;
|
|
subsystem_minor = image.SubSystemMinor;
|
|
FileName = image.FileName;
|
|
timestamp = image.Timestamp;
|
|
|
|
reader = new(this);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Image != null)
|
|
Image.Dispose();
|
|
|
|
if (symbol_reader != null)
|
|
symbol_reader.Dispose();
|
|
|
|
if (assembly_resolver.value != null)
|
|
assembly_resolver.Dispose();
|
|
}
|
|
|
|
public bool HasTypeReference(string fullName)
|
|
{
|
|
return HasTypeReference(string.Empty, fullName);
|
|
}
|
|
|
|
public bool HasTypeReference(string scope, string fullName)
|
|
{
|
|
Mixin.CheckFullName(fullName);
|
|
|
|
if (!HasImage)
|
|
return false;
|
|
|
|
return GetTypeReference(scope, fullName) != null;
|
|
}
|
|
|
|
public bool TryGetTypeReference(string fullName, out TypeReference type)
|
|
{
|
|
return TryGetTypeReference(string.Empty, fullName, out type);
|
|
}
|
|
|
|
public bool TryGetTypeReference(string scope, string fullName, out TypeReference type)
|
|
{
|
|
Mixin.CheckFullName(fullName);
|
|
|
|
if (!HasImage)
|
|
{
|
|
type = null;
|
|
return false;
|
|
}
|
|
|
|
return (type = GetTypeReference(scope, fullName)) != null;
|
|
}
|
|
|
|
private TypeReference GetTypeReference(string scope, string fullname)
|
|
{
|
|
return Read(new Row<string, string>(scope, fullname), (row, reader) => reader.GetTypeReference(row.Col1, row.Col2));
|
|
}
|
|
|
|
public IEnumerable<TypeReference> GetTypeReferences()
|
|
{
|
|
if (!HasImage)
|
|
return Empty<TypeReference>.Array;
|
|
|
|
return Read(this, (_, reader) => reader.GetTypeReferences());
|
|
}
|
|
|
|
public IEnumerable<MemberReference> GetMemberReferences()
|
|
{
|
|
if (!HasImage)
|
|
return Empty<MemberReference>.Array;
|
|
|
|
return Read(this, (_, reader) => reader.GetMemberReferences());
|
|
}
|
|
|
|
public IEnumerable<CustomAttribute> GetCustomAttributes()
|
|
{
|
|
if (!HasImage)
|
|
return Empty<CustomAttribute>.Array;
|
|
|
|
return Read(this, (_, reader) => reader.GetCustomAttributes());
|
|
}
|
|
|
|
public TypeReference GetType(string fullName, bool runtimeName)
|
|
{
|
|
return runtimeName ? TypeParser.ParseType(this, fullName, typeDefinitionOnly: true) : GetType(fullName);
|
|
}
|
|
|
|
public TypeDefinition GetType(string fullName)
|
|
{
|
|
Mixin.CheckFullName(fullName);
|
|
|
|
int position = fullName.IndexOf('/');
|
|
if (position > 0)
|
|
return GetNestedType(fullName);
|
|
|
|
return ((TypeDefinitionCollection)Types).GetType(fullName);
|
|
}
|
|
|
|
public TypeDefinition GetType(string @namespace, string name)
|
|
{
|
|
Mixin.CheckName(name);
|
|
|
|
return ((TypeDefinitionCollection)Types).GetType(@namespace ?? string.Empty, name);
|
|
}
|
|
|
|
public IEnumerable<TypeDefinition> GetTypes()
|
|
{
|
|
return GetTypes(Types);
|
|
}
|
|
|
|
private static IEnumerable<TypeDefinition> GetTypes(Collection<TypeDefinition> types)
|
|
{
|
|
for (int i = 0; i < types.Count; i++)
|
|
{
|
|
TypeDefinition type = types[i];
|
|
|
|
yield return type;
|
|
|
|
if (!type.HasNestedTypes)
|
|
continue;
|
|
|
|
foreach (TypeDefinition nested in GetTypes(type.NestedTypes))
|
|
yield return nested;
|
|
}
|
|
}
|
|
|
|
private TypeDefinition GetNestedType(string fullname)
|
|
{
|
|
string[] names = fullname.Split('/');
|
|
TypeDefinition type = GetType(names[0]);
|
|
|
|
if (type == null)
|
|
return null;
|
|
|
|
for (int i = 1; i < names.Length; i++)
|
|
{
|
|
TypeDefinition nested_type = type.GetNestedType(names[i]);
|
|
if (nested_type == null)
|
|
return null;
|
|
|
|
type = nested_type;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
internal FieldDefinition Resolve(FieldReference field)
|
|
{
|
|
return MetadataResolver.Resolve(field);
|
|
}
|
|
|
|
internal MethodDefinition Resolve(MethodReference method)
|
|
{
|
|
return MetadataResolver.Resolve(method);
|
|
}
|
|
|
|
internal TypeDefinition Resolve(TypeReference type)
|
|
{
|
|
return MetadataResolver.Resolve(type);
|
|
}
|
|
|
|
private static void CheckContext(IGenericParameterProvider context, ModuleDefinition module)
|
|
{
|
|
if (context == null)
|
|
return;
|
|
|
|
if (context.Module != module)
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public TypeReference Import(Type type)
|
|
{
|
|
return ImportReference(type, null);
|
|
}
|
|
|
|
public TypeReference ImportReference(Type type)
|
|
{
|
|
return ImportReference(type, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public TypeReference Import(Type type, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(type, context);
|
|
}
|
|
|
|
public TypeReference ImportReference(Type type, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckType(type);
|
|
CheckContext(context, this);
|
|
|
|
return ReflectionImporter.ImportReference(type, context);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public FieldReference Import(SR.FieldInfo field)
|
|
{
|
|
return ImportReference(field, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public FieldReference Import(SR.FieldInfo field, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(field, context);
|
|
}
|
|
|
|
public FieldReference ImportReference(SR.FieldInfo field)
|
|
{
|
|
return ImportReference(field, null);
|
|
}
|
|
|
|
public FieldReference ImportReference(SR.FieldInfo field, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckField(field);
|
|
CheckContext(context, this);
|
|
|
|
return ReflectionImporter.ImportReference(field, context);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public MethodReference Import(SR.MethodBase method)
|
|
{
|
|
return ImportReference(method, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public MethodReference Import(SR.MethodBase method, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(method, context);
|
|
}
|
|
|
|
public MethodReference ImportReference(SR.MethodBase method)
|
|
{
|
|
return ImportReference(method, null);
|
|
}
|
|
|
|
public MethodReference ImportReference(SR.MethodBase method, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckMethod(method);
|
|
CheckContext(context, this);
|
|
|
|
return ReflectionImporter.ImportReference(method, context);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public TypeReference Import(TypeReference type)
|
|
{
|
|
return ImportReference(type, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public TypeReference Import(TypeReference type, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(type, context);
|
|
}
|
|
|
|
public TypeReference ImportReference(TypeReference type)
|
|
{
|
|
return ImportReference(type, null);
|
|
}
|
|
|
|
public TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckType(type);
|
|
|
|
if (type.Module == this)
|
|
return type;
|
|
|
|
CheckContext(context, this);
|
|
|
|
return MetadataImporter.ImportReference(type, context);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public FieldReference Import(FieldReference field)
|
|
{
|
|
return ImportReference(field, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public FieldReference Import(FieldReference field, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(field, context);
|
|
}
|
|
|
|
public FieldReference ImportReference(FieldReference field)
|
|
{
|
|
return ImportReference(field, null);
|
|
}
|
|
|
|
public FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckField(field);
|
|
|
|
if (field.Module == this)
|
|
return field;
|
|
|
|
CheckContext(context, this);
|
|
|
|
return MetadataImporter.ImportReference(field, context);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public MethodReference Import(MethodReference method)
|
|
{
|
|
return ImportReference(method, null);
|
|
}
|
|
|
|
[Obsolete("Use ImportReference", error: false)]
|
|
public MethodReference Import(MethodReference method, IGenericParameterProvider context)
|
|
{
|
|
return ImportReference(method, context);
|
|
}
|
|
|
|
public MethodReference ImportReference(MethodReference method)
|
|
{
|
|
return ImportReference(method, null);
|
|
}
|
|
|
|
public MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
|
|
{
|
|
Mixin.CheckMethod(method);
|
|
|
|
if (method.Module == this)
|
|
return method;
|
|
|
|
CheckContext(context, this);
|
|
|
|
return MetadataImporter.ImportReference(method, context);
|
|
}
|
|
|
|
public IMetadataTokenProvider LookupToken(int token)
|
|
{
|
|
return LookupToken(new MetadataToken((uint)token));
|
|
}
|
|
|
|
public IMetadataTokenProvider LookupToken(MetadataToken token)
|
|
{
|
|
return Read(token, (t, reader) => reader.LookupToken(t));
|
|
}
|
|
|
|
public void ImmediateRead()
|
|
{
|
|
if (!HasImage)
|
|
return;
|
|
ReadingMode = ReadingMode.Immediate;
|
|
ImmediateModuleReader moduleReader = new(Image);
|
|
moduleReader.ReadModule(this, resolve_attributes: true);
|
|
}
|
|
|
|
internal object SyncRoot { get; } = new();
|
|
|
|
internal void Read<TItem>(TItem item, Action<TItem, MetadataReader> read)
|
|
{
|
|
lock (SyncRoot)
|
|
{
|
|
int position = reader.position;
|
|
IGenericContext context = reader.context;
|
|
|
|
read(item, reader);
|
|
|
|
reader.position = position;
|
|
reader.context = context;
|
|
}
|
|
}
|
|
|
|
internal TRet Read<TItem, TRet>(TItem item, Func<TItem, MetadataReader, TRet> read)
|
|
{
|
|
lock (SyncRoot)
|
|
{
|
|
int position = reader.position;
|
|
IGenericContext context = reader.context;
|
|
|
|
TRet ret = read(item, reader);
|
|
|
|
reader.position = position;
|
|
reader.context = context;
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
internal TRet Read<TItem, TRet>(ref TRet variable, TItem item, Func<TItem, MetadataReader, TRet> read) where TRet : class
|
|
{
|
|
lock (SyncRoot)
|
|
{
|
|
if (variable != null)
|
|
return variable;
|
|
|
|
int position = reader.position;
|
|
IGenericContext context = reader.context;
|
|
|
|
TRet ret = read(item, reader);
|
|
|
|
reader.position = position;
|
|
reader.context = context;
|
|
|
|
return variable = ret;
|
|
}
|
|
}
|
|
|
|
public bool HasDebugHeader
|
|
{
|
|
get { return Image != null && Image.DebugHeader != null; }
|
|
}
|
|
|
|
public ImageDebugHeader GetDebugHeader()
|
|
{
|
|
return Image.DebugHeader ?? new ImageDebugHeader();
|
|
}
|
|
|
|
public static ModuleDefinition CreateModule(string name, ModuleKind kind)
|
|
{
|
|
return CreateModule(name, new ModuleParameters { Kind = kind });
|
|
}
|
|
|
|
public static ModuleDefinition CreateModule(string name, ModuleParameters parameters)
|
|
{
|
|
Mixin.CheckName(name);
|
|
Mixin.CheckParameters(parameters);
|
|
|
|
ModuleDefinition module = new()
|
|
{
|
|
Name = name,
|
|
kind = parameters.Kind,
|
|
timestamp = parameters.Timestamp ?? Mixin.GetTimestamp(),
|
|
Runtime = parameters.Runtime,
|
|
Architecture = parameters.Architecture,
|
|
Mvid = Guid.NewGuid(),
|
|
Attributes = ModuleAttributes.ILOnly,
|
|
Characteristics = (ModuleCharacteristics)0x8540
|
|
};
|
|
|
|
if (parameters.AssemblyResolver != null)
|
|
module.assembly_resolver = Disposable.NotOwned(parameters.AssemblyResolver);
|
|
|
|
if (parameters.MetadataResolver != null)
|
|
module.metadata_resolver = parameters.MetadataResolver;
|
|
|
|
if (parameters.MetadataImporterProvider != null)
|
|
module.metadata_importer = parameters.MetadataImporterProvider.GetMetadataImporter(module);
|
|
|
|
if (parameters.ReflectionImporterProvider != null)
|
|
module.reflection_importer = parameters.ReflectionImporterProvider.GetReflectionImporter(module);
|
|
|
|
if (parameters.Kind != ModuleKind.NetModule)
|
|
{
|
|
AssemblyDefinition assembly = new();
|
|
module.assembly = assembly;
|
|
module.assembly.Name = CreateAssemblyName(name);
|
|
assembly.main_module = module;
|
|
}
|
|
|
|
module.Types.Add(new(string.Empty, "<Module>", TypeAttributes.NotPublic));
|
|
|
|
return module;
|
|
}
|
|
|
|
private static AssemblyNameDefinition CreateAssemblyName(string name)
|
|
{
|
|
if (name.EndsWith(".dll") || name.EndsWith(".exe"))
|
|
name = name.Substring(0, name.Length - 4);
|
|
|
|
return new(name, Mixin.ZeroVersion);
|
|
}
|
|
|
|
public void ReadSymbols()
|
|
{
|
|
if (string.IsNullOrEmpty(FileName))
|
|
throw new InvalidOperationException();
|
|
|
|
DefaultSymbolReaderProvider provider = new(throwIfNoSymbol: true);
|
|
ReadSymbols(provider.GetSymbolReader(this, FileName), throwIfSymbolsAreNotMaching: true);
|
|
}
|
|
|
|
public void ReadSymbols(ISymbolReader reader)
|
|
{
|
|
ReadSymbols(reader, throwIfSymbolsAreNotMaching: true);
|
|
}
|
|
|
|
public void ReadSymbols(ISymbolReader reader, bool throwIfSymbolsAreNotMaching)
|
|
{
|
|
if (reader == null)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
symbol_reader = reader;
|
|
|
|
if (!symbol_reader.ProcessDebugHeader(GetDebugHeader()))
|
|
{
|
|
symbol_reader = null;
|
|
|
|
if (throwIfSymbolsAreNotMaching)
|
|
throw new SymbolsNotMatchingException("Symbols were found but are not matching the assembly");
|
|
|
|
return;
|
|
}
|
|
|
|
if (HasImage && ReadingMode == ReadingMode.Immediate)
|
|
{
|
|
ImmediateModuleReader immediate_reader = new(Image);
|
|
immediate_reader.ReadSymbols(this);
|
|
}
|
|
}
|
|
|
|
public static ModuleDefinition ReadModule(string fileName)
|
|
{
|
|
return ReadModule(fileName, new(ReadingMode.Deferred));
|
|
}
|
|
|
|
public static ModuleDefinition ReadModule(string fileName, ReaderParameters parameters)
|
|
{
|
|
Stream stream = GetFileStream(fileName, FileMode.Open, parameters.ReadWrite ? FileAccess.ReadWrite : FileAccess.Read, FileShare.Read);
|
|
|
|
if (parameters.InMemory)
|
|
{
|
|
MemoryStream memory = new(stream.CanSeek ? (int)stream.Length : 0);
|
|
using (stream)
|
|
{
|
|
stream.CopyTo(memory);
|
|
}
|
|
|
|
memory.Position = 0;
|
|
stream = memory;
|
|
}
|
|
|
|
try
|
|
{
|
|
return ReadModule(Disposable.Owned(stream), fileName, parameters);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
stream.Dispose();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private static Stream GetFileStream(string fileName, FileMode mode, FileAccess access, FileShare share)
|
|
{
|
|
Mixin.CheckFileName(fileName);
|
|
|
|
return new FileStream(fileName, mode, access, share);
|
|
}
|
|
|
|
public static ModuleDefinition ReadModule(Stream stream)
|
|
{
|
|
return ReadModule(stream, new(ReadingMode.Deferred));
|
|
}
|
|
|
|
public static ModuleDefinition ReadModule(Stream stream, ReaderParameters parameters)
|
|
{
|
|
Mixin.CheckStream(stream);
|
|
Mixin.CheckReadSeek(stream);
|
|
|
|
return ReadModule(Disposable.NotOwned(stream), stream.GetFileName(), parameters);
|
|
}
|
|
|
|
private static ModuleDefinition ReadModule(Disposable<Stream> stream, string fileName, ReaderParameters parameters)
|
|
{
|
|
Mixin.CheckParameters(parameters);
|
|
|
|
return ModuleReader.CreateModule(ImageReader.ReadImage(stream, fileName), parameters);
|
|
}
|
|
|
|
public void Write(string fileName)
|
|
{
|
|
Write(fileName, new());
|
|
}
|
|
|
|
public void Write(string fileName, WriterParameters parameters)
|
|
{
|
|
Mixin.CheckParameters(parameters);
|
|
Stream file = GetFileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
|
|
ModuleWriter.WriteModule(this, Disposable.Owned(file), parameters);
|
|
}
|
|
|
|
public void Write()
|
|
{
|
|
Write(new WriterParameters());
|
|
}
|
|
|
|
public void Write(WriterParameters parameters)
|
|
{
|
|
if (!HasImage)
|
|
throw new InvalidOperationException();
|
|
|
|
Write(Image.Stream.value, parameters);
|
|
}
|
|
|
|
public void Write(Stream stream)
|
|
{
|
|
Write(stream, new());
|
|
}
|
|
|
|
public void Write(Stream stream, WriterParameters parameters)
|
|
{
|
|
Mixin.CheckStream(stream);
|
|
Mixin.CheckWriteSeek(stream);
|
|
Mixin.CheckParameters(parameters);
|
|
|
|
ModuleWriter.WriteModule(this, Disposable.NotOwned(stream), parameters);
|
|
}
|
|
}
|
|
|
|
internal static partial class Mixin
|
|
{
|
|
public enum Argument
|
|
{
|
|
name,
|
|
fileName,
|
|
fullName,
|
|
stream,
|
|
type,
|
|
method,
|
|
field,
|
|
parameters,
|
|
module,
|
|
modifierType,
|
|
eventType,
|
|
fieldType,
|
|
declaringType,
|
|
returnType,
|
|
propertyType,
|
|
interfaceType,
|
|
constraintType
|
|
}
|
|
|
|
public static void CheckName(object name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException(Argument.name.ToString());
|
|
}
|
|
|
|
public static void CheckName(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name))
|
|
throw new ArgumentNullOrEmptyException(Argument.name.ToString());
|
|
}
|
|
|
|
public static void CheckFileName(string fileName)
|
|
{
|
|
if (string.IsNullOrEmpty(fileName))
|
|
throw new ArgumentNullOrEmptyException(Argument.fileName.ToString());
|
|
}
|
|
|
|
public static void CheckFullName(string fullName)
|
|
{
|
|
if (string.IsNullOrEmpty(fullName))
|
|
throw new ArgumentNullOrEmptyException(Argument.fullName.ToString());
|
|
}
|
|
|
|
public static void CheckStream(object stream)
|
|
{
|
|
if (stream == null)
|
|
throw new ArgumentNullException(Argument.stream.ToString());
|
|
}
|
|
|
|
public static void CheckWriteSeek(Stream stream)
|
|
{
|
|
if (!stream.CanWrite || !stream.CanSeek)
|
|
throw new ArgumentException("Stream must be writable and seekable.");
|
|
}
|
|
|
|
public static void CheckReadSeek(Stream stream)
|
|
{
|
|
if (!stream.CanRead || !stream.CanSeek)
|
|
throw new ArgumentException("Stream must be readable and seekable.");
|
|
}
|
|
|
|
public static void CheckType(object type)
|
|
{
|
|
if (type == null)
|
|
throw new ArgumentNullException(Argument.type.ToString());
|
|
}
|
|
|
|
public static void CheckType(object type, Argument argument)
|
|
{
|
|
if (type == null)
|
|
throw new ArgumentNullException(argument.ToString());
|
|
}
|
|
|
|
public static void CheckField(object field)
|
|
{
|
|
if (field == null)
|
|
throw new ArgumentNullException(Argument.field.ToString());
|
|
}
|
|
|
|
public static void CheckMethod(object method)
|
|
{
|
|
if (method == null)
|
|
throw new ArgumentNullException(Argument.method.ToString());
|
|
}
|
|
|
|
public static void CheckParameters(object parameters)
|
|
{
|
|
if (parameters == null)
|
|
throw new ArgumentNullException(Argument.parameters.ToString());
|
|
}
|
|
|
|
public static uint GetTimestamp()
|
|
{
|
|
return (uint)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
|
}
|
|
|
|
public static bool HasImage(this ModuleDefinition self)
|
|
{
|
|
return self != null && self.HasImage;
|
|
}
|
|
|
|
public static string GetFileName(this Stream self)
|
|
{
|
|
FileStream file_stream = self as FileStream;
|
|
if (file_stream == null)
|
|
return string.Empty;
|
|
|
|
return Path.GetFullPath(file_stream.Name);
|
|
}
|
|
|
|
public static TargetRuntime ParseRuntime(this string self)
|
|
{
|
|
if (string.IsNullOrEmpty(self))
|
|
return TargetRuntime.Net_4_0;
|
|
|
|
switch (self[1])
|
|
{
|
|
case '1':
|
|
return self[3] == '0' ? TargetRuntime.Net_1_0 : TargetRuntime.Net_1_1;
|
|
case '2':
|
|
return TargetRuntime.Net_2_0;
|
|
case '4':
|
|
default:
|
|
return TargetRuntime.Net_4_0;
|
|
}
|
|
}
|
|
|
|
public static string RuntimeVersionString(this TargetRuntime runtime)
|
|
{
|
|
switch (runtime)
|
|
{
|
|
case TargetRuntime.Net_1_0:
|
|
return "v1.0.3705";
|
|
case TargetRuntime.Net_1_1:
|
|
return "v1.1.4322";
|
|
case TargetRuntime.Net_2_0:
|
|
return "v2.0.50727";
|
|
case TargetRuntime.Net_4_0:
|
|
default:
|
|
return "v4.0.30319";
|
|
}
|
|
}
|
|
|
|
public static bool IsWindowsMetadata(this ModuleDefinition module)
|
|
{
|
|
return module.MetadataKind != MetadataKind.Ecma335;
|
|
}
|
|
|
|
public static byte[] ReadAll(this Stream self)
|
|
{
|
|
int read;
|
|
MemoryStream memory = new((int)self.Length);
|
|
byte[] buffer = new byte [1024];
|
|
|
|
while ((read = self.Read(buffer, 0, buffer.Length)) != 0)
|
|
memory.Write(buffer, 0, read);
|
|
|
|
return memory.ToArray();
|
|
}
|
|
|
|
public static void Read(object o) { }
|
|
}
|
|
} |