// // ReflectionReader.cs // // Author: // Jb Evain (jbevain@gmail.com) // // (C) 2005 - 2007 Jb Evain // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // namespace Mono.Cecil { using System; using System.IO; using System.Text; using Mono.Cecil.Binary; using Mono.Cecil.Cil; using Mono.Cecil.Metadata; using Mono.Cecil.Signatures; internal abstract class ReflectionReader : BaseReflectionReader { ModuleDefinition m_module; ImageReader m_reader; SecurityDeclarationReader m_secReader; protected MetadataTableReader m_tableReader; protected MetadataRoot m_root; protected TablesHeap m_tHeap; protected bool m_checkDeleted; protected TypeDefinition [] m_typeDefs; protected TypeReference [] m_typeRefs; protected TypeReference [] m_typeSpecs; protected MethodDefinition [] m_meths; protected FieldDefinition [] m_fields; protected EventDefinition [] m_events; protected PropertyDefinition [] m_properties; protected MemberReference [] m_memberRefs; protected ParameterDefinition [] m_parameters; protected GenericParameter [] m_genericParameters; protected GenericInstanceMethod [] m_methodSpecs; bool m_isCorlib; AssemblyNameReference m_corlib; protected SignatureReader m_sigReader; protected CodeReader m_codeReader; protected ISymbolReader m_symbolReader; internal AssemblyNameReference Corlib { get { if (m_corlib != null) return m_corlib; foreach (AssemblyNameReference ar in m_module.AssemblyReferences) { if (ar.Name == Constants.Corlib) { m_corlib = ar; return m_corlib; } } return null; } } public ModuleDefinition Module { get { return m_module; } } public SignatureReader SigReader { get { return m_sigReader; } } public MetadataTableReader TableReader { get { return m_tableReader; } } public CodeReader Code { get { return m_codeReader; } } public ISymbolReader SymbolReader { get { return m_symbolReader; } set { m_symbolReader = value; } } public MetadataRoot MetadataRoot { get { return m_root; } } public ReflectionReader (ModuleDefinition module) { m_module = module; m_reader = m_module.ImageReader; m_root = m_module.Image.MetadataRoot; m_tHeap = m_root.Streams.TablesHeap; m_checkDeleted = (m_tHeap.HeapSizes & 0x80) != 0; if (m_reader != null) m_tableReader = m_reader.MetadataReader.TableReader; m_codeReader = new CodeReader (this); m_sigReader = new SignatureReader (m_root, this); m_isCorlib = module.Assembly.Name.Name == Constants.Corlib; } public TypeDefinition GetTypeDefAt (uint rid) { if (rid > m_typeDefs.Length) return null; return m_typeDefs [rid - 1]; } public TypeReference GetTypeRefAt (uint rid) { if (rid > m_typeRefs.Length) return null; return m_typeRefs [rid - 1]; } public TypeReference GetTypeSpecAt (uint rid, GenericContext context) { if (rid > m_typeSpecs.Length) return null; int index = (int) rid - 1; TypeSpecTable tsTable = m_tableReader.GetTypeSpecTable (); TypeSpecRow tsRow = tsTable [index]; TypeSpec ts = m_sigReader.GetTypeSpec (tsRow.Signature); // don't cache context dependent generic stuff if (IsGenericTypeSpec (ts.Type.ElementType)) return CreateTypeSpecFromSig (ts, index, context); TypeReference tspec = m_typeSpecs [index]; if (tspec != null) return tspec; tspec = CreateTypeSpecFromSig (ts, index, context); m_typeSpecs [index] = tspec; return tspec; } static bool IsGenericTypeSpec (ElementType etype) { return etype == ElementType.GenericInst || etype == ElementType.Var || etype == ElementType.MVar; } TypeReference CreateTypeSpecFromSig (TypeSpec ts, int index, GenericContext context) { TypeReference tspec = GetTypeRefFromSig (ts.Type, context); tspec = GetModifierType (ts.CustomMods, tspec); tspec.MetadataToken = MetadataToken.FromMetadataRow (TokenType.TypeSpec, index); return tspec; } public FieldDefinition GetFieldDefAt (uint rid) { if (rid > m_fields.Length) return null; return m_fields [rid - 1]; } public MethodDefinition GetMethodDefAt (uint rid) { if (rid > m_meths.Length) return null; return m_meths [rid - 1]; } protected bool IsDeleted (IMemberDefinition member) { if (!m_checkDeleted) return false; if (!member.IsSpecialName || !member.IsRuntimeSpecialName) return false; return member.Name.StartsWith (Constants.Deleted); } public MemberReference GetMemberRefAt (uint rid, GenericContext context) { if (rid > m_memberRefs.Length) return null; int index = (int) rid - 1; MemberReference member = m_memberRefs [index]; if (member != null) return member; MemberRefTable mrTable = m_tableReader.GetMemberRefTable (); MemberRefRow mrefRow = mrTable [index]; Signature sig = m_sigReader.GetMemberRefSig (mrefRow.Class.TokenType, mrefRow.Signature); switch (mrefRow.Class.TokenType) { case TokenType.TypeDef : case TokenType.TypeRef : case TokenType.TypeSpec : TypeReference declaringType = GetTypeDefOrRef (mrefRow.Class, context); GenericContext nc = context.Clone (); if (declaringType is GenericInstanceType) { TypeReference ct = declaringType; while (ct is GenericInstanceType) ct = (ct as GenericInstanceType).ElementType; nc.Type = ct; } if (sig is FieldSig) { FieldSig fs = sig as FieldSig; TypeReference fieldType = GetTypeRefFromSig (fs.Type, nc); fieldType = GetModifierType (fs.CustomMods, fieldType); member = new FieldReference ( m_root.Streams.StringsHeap [mrefRow.Name], declaringType, fieldType); } else { string name = m_root.Streams.StringsHeap [mrefRow.Name]; MethodSig ms = (MethodSig) sig; member = CreateMethodReferenceFromSig (ms, name, declaringType, nc); } break; case TokenType.Method : // really not sure about this MethodDefinition methdef = GetMethodDefAt (mrefRow.Class.RID); member = CreateMethodReferenceFromSig ((MethodSig) sig, methdef.Name, methdef.DeclaringType, new GenericContext ()); break; case TokenType.ModuleRef : break; // TODO, implement that, or not } member.MetadataToken = MetadataToken.FromMetadataRow (TokenType.MemberRef, index); m_module.MemberReferences.Add (member); m_memberRefs [index] = member; return member; } MethodReference CreateMethodReferenceFromSig (MethodSig ms, string name, TypeReference declaringType, GenericContext context) { MethodReference methref = new MethodReference ( name, ms.HasThis, ms.ExplicitThis, ms.MethCallConv); methref.DeclaringType = declaringType; if (ms is MethodDefSig) { int arity = (ms as MethodDefSig).GenericParameterCount; for (int i = 0; i < arity; i++) methref.GenericParameters.Add (new GenericParameter (i, methref)); } if (methref.GenericParameters.Count > 0) context.Method = methref; methref.ReturnType = GetMethodReturnType (ms, context); methref.ReturnType.Method = methref; for (int j = 0; j < ms.ParamCount; j++) { Param p = ms.Parameters [j]; ParameterDefinition pdef = BuildParameterDefinition (j, p, context); pdef.Method = methref; methref.Parameters.Add (pdef); } CreateSentinelIfNeeded (methref, ms); return methref; } public static void CreateSentinelIfNeeded (IMethodSignature meth, MethodSig signature) { MethodDefSig sig = signature as MethodDefSig; if (sig == null) return; int sentinel = sig.Sentinel; if (sig.Sentinel < 0 || sig.Sentinel >= meth.Parameters.Count) return; ParameterDefinition param = meth.Parameters [sentinel]; param.ParameterType = new SentinelType (param.ParameterType); } public PropertyDefinition GetPropertyDefAt (uint rid) { if (rid > m_properties.Length) return null; return m_properties [rid - 1]; } public EventDefinition GetEventDefAt (uint rid) { if (rid > m_events.Length) return null; return m_events [rid - 1]; } public ParameterDefinition GetParamDefAt (uint rid) { if (rid > m_parameters.Length) return null; return m_parameters [rid - 1]; } public GenericParameter GetGenericParameterAt (uint rid) { if (rid > m_genericParameters.Length) return null; return m_genericParameters [rid - 1]; } public GenericInstanceMethod GetMethodSpecAt (uint rid, GenericContext context) { if (rid > m_methodSpecs.Length) return null; int index = (int) rid - 1; GenericInstanceMethod gim = m_methodSpecs [index]; if (gim != null) return gim; MethodSpecTable msTable = m_tableReader.GetMethodSpecTable (); MethodSpecRow msRow = msTable [index]; MethodSpec sig = m_sigReader.GetMethodSpec (msRow.Instantiation); MethodReference meth; if (msRow.Method.TokenType == TokenType.Method) meth = GetMethodDefAt (msRow.Method.RID); else if (msRow.Method.TokenType == TokenType.MemberRef) meth = (MethodReference) GetMemberRefAt (msRow.Method.RID, context); else throw new ReflectionException ("Unknown method type for method spec"); gim = new GenericInstanceMethod (meth); context.CheckProvider (meth, sig.Signature.Arity); foreach (GenericArg arg in sig.Signature.Types) gim.GenericArguments.Add (GetGenericArg (arg, context)); m_methodSpecs [index] = gim; return gim; } public TypeReference GetTypeDefOrRef (MetadataToken token, GenericContext context) { if (token.RID == 0) return null; switch (token.TokenType) { case TokenType.TypeDef : return GetTypeDefAt (token.RID); case TokenType.TypeRef : return GetTypeRefAt (token.RID); case TokenType.TypeSpec : return GetTypeSpecAt (token.RID, context); default : return null; } } public TypeReference SearchCoreType (string fullName) { if (m_isCorlib) return m_module.Types [fullName]; TypeReference coreType = m_module.TypeReferences [fullName]; if (coreType == null) { string [] parts = fullName.Split ('.'); if (parts.Length != 2) throw new ReflectionException ("Unvalid core type name"); coreType = new TypeReference (parts [1], parts [0], Corlib); m_module.TypeReferences.Add (coreType); } if (!coreType.IsValueType) { switch (coreType.FullName) { case Constants.Boolean : case Constants.Char : case Constants.Single : case Constants.Double : case Constants.SByte : case Constants.Byte : case Constants.Int16 : case Constants.UInt16 : case Constants.Int32 : case Constants.UInt32 : case Constants.Int64 : case Constants.UInt64 : case Constants.IntPtr : case Constants.UIntPtr : coreType.IsValueType = true; break; } } return coreType; } public IMetadataTokenProvider LookupByToken (MetadataToken token) { switch (token.TokenType) { case TokenType.TypeDef : return GetTypeDefAt (token.RID); case TokenType.TypeRef : return GetTypeRefAt (token.RID); case TokenType.Method : return GetMethodDefAt (token.RID); case TokenType.Field : return GetFieldDefAt (token.RID); case TokenType.Event : return GetEventDefAt (token.RID); case TokenType.Property : return GetPropertyDefAt (token.RID); case TokenType.Param : return GetParamDefAt (token.RID); default : throw new NotSupportedException ("Lookup is not allowed on this kind of token"); } } public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data, bool resolve) { CustomAttrib sig = m_sigReader.GetCustomAttrib (data, ctor, resolve); return BuildCustomAttribute (ctor, data, sig); } public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data) { return GetCustomAttribute (ctor, data, false); } public override void VisitModuleDefinition (ModuleDefinition mod) { VisitTypeDefinitionCollection (mod.Types); } public override void VisitTypeDefinitionCollection (TypeDefinitionCollection types) { // type def reading TypeDefTable typesTable = m_tableReader.GetTypeDefTable (); m_typeDefs = new TypeDefinition [typesTable.Rows.Count]; for (int i = 0; i < typesTable.Rows.Count; i++) { TypeDefRow type = typesTable [i]; TypeDefinition t = new TypeDefinition ( m_root.Streams.StringsHeap [type.Name], m_root.Streams.StringsHeap [type.Namespace], type.Flags); t.MetadataToken = MetadataToken.FromMetadataRow (TokenType.TypeDef, i); m_typeDefs [i] = t; } // nested types if (m_tHeap.HasTable (NestedClassTable.RId)) { NestedClassTable nested = m_tableReader.GetNestedClassTable (); for (int i = 0; i < nested.Rows.Count; i++) { NestedClassRow row = nested [i]; TypeDefinition parent = GetTypeDefAt (row.EnclosingClass); TypeDefinition child = GetTypeDefAt (row.NestedClass); if (!IsDeleted (child)) parent.NestedTypes.Add (child); } } foreach (TypeDefinition type in m_typeDefs) if (!IsDeleted (type)) types.Add (type); // type ref reading if (m_tHeap.HasTable (TypeRefTable.RId)) { TypeRefTable typesRef = m_tableReader.GetTypeRefTable (); m_typeRefs = new TypeReference [typesRef.Rows.Count]; for (int i = 0; i < typesRef.Rows.Count; i++) AddTypeRef (typesRef, i); } else m_typeRefs = new TypeReference [0]; ReadTypeSpecs (); ReadMethodSpecs (); ReadMethods (); ReadGenericParameters (); // set base types for (int i = 0; i < typesTable.Rows.Count; i++) { TypeDefRow type = typesTable [i]; TypeDefinition child = m_typeDefs [i]; child.BaseType = GetTypeDefOrRef (type.Extends, new GenericContext (child)); } CompleteMethods (); ReadAllFields (); ReadMemberReferences (); } void AddTypeRef (TypeRefTable typesRef, int i) { if (i >= typesRef.Rows.Count) return; // Check if index has been already added. if (m_typeRefs [i] != null) return; TypeRefRow type = typesRef [i]; IMetadataScope scope = null; TypeReference parent = null; if (type.ResolutionScope.RID != 0) { int rid = (int) type.ResolutionScope.RID - 1; switch (type.ResolutionScope.TokenType) { case TokenType.AssemblyRef: scope = m_module.AssemblyReferences [rid]; break; case TokenType.ModuleRef: scope = m_module.ModuleReferences [rid]; break; case TokenType.Module: scope = m_module.Assembly.Modules [rid]; break; case TokenType.TypeRef: AddTypeRef (typesRef, rid); parent = GetTypeRefAt (type.ResolutionScope.RID); if (parent != null) scope = parent.Scope; break; } } TypeReference t = new TypeReference ( m_root.Streams.StringsHeap [type.Name], m_root.Streams.StringsHeap [type.Namespace], scope); t.MetadataToken = MetadataToken.FromMetadataRow (TokenType.TypeRef, i); if (parent != null) t.DeclaringType = parent; m_typeRefs [i] = t; m_module.TypeReferences.Add (t); } void ReadTypeSpecs () { if (!m_tHeap.HasTable (TypeSpecTable.RId)) return; TypeSpecTable tsTable = m_tableReader.GetTypeSpecTable (); m_typeSpecs = new TypeReference [tsTable.Rows.Count]; } void ReadMethodSpecs () { if (!m_tHeap.HasTable (MethodSpecTable.RId)) return; MethodSpecTable msTable = m_tableReader.GetMethodSpecTable (); m_methodSpecs = new GenericInstanceMethod [msTable.Rows.Count]; } void ReadGenericParameters () { if (!m_tHeap.HasTable (GenericParamTable.RId)) return; GenericParamTable gpTable = m_tableReader.GetGenericParamTable (); m_genericParameters = new GenericParameter [gpTable.Rows.Count]; for (int i = 0; i < gpTable.Rows.Count; i++) { GenericParamRow gpRow = gpTable [i]; IGenericParameterProvider owner; if (gpRow.Owner.TokenType == TokenType.Method) owner = GetMethodDefAt (gpRow.Owner.RID); else if (gpRow.Owner.TokenType == TokenType.TypeDef) owner = GetTypeDefAt (gpRow.Owner.RID); else throw new ReflectionException ("Unknown owner type for generic parameter"); GenericParameter gp = new GenericParameter (gpRow.Number, owner); gp.Attributes = gpRow.Flags; gp.Name = MetadataRoot.Streams.StringsHeap [gpRow.Name]; gp.MetadataToken = MetadataToken.FromMetadataRow (TokenType.GenericParam, i); owner.GenericParameters.Add (gp); m_genericParameters [i] = gp; } } void ReadAllFields () { TypeDefTable tdefTable = m_tableReader.GetTypeDefTable (); if (!m_tHeap.HasTable (FieldTable.RId)) { m_fields = new FieldDefinition [0]; return; } FieldTable fldTable = m_tableReader.GetFieldTable (); m_fields = new FieldDefinition [fldTable.Rows.Count]; for (int i = 0; i < m_typeDefs.Length; i++) { TypeDefinition dec = m_typeDefs [i]; GenericContext context = new GenericContext (dec); int index = i, next; if (index == tdefTable.Rows.Count - 1) next = fldTable.Rows.Count + 1; else next = (int) (tdefTable [index + 1]).FieldList; for (int j = (int) tdefTable [index].FieldList; j < next; j++) { FieldRow frow = fldTable [j - 1]; FieldSig fsig = m_sigReader.GetFieldSig (frow.Signature); FieldDefinition fdef = new FieldDefinition ( m_root.Streams.StringsHeap [frow.Name], GetTypeRefFromSig (fsig.Type, context), frow.Flags); fdef.MetadataToken = MetadataToken.FromMetadataRow (TokenType.Field, j - 1); if (fsig.CustomMods.Length > 0) fdef.FieldType = GetModifierType (fsig.CustomMods, fdef.FieldType); if (!IsDeleted (fdef)) dec.Fields.Add (fdef); m_fields [j - 1] = fdef; } } } void ReadMethods () { if (!m_tHeap.HasTable (MethodTable.RId)) { m_meths = new MethodDefinition [0]; return; } MethodTable mTable = m_tableReader.GetMethodTable (); m_meths = new MethodDefinition [mTable.Rows.Count]; for (int i = 0; i < mTable.Rows.Count; i++) { MethodRow mRow = mTable [i]; MethodDefinition meth = new MethodDefinition ( m_root.Streams.StringsHeap [mRow.Name], mRow.Flags); meth.RVA = mRow.RVA; meth.ImplAttributes = mRow.ImplFlags; meth.MetadataToken = MetadataToken.FromMetadataRow (TokenType.Method, i); m_meths [i] = meth; } } void CompleteMethods () { TypeDefTable tdefTable = m_tableReader.GetTypeDefTable (); if (!m_tHeap.HasTable (MethodTable.RId)) { m_meths = new MethodDefinition [0]; return; } MethodTable methTable = m_tableReader.GetMethodTable (); ParamTable paramTable = m_tableReader.GetParamTable (); if (!m_tHeap.HasTable (ParamTable.RId)) m_parameters = new ParameterDefinition [0]; else m_parameters = new ParameterDefinition [paramTable.Rows.Count]; for (int i = 0; i < m_typeDefs.Length; i++) { TypeDefinition dec = m_typeDefs [i]; int index = i, next; if (index == tdefTable.Rows.Count - 1) next = methTable.Rows.Count + 1; else next = (int) (tdefTable [index + 1]).MethodList; for (int j = (int) tdefTable [index].MethodList; j < next; j++) { MethodRow methRow = methTable [j - 1]; MethodDefinition mdef = m_meths [j - 1]; if (!IsDeleted (mdef)) { if (mdef.IsConstructor) dec.Constructors.Add (mdef); else dec.Methods.Add (mdef); } GenericContext context = new GenericContext (mdef); MethodDefSig msig = m_sigReader.GetMethodDefSig (methRow.Signature); mdef.HasThis = msig.HasThis; mdef.ExplicitThis = msig.ExplicitThis; mdef.CallingConvention = msig.MethCallConv; int prms; if (j == methTable.Rows.Count) prms = m_parameters.Length + 1; else prms = (int) (methTable [j]).ParamList; ParameterDefinition retparam = null; //TODO: optimize this int start = (int) methRow.ParamList - 1; if (paramTable != null && start < prms - 1) { ParamRow pRetRow = paramTable [start]; if (pRetRow != null && pRetRow.Sequence == 0) { // ret type retparam = new ParameterDefinition ( m_root.Streams.StringsHeap [pRetRow.Name], 0, pRetRow.Flags, null); retparam.Method = mdef; m_parameters [start] = retparam; start++; } } for (int k = 0; k < msig.ParamCount; k++) { int pointer = start + k; ParamRow pRow = null; if (paramTable != null && pointer < prms - 1) pRow = paramTable [pointer]; Param psig = msig.Parameters [k]; ParameterDefinition pdef; if (pRow != null) { pdef = BuildParameterDefinition ( m_root.Streams.StringsHeap [pRow.Name], pRow.Sequence, pRow.Flags, psig, context); pdef.MetadataToken = MetadataToken.FromMetadataRow (TokenType.Param, pointer); m_parameters [pointer] = pdef; } else pdef = BuildParameterDefinition (k + 1, psig, context); pdef.Method = mdef; mdef.Parameters.Add (pdef); } mdef.ReturnType = GetMethodReturnType (msig, context); MethodReturnType mrt = mdef.ReturnType; mrt.Method = mdef; if (retparam != null) { mrt.Parameter = retparam; mrt.Parameter.ParameterType = mrt.ReturnType; } } } uint eprid = CodeReader.GetRid ((int) m_reader.Image.CLIHeader.EntryPointToken); if (eprid > 0 && eprid <= m_meths.Length) m_module.Assembly.EntryPoint = GetMethodDefAt (eprid); } void ReadMemberReferences () { if (!m_tHeap.HasTable (MemberRefTable.RId)) return; MemberRefTable mrefTable = m_tableReader.GetMemberRefTable (); m_memberRefs = new MemberReference [mrefTable.Rows.Count]; } public override void VisitExternTypeCollection (ExternTypeCollection externs) { ExternTypeCollection ext = externs; if (!m_tHeap.HasTable (ExportedTypeTable.RId)) return; ExportedTypeTable etTable = m_tableReader.GetExportedTypeTable (); TypeReference [] buffer = new TypeReference [etTable.Rows.Count]; for (int i = 0; i < etTable.Rows.Count; i++) { ExportedTypeRow etRow = etTable [i]; buffer [i] = new TypeDefinition ( m_root.Streams.StringsHeap [etRow.TypeName], m_root.Streams.StringsHeap [etRow.TypeNamespace], etRow.Flags); buffer [i].AttachToScope (GetExportedTypeScope (etRow.Implementation)); } for (int i = 0; i < etTable.Rows.Count; i++) { ExportedTypeRow etRow = etTable [i]; if (etRow.Implementation.TokenType != TokenType.ExportedType) continue; TypeReference exported = buffer [i]; TypeReference owner = buffer [etRow.Implementation.RID - 1]; exported.DeclaringType = owner; exported.AttachToScope (owner.Scope); } for (int i = 0; i < buffer.Length; i++) { TypeReference curs = buffer [i]; if (curs != null) ext.Add (curs); } } IMetadataScope GetExportedTypeScope (MetadataToken scope) { int index = (int) scope.RID - 1; switch (scope.TokenType) { case TokenType.AssemblyRef: return Module.AssemblyReferences [index]; case TokenType.File: return Module.ModuleReferences [index]; case TokenType.ExportedType: return null; // resolved later default: throw new NotSupportedException (); } } static object GetFixedArgValue (CustomAttrib.FixedArg fa) { if (fa.SzArray) { object [] vals = new object [fa.NumElem]; for (int j = 0; j < vals.Length; j++) vals [j] = fa.Elems [j].Value; return vals; } else return fa.Elems [0].Value; } TypeReference GetFixedArgType (CustomAttrib.FixedArg fa) { if (fa.SzArray) { if (fa.NumElem == 0) return new ArrayType (SearchCoreType (Constants.Object)); else return new ArrayType (fa.Elems [0].ElemType); } else return fa.Elems [0].ElemType; } TypeReference GetNamedArgType (CustomAttrib.NamedArg na) { if (na.FieldOrPropType == ElementType.Boxed) return SearchCoreType (Constants.Object); return GetFixedArgType (na.FixedArg); } protected CustomAttribute BuildCustomAttribute (MethodReference ctor, byte [] data, CustomAttrib sig) { CustomAttribute cattr = new CustomAttribute (ctor); if (!sig.Read) { cattr.Resolved = false; cattr.Blob = data; return cattr; } foreach (CustomAttrib.FixedArg fa in sig.FixedArgs) cattr.ConstructorParameters.Add (GetFixedArgValue (fa)); foreach (CustomAttrib.NamedArg na in sig.NamedArgs) { object value = GetFixedArgValue (na.FixedArg); if (na.Field) { cattr.Fields [na.FieldOrPropName] = value; cattr.SetFieldType (na.FieldOrPropName, GetNamedArgType (na)); } else if (na.Property) { cattr.Properties [na.FieldOrPropName] = value; cattr.SetPropertyType (na.FieldOrPropName, GetNamedArgType (na)); } else throw new ReflectionException ("Non valid named arg"); } return cattr; } void CompleteParameter (ParameterDefinition parameter, Param signature, GenericContext context) { TypeReference paramType; if (signature.TypedByRef) paramType = SearchCoreType (Constants.TypedReference); else paramType = GetTypeRefFromSig (signature.Type, context); paramType = GetModifierType (signature.CustomMods, paramType); if (signature.ByRef) paramType = new ReferenceType (paramType); parameter.ParameterType = paramType; } public ParameterDefinition BuildParameterDefinition (int sequence, Param psig, GenericContext context) { ParameterDefinition parameter = new ParameterDefinition (null); parameter.Sequence = sequence; CompleteParameter (parameter, psig, context); return parameter; } public ParameterDefinition BuildParameterDefinition (string name, int sequence, ParameterAttributes attrs, Param psig, GenericContext context) { ParameterDefinition parameter = new ParameterDefinition (name, sequence, attrs, null); CompleteParameter (parameter, psig, context); return parameter; } protected SecurityDeclaration BuildSecurityDeclaration (DeclSecurityRow dsRow) { return BuildSecurityDeclaration (dsRow.Action, m_root.Streams.BlobHeap.Read (dsRow.PermissionSet)); } public SecurityDeclaration BuildSecurityDeclaration (SecurityAction action, byte [] permset) { if (m_secReader == null) m_secReader = new SecurityDeclarationReader (m_root, this); return m_secReader.FromByteArray (action, permset); } protected MarshalSpec BuildMarshalDesc (MarshalSig ms, IHasMarshalSpec container) { if (ms.Spec is MarshalSig.Array) { ArrayMarshalSpec amd = new ArrayMarshalSpec (container); MarshalSig.Array ar = (MarshalSig.Array) ms.Spec; amd.ElemType = ar.ArrayElemType; amd.NumElem = ar.NumElem; amd.ParamNum = ar.ParamNum; amd.ElemMult = ar.ElemMult; return amd; } else if (ms.Spec is MarshalSig.CustomMarshaler) { CustomMarshalerSpec cmd = new CustomMarshalerSpec (container); MarshalSig.CustomMarshaler cmsig = (MarshalSig.CustomMarshaler) ms.Spec; cmd.Guid = cmsig.Guid.Length > 0 ? new Guid (cmsig.Guid) : new Guid (); cmd.UnmanagedType = cmsig.UnmanagedType; cmd.ManagedType = cmsig.ManagedType; cmd.Cookie = cmsig.Cookie; return cmd; } else if (ms.Spec is MarshalSig.FixedArray) { FixedArraySpec fad = new FixedArraySpec (container); MarshalSig.FixedArray fasig = (MarshalSig.FixedArray) ms.Spec; fad.ElemType = fasig.ArrayElemType; fad.NumElem = fasig.NumElem; return fad; } else if (ms.Spec is MarshalSig.FixedSysString) { FixedSysStringSpec fssc = new FixedSysStringSpec (container); fssc.Size = ((MarshalSig.FixedSysString) ms.Spec).Size; return fssc; } else if (ms.Spec is MarshalSig.SafeArray) { SafeArraySpec sad = new SafeArraySpec (container); sad.ElemType = ((MarshalSig.SafeArray) ms.Spec).ArrayElemType; return sad; } else { return new MarshalSpec (ms.NativeInstrinsic, container); } } public TypeReference GetModifierType (CustomMod [] cmods, TypeReference type) { if (cmods == null || cmods.Length == 0) return type; TypeReference ret = type; for (int i = cmods.Length - 1; i >= 0; i--) { CustomMod cmod = cmods [i]; TypeReference modType; if (cmod.TypeDefOrRef.RID == 0) continue; if (cmod.TypeDefOrRef.TokenType == TokenType.TypeDef) modType = GetTypeDefAt (cmod.TypeDefOrRef.RID); else modType = GetTypeRefAt (cmod.TypeDefOrRef.RID); if (cmod.CMOD == CustomMod.CMODType.OPT) ret = new ModifierOptional (ret, modType); else if (cmod.CMOD == CustomMod.CMODType.REQD) ret = new ModifierRequired (ret, modType); } return ret; } public MethodReturnType GetMethodReturnType (MethodSig msig, GenericContext context) { TypeReference retType; if (msig.RetType.Void) retType = SearchCoreType (Constants.Void); else if (msig.RetType.TypedByRef) retType = SearchCoreType (Constants.TypedReference); else retType = GetTypeRefFromSig (msig.RetType.Type, context); retType = GetModifierType (msig.RetType.CustomMods, retType); if (msig.RetType.ByRef) retType = new ReferenceType (retType); return new MethodReturnType (retType); } public TypeReference GetTypeRefFromSig (SigType t, GenericContext context) { switch (t.ElementType) { case ElementType.Class : CLASS c = t as CLASS; return GetTypeDefOrRef (c.Type, context); case ElementType.ValueType : VALUETYPE vt = t as VALUETYPE; TypeReference vtr = GetTypeDefOrRef (vt.Type, context); vtr.IsValueType = true; return vtr; case ElementType.String : return SearchCoreType (Constants.String); case ElementType.Object : return SearchCoreType (Constants.Object); case ElementType.Void : return SearchCoreType (Constants.Void); case ElementType.Boolean : return SearchCoreType (Constants.Boolean); case ElementType.Char : return SearchCoreType (Constants.Char); case ElementType.I1 : return SearchCoreType (Constants.SByte); case ElementType.U1 : return SearchCoreType (Constants.Byte); case ElementType.I2 : return SearchCoreType (Constants.Int16); case ElementType.U2 : return SearchCoreType (Constants.UInt16); case ElementType.I4 : return SearchCoreType (Constants.Int32); case ElementType.U4 : return SearchCoreType (Constants.UInt32); case ElementType.I8 : return SearchCoreType (Constants.Int64); case ElementType.U8 : return SearchCoreType (Constants.UInt64); case ElementType.R4 : return SearchCoreType (Constants.Single); case ElementType.R8 : return SearchCoreType (Constants.Double); case ElementType.I : return SearchCoreType (Constants.IntPtr); case ElementType.U : return SearchCoreType (Constants.UIntPtr); case ElementType.TypedByRef : return SearchCoreType (Constants.TypedReference); case ElementType.Array : ARRAY ary = t as ARRAY; return new ArrayType (GetTypeRefFromSig (ary.Type, context), ary.Shape); case ElementType.SzArray : SZARRAY szary = t as SZARRAY; ArrayType at = new ArrayType (GetTypeRefFromSig (szary.Type, context)); return at; case ElementType.Ptr : PTR pointer = t as PTR; if (pointer.Void) return new PointerType (SearchCoreType (Constants.Void)); return new PointerType (GetTypeRefFromSig (pointer.PtrType, context)); case ElementType.FnPtr : FNPTR funcptr = t as FNPTR; FunctionPointerType fnptr = new FunctionPointerType (funcptr.Method.HasThis, funcptr.Method.ExplicitThis, funcptr.Method.MethCallConv, GetMethodReturnType (funcptr.Method, context)); for (int i = 0; i < funcptr.Method.ParamCount; i++) { Param p = funcptr.Method.Parameters [i]; fnptr.Parameters.Add (BuildParameterDefinition (i, p, context)); } CreateSentinelIfNeeded (fnptr, funcptr.Method); return fnptr; case ElementType.Var: VAR var = t as VAR; context.CheckProvider (context.Type, var.Index + 1); if (context.Type is GenericInstanceType) return (context.Type as GenericInstanceType).GenericArguments [var.Index]; else return context.Type.GenericParameters [var.Index]; case ElementType.MVar: MVAR mvar = t as MVAR; context.CheckProvider (context.Method, mvar.Index + 1); if (context.Method is GenericInstanceMethod) return (context.Method as GenericInstanceMethod).GenericArguments [mvar.Index]; else return context.Method.GenericParameters [mvar.Index]; case ElementType.GenericInst: GENERICINST ginst = t as GENERICINST; GenericInstanceType instance = new GenericInstanceType (GetTypeDefOrRef (ginst.Type, context)); instance.IsValueType = ginst.ValueType; context.CheckProvider (instance.GetOriginalType (), ginst.Signature.Arity); for (int i = 0; i < ginst.Signature.Arity; i++) instance.GenericArguments.Add (GetGenericArg ( ginst.Signature.Types [i], context)); return instance; default: break; } return null; } TypeReference GetGenericArg (GenericArg arg, GenericContext context) { TypeReference type = GetTypeRefFromSig (arg.Type, context); type = GetModifierType (arg.CustomMods, type); return type; } static bool IsOdd (int i) { return (i & 1) == 1; } protected object GetConstant (uint pos, ElementType elemType) { if (elemType == ElementType.Class) return null; byte [] constant = m_root.Streams.BlobHeap.Read (pos); if (elemType == ElementType.String) { int length = constant.Length; if (IsOdd (length)) length--; return Encoding.Unicode.GetString (constant, 0, length); } // One byte types can always be read using BitConverter. However it can't be used // elsewhere since it behaves differently in Mono compared to CF on BE architectures switch (elemType) { case ElementType.Boolean : return BitConverter.ToBoolean (constant, 0); case ElementType.I1 : return (sbyte) constant [0]; case ElementType.U1 : return (byte) constant [0]; case ElementType.Object: // illegal, but foundable return null; default : if (BitConverter.IsLittleEndian) return GetConstantLittleEndian (elemType, constant); else return GetConstantBigEndian (elemType, constant); } } static object GetConstantLittleEndian (ElementType elemType, byte [] constant) { switch (elemType) { case ElementType.Char : return BitConverter.ToChar (constant, 0); case ElementType.I2 : return BitConverter.ToInt16 (constant, 0); case ElementType.I4 : return BitConverter.ToInt32 (constant, 0); case ElementType.I8 : return BitConverter.ToInt64 (constant, 0); case ElementType.U2 : return BitConverter.ToUInt16 (constant, 0); case ElementType.U4 : return BitConverter.ToUInt32 (constant, 0); case ElementType.U8 : return BitConverter.ToUInt64 (constant, 0); case ElementType.R4 : return BitConverter.ToSingle (constant, 0); case ElementType.R8 : return BitConverter.ToDouble (constant, 0); default: throw new ReflectionException ("Non valid element in constant table"); } } static object GetConstantBigEndian (ElementType elemType, byte [] constant) { // BinaryReader always read it's data in LE format // note: this could be further optimized (even without unsafe code) BinaryReader br = new BinaryReader (new MemoryStream (constant)); switch (elemType) { case ElementType.Char : return (char) br.ReadUInt16 (); case ElementType.I2 : return br.ReadInt16 (); case ElementType.I4 : return br.ReadInt32 (); case ElementType.I8 : return br.ReadInt64 (); case ElementType.U2 : return br.ReadUInt16 (); case ElementType.U4 : return br.ReadUInt32 (); case ElementType.U8 : return br.ReadUInt64 (); case ElementType.R4 : return br.ReadSingle (); case ElementType.R8 : return br.ReadDouble (); default: throw new ReflectionException ("Non valid element in constant table"); } } protected void SetInitialValue (FieldDefinition field) { int size = 0; TypeReference fieldType = field.FieldType; switch (fieldType.FullName) { case Constants.Boolean: case Constants.Byte: case Constants.SByte: size = 1; break; case Constants.Int16: case Constants.UInt16: case Constants.Char: size = 2; break; case Constants.Int32: case Constants.UInt32: case Constants.Single: size = 4; break; case Constants.Int64: case Constants.UInt64: case Constants.Double: size = 8; break; default: fieldType = fieldType.GetOriginalType (); TypeDefinition fieldTypeDef = fieldType as TypeDefinition; if (fieldTypeDef != null) size = (int) fieldTypeDef.ClassSize; break; } if (size > 0 && field.RVA != RVA.Zero) { byte [] data = new byte [size]; Section sect = m_reader.Image.GetSectionAtVirtualAddress (field.RVA); if (sect != null) Buffer.BlockCopy (sect.Data, (int) (long) (field.RVA - sect.VirtualAddress), data, 0, size); field.InitialValue = data; } else field.InitialValue = new byte [0]; } } }