/* 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.Threading; namespace dnSpy.Debugger.DotNet.Metadata.Impl { sealed class DmdModuleImpl : DmdModule { sealed private protected override void YouCantDeriveFromThisClass() => throw new InvalidOperationException(); public override DmdAppDomain AppDomain => Assembly.AppDomain; public override string FullyQualifiedName { get; } public override DmdAssembly Assembly => assembly; public override bool IsDynamic { get; } public override bool IsInMemory { get; } public override bool IsSynthetic { get; } public override Guid ModuleVersionId => metadataReader.ModuleVersionId; public override int MetadataToken => 0x00000001; public override DmdType GlobalType => ResolveType(0x02000001)!; public override int MDStreamVersion => metadataReader.MDStreamVersion; public override string ScopeName { get => scopeNameOverride ?? metadataReader.ModuleScopeName; set => scopeNameOverride = value; } public override int DynamicModuleVersion => DynamicModuleVersionInternal; internal volatile int DynamicModuleVersionInternal; internal DmdMetadataReader MetadataReader => metadataReader; readonly DmdAssemblyImpl assembly; readonly DmdMetadataReader metadataReader; string? scopeNameOverride; public DmdModuleImpl(DmdAssemblyImpl assembly, DmdMetadataReader metadataReader, bool isInMemory, bool isDynamic, bool isSynthetic, string fullyQualifiedName) { this.assembly = assembly ?? throw new ArgumentNullException(nameof(assembly)); this.metadataReader = metadataReader ?? throw new ArgumentNullException(nameof(metadataReader)); FullyQualifiedName = fullyQualifiedName ?? throw new ArgumentNullException(nameof(fullyQualifiedName)); IsDynamic = isDynamic; IsInMemory = isInMemory; IsSynthetic = isSynthetic; } public override DmdType[] GetTypes() => metadataReader.GetTypes(); public override DmdType[] GetExportedTypes() => metadataReader.GetExportedTypes(); public override DmdMethodBase? ResolveMethod(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) => metadataReader.ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments, options); public override DmdFieldInfo? ResolveField(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) => metadataReader.ResolveField(metadataToken, genericTypeArguments, genericMethodArguments, options); public override DmdType? ResolveType(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) => metadataReader.ResolveType(metadataToken, genericTypeArguments, genericMethodArguments, options); public override DmdMemberInfo? ResolveMember(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) => metadataReader.ResolveMember(metadataToken, genericTypeArguments, genericMethodArguments, options); public override DmdMethodSignature? ResolveMethodSignature(int metadataToken, IList? genericTypeArguments, IList? genericMethodArguments, DmdResolveOptions options) => metadataReader.ResolveMethodSignature(metadataToken, genericTypeArguments, genericMethodArguments, options); public override byte[]? ResolveSignature(int metadataToken) => metadataReader.ResolveSignature(metadataToken); public override string ResolveString(int metadataToken) => metadataReader.ResolveString(metadataToken); public override void GetPEKind(out DmdPortableExecutableKinds peKind, out DmdImageFileMachine machine) => metadataReader.GetPEKind(out peKind, out machine); public override DmdReadOnlyAssemblyName[] GetReferencedAssemblies() => metadataReader.GetReferencedAssemblies(); public override unsafe bool ReadMemory(uint rva, void* destination, int size) => metadataReader.ReadMemory(rva, destination, size); sealed class TypeDefResolver : ITypeDefResolver { readonly DmdModuleImpl module; readonly bool ignoreCase; public TypeDefResolver(DmdModuleImpl module, bool ignoreCase) { this.module = module ?? throw new ArgumentNullException(nameof(module)); this.ignoreCase = ignoreCase; } public DmdTypeDef? GetTypeDef(IDmdAssemblyName? assemblyName, List typeNames) { if (typeNames.Count == 0) return null; DmdModuleImpl? targetModule = module; DmdAssemblyImpl? targetAssembly = targetModule.assembly; if (assemblyName is not null && !module.assembly.AppDomainImpl.AssemblyNameEqualityComparer.Equals(targetAssembly.GetName(), assemblyName)) { targetAssembly = (DmdAssemblyImpl?)targetAssembly.AppDomain.GetAssembly(assemblyName); targetModule = (DmdModuleImpl?)targetAssembly?.ManifestModule; if (targetModule is null) return null; } DmdTypeDef? type; DmdTypeUtilities.SplitFullName(typeNames[0], out var @namespace, out var name); var typeRef = new DmdParsedTypeRef(targetModule, null, DmdTypeScope.Invalid, @namespace, name, null); type = targetModule.GetType(typeRef, ignoreCase); if (type is null) return null; for (int i = 1; i < typeNames.Count; i++) { var flags = DmdBindingFlags.Public | DmdBindingFlags.NonPublic; if (ignoreCase) flags |= DmdBindingFlags.IgnoreCase; type = (DmdTypeDef?)type.GetNestedType(typeNames[i], flags); if (type is null) return null; } return type; } } public override DmdType? GetType(string typeName, DmdGetTypeOptions options) { if (typeName is null) throw new ArgumentNullException(nameof(typeName)); var resolver = new TypeDefResolver(this, (options & DmdGetTypeOptions.IgnoreCase) != 0); var type = DmdTypeNameParser.Parse(resolver, typeName); if (type is not null) return AppDomain.Intern(type, DmdMakeTypeOptions.NoResolve); if ((options & DmdGetTypeOptions.ThrowOnError) != 0) throw new TypeNotFoundException(typeName); return null; } DmdTypeDef? GetType(DmdTypeRef typeRef, bool ignoreCase) => assembly.AppDomainImpl.TryLookup(this, typeRef, ignoreCase); public override ReadOnlyCollection GetCustomAttributesData() { if (customAttributes is not null) return customAttributes; var cas = metadataReader.ReadCustomAttributes(0x00000001); var newCAs = CustomAttributesHelper.AddPseudoCustomAttributes(this, cas); Interlocked.CompareExchange(ref customAttributes, newCAs, null); return customAttributes!; } volatile ReadOnlyCollection? customAttributes; } }