/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using dnSpy.Debugger.DotNet.Metadata.Impl;
namespace dnSpy.Debugger.DotNet.Metadata {
///
/// A .NET module
///
public abstract class DmdModule : DmdObject, IDmdCustomAttributeProvider {
///
/// Dummy abstract method to make sure no-one outside this assembly can create their own
///
private protected abstract void YouCantDeriveFromThisClass();
///
/// Returns the fully qualified name
///
/// true if the module is in memory
/// true if it's a dynamic module
/// Module filename or null
///
public static string GetFullyQualifiedName(bool isInMemory, bool isDynamic, string? fullyQualifiedName) {
if (isDynamic)
return "";
if (isInMemory)
return "";
return fullyQualifiedName ?? string.Empty;
}
///
/// Gets the AppDomain
///
public abstract DmdAppDomain AppDomain { get; }
///
/// Gets the fully qualified name
///
public abstract string FullyQualifiedName { get; }
///
/// true if this is the corlib module
///
public bool IsCorLib => this == AppDomain.CorLib?.ManifestModule;
///
/// Gets all types in this module
///
///
public abstract DmdType[] GetTypes();
///
/// Gets all types that exist in the ExportedType table. This includes types that have been
/// forwarded to other assemblies.
///
///
public abstract DmdType[] GetExportedTypes();
///
/// Gets the module version ID
///
public abstract Guid ModuleVersionId { get; }
///
/// Gets the metadata token
///
public abstract int MetadataToken { get; }
///
/// Gets the global type
///
public abstract DmdType GlobalType { get; }
///
/// Gets the metadata stream version
///
public abstract int MDStreamVersion { get; }
///
/// Gets the metadata name of the module
///
public abstract string ScopeName { get; set; }
///
/// Gets a dynamic module's version number. It gets incremented each time a new type gets added to the dynamic module.
///
public abstract int DynamicModuleVersion { get; }
///
/// Gets the module name
///
public string Name {
get {
var fqn = FullyQualifiedName;
// Don't use Path.GetFileName() since fqn could contain invalid characters
int index = fqn.LastIndexOfAny(dirSepChars);
if (index >= 0)
fqn = fqn.Substring(index + 1);
if (fqn.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase))
fqn = fqn.Substring(0, fqn.Length - ".ni.dll".Length) + fqn.Substring(fqn.Length - ".dll".Length);
else if (fqn.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase))
fqn = fqn.Substring(0, fqn.Length - ".ni.exe".Length) + fqn.Substring(fqn.Length - ".exe".Length);
return fqn;
}
}
static readonly char[] dirSepChars = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
///
/// Gets the assembly
///
public abstract DmdAssembly Assembly { get; }
///
/// true if it's a dynamic module (types can be added at runtime)
///
public abstract bool IsDynamic { get; }
///
/// true if it's an in-memory module (eg. loaded from a array)
///
public abstract bool IsInMemory { get; }
///
/// true if it's a synthetic module; it's not loaded in the debugged process
///
public abstract bool IsSynthetic { get; }
///
/// Gets the custom attributes
///
public ReadOnlyCollection CustomAttributes => GetCustomAttributesData();
///
/// Gets the custom attributes
///
///
public abstract ReadOnlyCollection GetCustomAttributesData();
///
/// Checks if a custom attribute is present
///
/// Full name of the custom attribute type
/// true to check custom attributes in all base classes
///
public bool IsDefined(string attributeTypeFullName, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), attributeTypeFullName);
///
/// Checks if a custom attribute is present
///
/// Custom attribute type
/// true to check custom attributes in all base classes
///
public bool IsDefined(DmdType? attributeType, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), attributeType);
///
/// Checks if a custom attribute is present
///
/// Custom attribute type
/// true to check custom attributes in all base classes
///
public bool IsDefined(Type attributeType, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), DmdTypeUtilities.ToDmdType(attributeType, AppDomain));
///
/// Finds a custom attribute
///
/// Full name of the custom attribute type
/// true to check custom attributes in all base classes
///
public DmdCustomAttributeData? FindCustomAttribute(string attributeTypeFullName, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), attributeTypeFullName);
///
/// Finds a custom attribute
///
/// Custom attribute type
/// true to check custom attributes in all base classes
///
public DmdCustomAttributeData? FindCustomAttribute(DmdType? attributeType, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), attributeType);
///
/// Finds a custom attribute
///
/// Custom attribute type
/// true to check custom attributes in all base classes
///
public DmdCustomAttributeData? FindCustomAttribute(Type attributeType, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), DmdTypeUtilities.ToDmdType(attributeType, AppDomain));
///
/// Resolves a method
///
/// Token
///
public DmdMethodBase? ResolveMethod(int metadataToken) => ResolveMethod(metadataToken, (IList?)null, null);
///
/// Resolves a method
///
/// Token
/// Resolve options
///
public DmdMethodBase? ResolveMethod(int metadataToken, DmdResolveOptions options) => ResolveMethod(metadataToken, (IList?)null, null, options);
///
/// Resolves a method
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMethodBase ResolveMethod(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a method
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMethodBase ResolveMethod(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a method
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public abstract DmdMethodBase? ResolveMethod(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options);
///
/// Resolves a method
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public DmdMethodBase? ResolveMethod(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) =>
ResolveMethod(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), options);
///
/// Resolves a field
///
/// Token
///
public DmdFieldInfo? ResolveField(int metadataToken) => ResolveField(metadataToken, (IList?)null, null);
///
/// Resolves a field
///
/// Token
/// Resolve options
///
public DmdFieldInfo? ResolveField(int metadataToken, DmdResolveOptions options) => ResolveField(metadataToken, (IList?)null, null, options);
///
/// Resolves a field
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdFieldInfo ResolveField(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveField(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a field
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdFieldInfo ResolveField(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveField(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a field
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public abstract DmdFieldInfo? ResolveField(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options);
///
/// Resolves a field
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public DmdFieldInfo? ResolveField(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) =>
ResolveField(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), options);
///
/// Resolves a type
///
/// Token
///
public DmdType? ResolveType(int metadataToken) => ResolveType(metadataToken, (IList?)null, null);
///
/// Resolves a type
///
/// Token
/// Resolve options
///
public DmdType? ResolveType(int metadataToken, DmdResolveOptions options) => ResolveType(metadataToken, (IList?)null, null, options);
///
/// Resolves a type
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdType ResolveType(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveType(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a type
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdType ResolveType(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveType(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a type
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public abstract DmdType? ResolveType(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options);
///
/// Resolves a type
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public DmdType? ResolveType(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) =>
ResolveType(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), options);
///
/// Resolves a member
///
/// Token
///
public DmdMemberInfo? ResolveMember(int metadataToken) => ResolveMember(metadataToken, (IList?)null, null);
///
/// Resolves a member
///
/// Token
/// Resolve options
///
public DmdMemberInfo? ResolveMember(int metadataToken, DmdResolveOptions options) => ResolveMember(metadataToken, (IList?)null, null, options);
///
/// Resolves a member
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMemberInfo ResolveMember(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a member
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMemberInfo ResolveMember(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMember(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a member
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public abstract DmdMemberInfo? ResolveMember(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options);
///
/// Resolves a member
///
/// Token
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public DmdMemberInfo? ResolveMember(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) =>
ResolveMember(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), options);
///
/// Resolves a method signature
///
/// StandaloneSig token from a method body
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMethodSignature ResolveMethodSignature(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMethodSignature(metadataToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a method signature
///
/// StandaloneSig token from a method body
/// Generic type arguments or null
/// Generic method arguments or null
///
public DmdMethodSignature ResolveMethodSignature(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments) =>
ResolveMethodSignature(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), DmdResolveOptions.ThrowOnError)!;
///
/// Resolves a method signature
///
/// StandaloneSig token from a method body
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public abstract DmdMethodSignature? ResolveMethodSignature(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options);
///
/// Resolves a method signature
///
/// StandaloneSig token from a method body
/// Generic type arguments or null
/// Generic method arguments or null
/// Resolve options
///
public DmdMethodSignature? ResolveMethodSignature(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) =>
ResolveMethodSignature(metadataToken, genericTypeArguments.ToDmdType(AppDomain), genericMethodArguments.ToDmdType(AppDomain), options);
///
/// Resolves a signature
///
/// Token
///
public abstract byte[]? ResolveSignature(int metadataToken);
///
/// Resolves a string
///
/// String token (0x70xxxxxx)
///
public abstract string ResolveString(int metadataToken);
///
/// Gets PE information
///
/// PE Kind
/// Machine
public abstract void GetPEKind(out DmdPortableExecutableKinds peKind, out DmdImageFileMachine machine);
///
/// Gets a type
///
/// Type
///
public DmdType? GetType(Type type) => GetType(type, DmdGetTypeOptions.None);
///
/// Gets a type and throws if it couldn't be found
///
///
///
public DmdType GetTypeThrow(Type type) => GetType(type, DmdGetTypeOptions.ThrowOnError)!;
///
/// Gets a type
///
/// Type
/// Options
///
public DmdType? GetType(Type type, DmdGetTypeOptions options) {
if (type is null)
throw new ArgumentNullException(nameof(type));
var fullname = type.FullName ?? throw new ArgumentException();
return GetType(fullname, options);
}
///
/// Gets a type
///
/// Name of type
/// true to ignore case
///
public DmdType? GetType(string className, bool ignoreCase) => GetType(className, ignoreCase ? DmdGetTypeOptions.IgnoreCase : 0);
///
/// Gets a type
///
/// Name of type
///
public DmdType? GetType(string className) => GetType(className, DmdGetTypeOptions.None);
///
/// Gets a type and throws if it couldn't be found
///
/// Name of type
///
public DmdType GetTypeThrow(string className) => GetType(className, DmdGetTypeOptions.ThrowOnError)!;
///
/// Gets a type
///
/// Name of type
/// true to throw if the type couldn't be found
/// true to ignore case
///
public DmdType? GetType(string className, bool throwOnError, bool ignoreCase) =>
GetType(className, (throwOnError ? DmdGetTypeOptions.ThrowOnError : 0) | (ignoreCase ? DmdGetTypeOptions.IgnoreCase : 0));
///
/// Gets a type
///
/// Full name of the type ()
/// Options
///
public abstract DmdType? GetType(string typeName, DmdGetTypeOptions options);
///
/// Gets all global public static and instance fields
///
///
public DmdFieldInfo[] GetFields() => GetFields(DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public);
///
/// Gets all global fields
///
/// Binding attributes
///
public DmdFieldInfo[] GetFields(DmdBindingFlags bindingFlags) => GlobalType.GetFields(bindingFlags);
///
/// Gets a global public static or instance field
///
/// Field name
///
public DmdFieldInfo? GetField(string name) => GetField(name, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public);
///
/// Gets a global field
///
/// Field name
/// Binding attributes
///
public DmdFieldInfo? GetField(string name, DmdBindingFlags bindingAttr) => GlobalType.GetField(name, bindingAttr);
///
/// Gets all global public static or instance methods
///
///
public DmdMethodInfo[] GetMethods() => GetMethods(DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public);
///
/// Gets global methods
///
/// Binding attributes
///
public DmdMethodInfo[] GetMethods(DmdBindingFlags bindingFlags) => GlobalType.GetMethods(bindingFlags);
///
/// Gets a global method
///
/// Method name
/// Binding attributes
/// Calling convention
/// Method parameter types or null
///
public DmdMethodInfo? GetMethod(string name, DmdBindingFlags bindingAttr, DmdCallingConventions callConvention, IList? types) {
if (types is null)
return GlobalType.GetMethod(name, bindingAttr);
return GlobalType.GetMethod(name, bindingAttr, callConvention, types);
}
///
/// Gets a global method
///
/// Method name
/// Binding attributes
/// Calling convention
/// Method parameter types or null
///
public DmdMethodInfo? GetMethod(string name, DmdBindingFlags bindingAttr, DmdCallingConventions callConvention, IList? types) =>
GetMethod(name, bindingAttr, callConvention, types.ToDmdType(AppDomain));
///
/// Gets a global public static or instance method
///
/// Method name
/// Method parameter types
///
public DmdMethodInfo? GetMethod(string name, IList types) => GetMethod(name, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public, DmdCallingConventions.Any, types);
///
/// Gets a global public static or instance method
///
/// Method name
/// Method parameter types
///
public DmdMethodInfo? GetMethod(string name, IList types) => GetMethod(name, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public, DmdCallingConventions.Any, types.ToDmdType(AppDomain));
///
/// Gets a global public static or instance method
///
/// Method name
///
public DmdMethodInfo? GetMethod(string name) => GetMethod(name, DmdBindingFlags.Instance | DmdBindingFlags.Static | DmdBindingFlags.Public, DmdCallingConventions.Any, (IList?)null);
///
/// Gets all referenced assemblies
///
///
public abstract DmdReadOnlyAssemblyName[] GetReferencedAssemblies();
///
/// Reads memory. Returns false if data couldn't be read.
///
/// RVA of data
/// Destination address
/// Number of bytes to read
///
public abstract unsafe bool ReadMemory(uint rva, void* destination, int size);
///
/// Reads memory. Returns false if data couldn't be read.
///
/// RVA of data
/// Destination buffer
/// Destination index
/// Number of bytes to read
///
public unsafe bool ReadMemory(uint rva, byte[] destination, int destinationIndex, int size) {
if (destination is null)
throw new ArgumentNullException(nameof(destination));
if ((uint)destinationIndex > (uint)destination.Length)
throw new ArgumentOutOfRangeException(nameof(destinationIndex));
if (size < 0)
throw new ArgumentOutOfRangeException(nameof(size));
if ((uint)(destinationIndex + size) > (uint)destination.Length)
throw new ArgumentOutOfRangeException(nameof(destinationIndex));
if (size == 0)
return true;
fixed (void* p = &destination[destinationIndex])
return ReadMemory(rva, p, size);
}
///
/// Reads memory. Returns null if data couldn't be read.
///
/// RVA of data
/// Number of bytes to read
///
public byte[]? ReadMemory(uint rva, int size) {
if (size == 0)
return Array.Empty();
var res = new byte[size];
if (!ReadMemory(rva, res, 0, size))
return null;
return res;
}
///
/// Returns the metadata name ()
///
///
public sealed override string ToString() => ScopeName;
}
///
/// Type/member resolve options
///
[Flags]
public enum DmdResolveOptions {
///
/// No bit is set
///
None = 0,
///
/// Throw if the type or member couldn't be resolved
///
ThrowOnError = 0x00000001,
///
/// Don't try to resolve type refs, field refs, method refs
///
NoTryResolveRefs = 0x00000002,
}
}