/* 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, } }