/* 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.Diagnostics; using System.IO; using dnlib.DotNet; using dnlib.DotNet.MD; using dnlib.PE; using SSP = System.Security.Permissions; namespace dnSpy.Debugger.DotNet.Metadata.Impl.MD { sealed class DmdEcma335MetadataReader : DmdMetadataReaderBase, IMethodBodyResolver { public override Guid ModuleVersionId { get; } public override int MDStreamVersion => ((TablesStream.Version & 0xFF00) << 8) | (TablesStream.Version & 0xFF); public override string ModuleScopeName { get; } public override string ImageRuntimeVersion => Metadata.VersionString; public override DmdMethodInfo? EntryPoint { get { if ((Metadata.ImageCor20Header.Flags & ComImageFlags.NativeEntryPoint) != 0) return null; uint token = Metadata.ImageCor20Header.EntryPointToken_or_RVA; if ((token >> 24) != (uint)Table.File) return ResolveMethod((int)token, null, null, DmdResolveOptions.None) as DmdMethodInfo; return null; } } public static DmdEcma335MetadataReader Create(DmdModuleImpl module, IntPtr address, uint size, bool isFileLayout) { var peImage = new PEImage(address, size, isFileLayout ? ImageLayout.File : ImageLayout.Memory, true); return Create(module, peImage); } public static DmdEcma335MetadataReader Create(DmdModuleImpl module, byte[] bytes, bool isFileLayout) { var peImage = new PEImage(bytes, isFileLayout ? ImageLayout.File : ImageLayout.Memory, true); return Create(module, peImage); } public static DmdEcma335MetadataReader Create(DmdModuleImpl module, string filename, bool isFileLayout) => Create(module, File.ReadAllBytes(filename), isFileLayout); static DmdEcma335MetadataReader Create(DmdModuleImpl module, IPEImage peImage) { var metadata = MetadataFactory.CreateMetadata(peImage); return new DmdEcma335MetadataReader(module, metadata); } internal DmdModule Module => module; internal dnlib.DotNet.MD.Metadata Metadata { get; } internal TablesStream TablesStream => Metadata.TablesStream; internal StringsStream StringsStream => Metadata.StringsStream; internal GuidStream GuidStream => Metadata.GuidStream; internal BlobStream BlobStream => Metadata.BlobStream; readonly object signatureLock; readonly DmdModuleImpl module; readonly LazyList typeRefList; readonly LazyList fieldList; readonly LazyList typeDefList; readonly LazyList methodList; readonly LazyList2?, IList?> memberRefList; readonly LazyList eventList; readonly LazyList propertyList; readonly LazyList2?, IList?> typeSpecList; readonly LazyList exportedTypeList; readonly DmdNullGlobalType globalTypeIfThereAreNoTypes; readonly Dictionary fieldTypeCache; readonly Dictionary methodSignatureCache; DmdEcma335MetadataReader(DmdModuleImpl module, dnlib.DotNet.MD.Metadata metadata) { signatureLock = new object(); this.module = module; Metadata = metadata; fieldTypeCache = new Dictionary(); methodSignatureCache = new Dictionary(); TablesStream.TryReadModuleRow(1, out var row); ModuleScopeName = metadata.StringsStream.ReadNoNull(row.Name); ModuleVersionId = metadata.GuidStream.Read(row.Mvid) ?? Guid.Empty; var ts = TablesStream; typeRefList = new LazyList(ts.TypeRefTable.Rows, rid => new DmdTypeRefMD(this, rid, null)); fieldList = new LazyList(ts.FieldTable.Rows, CreateResolvedField); typeDefList = new LazyList(ts.TypeDefTable.Rows, rid => new DmdTypeDefMD(this, rid, null)); methodList = new LazyList(ts.MethodTable.Rows, CreateResolvedMethod); memberRefList = new LazyList2?, IList?>(ts.MemberRefTable.Rows, CreateResolvedMemberRef); eventList = new LazyList(ts.EventTable.Rows, CreateResolvedEvent); propertyList = new LazyList(ts.PropertyTable.Rows, CreateResolvedProperty); typeSpecList = new LazyList2?, IList?>(ts.TypeSpecTable.Rows, ReadTypeSpec); exportedTypeList = new LazyList(ts.ExportedTypeTable.Rows, rid => new DmdExportedTypeMD(this, rid, null)); globalTypeIfThereAreNoTypes = new DmdNullGlobalType(module, null); } (DmdType type, bool containedGenericParams) ReadTypeSpec(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) { Metadata.TablesStream.TryReadTypeSpecRow(rid, out var row); var reader = BlobStream.CreateReader(row.Signature); return DmdSignatureReader.ReadTypeSignature(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments, resolveTypes); } DmdFieldDefMD CreateResolvedField(uint rid, DmdTypeDef? declaringType) { if (declaringType is null) declaringType = ResolveTypeDef(Metadata.GetOwnerTypeOfField(rid)) ?? globalTypeIfThereAreNoTypes; else Debug.Assert((object)declaringType == ResolveTypeDef(Metadata.GetOwnerTypeOfField(rid))); return CreateFieldDefCore(rid, declaringType, declaringType); } internal DmdFieldDef CreateFieldDef(uint rid, DmdType declaringType, DmdType reflectedType) { if ((object)declaringType == reflectedType && declaringType is DmdTypeDef declaringTypeDef) return ResolveFieldDef(rid, declaringTypeDef)!; return CreateFieldDefCore(rid, declaringType, reflectedType); } DmdFieldDefMD CreateFieldDefCore(uint rid, DmdType declaringType, DmdType reflectedType) => new DmdFieldDefMD(this, rid, declaringType, reflectedType); internal DmdType ReadFieldType(uint signature, IList genericTypeArguments) { lock (signatureLock) { if (fieldTypeCache.TryGetValue(signature, out var fieldType)) { if (fieldType is not null) return fieldType; var info = ReadFieldTypeCore(signature, genericTypeArguments); Debug.Assert(info.containedGenericParams); return info.fieldType; } else { var info = ReadFieldTypeCore(signature, genericTypeArguments); if (info.containedGenericParams) fieldTypeCache.Add(signature, null); else fieldTypeCache.Add(signature, info.fieldType); return info.fieldType; } } } (DmdType fieldType, bool containedGenericParams) ReadFieldTypeCore(uint signature, IList? genericTypeArguments) { var reader = BlobStream.CreateReader(signature); return DmdSignatureReader.ReadFieldSignature(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, resolveTypes); } DmdMethodBase CreateResolvedMethod(uint rid, DmdTypeDef? declaringType) { if (declaringType is null) declaringType = ResolveTypeDef(Metadata.GetOwnerTypeOfMethod(rid)) ?? globalTypeIfThereAreNoTypes; else Debug.Assert((object)declaringType == ResolveTypeDef(Metadata.GetOwnerTypeOfMethod(rid))); return CreateMethodDefCore(rid, declaringType, declaringType); } internal DmdMethodBase CreateMethodDef(uint rid, DmdType declaringType, DmdType reflectedType) { if ((object)declaringType == reflectedType && declaringType is DmdTypeDef declaringTypeDef) return ResolveMethodDef(rid, declaringTypeDef)!; return CreateMethodDefCore(rid, declaringType, reflectedType); } DmdMethodBase CreateMethodDefCore(uint rid, DmdType declaringType, DmdType reflectedType) { TablesStream.TryReadMethodRow(rid, out var row); string name = StringsStream.ReadNoNull(row.Name); if ((row.Flags & (int)DmdMethodAttributes.RTSpecialName) != 0 && name.Length > 0 && name[0] == '.') { if (name == DmdConstructorInfo.ConstructorName || name == DmdConstructorInfo.TypeConstructorName) return new DmdConstructorDefMD(this, row, rid, name, declaringType, reflectedType); } return new DmdMethodDefMD(this, row, rid, name, declaringType, reflectedType); } internal DmdMethodSignature ReadMethodSignature(uint signature, IList? genericTypeArguments, IList? genericMethodArguments, bool isProperty) { lock (signatureLock) { if (methodSignatureCache.TryGetValue(signature, out var methodSignature)) { if (methodSignature is not null) return methodSignature; var info = ReadMethodSignatureCore(signature, genericTypeArguments, genericMethodArguments, isProperty); Debug.Assert(info.containedGenericParams); return info.methodSignature; } else { var info = ReadMethodSignatureCore(signature, genericTypeArguments, genericMethodArguments, isProperty); if (info.containedGenericParams) methodSignatureCache.Add(signature, null); else methodSignatureCache.Add(signature, info.methodSignature); return info.methodSignature; } } } (DmdMethodSignature methodSignature, bool containedGenericParams) ReadMethodSignatureCore(uint signature, IList? genericTypeArguments, IList? genericMethodArguments, bool isProperty) { var reader = BlobStream.CreateReader(signature); return DmdSignatureReader.ReadMethodSignature(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments, isProperty, resolveTypes); } internal (DmdParameterInfo? returnParameter, DmdParameterInfo[] parameters) CreateParameters(DmdMethodBase method, bool createReturnParameter) { var ridList = Metadata.GetParamRidList((uint)method.MetadataToken & 0x00FFFFFF); var methodSignature = method.GetMethodSignature(); var sigParamTypes = methodSignature.GetParameterTypes(); DmdParameterInfo? returnParameter = null; var parameters = sigParamTypes.Count == 0 ? Array.Empty() : new DmdParameterInfo[sigParamTypes.Count]; for (int i = 0; i < ridList.Count; i++) { uint rid = ridList[i]; TablesStream.TryReadParamRow(rid, out var row); var name = StringsStream.Read(row.Name); if (row.Sequence == 0) { if (createReturnParameter && returnParameter is null) returnParameter = new DmdParameterDefMD(this, rid, name, (DmdParameterAttributes)row.Flags, method, -1, methodSignature.ReturnType); } else { int paramIndex = row.Sequence - 1; if ((uint)paramIndex < (uint)parameters.Length) { if (parameters[paramIndex] is null) parameters[paramIndex] = new DmdParameterDefMD(this, rid, name, (DmdParameterAttributes)row.Flags, method, paramIndex, sigParamTypes[paramIndex]); } } } for (int i = 0; i < parameters.Length; i++) { if (parameters[i] is null) parameters[i] = new DmdCreatedParameterDef(method, i, sigParamTypes[i]); } if (createReturnParameter && returnParameter is null) returnParameter = new DmdCreatedParameterDef(method, -1, methodSignature.ReturnType); return (returnParameter, parameters); } DmdEventDef CreateResolvedEvent(uint rid, DmdTypeDef? declaringType) { if (declaringType is null) declaringType = ResolveTypeDef(Metadata.GetOwnerTypeOfEvent(rid)) ?? globalTypeIfThereAreNoTypes; else Debug.Assert((object)declaringType == ResolveTypeDef(Metadata.GetOwnerTypeOfEvent(rid))); return CreateEventDefCore(rid, declaringType, declaringType); } internal DmdEventDef CreateEventDef(uint rid, DmdType declaringType, DmdType reflectedType) { if ((object)declaringType == reflectedType && declaringType is DmdTypeDef declaringTypeDef) return ResolveEventDef(rid, declaringTypeDef)!; return CreateEventDefCore(rid, declaringType, reflectedType); } DmdEventDef CreateEventDefCore(uint rid, DmdType declaringType, DmdType reflectedType) => new DmdEventDefMD(this, rid, declaringType, reflectedType); DmdPropertyDef CreateResolvedProperty(uint rid, DmdTypeDef? declaringType) { if (declaringType is null) declaringType = ResolveTypeDef(Metadata.GetOwnerTypeOfProperty(rid)) ?? globalTypeIfThereAreNoTypes; else Debug.Assert((object)declaringType == ResolveTypeDef(Metadata.GetOwnerTypeOfProperty(rid))); return CreatePropertyDefCore(rid, declaringType, declaringType); } internal DmdPropertyDef CreatePropertyDef(uint rid, DmdType declaringType, DmdType reflectedType) { if ((object)declaringType == reflectedType && declaringType is DmdTypeDef declaringTypeDef) return ResolvePropertyDef(rid, declaringTypeDef)!; return CreatePropertyDefCore(rid, declaringType, reflectedType); } DmdPropertyDef CreatePropertyDefCore(uint rid, DmdType declaringType, DmdType reflectedType) => new DmdPropertyDefMD(this, rid, declaringType, reflectedType); internal DmdType[]? CreateGenericParameters(DmdMethodBase method) { var ridList = Metadata.GetGenericParamRidList(Table.Method, (uint)method.MetadataToken & 0x00FFFFFF); if (ridList.Count == 0) return null; var genericParams = new DmdType[ridList.Count]; for (int i = 0; i < genericParams.Length; i++) { uint rid = ridList[i]; TablesStream.TryReadGenericParamRow(rid, out var row); var gpName = StringsStream.ReadNoNull(row.Name); var gpType = new DmdGenericParameterTypeMD(this, rid, method, gpName, row.Number, (DmdGenericParameterAttributes)row.Flags, null); genericParams[i] = gpType; } return genericParams; } (DmdMemberInfo member, bool containedGenericParams) CreateResolvedMemberRef(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) { TablesStream.TryReadMemberRefRow(rid, out var row); var name = StringsStream.ReadNoNull(row.Name); if (!CodedToken.MemberRefParent.Decode(row.Class, out uint classToken)) classToken = uint.MaxValue; var reflectedTypeRef = GetMemberRefParent(classToken, genericTypeArguments, genericMethodArguments); if (reflectedTypeRef is DmdGenericInstanceType || reflectedTypeRef is DmdGenericInstanceTypeRef) genericTypeArguments = reflectedTypeRef.GetGenericArguments(); var info = ReadMethodSignatureOrFieldType(row.Signature, genericTypeArguments, genericMethodArguments); var rawInfo = info.containedGenericParams ? ReadMethodSignatureOrFieldType(row.Signature, null, null) : info; bool containedGenericParams = info.containedGenericParams; if ((classToken >> 24) == 0x1B) containedGenericParams = true; if (info.fieldType is not null) { var fieldRef = new DmdFieldRef(reflectedTypeRef, name, rawInfo.fieldType!, info.fieldType); return (fieldRef, containedGenericParams); } else { Debug2.Assert(info.methodSignature is not null); if (name == DmdConstructorInfo.ConstructorName || name == DmdConstructorInfo.TypeConstructorName) { var ctorRef = new DmdConstructorRef(reflectedTypeRef, name, rawInfo.methodSignature!, info.methodSignature); return (ctorRef, containedGenericParams); } else { var methodRef = new DmdMethodRefMD(this, row.Signature, genericTypeArguments, reflectedTypeRef, name, rawInfo.methodSignature!, info.methodSignature); return (methodRef, containedGenericParams); } } } DmdType GetMemberRefParent(uint classToken, IList? genericTypeArguments, IList? genericMethodArguments) { uint rid = classToken & 0x00FFFFFF; switch ((Table)(classToken >> 24)) { case Table.TypeRef: case Table.TypeDef: case Table.TypeSpec: return ResolveType((int)classToken, genericTypeArguments, genericMethodArguments, DmdResolveOptions.None) ?? Module.AppDomain.System_Void; case Table.ModuleRef: TablesStream.TryReadModuleRefRow(classToken & 0x00FFFFFF, out var moduleRefRow); var moduleName = StringsStream.ReadNoNull(moduleRefRow.Name); if (StringComparer.OrdinalIgnoreCase.Equals(moduleName, Module.ScopeName)) return Module.GlobalType; var referencedModule = Module.Assembly.GetModule(moduleName); return referencedModule?.GlobalType ?? Module.AppDomain.System_Void; case Table.Method: return ResolveMethodDef(rid)?.DeclaringType ?? Module.AppDomain.System_Void; default: return Module.AppDomain.System_Void; } } (DmdType? fieldType, DmdMethodSignature? methodSignature, bool containedGenericParams) ReadMethodSignatureOrFieldType(uint signature, IList? genericTypeArguments, IList? genericMethodArguments) { lock (signatureLock) { if (methodSignatureCache.TryGetValue(signature, out var methodSignature)) { if (methodSignature is not null) return (null, methodSignature, false); var info = ReadMethodSignatureCore(signature, genericTypeArguments, genericMethodArguments, isProperty: false); if (info.methodSignature is null) throw new InvalidOperationException(); Debug.Assert(info.containedGenericParams); return (null, info.methodSignature, info.containedGenericParams); } else if (fieldTypeCache.TryGetValue(signature, out var fieldType)) { if (fieldType is not null) return (fieldType, null, false); var info = ReadFieldTypeCore(signature, genericTypeArguments); if (info.fieldType is null) throw new InvalidOperationException(); Debug.Assert(info.containedGenericParams); return (info.fieldType, null, info.containedGenericParams); } else { var reader = BlobStream.CreateReader(signature); var info = DmdSignatureReader.ReadMethodSignatureOrFieldType(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments, resolveTypes); if (info.fieldType is not null) { if (info.containedGenericParams) fieldTypeCache.Add(signature, null); else fieldTypeCache.Add(signature, info.fieldType); return (info.fieldType, null, info.containedGenericParams); } else { Debug2.Assert(info.methodSignature is not null); if (info.containedGenericParams) methodSignatureCache.Add(signature, null); else methodSignatureCache.Add(signature, info.methodSignature); return (null, info.methodSignature, info.containedGenericParams); } } } } internal DmdMethodBody? GetMethodBody(DmdMethodBase method, IList? genericTypeArguments, IList? genericMethodArguments) { if ((method.MethodImplementationFlags & DmdMethodImplAttributes.CodeTypeMask) != DmdMethodImplAttributes.IL) return null; if (!TablesStream.TryReadMethodRow((uint)method.MetadataToken & 0x00FFFFFF, out var row)) return null; if (row.RVA == 0) return null; var reader = Metadata.PEImage.CreateReader(); reader.Position = (uint)Metadata.PEImage.ToFileOffset((RVA)row.RVA); var body = DmdMethodBodyReader.Create(this, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments); Debug2.Assert(body is not null); return body; } internal uint GetRVA(DmdMethodBase method) { TablesStream.TryReadMethodRow((uint)method.MetadataToken & 0x00FFFFFF, out var row); return row.RVA; } (DmdType type, bool isPinned)[] IMethodBodyResolver.ReadLocals(int localSignatureMetadataToken, IList? genericTypeArguments, IList? genericMethodArguments) { if ((localSignatureMetadataToken & 0x00FFFFFF) == 0 || (localSignatureMetadataToken >> 24) != 0x11) return Array.Empty<(DmdType, bool)>(); uint rid = (uint)localSignatureMetadataToken & 0x00FFFFFF; if (!TablesStream.TryReadStandAloneSigRow(rid, out var row)) return Array.Empty<(DmdType, bool)>(); var reader = BlobStream.CreateReader(row.Signature); return DmdSignatureReader.ReadLocalsSignature(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments, resolveTypes); } public override DmdTypeDef[] GetTypes() { uint typeDefRows = TablesStream.TypeDefTable.Rows; // This should never happen but we must return at least one type if (typeDefRows == 0) return new DmdTypeDef[] { globalTypeIfThereAreNoTypes }; var result = new DmdTypeDef[typeDefRows]; for (int i = 0; i < result.Length; i++) { var type = ResolveTypeDef((uint)i + 1); result[i] = type ?? throw new InvalidOperationException(); } return result; } public override DmdTypeRef[] GetExportedTypes() { if (TablesStream.ExportedTypeTable.Rows == 0) return Array.Empty(); var result = new DmdTypeRef[TablesStream.ExportedTypeTable.Rows]; for (int i = 0; i < result.Length; i++) { var type = ResolveExportedType((uint)i + 1); result[i] = type ?? throw new InvalidOperationException(); } return result; } protected override DmdTypeRef? ResolveTypeRef(uint rid) => typeRefList[rid - 1]; protected override DmdTypeDef? ResolveTypeDef(uint rid) { var type = typeDefList[rid - 1]; if (type is null && rid == 1) return globalTypeIfThereAreNoTypes; return type; } protected override DmdFieldDef? ResolveFieldDef(uint rid) => fieldList[rid - 1, null]; DmdFieldDef? ResolveFieldDef(uint rid, DmdTypeDef declaringType) => fieldList[rid - 1, declaringType]; protected override DmdMethodBase? ResolveMethodDef(uint rid) => methodList[rid - 1, null]; DmdMethodBase? ResolveMethodDef(uint rid, DmdTypeDef declaringType) => methodList[rid - 1, declaringType]; protected override DmdMemberInfo? ResolveMemberRef(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) => memberRefList[rid - 1, genericTypeArguments, genericMethodArguments]; protected override DmdEventDef? ResolveEventDef(uint rid) => eventList[rid - 1, null]; DmdEventDef? ResolveEventDef(uint rid, DmdTypeDef declaringType) => eventList[rid - 1, declaringType]; protected override DmdPropertyDef? ResolvePropertyDef(uint rid) => propertyList[rid - 1, null]; DmdPropertyDef? ResolvePropertyDef(uint rid, DmdTypeDef declaringType) => propertyList[rid - 1, declaringType]; protected override DmdType? ResolveTypeSpec(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) => typeSpecList[rid - 1, genericTypeArguments, genericMethodArguments]; protected override DmdTypeRef? ResolveExportedType(uint rid) => exportedTypeList[rid - 1]; protected override DmdMethodBase? ResolveMethodSpec(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) { if (!TablesStream.TryReadMethodSpecRow(rid, out var row)) return null; DmdType[] instantiation; var reader = BlobStream.CreateReader(row.Instantiation); instantiation = DmdSignatureReader.ReadMethodSpecSignature(module, new DmdDataStreamImpl(ref reader), genericTypeArguments, genericMethodArguments, resolveTypes).types; if (!CodedToken.MethodDefOrRef.Decode(row.Method, out uint token)) return null; var genericMethod = ResolveMethod((int)token, genericTypeArguments, genericMethodArguments, DmdResolveOptions.None) as DmdMethodInfo; if (genericMethod?.IsGenericMethodDefinition != true) return null; return genericMethod.MakeGenericMethod(instantiation); } protected override DmdMethodSignature? ResolveMethodSignature(uint rid, IList? genericTypeArguments, IList? genericMethodArguments) { if (!TablesStream.TryReadStandAloneSigRow(rid, out var row)) return null; return ReadMethodSignature(row.Signature, genericTypeArguments, genericMethodArguments, isProperty: false); } protected override byte[]? ResolveFieldSignature(uint rid) { if (!TablesStream.TryReadFieldRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Signature); } protected override byte[]? ResolveMethodSignature(uint rid) { if (!TablesStream.TryReadMethodRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Signature); } protected override byte[]? ResolveMemberRefSignature(uint rid) { if (!TablesStream.TryReadMemberRefRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Signature); } protected override byte[]? ResolveStandAloneSigSignature(uint rid) { if (!TablesStream.TryReadStandAloneSigRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Signature); } protected override byte[]? ResolveTypeSpecSignature(uint rid) { if (!TablesStream.TryReadTypeSpecRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Signature); } protected override byte[]? ResolveMethodSpecSignature(uint rid) { if (!TablesStream.TryReadMethodSpecRow(rid, out var row)) return null; return Metadata.BlobStream.Read(row.Instantiation); } protected override string ResolveStringCore(uint offset) => Metadata.USStream.Read(offset); public override void GetPEKind(out DmdPortableExecutableKinds peKind, out DmdImageFileMachine machine) { // coreclr: PEDecoder::GetPEKindAndMachine machine = (DmdImageFileMachine)Metadata.PEImage.ImageNTHeaders.FileHeader.Machine; peKind = 0; if (Metadata.PEImage.ImageNTHeaders.OptionalHeader.Magic != 0x010B) peKind |= DmdPortableExecutableKinds.PE32Plus; if ((Metadata.ImageCor20Header.Flags & ComImageFlags.ILOnly) != 0) peKind |= DmdPortableExecutableKinds.ILOnly; // Hack for NGEN'd images if ((Metadata.ImageCor20Header.Flags & ComImageFlags.ILLibrary) != 0) peKind |= DmdPortableExecutableKinds.ILOnly; if ((Metadata.ImageCor20Header.Flags & (ComImageFlags.Bit32Required | ComImageFlags.Bit32Preferred)) == ComImageFlags.Bit32Required) peKind |= DmdPortableExecutableKinds.Required32Bit; else if ((Metadata.ImageCor20Header.Flags & (ComImageFlags.Bit32Required | ComImageFlags.Bit32Preferred)) == (ComImageFlags.Bit32Required | ComImageFlags.Bit32Preferred)) peKind |= DmdPortableExecutableKinds.Preferred32Bit; if (peKind == 0) peKind = DmdPortableExecutableKinds.Required32Bit; } public override DmdReadOnlyAssemblyName GetName() { if (!TablesStream.TryReadAssemblyRow(1, out var row)) return new DmdReadOnlyAssemblyName("no-asm-" + Guid.NewGuid().ToString(), null, null, 0, null, null, 0); var version = new Version(row.MajorVersion, row.MinorVersion, row.BuildNumber, row.RevisionNumber); var name = StringsStream.ReadNoNull(row.Name); var cultureName = StringsStream.ReadNoNull(row.Locale); var hashAlgorithm = (DmdAssemblyHashAlgorithm)row.HashAlgId; var publicKey = BlobStream.ReadNoNull(row.PublicKey); var flags = (DmdAssemblyNameFlags)row.Flags; return new DmdReadOnlyAssemblyName(name, version, cultureName, flags, publicKey, null, hashAlgorithm); } public override DmdReadOnlyAssemblyName[] GetReferencedAssemblies() { var tbl = TablesStream.AssemblyRefTable; if (tbl.Rows == 0) return Array.Empty(); var res = new DmdReadOnlyAssemblyName[tbl.Rows]; for (int i = 0; i < res.Length; i++) res[i] = ReadAssemblyName((uint)i + 1); return res; } internal DmdReadOnlyAssemblyName ReadAssemblyName(uint rid) { TablesStream.TryReadAssemblyRefRow(rid, out var row); var name = Metadata.StringsStream.ReadNoNull(row.Name); var cultureName = Metadata.StringsStream.ReadNoNull(row.Locale); var version = new Version(row.MajorVersion, row.MinorVersion, row.BuildNumber, row.RevisionNumber); byte[]? publicKeyOrToken = null; if (row.PublicKeyOrToken != 0) publicKeyOrToken = Metadata.BlobStream.ReadNoNull(row.PublicKeyOrToken); var flags = (DmdAssemblyNameFlags)row.Flags; return new DmdReadOnlyAssemblyName(name, version, cultureName, flags, publicKeyOrToken, DmdAssemblyHashAlgorithm.None); } public override unsafe bool ReadMemory(uint rva, void* destination, int size) { if (destination is null && size != 0) throw new ArgumentNullException(nameof(destination)); if (size < 0) throw new ArgumentOutOfRangeException(nameof(size)); var reader = Metadata.PEImage.CreateReader((RVA)rva, (uint)size); if (reader.Length < size) return false; reader.ReadBytes(destination, size); return true; } protected override DmdCustomAttributeData[] ReadAssemblyCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Assembly, rid); protected override DmdCustomAttributeData[] ReadModuleCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Module, rid); protected override DmdCustomAttributeData[] ReadTypeDefCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.TypeDef, rid); protected override DmdCustomAttributeData[] ReadFieldCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Field, rid); protected override DmdCustomAttributeData[] ReadMethodCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Method, rid); protected override DmdCustomAttributeData[] ReadParamCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Param, rid); protected override DmdCustomAttributeData[] ReadEventCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Event, rid); protected override DmdCustomAttributeData[] ReadPropertyCustomAttributes(uint rid) => ReadCustomAttributesCore(Table.Property, rid); DmdCustomAttributeData[] ReadCustomAttributesCore(Table table, uint rid) { var ridList = Metadata.GetCustomAttributeRidList(table, rid); if (ridList.Count == 0) return Array.Empty(); var res = new DmdCustomAttributeData[ridList.Count]; int w = 0; for (int i = 0; i < ridList.Count; i++) { if (!TablesStream.TryReadCustomAttributeRow(ridList[i], out var row)) continue; var ctor = ResolveCustomAttributeType(row.Type, null); if (ctor is null) continue; var reader = BlobStream.CreateReader(row.Value); var ca = DmdCustomAttributeReader.Read(module, new DmdDataStreamImpl(ref reader), ctor); if (ca is null) continue; res[w++] = ca; } if (res.Length != w) Array.Resize(ref res, w); return res; } protected override DmdCustomAttributeData[] ReadAssemblySecurityAttributes(uint rid) => ReadSecurityAttributesCore(Table.Assembly, rid); protected override DmdCustomAttributeData[] ReadTypeDefSecurityAttributes(uint rid) => ReadSecurityAttributesCore(Table.TypeDef, rid); protected override DmdCustomAttributeData[] ReadMethodSecurityAttributes(uint rid) => ReadSecurityAttributesCore(Table.Method, rid); #pragma warning disable SYSLIB0003 // SecurityAction DmdCustomAttributeData[] ReadSecurityAttributesCore(Table table, uint rid) { var ridList = Metadata.GetDeclSecurityRidList(table, rid); if (ridList.Count == 0) return Array.Empty(); IList? genericTypeArguments = null; DmdCustomAttributeData[]? firstCas = null; SSP.SecurityAction firstAction = 0; List<(DmdCustomAttributeData[] cas, SSP.SecurityAction action)>? res = null; for (int i = 0; i < ridList.Count; i++) { if (!TablesStream.TryReadDeclSecurityRow(ridList[i], out var row)) continue; var action = (SSP.SecurityAction)(row.Action & 0x1F); var reader = BlobStream.CreateReader(row.PermissionSet); var cas = DmdDeclSecurityReader.Read(module, new DmdDataStreamImpl(ref reader), action, genericTypeArguments); if (cas.Length == 0) continue; if (res is null && firstCas is null) { firstAction = action; firstCas = cas; } else { if (res is null) { res = new List<(DmdCustomAttributeData[], SSP.SecurityAction)>(firstCas!.Length + cas.Length); res.Add((firstCas, firstAction)); firstCas = null; } res.Add((cas, action)); } } if (firstCas is not null) return firstCas; if (res is null) return Array.Empty(); // Reflection sorts it by action res.Sort((a, b) => (int)a.action - (int)b.action); int count = 0; for (int i = 0; i < res.Count; i++) count += res[i].cas.Length; var sas = new DmdCustomAttributeData[count]; int w = 0; for (int i = 0; i < res.Count; i++) { foreach (var ca in res[i].cas) sas[w++] = ca; } if (sas.Length != w) throw new InvalidOperationException(); return sas; } #pragma warning restore SYSLIB0003 // SecurityAction internal DmdMarshalType? ReadMarshalType(int metadataToken, DmdModule module, IList? genericTypeArguments) { if (!TablesStream.TryReadFieldMarshalRow(Metadata.GetFieldMarshalRid((Table)((uint)metadataToken >> 24), (uint)metadataToken & 0x00FFFFFF), out var row)) return null; var reader = BlobStream.CreateReader(row.NativeType); return DmdMarshalBlobReader.Read(module, new DmdDataStreamImpl(ref reader), genericTypeArguments); } DmdConstructorInfo? ResolveCustomAttributeType(uint caType, IList? genericTypeArguments) { if (!CodedToken.CustomAttributeType.Decode(caType, out uint ctorToken)) return null; var method = ResolveMethod((int)ctorToken, genericTypeArguments, null, DmdResolveOptions.None); return (method?.ResolveMemberNoThrow() ?? method) as DmdConstructorInfo; } internal (object? value, bool hasValue) ReadConstant(int metadataToken) { var constantRid = Metadata.GetConstantRid((Table)((uint)metadataToken >> 24), (uint)(metadataToken & 0x00FFFFFF)); if (constantRid == 0) return (null, false); if (!TablesStream.TryReadConstantRow(constantRid, out var row)) return (null, false); var reader = BlobStream.CreateReader(row.Value); return (MetadataConstantUtilities.GetValue((ElementType)row.Type, ref reader), true); } } }