2021-09-20 18:20:01 +02:00

701 lines
33 KiB
C#

/*
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 <http://www.gnu.org/licenses/>.
*/
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<DmdTypeRef> typeRefList;
readonly LazyList<DmdFieldDef, DmdTypeDef?> fieldList;
readonly LazyList<DmdTypeDef> typeDefList;
readonly LazyList<DmdMethodBase, DmdTypeDef?> methodList;
readonly LazyList2<DmdMemberInfo, IList<DmdType>?, IList<DmdType>?> memberRefList;
readonly LazyList<DmdEventDef, DmdTypeDef?> eventList;
readonly LazyList<DmdPropertyDef, DmdTypeDef?> propertyList;
readonly LazyList2<DmdType, IList<DmdType>?, IList<DmdType>?> typeSpecList;
readonly LazyList<DmdTypeRef> exportedTypeList;
readonly DmdNullGlobalType globalTypeIfThereAreNoTypes;
readonly Dictionary<uint, DmdType?> fieldTypeCache;
readonly Dictionary<uint, DmdMethodSignature?> methodSignatureCache;
DmdEcma335MetadataReader(DmdModuleImpl module, dnlib.DotNet.MD.Metadata metadata) {
signatureLock = new object();
this.module = module;
Metadata = metadata;
fieldTypeCache = new Dictionary<uint, DmdType?>();
methodSignatureCache = new Dictionary<uint, DmdMethodSignature?>();
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<DmdTypeRef>(ts.TypeRefTable.Rows, rid => new DmdTypeRefMD(this, rid, null));
fieldList = new LazyList<DmdFieldDef, DmdTypeDef?>(ts.FieldTable.Rows, CreateResolvedField);
typeDefList = new LazyList<DmdTypeDef>(ts.TypeDefTable.Rows, rid => new DmdTypeDefMD(this, rid, null));
methodList = new LazyList<DmdMethodBase, DmdTypeDef?>(ts.MethodTable.Rows, CreateResolvedMethod);
memberRefList = new LazyList2<DmdMemberInfo, IList<DmdType>?, IList<DmdType>?>(ts.MemberRefTable.Rows, CreateResolvedMemberRef);
eventList = new LazyList<DmdEventDef, DmdTypeDef?>(ts.EventTable.Rows, CreateResolvedEvent);
propertyList = new LazyList<DmdPropertyDef, DmdTypeDef?>(ts.PropertyTable.Rows, CreateResolvedProperty);
typeSpecList = new LazyList2<DmdType, IList<DmdType>?, IList<DmdType>?>(ts.TypeSpecTable.Rows, ReadTypeSpec);
exportedTypeList = new LazyList<DmdTypeRef>(ts.ExportedTypeTable.Rows, rid => new DmdExportedTypeMD(this, rid, null));
globalTypeIfThereAreNoTypes = new DmdNullGlobalType(module, null);
}
(DmdType type, bool containedGenericParams) ReadTypeSpec(uint rid, IList<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType> 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<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdParameterInfo>() : 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdTypeRef>();
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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? genericMethodArguments) => typeSpecList[rid - 1, genericTypeArguments, genericMethodArguments];
protected override DmdTypeRef? ResolveExportedType(uint rid) => exportedTypeList[rid - 1];
protected override DmdMethodBase? ResolveMethodSpec(uint rid, IList<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdType>? genericTypeArguments, IList<DmdType>? 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<DmdReadOnlyAssemblyName>();
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<DmdCustomAttributeData>();
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<DmdCustomAttributeData>();
IList<DmdType>? 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<DmdCustomAttributeData>();
// 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<DmdType>? 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<DmdType>? 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);
}
}
}