// // Author: // Jb Evain (jbevain@gmail.com) // // Copyright (c) 2008 - 2015 Jb Evain // Copyright (c) 2008 - 2011 Novell, Inc. // // Licensed under the MIT/X11 license. // using MonoFN.Cecil.Cil; using MonoFN.Cecil.Metadata; using MonoFN.Cecil.PE; using MonoFN.Collections.Generic; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Text; using RVA = System.UInt32; namespace MonoFN.Cecil { abstract class ModuleReader { readonly protected ModuleDefinition module; protected ModuleReader (Image image, ReadingMode mode) { this.module = new ModuleDefinition (image); this.module.ReadingMode = mode; } protected abstract void ReadModule (); public abstract void ReadSymbols (ModuleDefinition module); protected void ReadModuleManifest (MetadataReader reader) { reader.Populate (module); ReadAssembly (reader); } void ReadAssembly (MetadataReader reader) { var name = reader.ReadAssemblyNameDefinition (); if (name == null) { module.kind = ModuleKind.NetModule; return; } var assembly = new AssemblyDefinition (); assembly.Name = name; module.assembly = assembly; assembly.main_module = module; } public static ModuleDefinition CreateModule (Image image, ReaderParameters parameters) { var reader = CreateModuleReader (image, parameters.ReadingMode); var module = reader.module; if (parameters.assembly_resolver != null) module.assembly_resolver = Disposable.NotOwned (parameters.assembly_resolver); if (parameters.metadata_resolver != null) module.metadata_resolver = parameters.metadata_resolver; if (parameters.metadata_importer_provider != null) module.metadata_importer = parameters.metadata_importer_provider.GetMetadataImporter (module); if (parameters.reflection_importer_provider != null) module.reflection_importer = parameters.reflection_importer_provider.GetReflectionImporter (module); GetMetadataKind (module, parameters); reader.ReadModule (); ReadSymbols (module, parameters); reader.ReadSymbols (module); if (parameters.ReadingMode == ReadingMode.Immediate) module.MetadataSystem.Clear (); return module; } static void ReadSymbols (ModuleDefinition module, ReaderParameters parameters) { var symbol_reader_provider = parameters.SymbolReaderProvider; if (symbol_reader_provider == null && parameters.ReadSymbols) symbol_reader_provider = new DefaultSymbolReaderProvider (); if (symbol_reader_provider != null) { module.SymbolReaderProvider = symbol_reader_provider; var reader = parameters.SymbolStream != null ? symbol_reader_provider.GetSymbolReader (module, parameters.SymbolStream) : symbol_reader_provider.GetSymbolReader (module, module.FileName); if (reader != null) { try { module.ReadSymbols (reader, parameters.ThrowIfSymbolsAreNotMatching); } catch (Exception) { reader.Dispose (); throw; } } } if (module.Image.HasDebugTables ()) module.ReadSymbols (new PortablePdbReader (module.Image, module)); } static void GetMetadataKind (ModuleDefinition module, ReaderParameters parameters) { if (!parameters.ApplyWindowsRuntimeProjections) { module.MetadataKind = MetadataKind.Ecma335; return; } var runtime_version = module.RuntimeVersion; if (!runtime_version.Contains ("WindowsRuntime")) module.MetadataKind = MetadataKind.Ecma335; else if (runtime_version.Contains ("CLR")) module.MetadataKind = MetadataKind.ManagedWindowsMetadata; else module.MetadataKind = MetadataKind.WindowsMetadata; } static ModuleReader CreateModuleReader (Image image, ReadingMode mode) { switch (mode) { case ReadingMode.Immediate: return new ImmediateModuleReader (image); case ReadingMode.Deferred: return new DeferredModuleReader (image); default: throw new ArgumentException (); } } } sealed class ImmediateModuleReader : ModuleReader { bool resolve_attributes; public ImmediateModuleReader (Image image) : base (image, ReadingMode.Immediate) { } protected override void ReadModule () { this.module.Read (this.module, (module, reader) => { ReadModuleManifest (reader); ReadModule (module, resolve_attributes: true); }); } public void ReadModule (ModuleDefinition module, bool resolve_attributes) { this.resolve_attributes = resolve_attributes; if (module.HasAssemblyReferences) Mixin.Read (module.AssemblyReferences); if (module.HasResources) Mixin.Read (module.Resources); if (module.HasModuleReferences) Mixin.Read (module.ModuleReferences); if (module.HasTypes) ReadTypes (module.Types); if (module.HasExportedTypes) Mixin.Read (module.ExportedTypes); ReadCustomAttributes (module); var assembly = module.Assembly; if (module.kind == ModuleKind.NetModule || assembly == null) return; ReadCustomAttributes (assembly); ReadSecurityDeclarations (assembly); } void ReadTypes (Collection types) { for (int i = 0; i < types.Count; i++) ReadType (types [i]); } void ReadType (TypeDefinition type) { ReadGenericParameters (type); if (type.HasInterfaces) ReadInterfaces (type); if (type.HasNestedTypes) ReadTypes (type.NestedTypes); if (type.HasLayoutInfo) Mixin.Read (type.ClassSize); if (type.HasFields) ReadFields (type); if (type.HasMethods) ReadMethods (type); if (type.HasProperties) ReadProperties (type); if (type.HasEvents) ReadEvents (type); ReadSecurityDeclarations (type); ReadCustomAttributes (type); } void ReadInterfaces (TypeDefinition type) { var interfaces = type.Interfaces; for (int i = 0; i < interfaces.Count; i++) ReadCustomAttributes (interfaces [i]); } void ReadGenericParameters (IGenericParameterProvider provider) { if (!provider.HasGenericParameters) return; var parameters = provider.GenericParameters; for (int i = 0; i < parameters.Count; i++) { var parameter = parameters [i]; if (parameter.HasConstraints) ReadGenericParameterConstraints (parameter); ReadCustomAttributes (parameter); } } void ReadGenericParameterConstraints (GenericParameter parameter) { var constraints = parameter.Constraints; for (int i = 0; i < constraints.Count; i++) ReadCustomAttributes (constraints [i]); } void ReadSecurityDeclarations (ISecurityDeclarationProvider provider) { if (!provider.HasSecurityDeclarations) return; var security_declarations = provider.SecurityDeclarations; if (!resolve_attributes) return; for (int i = 0; i < security_declarations.Count; i++) { var security_declaration = security_declarations [i]; Mixin.Read (security_declaration.SecurityAttributes); } } void ReadCustomAttributes (ICustomAttributeProvider provider) { if (!provider.HasCustomAttributes) return; var custom_attributes = provider.CustomAttributes; if (!resolve_attributes) return; for (int i = 0; i < custom_attributes.Count; i++) { var custom_attribute = custom_attributes [i]; Mixin.Read (custom_attribute.ConstructorArguments); } } void ReadFields (TypeDefinition type) { var fields = type.Fields; for (int i = 0; i < fields.Count; i++) { var field = fields [i]; if (field.HasConstant) Mixin.Read (field.Constant); if (field.HasLayoutInfo) Mixin.Read (field.Offset); if (field.RVA > 0) Mixin.Read (field.InitialValue); if (field.HasMarshalInfo) Mixin.Read (field.MarshalInfo); ReadCustomAttributes (field); } } void ReadMethods (TypeDefinition type) { var methods = type.Methods; for (int i = 0; i < methods.Count; i++) { var method = methods [i]; ReadGenericParameters (method); if (method.HasParameters) ReadParameters (method); if (method.HasOverrides) Mixin.Read (method.Overrides); if (method.IsPInvokeImpl) Mixin.Read (method.PInvokeInfo); ReadSecurityDeclarations (method); ReadCustomAttributes (method); var return_type = method.MethodReturnType; if (return_type.HasConstant) Mixin.Read (return_type.Constant); if (return_type.HasMarshalInfo) Mixin.Read (return_type.MarshalInfo); ReadCustomAttributes (return_type); } } void ReadParameters (MethodDefinition method) { var parameters = method.Parameters; for (int i = 0; i < parameters.Count; i++) { var parameter = parameters [i]; if (parameter.HasConstant) Mixin.Read (parameter.Constant); if (parameter.HasMarshalInfo) Mixin.Read (parameter.MarshalInfo); ReadCustomAttributes (parameter); } } void ReadProperties (TypeDefinition type) { var properties = type.Properties; for (int i = 0; i < properties.Count; i++) { var property = properties [i]; Mixin.Read (property.GetMethod); if (property.HasConstant) Mixin.Read (property.Constant); ReadCustomAttributes (property); } } void ReadEvents (TypeDefinition type) { var events = type.Events; for (int i = 0; i < events.Count; i++) { var @event = events [i]; Mixin.Read (@event.AddMethod); ReadCustomAttributes (@event); } } public override void ReadSymbols (ModuleDefinition module) { if (module.symbol_reader == null) return; ReadTypesSymbols (module.Types, module.symbol_reader); } void ReadTypesSymbols (Collection types, ISymbolReader symbol_reader) { for (int i = 0; i < types.Count; i++) { var type = types [i]; if (type.HasNestedTypes) ReadTypesSymbols (type.NestedTypes, symbol_reader); if (type.HasMethods) ReadMethodsSymbols (type, symbol_reader); } } void ReadMethodsSymbols (TypeDefinition type, ISymbolReader symbol_reader) { var methods = type.Methods; for (int i = 0; i < methods.Count; i++) { var method = methods [i]; if (method.HasBody && method.token.RID != 0 && method.debug_info == null) method.debug_info = symbol_reader.Read (method); } } } sealed class DeferredModuleReader : ModuleReader { public DeferredModuleReader (Image image) : base (image, ReadingMode.Deferred) { } protected override void ReadModule () { this.module.Read (this.module, (_, reader) => ReadModuleManifest (reader)); } public override void ReadSymbols (ModuleDefinition module) { } } sealed class MetadataReader : ByteBuffer { readonly internal Image image; readonly internal ModuleDefinition module; readonly internal MetadataSystem metadata; internal CodeReader code; internal IGenericContext context; readonly MetadataReader metadata_reader; public MetadataReader (ModuleDefinition module) : base (module.Image.TableHeap.data) { this.image = module.Image; this.module = module; this.metadata = module.MetadataSystem; this.code = new CodeReader (this); } public MetadataReader (Image image, ModuleDefinition module, MetadataReader metadata_reader) : base (image.TableHeap.data) { this.image = image; this.module = module; this.metadata = module.MetadataSystem; this.metadata_reader = metadata_reader; } int GetCodedIndexSize (CodedIndex index) { return image.GetCodedIndexSize (index); } uint ReadByIndexSize (int size) { if (size == 4) return ReadUInt32 (); else return ReadUInt16 (); } byte [] ReadBlob () { var blob_heap = image.BlobHeap; if (blob_heap == null) { position += 2; return Empty.Array; } return blob_heap.Read (ReadBlobIndex ()); } byte [] ReadBlob (uint signature) { var blob_heap = image.BlobHeap; if (blob_heap == null) return Empty.Array; return blob_heap.Read (signature); } uint ReadBlobIndex () { var blob_heap = image.BlobHeap; return ReadByIndexSize (blob_heap != null ? blob_heap.IndexSize : 2); } void GetBlobView (uint signature, out byte [] blob, out int index, out int count) { var blob_heap = image.BlobHeap; if (blob_heap == null) { blob = null; index = count = 0; return; } blob_heap.GetView (signature, out blob, out index, out count); } string ReadString () { return image.StringHeap.Read (ReadByIndexSize (image.StringHeap.IndexSize)); } uint ReadStringIndex () { return ReadByIndexSize (image.StringHeap.IndexSize); } Guid ReadGuid () { return image.GuidHeap.Read (ReadByIndexSize (image.GuidHeap.IndexSize)); } uint ReadTableIndex (Table table) { return ReadByIndexSize (image.GetTableIndexSize (table)); } MetadataToken ReadMetadataToken (CodedIndex index) { return index.GetMetadataToken (ReadByIndexSize (GetCodedIndexSize (index))); } int MoveTo (Table table) { var info = image.TableHeap [table]; if (info.Length != 0) this.position = (int)info.Offset; return (int)info.Length; } bool MoveTo (Table table, uint row) { var info = image.TableHeap [table]; var length = info.Length; if (length == 0 || row > length) return false; this.position = (int)(info.Offset + (info.RowSize * (row - 1))); return true; } public AssemblyNameDefinition ReadAssemblyNameDefinition () { if (MoveTo (Table.Assembly) == 0) return null; var name = new AssemblyNameDefinition (); name.HashAlgorithm = (AssemblyHashAlgorithm)ReadUInt32 (); PopulateVersionAndFlags (name); name.PublicKey = ReadBlob (); PopulateNameAndCulture (name); return name; } public ModuleDefinition Populate (ModuleDefinition module) { if (MoveTo (Table.Module) == 0) return module; Advance (2); // Generation module.Name = ReadString (); module.Mvid = ReadGuid (); return module; } void InitializeAssemblyReferences () { if (metadata.AssemblyReferences != null) return; int length = MoveTo (Table.AssemblyRef); var references = metadata.AssemblyReferences = new AssemblyNameReference [length]; for (uint i = 0; i < length; i++) { var reference = new AssemblyNameReference (); reference.token = new MetadataToken (TokenType.AssemblyRef, i + 1); PopulateVersionAndFlags (reference); var key_or_token = ReadBlob (); if (reference.HasPublicKey) reference.PublicKey = key_or_token; else reference.PublicKeyToken = key_or_token; PopulateNameAndCulture (reference); reference.Hash = ReadBlob (); references [i] = reference; } } public Collection ReadAssemblyReferences () { InitializeAssemblyReferences (); var references = new Collection (metadata.AssemblyReferences); if (module.IsWindowsMetadata ()) module.Projections.AddVirtualReferences (references); return references; } public MethodDefinition ReadEntryPoint () { if (module.Image.EntryPointToken == 0) return null; var token = new MetadataToken (module.Image.EntryPointToken); return GetMethodDefinition (token.RID); } public Collection ReadModules () { var modules = new Collection (1); modules.Add (this.module); int length = MoveTo (Table.File); for (uint i = 1; i <= length; i++) { var attributes = (FileAttributes)ReadUInt32 (); var name = ReadString (); ReadBlobIndex (); if (attributes != FileAttributes.ContainsMetaData) continue; var parameters = new ReaderParameters { ReadingMode = module.ReadingMode, SymbolReaderProvider = module.SymbolReaderProvider, AssemblyResolver = module.AssemblyResolver }; var netmodule = ModuleDefinition.ReadModule (GetModuleFileName (name), parameters); netmodule.assembly = this.module.assembly; modules.Add (netmodule); } return modules; } string GetModuleFileName (string name) { if (module.FileName == null) throw new NotSupportedException (); var path = Path.GetDirectoryName (module.FileName); return Path.Combine (path, name); } void InitializeModuleReferences () { if (metadata.ModuleReferences != null) return; int length = MoveTo (Table.ModuleRef); var references = metadata.ModuleReferences = new ModuleReference [length]; for (uint i = 0; i < length; i++) { var reference = new ModuleReference (ReadString ()); reference.token = new MetadataToken (TokenType.ModuleRef, i + 1); references [i] = reference; } } public Collection ReadModuleReferences () { InitializeModuleReferences (); return new Collection (metadata.ModuleReferences); } public bool HasFileResource () { int length = MoveTo (Table.File); if (length == 0) return false; for (uint i = 1; i <= length; i++) if (ReadFileRecord (i).Col1 == FileAttributes.ContainsNoMetaData) return true; return false; } public Collection ReadResources () { int length = MoveTo (Table.ManifestResource); var resources = new Collection (length); for (int i = 1; i <= length; i++) { var offset = ReadUInt32 (); var flags = (ManifestResourceAttributes)ReadUInt32 (); var name = ReadString (); var implementation = ReadMetadataToken (CodedIndex.Implementation); Resource resource; if (implementation.RID == 0) { resource = new EmbeddedResource (name, flags, offset, this); } else if (implementation.TokenType == TokenType.AssemblyRef) { resource = new AssemblyLinkedResource (name, flags) { Assembly = (AssemblyNameReference)GetTypeReferenceScope (implementation), }; } else if (implementation.TokenType == TokenType.File) { var file_record = ReadFileRecord (implementation.RID); resource = new LinkedResource (name, flags) { File = file_record.Col2, hash = ReadBlob (file_record.Col3) }; } else continue; resources.Add (resource); } return resources; } Row ReadFileRecord (uint rid) { var position = this.position; if (!MoveTo (Table.File, rid)) throw new ArgumentException (); var record = new Row ( (FileAttributes)ReadUInt32 (), ReadString (), ReadBlobIndex ()); this.position = position; return record; } public byte [] GetManagedResource (uint offset) { return image.GetReaderAt (image.Resources.VirtualAddress, offset, (o, reader) => { reader.Advance ((int)o); return reader.ReadBytes (reader.ReadInt32 ()); }) ?? Empty.Array; } void PopulateVersionAndFlags (AssemblyNameReference name) { name.Version = new Version ( ReadUInt16 (), ReadUInt16 (), ReadUInt16 (), ReadUInt16 ()); name.Attributes = (AssemblyAttributes)ReadUInt32 (); } void PopulateNameAndCulture (AssemblyNameReference name) { name.Name = ReadString (); name.Culture = ReadString (); } public TypeDefinitionCollection ReadTypes () { InitializeTypeDefinitions (); var mtypes = metadata.Types; var type_count = mtypes.Length - metadata.NestedTypes.Count; var types = new TypeDefinitionCollection (module, type_count); for (int i = 0; i < mtypes.Length; i++) { var type = mtypes [i]; if (IsNested (type.Attributes)) continue; types.Add (type); } if (image.HasTable (Table.MethodPtr) || image.HasTable (Table.FieldPtr)) CompleteTypes (); return types; } void CompleteTypes () { var types = metadata.Types; for (int i = 0; i < types.Length; i++) { var type = types [i]; Mixin.Read (type.Fields); Mixin.Read (type.Methods); } } void InitializeTypeDefinitions () { if (metadata.Types != null) return; InitializeNestedTypes (); InitializeFields (); InitializeMethods (); int length = MoveTo (Table.TypeDef); var types = metadata.Types = new TypeDefinition [length]; for (uint i = 0; i < length; i++) { if (types [i] != null) continue; types [i] = ReadType (i + 1); } if (module.IsWindowsMetadata ()) { for (uint i = 0; i < length; i++) { WindowsRuntimeProjections.Project (types [i]); } } } static bool IsNested (TypeAttributes attributes) { switch (attributes & TypeAttributes.VisibilityMask) { case TypeAttributes.NestedAssembly: case TypeAttributes.NestedFamANDAssem: case TypeAttributes.NestedFamily: case TypeAttributes.NestedFamORAssem: case TypeAttributes.NestedPrivate: case TypeAttributes.NestedPublic: return true; default: return false; } } public bool HasNestedTypes (TypeDefinition type) { Collection mapping; InitializeNestedTypes (); if (!metadata.TryGetNestedTypeMapping (type, out mapping)) return false; return mapping.Count > 0; } public Collection ReadNestedTypes (TypeDefinition type) { InitializeNestedTypes (); Collection mapping; if (!metadata.TryGetNestedTypeMapping (type, out mapping)) return new MemberDefinitionCollection (type); var nested_types = new MemberDefinitionCollection (type, mapping.Count); for (int i = 0; i < mapping.Count; i++) { var nested_type = GetTypeDefinition (mapping [i]); if (nested_type != null) nested_types.Add (nested_type); } metadata.RemoveNestedTypeMapping (type); return nested_types; } void InitializeNestedTypes () { if (metadata.NestedTypes != null) return; var length = MoveTo (Table.NestedClass); metadata.NestedTypes = new Dictionary> (length); metadata.ReverseNestedTypes = new Dictionary (length); if (length == 0) return; for (int i = 1; i <= length; i++) { var nested = ReadTableIndex (Table.TypeDef); var declaring = ReadTableIndex (Table.TypeDef); AddNestedMapping (declaring, nested); } } void AddNestedMapping (uint declaring, uint nested) { metadata.SetNestedTypeMapping (declaring, AddMapping (metadata.NestedTypes, declaring, nested)); metadata.SetReverseNestedTypeMapping (nested, declaring); } static Collection AddMapping (Dictionary> cache, TKey key, TValue value) { Collection mapped; if (!cache.TryGetValue (key, out mapped)) { mapped = new Collection (); } mapped.Add (value); return mapped; } TypeDefinition ReadType (uint rid) { if (!MoveTo (Table.TypeDef, rid)) return null; var attributes = (TypeAttributes)ReadUInt32 (); var name = ReadString (); var @namespace = ReadString (); var type = new TypeDefinition (@namespace, name, attributes); type.token = new MetadataToken (TokenType.TypeDef, rid); type.scope = module; type.module = module; metadata.AddTypeDefinition (type); this.context = type; type.BaseType = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); type.fields_range = ReadListRange (rid, Table.TypeDef, Table.Field); type.methods_range = ReadListRange (rid, Table.TypeDef, Table.Method); if (IsNested (attributes)) type.DeclaringType = GetNestedTypeDeclaringType (type); return type; } TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type) { uint declaring_rid; if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid)) return null; metadata.RemoveReverseNestedTypeMapping (type); return GetTypeDefinition (declaring_rid); } Range ReadListRange (uint current_index, Table current, Table target) { var list = new Range (); var start = ReadTableIndex (target); if (start == 0) return list; uint next_index; var current_table = image.TableHeap [current]; if (current_index == current_table.Length) next_index = image.TableHeap [target].Length + 1; else { var position = this.position; this.position += (int)(current_table.RowSize - image.GetTableIndexSize (target)); next_index = ReadTableIndex (target); this.position = position; } list.Start = start; list.Length = next_index - start; return list; } public Row ReadTypeLayout (TypeDefinition type) { InitializeTypeLayouts (); Row class_layout; var rid = type.token.RID; if (!metadata.ClassLayouts.TryGetValue (rid, out class_layout)) return new Row (Mixin.NoDataMarker, Mixin.NoDataMarker); type.PackingSize = (short)class_layout.Col1; type.ClassSize = (int)class_layout.Col2; metadata.ClassLayouts.Remove (rid); return new Row ((short)class_layout.Col1, (int)class_layout.Col2); } void InitializeTypeLayouts () { if (metadata.ClassLayouts != null) return; int length = MoveTo (Table.ClassLayout); var class_layouts = metadata.ClassLayouts = new Dictionary> (length); for (uint i = 0; i < length; i++) { var packing_size = ReadUInt16 (); var class_size = ReadUInt32 (); var parent = ReadTableIndex (Table.TypeDef); class_layouts.Add (parent, new Row (packing_size, class_size)); } } public TypeReference GetTypeDefOrRef (MetadataToken token) { return (TypeReference)LookupToken (token); } public TypeDefinition GetTypeDefinition (uint rid) { InitializeTypeDefinitions (); var type = metadata.GetTypeDefinition (rid); if (type != null) return type; type = ReadTypeDefinition (rid); if (module.IsWindowsMetadata ()) WindowsRuntimeProjections.Project (type); return type; } TypeDefinition ReadTypeDefinition (uint rid) { if (!MoveTo (Table.TypeDef, rid)) return null; return ReadType (rid); } void InitializeTypeReferences () { if (metadata.TypeReferences != null) return; metadata.TypeReferences = new TypeReference [image.GetTableLength (Table.TypeRef)]; } public TypeReference GetTypeReference (string scope, string full_name) { InitializeTypeReferences (); var length = metadata.TypeReferences.Length; for (uint i = 1; i <= length; i++) { var type = GetTypeReference (i); if (type.FullName != full_name) continue; if (string.IsNullOrEmpty (scope)) return type; if (type.Scope.Name == scope) return type; } return null; } TypeReference GetTypeReference (uint rid) { InitializeTypeReferences (); var type = metadata.GetTypeReference (rid); if (type != null) return type; return ReadTypeReference (rid); } TypeReference ReadTypeReference (uint rid) { if (!MoveTo (Table.TypeRef, rid)) return null; TypeReference declaring_type = null; IMetadataScope scope; var scope_token = ReadMetadataToken (CodedIndex.ResolutionScope); var name = ReadString (); var @namespace = ReadString (); var type = new TypeReference ( @namespace, name, module, null); type.token = new MetadataToken (TokenType.TypeRef, rid); metadata.AddTypeReference (type); if (scope_token.TokenType == TokenType.TypeRef) { if (scope_token.RID != rid) { declaring_type = GetTypeDefOrRef (scope_token); scope = declaring_type != null ? declaring_type.Scope : module; } else // obfuscated typeref row pointing to self scope = module; } else scope = GetTypeReferenceScope (scope_token); type.scope = scope; type.DeclaringType = declaring_type; MetadataSystem.TryProcessPrimitiveTypeReference (type); if (type.Module.IsWindowsMetadata ()) WindowsRuntimeProjections.Project (type); return type; } IMetadataScope GetTypeReferenceScope (MetadataToken scope) { if (scope.TokenType == TokenType.Module) return module; IMetadataScope [] scopes; switch (scope.TokenType) { case TokenType.AssemblyRef: InitializeAssemblyReferences (); scopes = metadata.AssemblyReferences; break; case TokenType.ModuleRef: InitializeModuleReferences (); scopes = metadata.ModuleReferences; break; default: throw new NotSupportedException (); } var index = scope.RID - 1; if (index < 0 || index >= scopes.Length) return null; return scopes [index]; } public IEnumerable GetTypeReferences () { InitializeTypeReferences (); var length = image.GetTableLength (Table.TypeRef); var type_references = new TypeReference [length]; for (uint i = 1; i <= length; i++) type_references [i - 1] = GetTypeReference (i); return type_references; } TypeReference GetTypeSpecification (uint rid) { if (!MoveTo (Table.TypeSpec, rid)) return null; var reader = ReadSignature (ReadBlobIndex ()); var type = reader.ReadTypeSignature (); if (type.token.RID == 0) type.token = new MetadataToken (TokenType.TypeSpec, rid); return type; } SignatureReader ReadSignature (uint signature) { return new SignatureReader (signature, this); } public bool HasInterfaces (TypeDefinition type) { InitializeInterfaces (); Collection> mapping; return metadata.TryGetInterfaceMapping (type, out mapping); } public InterfaceImplementationCollection ReadInterfaces (TypeDefinition type) { InitializeInterfaces (); Collection> mapping; if (!metadata.TryGetInterfaceMapping (type, out mapping)) return new InterfaceImplementationCollection (type); var interfaces = new InterfaceImplementationCollection (type, mapping.Count); this.context = type; for (int i = 0; i < mapping.Count; i++) { interfaces.Add ( new InterfaceImplementation ( GetTypeDefOrRef (mapping [i].Col2), new MetadataToken (TokenType.InterfaceImpl, mapping [i].Col1))); } metadata.RemoveInterfaceMapping (type); return interfaces; } void InitializeInterfaces () { if (metadata.Interfaces != null) return; int length = MoveTo (Table.InterfaceImpl); metadata.Interfaces = new Dictionary>> (length); for (uint i = 1; i <= length; i++) { var type = ReadTableIndex (Table.TypeDef); var @interface = ReadMetadataToken (CodedIndex.TypeDefOrRef); AddInterfaceMapping (type, new Row (i, @interface)); } } void AddInterfaceMapping (uint type, Row @interface) { metadata.SetInterfaceMapping (type, AddMapping (metadata.Interfaces, type, @interface)); } public Collection ReadFields (TypeDefinition type) { var fields_range = type.fields_range; if (fields_range.Length == 0) return new MemberDefinitionCollection (type); var fields = new MemberDefinitionCollection (type, (int)fields_range.Length); this.context = type; if (!MoveTo (Table.FieldPtr, fields_range.Start)) { if (!MoveTo (Table.Field, fields_range.Start)) return fields; for (uint i = 0; i < fields_range.Length; i++) ReadField (fields_range.Start + i, fields); } else ReadPointers (Table.FieldPtr, Table.Field, fields_range, fields, ReadField); return fields; } void ReadField (uint field_rid, Collection fields) { var attributes = (FieldAttributes)ReadUInt16 (); var name = ReadString (); var signature = ReadBlobIndex (); var field = new FieldDefinition (name, attributes, ReadFieldType (signature)); field.token = new MetadataToken (TokenType.Field, field_rid); metadata.AddFieldDefinition (field); if (IsDeleted (field)) return; fields.Add (field); if (module.IsWindowsMetadata ()) WindowsRuntimeProjections.Project (field); } void InitializeFields () { if (metadata.Fields != null) return; metadata.Fields = new FieldDefinition [image.GetTableLength (Table.Field)]; } TypeReference ReadFieldType (uint signature) { var reader = ReadSignature (signature); const byte field_sig = 0x6; if (reader.ReadByte () != field_sig) throw new NotSupportedException (); return reader.ReadTypeSignature (); } public int ReadFieldRVA (FieldDefinition field) { InitializeFieldRVAs (); var rid = field.token.RID; RVA rva; if (!metadata.FieldRVAs.TryGetValue (rid, out rva)) return 0; var size = GetFieldTypeSize (field.FieldType); if (size == 0 || rva == 0) return 0; metadata.FieldRVAs.Remove (rid); field.InitialValue = GetFieldInitializeValue (size, rva); return (int)rva; } byte [] GetFieldInitializeValue (int size, RVA rva) { return image.GetReaderAt (rva, size, (s, reader) => reader.ReadBytes (s)) ?? Empty.Array; } static int GetFieldTypeSize (TypeReference type) { int size = 0; switch (type.etype) { case ElementType.Boolean: case ElementType.U1: case ElementType.I1: size = 1; break; case ElementType.U2: case ElementType.I2: case ElementType.Char: size = 2; break; case ElementType.U4: case ElementType.I4: case ElementType.R4: size = 4; break; case ElementType.U8: case ElementType.I8: case ElementType.R8: size = 8; break; case ElementType.Ptr: case ElementType.FnPtr: size = IntPtr.Size; break; case ElementType.CModOpt: case ElementType.CModReqD: return GetFieldTypeSize (((IModifierType)type).ElementType); default: var field_type = type.Resolve (); if (field_type != null && field_type.HasLayoutInfo) size = field_type.ClassSize; break; } return size; } void InitializeFieldRVAs () { if (metadata.FieldRVAs != null) return; int length = MoveTo (Table.FieldRVA); var field_rvas = metadata.FieldRVAs = new Dictionary (length); for (int i = 0; i < length; i++) { var rva = ReadUInt32 (); var field = ReadTableIndex (Table.Field); field_rvas.Add (field, rva); } } public int ReadFieldLayout (FieldDefinition field) { InitializeFieldLayouts (); var rid = field.token.RID; uint offset; if (!metadata.FieldLayouts.TryGetValue (rid, out offset)) return Mixin.NoDataMarker; metadata.FieldLayouts.Remove (rid); return (int)offset; } void InitializeFieldLayouts () { if (metadata.FieldLayouts != null) return; int length = MoveTo (Table.FieldLayout); var field_layouts = metadata.FieldLayouts = new Dictionary (length); for (int i = 0; i < length; i++) { var offset = ReadUInt32 (); var field = ReadTableIndex (Table.Field); field_layouts.Add (field, offset); } } public bool HasEvents (TypeDefinition type) { InitializeEvents (); Range range; if (!metadata.TryGetEventsRange (type, out range)) return false; return range.Length > 0; } public Collection ReadEvents (TypeDefinition type) { InitializeEvents (); Range range; if (!metadata.TryGetEventsRange (type, out range)) return new MemberDefinitionCollection (type); var events = new MemberDefinitionCollection (type, (int)range.Length); metadata.RemoveEventsRange (type); if (range.Length == 0) return events; this.context = type; if (!MoveTo (Table.EventPtr, range.Start)) { if (!MoveTo (Table.Event, range.Start)) return events; for (uint i = 0; i < range.Length; i++) ReadEvent (range.Start + i, events); } else ReadPointers (Table.EventPtr, Table.Event, range, events, ReadEvent); return events; } void ReadEvent (uint event_rid, Collection events) { var attributes = (EventAttributes)ReadUInt16 (); var name = ReadString (); var event_type = GetTypeDefOrRef (ReadMetadataToken (CodedIndex.TypeDefOrRef)); var @event = new EventDefinition (name, attributes, event_type); @event.token = new MetadataToken (TokenType.Event, event_rid); if (IsDeleted (@event)) return; events.Add (@event); } void InitializeEvents () { if (metadata.Events != null) return; int length = MoveTo (Table.EventMap); metadata.Events = new Dictionary (length); for (uint i = 1; i <= length; i++) { var type_rid = ReadTableIndex (Table.TypeDef); Range events_range = ReadListRange (i, Table.EventMap, Table.Event); metadata.AddEventsRange (type_rid, events_range); } } public bool HasProperties (TypeDefinition type) { InitializeProperties (); Range range; if (!metadata.TryGetPropertiesRange (type, out range)) return false; return range.Length > 0; } public Collection ReadProperties (TypeDefinition type) { InitializeProperties (); Range range; if (!metadata.TryGetPropertiesRange (type, out range)) return new MemberDefinitionCollection (type); metadata.RemovePropertiesRange (type); var properties = new MemberDefinitionCollection (type, (int)range.Length); if (range.Length == 0) return properties; this.context = type; if (!MoveTo (Table.PropertyPtr, range.Start)) { if (!MoveTo (Table.Property, range.Start)) return properties; for (uint i = 0; i < range.Length; i++) ReadProperty (range.Start + i, properties); } else ReadPointers (Table.PropertyPtr, Table.Property, range, properties, ReadProperty); return properties; } void ReadProperty (uint property_rid, Collection properties) { var attributes = (PropertyAttributes)ReadUInt16 (); var name = ReadString (); var signature = ReadBlobIndex (); var reader = ReadSignature (signature); const byte property_signature = 0x8; var calling_convention = reader.ReadByte (); if ((calling_convention & property_signature) == 0) throw new NotSupportedException (); var has_this = (calling_convention & 0x20) != 0; reader.ReadCompressedUInt32 (); // count var property = new PropertyDefinition (name, attributes, reader.ReadTypeSignature ()); property.HasThis = has_this; property.token = new MetadataToken (TokenType.Property, property_rid); if (IsDeleted (property)) return; properties.Add (property); } void InitializeProperties () { if (metadata.Properties != null) return; int length = MoveTo (Table.PropertyMap); metadata.Properties = new Dictionary (length); for (uint i = 1; i <= length; i++) { var type_rid = ReadTableIndex (Table.TypeDef); var properties_range = ReadListRange (i, Table.PropertyMap, Table.Property); metadata.AddPropertiesRange (type_rid, properties_range); } } MethodSemanticsAttributes ReadMethodSemantics (MethodDefinition method) { InitializeMethodSemantics (); Row row; if (!metadata.Semantics.TryGetValue (method.token.RID, out row)) return MethodSemanticsAttributes.None; var type = method.DeclaringType; switch (row.Col1) { case MethodSemanticsAttributes.AddOn: GetEvent (type, row.Col2).add_method = method; break; case MethodSemanticsAttributes.Fire: GetEvent (type, row.Col2).invoke_method = method; break; case MethodSemanticsAttributes.RemoveOn: GetEvent (type, row.Col2).remove_method = method; break; case MethodSemanticsAttributes.Getter: GetProperty (type, row.Col2).get_method = method; break; case MethodSemanticsAttributes.Setter: GetProperty (type, row.Col2).set_method = method; break; case MethodSemanticsAttributes.Other: switch (row.Col2.TokenType) { case TokenType.Event: { var @event = GetEvent (type, row.Col2); if (@event.other_methods == null) @event.other_methods = new Collection (); @event.other_methods.Add (method); break; } case TokenType.Property: { var property = GetProperty (type, row.Col2); if (property.other_methods == null) property.other_methods = new Collection (); property.other_methods.Add (method); break; } default: throw new NotSupportedException (); } break; default: throw new NotSupportedException (); } metadata.Semantics.Remove (method.token.RID); return row.Col1; } static EventDefinition GetEvent (TypeDefinition type, MetadataToken token) { if (token.TokenType != TokenType.Event) throw new ArgumentException (); return GetMember (type.Events, token); } static PropertyDefinition GetProperty (TypeDefinition type, MetadataToken token) { if (token.TokenType != TokenType.Property) throw new ArgumentException (); return GetMember (type.Properties, token); } static TMember GetMember (Collection members, MetadataToken token) where TMember : IMemberDefinition { for (int i = 0; i < members.Count; i++) { var member = members [i]; if (member.MetadataToken == token) return member; } throw new ArgumentException (); } void InitializeMethodSemantics () { if (metadata.Semantics != null) return; int length = MoveTo (Table.MethodSemantics); var semantics = metadata.Semantics = new Dictionary> (0); for (uint i = 0; i < length; i++) { var attributes = (MethodSemanticsAttributes)ReadUInt16 (); var method_rid = ReadTableIndex (Table.Method); var association = ReadMetadataToken (CodedIndex.HasSemantics); semantics [method_rid] = new Row (attributes, association); } } public void ReadMethods (PropertyDefinition property) { ReadAllSemantics (property.DeclaringType); } public void ReadMethods (EventDefinition @event) { ReadAllSemantics (@event.DeclaringType); } public void ReadAllSemantics (MethodDefinition method) { ReadAllSemantics (method.DeclaringType); } void ReadAllSemantics (TypeDefinition type) { var methods = type.Methods; for (int i = 0; i < methods.Count; i++) { var method = methods [i]; if (method.sem_attrs_ready) continue; method.sem_attrs = ReadMethodSemantics (method); method.sem_attrs_ready = true; } } public Collection ReadMethods (TypeDefinition type) { var methods_range = type.methods_range; if (methods_range.Length == 0) return new MemberDefinitionCollection (type); var methods = new MemberDefinitionCollection (type, (int)methods_range.Length); if (!MoveTo (Table.MethodPtr, methods_range.Start)) { if (!MoveTo (Table.Method, methods_range.Start)) return methods; for (uint i = 0; i < methods_range.Length; i++) ReadMethod (methods_range.Start + i, methods); } else ReadPointers (Table.MethodPtr, Table.Method, methods_range, methods, ReadMethod); return methods; } void ReadPointers (Table ptr, Table table, Range range, Collection members, Action> reader) where TMember : IMemberDefinition { for (uint i = 0; i < range.Length; i++) { MoveTo (ptr, range.Start + i); var rid = ReadTableIndex (table); MoveTo (table, rid); reader (rid, members); } } static bool IsDeleted (IMemberDefinition member) { return member.IsSpecialName && member.Name == "_Deleted"; } void InitializeMethods () { if (metadata.Methods != null) return; metadata.Methods = new MethodDefinition [image.GetTableLength (Table.Method)]; } void ReadMethod (uint method_rid, Collection methods) { var method = new MethodDefinition (); method.rva = ReadUInt32 (); method.ImplAttributes = (MethodImplAttributes)ReadUInt16 (); method.Attributes = (MethodAttributes)ReadUInt16 (); method.Name = ReadString (); method.token = new MetadataToken (TokenType.Method, method_rid); if (IsDeleted (method)) return; methods.Add (method); // attach method var signature = ReadBlobIndex (); var param_range = ReadListRange (method_rid, Table.Method, Table.Param); this.context = method; ReadMethodSignature (signature, method); metadata.AddMethodDefinition (method); if (param_range.Length != 0) { var position = base.position; ReadParameters (method, param_range); base.position = position; } if (module.IsWindowsMetadata ()) WindowsRuntimeProjections.Project (method); } void ReadParameters (MethodDefinition method, Range param_range) { if (!MoveTo (Table.ParamPtr, param_range.Start)) { if (!MoveTo (Table.Param, param_range.Start)) return; for (uint i = 0; i < param_range.Length; i++) ReadParameter (param_range.Start + i, method); } else ReadParameterPointers (method, param_range); } void ReadParameterPointers (MethodDefinition method, Range range) { for (uint i = 0; i < range.Length; i++) { MoveTo (Table.ParamPtr, range.Start + i); var rid = ReadTableIndex (Table.Param); MoveTo (Table.Param, rid); ReadParameter (rid, method); } } void ReadParameter (uint param_rid, MethodDefinition method) { var attributes = (ParameterAttributes)ReadUInt16 (); var sequence = ReadUInt16 (); var name = ReadString (); var parameter = sequence == 0 ? method.MethodReturnType.Parameter : method.Parameters [sequence - 1]; parameter.token = new MetadataToken (TokenType.Param, param_rid); parameter.Name = name; parameter.Attributes = attributes; } void ReadMethodSignature (uint signature, IMethodSignature method) { var reader = ReadSignature (signature); reader.ReadMethodSignature (method); } public PInvokeInfo ReadPInvokeInfo (MethodDefinition method) { InitializePInvokes (); Row row; var rid = method.token.RID; if (!metadata.PInvokes.TryGetValue (rid, out row)) return null; metadata.PInvokes.Remove (rid); return new PInvokeInfo ( row.Col1, image.StringHeap.Read (row.Col2), module.ModuleReferences [(int)row.Col3 - 1]); } void InitializePInvokes () { if (metadata.PInvokes != null) return; int length = MoveTo (Table.ImplMap); var pinvokes = metadata.PInvokes = new Dictionary> (length); for (int i = 1; i <= length; i++) { var attributes = (PInvokeAttributes)ReadUInt16 (); var method = ReadMetadataToken (CodedIndex.MemberForwarded); var name = ReadStringIndex (); var scope = ReadTableIndex (Table.File); if (method.TokenType != TokenType.Method) continue; pinvokes.Add (method.RID, new Row (attributes, name, scope)); } } public bool HasGenericParameters (IGenericParameterProvider provider) { InitializeGenericParameters (); Range [] ranges; if (!metadata.TryGetGenericParameterRanges (provider, out ranges)) return false; return RangesSize (ranges) > 0; } public Collection ReadGenericParameters (IGenericParameterProvider provider) { InitializeGenericParameters (); Range [] ranges; if (!metadata.TryGetGenericParameterRanges (provider, out ranges)) return new GenericParameterCollection (provider); metadata.RemoveGenericParameterRange (provider); var generic_parameters = new GenericParameterCollection (provider, RangesSize (ranges)); for (int i = 0; i < ranges.Length; i++) ReadGenericParametersRange (ranges [i], provider, generic_parameters); return generic_parameters; } void ReadGenericParametersRange (Range range, IGenericParameterProvider provider, GenericParameterCollection generic_parameters) { if (!MoveTo (Table.GenericParam, range.Start)) return; for (uint i = 0; i < range.Length; i++) { ReadUInt16 (); // index var flags = (GenericParameterAttributes)ReadUInt16 (); ReadMetadataToken (CodedIndex.TypeOrMethodDef); var name = ReadString (); var parameter = new GenericParameter (name, provider); parameter.token = new MetadataToken (TokenType.GenericParam, range.Start + i); parameter.Attributes = flags; generic_parameters.Add (parameter); } } void InitializeGenericParameters () { if (metadata.GenericParameters != null) return; metadata.GenericParameters = InitializeRanges ( Table.GenericParam, () => { Advance (4); var next = ReadMetadataToken (CodedIndex.TypeOrMethodDef); ReadStringIndex (); return next; }); } Dictionary InitializeRanges (Table table, Func get_next) { int length = MoveTo (table); var ranges = new Dictionary (length); if (length == 0) return ranges; MetadataToken owner = MetadataToken.Zero; Range range = new Range (1, 0); for (uint i = 1; i <= length; i++) { var next = get_next (); if (i == 1) { owner = next; range.Length++; } else if (next != owner) { AddRange (ranges, owner, range); range = new Range (i, 1); owner = next; } else range.Length++; } AddRange (ranges, owner, range); return ranges; } static void AddRange (Dictionary ranges, MetadataToken owner, Range range) { if (owner.RID == 0) return; Range [] slots; if (!ranges.TryGetValue (owner, out slots)) { ranges.Add (owner, new [] { range }); return; } ranges [owner] = slots.Add (range); } public bool HasGenericConstraints (GenericParameter generic_parameter) { InitializeGenericConstraints (); Collection> mapping; if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) return false; return mapping.Count > 0; } public GenericParameterConstraintCollection ReadGenericConstraints (GenericParameter generic_parameter) { InitializeGenericConstraints (); Collection> mapping; if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping)) return new GenericParameterConstraintCollection (generic_parameter); var constraints = new GenericParameterConstraintCollection (generic_parameter, mapping.Count); this.context = (IGenericContext)generic_parameter.Owner; for (int i = 0; i < mapping.Count; i++) { constraints.Add ( new GenericParameterConstraint ( GetTypeDefOrRef (mapping [i].Col2), new MetadataToken (TokenType.GenericParamConstraint, mapping [i].Col1))); } metadata.RemoveGenericConstraintMapping (generic_parameter); return constraints; } void InitializeGenericConstraints () { if (metadata.GenericConstraints != null) return; var length = MoveTo (Table.GenericParamConstraint); metadata.GenericConstraints = new Dictionary>> (length); for (uint i = 1; i <= length; i++) { AddGenericConstraintMapping ( ReadTableIndex (Table.GenericParam), new Row (i, ReadMetadataToken (CodedIndex.TypeDefOrRef))); } } void AddGenericConstraintMapping (uint generic_parameter, Row constraint) { metadata.SetGenericConstraintMapping ( generic_parameter, AddMapping (metadata.GenericConstraints, generic_parameter, constraint)); } public bool HasOverrides (MethodDefinition method) { InitializeOverrides (); Collection mapping; if (!metadata.TryGetOverrideMapping (method, out mapping)) return false; return mapping.Count > 0; } public Collection ReadOverrides (MethodDefinition method) { InitializeOverrides (); Collection mapping; if (!metadata.TryGetOverrideMapping (method, out mapping)) return new Collection (); var overrides = new Collection (mapping.Count); this.context = method; for (int i = 0; i < mapping.Count; i++) overrides.Add ((MethodReference)LookupToken (mapping [i])); metadata.RemoveOverrideMapping (method); return overrides; } void InitializeOverrides () { if (metadata.Overrides != null) return; var length = MoveTo (Table.MethodImpl); metadata.Overrides = new Dictionary> (length); for (int i = 1; i <= length; i++) { ReadTableIndex (Table.TypeDef); var method = ReadMetadataToken (CodedIndex.MethodDefOrRef); if (method.TokenType != TokenType.Method) throw new NotSupportedException (); var @override = ReadMetadataToken (CodedIndex.MethodDefOrRef); AddOverrideMapping (method.RID, @override); } } void AddOverrideMapping (uint method_rid, MetadataToken @override) { metadata.SetOverrideMapping ( method_rid, AddMapping (metadata.Overrides, method_rid, @override)); } public MethodBody ReadMethodBody (MethodDefinition method) { return code.ReadMethodBody (method); } public int ReadCodeSize (MethodDefinition method) { return code.ReadCodeSize (method); } public CallSite ReadCallSite (MetadataToken token) { if (!MoveTo (Table.StandAloneSig, token.RID)) return null; var signature = ReadBlobIndex (); var call_site = new CallSite (); ReadMethodSignature (signature, call_site); call_site.MetadataToken = token; return call_site; } public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token, MethodDefinition method = null) { if (!MoveTo (Table.StandAloneSig, local_var_token.RID)) return null; var reader = ReadSignature (ReadBlobIndex ()); const byte local_sig = 0x7; if (reader.ReadByte () != local_sig) throw new NotSupportedException (); var count = reader.ReadCompressedUInt32 (); if (count == 0) return null; var variables = new VariableDefinitionCollection (method, (int)count); for (int i = 0; i < count; i++) variables.Add (new VariableDefinition (reader.ReadTypeSignature ())); return variables; } public IMetadataTokenProvider LookupToken (MetadataToken token) { var rid = token.RID; if (rid == 0) return null; if (metadata_reader != null) return metadata_reader.LookupToken (token); IMetadataTokenProvider element; var position = this.position; var context = this.context; switch (token.TokenType) { case TokenType.TypeDef: element = GetTypeDefinition (rid); break; case TokenType.TypeRef: element = GetTypeReference (rid); break; case TokenType.TypeSpec: element = GetTypeSpecification (rid); break; case TokenType.Field: element = GetFieldDefinition (rid); break; case TokenType.Method: element = GetMethodDefinition (rid); break; case TokenType.MemberRef: element = GetMemberReference (rid); break; case TokenType.MethodSpec: element = GetMethodSpecification (rid); break; default: return null; } this.position = position; this.context = context; return element; } public FieldDefinition GetFieldDefinition (uint rid) { InitializeTypeDefinitions (); var field = metadata.GetFieldDefinition (rid); if (field != null) return field; return LookupField (rid); } FieldDefinition LookupField (uint rid) { var type = metadata.GetFieldDeclaringType (rid); if (type == null) return null; Mixin.Read (type.Fields); return metadata.GetFieldDefinition (rid); } public MethodDefinition GetMethodDefinition (uint rid) { InitializeTypeDefinitions (); var method = metadata.GetMethodDefinition (rid); if (method != null) return method; return LookupMethod (rid); } MethodDefinition LookupMethod (uint rid) { var type = metadata.GetMethodDeclaringType (rid); if (type == null) return null; Mixin.Read (type.Methods); return metadata.GetMethodDefinition (rid); } MethodSpecification GetMethodSpecification (uint rid) { if (!MoveTo (Table.MethodSpec, rid)) return null; var element_method = (MethodReference)LookupToken ( ReadMetadataToken (CodedIndex.MethodDefOrRef)); var signature = ReadBlobIndex (); var method_spec = ReadMethodSpecSignature (signature, element_method); method_spec.token = new MetadataToken (TokenType.MethodSpec, rid); return method_spec; } MethodSpecification ReadMethodSpecSignature (uint signature, MethodReference method) { var reader = ReadSignature (signature); const byte methodspec_sig = 0x0a; var call_conv = reader.ReadByte (); if (call_conv != methodspec_sig) throw new NotSupportedException (); var arity = reader.ReadCompressedUInt32 (); var instance = new GenericInstanceMethod (method, (int)arity); reader.ReadGenericInstanceSignature (method, instance, arity); return instance; } MemberReference GetMemberReference (uint rid) { InitializeMemberReferences (); var member = metadata.GetMemberReference (rid); if (member != null) return member; member = ReadMemberReference (rid); if (member != null && !member.ContainsGenericParameter) metadata.AddMemberReference (member); return member; } MemberReference ReadMemberReference (uint rid) { if (!MoveTo (Table.MemberRef, rid)) return null; var token = ReadMetadataToken (CodedIndex.MemberRefParent); var name = ReadString (); var signature = ReadBlobIndex (); MemberReference member; switch (token.TokenType) { case TokenType.TypeDef: case TokenType.TypeRef: case TokenType.TypeSpec: member = ReadTypeMemberReference (token, name, signature); break; case TokenType.Method: member = ReadMethodMemberReference (token, name, signature); break; default: throw new NotSupportedException (); } member.token = new MetadataToken (TokenType.MemberRef, rid); return member; } MemberReference ReadTypeMemberReference (MetadataToken type, string name, uint signature) { var declaring_type = GetTypeDefOrRef (type); if (!declaring_type.IsArray) this.context = declaring_type; var member = ReadMemberReferenceSignature (signature, declaring_type); member.Name = name; return member; } MemberReference ReadMemberReferenceSignature (uint signature, TypeReference declaring_type) { var reader = ReadSignature (signature); const byte field_sig = 0x6; if (reader.buffer [reader.position] == field_sig) { reader.position++; var field = new FieldReference (); field.DeclaringType = declaring_type; field.FieldType = reader.ReadTypeSignature (); return field; } else { var method = new MethodReference (); method.DeclaringType = declaring_type; reader.ReadMethodSignature (method); return method; } } MemberReference ReadMethodMemberReference (MetadataToken token, string name, uint signature) { var method = GetMethodDefinition (token.RID); this.context = method; var member = ReadMemberReferenceSignature (signature, method.DeclaringType); member.Name = name; return member; } void InitializeMemberReferences () { if (metadata.MemberReferences != null) return; metadata.MemberReferences = new MemberReference [image.GetTableLength (Table.MemberRef)]; } public IEnumerable GetMemberReferences () { InitializeMemberReferences (); var length = image.GetTableLength (Table.MemberRef); var type_system = module.TypeSystem; var context = new MethodDefinition (string.Empty, MethodAttributes.Static, type_system.Void); context.DeclaringType = new TypeDefinition (string.Empty, string.Empty, TypeAttributes.Public); var member_references = new MemberReference [length]; for (uint i = 1; i <= length; i++) { this.context = context; member_references [i - 1] = GetMemberReference (i); } return member_references; } void InitializeConstants () { if (metadata.Constants != null) return; var length = MoveTo (Table.Constant); var constants = metadata.Constants = new Dictionary> (length); for (uint i = 1; i <= length; i++) { var type = (ElementType)ReadUInt16 (); var owner = ReadMetadataToken (CodedIndex.HasConstant); var signature = ReadBlobIndex (); constants.Add (owner, new Row (type, signature)); } } public TypeReference ReadConstantSignature (MetadataToken token) { if (token.TokenType != TokenType.Signature) throw new NotSupportedException (); if (token.RID == 0) return null; if (!MoveTo (Table.StandAloneSig, token.RID)) return null; return ReadFieldType (ReadBlobIndex ()); } public object ReadConstant (IConstantProvider owner) { InitializeConstants (); Row row; if (!metadata.Constants.TryGetValue (owner.MetadataToken, out row)) return Mixin.NoValue; metadata.Constants.Remove (owner.MetadataToken); return ReadConstantValue (row.Col1, row.Col2); } object ReadConstantValue (ElementType etype, uint signature) { switch (etype) { case ElementType.Class: case ElementType.Object: return null; case ElementType.String: return ReadConstantString (signature); default: return ReadConstantPrimitive (etype, signature); } } string ReadConstantString (uint signature) { byte [] blob; int index, count; GetBlobView (signature, out blob, out index, out count); if (count == 0) return string.Empty; if ((count & 1) == 1) count--; return Encoding.Unicode.GetString (blob, index, count); } object ReadConstantPrimitive (ElementType type, uint signature) { var reader = ReadSignature (signature); return reader.ReadConstantSignature (type); } internal void InitializeCustomAttributes () { if (metadata.CustomAttributes != null) return; metadata.CustomAttributes = InitializeRanges ( Table.CustomAttribute, () => { var next = ReadMetadataToken (CodedIndex.HasCustomAttribute); ReadMetadataToken (CodedIndex.CustomAttributeType); ReadBlobIndex (); return next; }); } public bool HasCustomAttributes (ICustomAttributeProvider owner) { InitializeCustomAttributes (); Range [] ranges; if (!metadata.TryGetCustomAttributeRanges (owner, out ranges)) return false; return RangesSize (ranges) > 0; } public Collection ReadCustomAttributes (ICustomAttributeProvider owner) { InitializeCustomAttributes (); Range [] ranges; if (!metadata.TryGetCustomAttributeRanges (owner, out ranges)) return new Collection (); var custom_attributes = new Collection (RangesSize (ranges)); for (int i = 0; i < ranges.Length; i++) ReadCustomAttributeRange (ranges [i], custom_attributes); metadata.RemoveCustomAttributeRange (owner); if (module.IsWindowsMetadata ()) foreach (var custom_attribute in custom_attributes) WindowsRuntimeProjections.Project (owner, custom_attribute); return custom_attributes; } void ReadCustomAttributeRange (Range range, Collection custom_attributes) { if (!MoveTo (Table.CustomAttribute, range.Start)) return; for (var i = 0; i < range.Length; i++) { ReadMetadataToken (CodedIndex.HasCustomAttribute); var constructor = (MethodReference)LookupToken ( ReadMetadataToken (CodedIndex.CustomAttributeType)); var signature = ReadBlobIndex (); custom_attributes.Add (new CustomAttribute (signature, constructor)); } } static int RangesSize (Range [] ranges) { uint size = 0; for (int i = 0; i < ranges.Length; i++) size += ranges [i].Length; return (int)size; } public IEnumerable GetCustomAttributes () { InitializeTypeDefinitions (); var length = image.TableHeap [Table.CustomAttribute].Length; var custom_attributes = new Collection ((int)length); ReadCustomAttributeRange (new Range (1, length), custom_attributes); return custom_attributes; } public byte [] ReadCustomAttributeBlob (uint signature) { return ReadBlob (signature); } public void ReadCustomAttributeSignature (CustomAttribute attribute) { var reader = ReadSignature (attribute.signature); if (!reader.CanReadMore ()) return; if (reader.ReadUInt16 () != 0x0001) throw new InvalidOperationException (); var constructor = attribute.Constructor; if (constructor.HasParameters) reader.ReadCustomAttributeConstructorArguments (attribute, constructor.Parameters); if (!reader.CanReadMore ()) return; var named = reader.ReadUInt16 (); if (named == 0) return; reader.ReadCustomAttributeNamedArguments (named, ref attribute.fields, ref attribute.properties); } void InitializeMarshalInfos () { if (metadata.FieldMarshals != null) return; var length = MoveTo (Table.FieldMarshal); var marshals = metadata.FieldMarshals = new Dictionary (length); for (int i = 0; i < length; i++) { var token = ReadMetadataToken (CodedIndex.HasFieldMarshal); var signature = ReadBlobIndex (); if (token.RID == 0) continue; marshals.Add (token, signature); } } public bool HasMarshalInfo (IMarshalInfoProvider owner) { InitializeMarshalInfos (); return metadata.FieldMarshals.ContainsKey (owner.MetadataToken); } public MarshalInfo ReadMarshalInfo (IMarshalInfoProvider owner) { InitializeMarshalInfos (); uint signature; if (!metadata.FieldMarshals.TryGetValue (owner.MetadataToken, out signature)) return null; var reader = ReadSignature (signature); metadata.FieldMarshals.Remove (owner.MetadataToken); return reader.ReadMarshalInfo (); } void InitializeSecurityDeclarations () { if (metadata.SecurityDeclarations != null) return; metadata.SecurityDeclarations = InitializeRanges ( Table.DeclSecurity, () => { ReadUInt16 (); var next = ReadMetadataToken (CodedIndex.HasDeclSecurity); ReadBlobIndex (); return next; }); } public bool HasSecurityDeclarations (ISecurityDeclarationProvider owner) { InitializeSecurityDeclarations (); Range [] ranges; if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges)) return false; return RangesSize (ranges) > 0; } public Collection ReadSecurityDeclarations (ISecurityDeclarationProvider owner) { InitializeSecurityDeclarations (); Range [] ranges; if (!metadata.TryGetSecurityDeclarationRanges (owner, out ranges)) return new Collection (); var security_declarations = new Collection (RangesSize (ranges)); for (int i = 0; i < ranges.Length; i++) ReadSecurityDeclarationRange (ranges [i], security_declarations); metadata.RemoveSecurityDeclarationRange (owner); return security_declarations; } void ReadSecurityDeclarationRange (Range range, Collection security_declarations) { if (!MoveTo (Table.DeclSecurity, range.Start)) return; for (int i = 0; i < range.Length; i++) { var action = (SecurityAction)ReadUInt16 (); ReadMetadataToken (CodedIndex.HasDeclSecurity); var signature = ReadBlobIndex (); security_declarations.Add (new SecurityDeclaration (action, signature, module)); } } public byte [] ReadSecurityDeclarationBlob (uint signature) { return ReadBlob (signature); } public void ReadSecurityDeclarationSignature (SecurityDeclaration declaration) { var signature = declaration.signature; var reader = ReadSignature (signature); if (reader.buffer [reader.position] != '.') { ReadXmlSecurityDeclaration (signature, declaration); return; } reader.position++; var count = reader.ReadCompressedUInt32 (); var attributes = new Collection ((int)count); for (int i = 0; i < count; i++) attributes.Add (reader.ReadSecurityAttribute ()); declaration.security_attributes = attributes; } void ReadXmlSecurityDeclaration (uint signature, SecurityDeclaration declaration) { var attributes = new Collection (1); var attribute = new SecurityAttribute ( module.TypeSystem.LookupType ("System.Security.Permissions", "PermissionSetAttribute")); attribute.properties = new Collection (1); attribute.properties.Add ( new CustomAttributeNamedArgument ( "XML", new CustomAttributeArgument ( module.TypeSystem.String, ReadUnicodeStringBlob (signature)))); attributes.Add (attribute); declaration.security_attributes = attributes; } public Collection ReadExportedTypes () { var length = MoveTo (Table.ExportedType); if (length == 0) return new Collection (); var exported_types = new Collection (length); for (int i = 1; i <= length; i++) { var attributes = (TypeAttributes)ReadUInt32 (); var identifier = ReadUInt32 (); var name = ReadString (); var @namespace = ReadString (); var implementation = ReadMetadataToken (CodedIndex.Implementation); ExportedType declaring_type = null; IMetadataScope scope = null; switch (implementation.TokenType) { case TokenType.AssemblyRef: case TokenType.File: scope = GetExportedTypeScope (implementation); break; case TokenType.ExportedType: // FIXME: if the table is not properly sorted declaring_type = exported_types [(int)implementation.RID - 1]; break; } var exported_type = new ExportedType (@namespace, name, module, scope) { Attributes = attributes, Identifier = (int)identifier, DeclaringType = declaring_type, }; exported_type.token = new MetadataToken (TokenType.ExportedType, i); exported_types.Add (exported_type); } return exported_types; } IMetadataScope GetExportedTypeScope (MetadataToken token) { var position = this.position; IMetadataScope scope; switch (token.TokenType) { case TokenType.AssemblyRef: InitializeAssemblyReferences (); scope = metadata.GetAssemblyNameReference (token.RID); break; case TokenType.File: InitializeModuleReferences (); scope = GetModuleReferenceFromFile (token); break; default: throw new NotSupportedException (); } this.position = position; return scope; } ModuleReference GetModuleReferenceFromFile (MetadataToken token) { if (!MoveTo (Table.File, token.RID)) return null; ReadUInt32 (); var file_name = ReadString (); var modules = module.ModuleReferences; ModuleReference reference; for (int i = 0; i < modules.Count; i++) { reference = modules [i]; if (reference.Name == file_name) return reference; } reference = new ModuleReference (file_name); modules.Add (reference); return reference; } void InitializeDocuments () { if (metadata.Documents != null) return; int length = MoveTo (Table.Document); var documents = metadata.Documents = new Document [length]; for (uint i = 1; i <= length; i++) { var name_index = ReadBlobIndex (); var hash_algorithm = ReadGuid (); var hash = ReadBlob (); var language = ReadGuid (); var signature = ReadSignature (name_index); var name = signature.ReadDocumentName (); documents [i - 1] = new Document (name) { HashAlgorithmGuid = hash_algorithm, Hash = hash, LanguageGuid = language, token = new MetadataToken (TokenType.Document, i), }; } } public Collection ReadSequencePoints (MethodDefinition method) { InitializeDocuments (); if (!MoveTo (Table.MethodDebugInformation, method.MetadataToken.RID)) return new Collection (0); var document_index = ReadTableIndex (Table.Document); var signature = ReadBlobIndex (); if (signature == 0) return new Collection (0); var document = GetDocument (document_index); var reader = ReadSignature (signature); return reader.ReadSequencePoints (document); } public Document GetDocument (uint rid) { var document = metadata.GetDocument (rid); if (document == null) return null; document.custom_infos = GetCustomDebugInformation (document); return document; } void InitializeLocalScopes () { if (metadata.LocalScopes != null) return; InitializeMethods (); int length = MoveTo (Table.LocalScope); metadata.LocalScopes = new Dictionary>> (); for (uint i = 1; i <= length; i++) { var method = ReadTableIndex (Table.Method); var import = ReadTableIndex (Table.ImportScope); var variables = ReadListRange (i, Table.LocalScope, Table.LocalVariable); var constants = ReadListRange (i, Table.LocalScope, Table.LocalConstant); var scope_start = ReadUInt32 (); var scope_length = ReadUInt32 (); metadata.SetLocalScopes (method, AddMapping (metadata.LocalScopes, method, new Row (import, variables, constants, scope_start, scope_length, i))); } } public ScopeDebugInformation ReadScope (MethodDefinition method) { InitializeLocalScopes (); InitializeImportScopes (); Collection> records; if (!metadata.TryGetLocalScopes (method, out records)) return null; var method_scope = null as ScopeDebugInformation; for (int i = 0; i < records.Count; i++) { var scope = ReadLocalScope (records [i]); if (i == 0) { method_scope = scope; continue; } if (!AddScope (method_scope.scopes, scope)) method_scope.Scopes.Add (scope); } return method_scope; } static bool AddScope (Collection scopes, ScopeDebugInformation scope) { if (scopes.IsNullOrEmpty ()) return false; foreach (var sub_scope in scopes) { if (sub_scope.HasScopes && AddScope (sub_scope.Scopes, scope)) return true; if (scope.Start.Offset >= sub_scope.Start.Offset && scope.End.Offset <= sub_scope.End.Offset) { sub_scope.Scopes.Add (scope); return true; } } return false; } ScopeDebugInformation ReadLocalScope (Row record) { var scope = new ScopeDebugInformation { start = new InstructionOffset ((int)record.Col4), end = new InstructionOffset ((int)(record.Col4 + record.Col5)), token = new MetadataToken (TokenType.LocalScope, record.Col6), }; if (record.Col1 > 0) scope.import = metadata.GetImportScope (record.Col1); if (record.Col2.Length > 0) { scope.variables = new Collection ((int)record.Col2.Length); for (uint i = 0; i < record.Col2.Length; i++) { var variable = ReadLocalVariable (record.Col2.Start + i); if (variable != null) scope.variables.Add (variable); } } if (record.Col3.Length > 0) { scope.constants = new Collection ((int)record.Col3.Length); for (uint i = 0; i < record.Col3.Length; i++) { var constant = ReadLocalConstant (record.Col3.Start + i); if (constant != null) scope.constants.Add (constant); } } return scope; } VariableDebugInformation ReadLocalVariable (uint rid) { if (!MoveTo (Table.LocalVariable, rid)) return null; var attributes = (VariableAttributes)ReadUInt16 (); var index = ReadUInt16 (); var name = ReadString (); var variable = new VariableDebugInformation (index, name) { Attributes = attributes, token = new MetadataToken (TokenType.LocalVariable, rid) }; variable.custom_infos = GetCustomDebugInformation (variable); return variable; } ConstantDebugInformation ReadLocalConstant (uint rid) { if (!MoveTo (Table.LocalConstant, rid)) return null; var name = ReadString (); var signature = ReadSignature (ReadBlobIndex ()); var type = signature.ReadTypeSignature (); object value; if (type.etype == ElementType.String) { if (signature.CanReadMore () && signature.buffer [signature.position] != 0xff) { var bytes = signature.ReadBytes ((int)(signature.sig_length - (signature.position - signature.start))); value = Encoding.Unicode.GetString (bytes, 0, bytes.Length); } else value = null; } else if (type.IsTypeOf ("System", "Decimal")) { var b = signature.ReadByte (); value = new decimal (signature.ReadInt32 (), signature.ReadInt32 (), signature.ReadInt32 (), (b & 0x80) != 0, (byte)(b & 0x7f)); } else if (type.IsTypeOf ("System", "DateTime")) { value = new DateTime (signature.ReadInt64 ()); } else if (type.etype == ElementType.Object || type.etype == ElementType.None || type.etype == ElementType.Class || type.etype == ElementType.Array || type.etype == ElementType.GenericInst) { value = null; } else value = signature.ReadConstantSignature (type.etype); var constant = new ConstantDebugInformation (name, type, value) { token = new MetadataToken (TokenType.LocalConstant, rid) }; constant.custom_infos = GetCustomDebugInformation (constant); return constant; } void InitializeImportScopes () { if (metadata.ImportScopes != null) return; var length = MoveTo (Table.ImportScope); metadata.ImportScopes = new ImportDebugInformation [length]; for (int i = 1; i <= length; i++) { ReadTableIndex (Table.ImportScope); var import = new ImportDebugInformation (); import.token = new MetadataToken (TokenType.ImportScope, i); var signature = ReadSignature (ReadBlobIndex ()); while (signature.CanReadMore ()) import.Targets.Add (ReadImportTarget (signature)); metadata.ImportScopes [i - 1] = import; } MoveTo (Table.ImportScope); for (int i = 0; i < length; i++) { var parent = ReadTableIndex (Table.ImportScope); ReadBlobIndex (); if (parent != 0) metadata.ImportScopes [i].Parent = metadata.GetImportScope (parent); } } public string ReadUTF8StringBlob (uint signature) { return ReadStringBlob (signature, Encoding.UTF8); } string ReadUnicodeStringBlob (uint signature) { return ReadStringBlob (signature, Encoding.Unicode); } string ReadStringBlob (uint signature, Encoding encoding) { byte [] blob; int index, count; GetBlobView (signature, out blob, out index, out count); if (count == 0) return string.Empty; return encoding.GetString (blob, index, count); } ImportTarget ReadImportTarget (SignatureReader signature) { AssemblyNameReference reference = null; string @namespace = null; string alias = null; TypeReference type = null; var kind = (ImportTargetKind)signature.ReadCompressedUInt32 (); switch (kind) { case ImportTargetKind.ImportNamespace: @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.ImportNamespaceInAssembly: reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.ImportType: type = signature.ReadTypeToken (); break; case ImportTargetKind.ImportXmlNamespaceWithAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.ImportAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.DefineAssemblyAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.DefineNamespaceAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.DefineNamespaceInAssemblyAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); reference = metadata.GetAssemblyNameReference (signature.ReadCompressedUInt32 ()); @namespace = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); break; case ImportTargetKind.DefineTypeAlias: alias = ReadUTF8StringBlob (signature.ReadCompressedUInt32 ()); type = signature.ReadTypeToken (); break; } return new ImportTarget (kind) { alias = alias, type = type, @namespace = @namespace, reference = reference, }; } void InitializeStateMachineMethods () { if (metadata.StateMachineMethods != null) return; var length = MoveTo (Table.StateMachineMethod); metadata.StateMachineMethods = new Dictionary (length); for (int i = 0; i < length; i++) metadata.StateMachineMethods.Add (ReadTableIndex (Table.Method), ReadTableIndex (Table.Method)); } public MethodDefinition ReadStateMachineKickoffMethod (MethodDefinition method) { InitializeStateMachineMethods (); uint rid; if (!metadata.TryGetStateMachineKickOffMethod (method, out rid)) return null; return GetMethodDefinition (rid); } void InitializeCustomDebugInformations () { if (metadata.CustomDebugInformations != null) return; var length = MoveTo (Table.CustomDebugInformation); metadata.CustomDebugInformations = new Dictionary []> (); for (uint i = 1; i <= length; i++) { var token = ReadMetadataToken (CodedIndex.HasCustomDebugInformation); var info = new Row (ReadGuid (), ReadBlobIndex (), i); Row [] infos; metadata.CustomDebugInformations.TryGetValue (token, out infos); metadata.CustomDebugInformations [token] = infos.Add (info); } } public Collection GetCustomDebugInformation (ICustomDebugInformationProvider provider) { InitializeCustomDebugInformations (); Row [] rows; if (!metadata.CustomDebugInformations.TryGetValue (provider.MetadataToken, out rows)) return null; var infos = new Collection (rows.Length); for (int i = 0; i < rows.Length; i++) { if (rows [i].Col1 == StateMachineScopeDebugInformation.KindIdentifier) { var signature = ReadSignature (rows [i].Col2); var scopes = new Collection (); while (signature.CanReadMore ()) { var start = signature.ReadInt32 (); var end = start + signature.ReadInt32 (); scopes.Add (new StateMachineScope (start, end)); } var state_machine = new StateMachineScopeDebugInformation (); state_machine.scopes = scopes; infos.Add (state_machine); } else if (rows [i].Col1 == AsyncMethodBodyDebugInformation.KindIdentifier) { var signature = ReadSignature (rows [i].Col2); var catch_offset = signature.ReadInt32 () - 1; var yields = new Collection (); var resumes = new Collection (); var resume_methods = new Collection (); while (signature.CanReadMore ()) { yields.Add (new InstructionOffset (signature.ReadInt32 ())); resumes.Add (new InstructionOffset (signature.ReadInt32 ())); resume_methods.Add (GetMethodDefinition (signature.ReadCompressedUInt32 ())); } var async_body = new AsyncMethodBodyDebugInformation (catch_offset); async_body.yields = yields; async_body.resumes = resumes; async_body.resume_methods = resume_methods; infos.Add (async_body); } else if (rows [i].Col1 == EmbeddedSourceDebugInformation.KindIdentifier) { infos.Add (new EmbeddedSourceDebugInformation (rows [i].Col2, this)); } else if (rows [i].Col1 == SourceLinkDebugInformation.KindIdentifier) { infos.Add (new SourceLinkDebugInformation (Encoding.UTF8.GetString (ReadBlob (rows [i].Col2)))); } else { infos.Add (new BinaryCustomDebugInformation (rows [i].Col1, ReadBlob (rows [i].Col2))); } infos [i].token = new MetadataToken (TokenType.CustomDebugInformation, rows [i].Col3); } return infos; } public byte [] ReadRawEmbeddedSourceDebugInformation (uint index) { var signature = ReadSignature (index); return signature.ReadBytes ((int)signature.sig_length); } public Row ReadEmbeddedSourceDebugInformation (uint index) { var signature = ReadSignature (index); var format = signature.ReadInt32 (); var length = signature.sig_length - 4; if (format == 0) { return new Row (signature.ReadBytes ((int)length), false); } else if (format > 0) { var compressed_stream = new MemoryStream (signature.ReadBytes ((int)length)); var decompressed_document = new byte [format]; // if positive, format is the decompressed length of the document var decompressed_stream = new MemoryStream (decompressed_document); using (var deflate_stream = new DeflateStream (compressed_stream, CompressionMode.Decompress, leaveOpen: true)) deflate_stream.CopyTo (decompressed_stream); return new Row (decompressed_document, true); } else throw new NotSupportedException (); } } sealed class SignatureReader : ByteBuffer { readonly MetadataReader reader; readonly internal uint start, sig_length; TypeSystem TypeSystem { get { return reader.module.TypeSystem; } } public SignatureReader (uint blob, MetadataReader reader) : base (reader.image.BlobHeap.data) { this.reader = reader; this.position = (int)blob; this.sig_length = ReadCompressedUInt32 (); this.start = (uint)this.position; } MetadataToken ReadTypeTokenSignature () { return CodedIndex.TypeDefOrRef.GetMetadataToken (ReadCompressedUInt32 ()); } GenericParameter GetGenericParameter (GenericParameterType type, uint var) { var context = reader.context; int index = (int)var; if (context == null) return GetUnboundGenericParameter (type, index); IGenericParameterProvider provider; switch (type) { case GenericParameterType.Type: provider = context.Type; break; case GenericParameterType.Method: provider = context.Method; break; default: throw new NotSupportedException (); } if (!context.IsDefinition) CheckGenericContext (provider, index); if (index >= provider.GenericParameters.Count) return GetUnboundGenericParameter (type, index); return provider.GenericParameters [index]; } GenericParameter GetUnboundGenericParameter (GenericParameterType type, int index) { return new GenericParameter (index, type, reader.module); } static void CheckGenericContext (IGenericParameterProvider owner, int index) { var owner_parameters = owner.GenericParameters; for (int i = owner_parameters.Count; i <= index; i++) owner_parameters.Add (new GenericParameter (owner)); } public void ReadGenericInstanceSignature (IGenericParameterProvider provider, IGenericInstance instance, uint arity) { if (!provider.IsDefinition) CheckGenericContext (provider, (int)arity - 1); var instance_arguments = instance.GenericArguments; for (int i = 0; i < arity; i++) instance_arguments.Add (ReadTypeSignature ()); } ArrayType ReadArrayTypeSignature () { var array = new ArrayType (ReadTypeSignature ()); var rank = ReadCompressedUInt32 (); var sizes = new uint [ReadCompressedUInt32 ()]; for (int i = 0; i < sizes.Length; i++) sizes [i] = ReadCompressedUInt32 (); var low_bounds = new int [ReadCompressedUInt32 ()]; for (int i = 0; i < low_bounds.Length; i++) low_bounds [i] = ReadCompressedInt32 (); array.Dimensions.Clear (); for (int i = 0; i < rank; i++) { int? lower = null, upper = null; if (i < low_bounds.Length) lower = low_bounds [i]; if (i < sizes.Length) upper = lower + (int)sizes [i] - 1; array.Dimensions.Add (new ArrayDimension (lower, upper)); } return array; } TypeReference GetTypeDefOrRef (MetadataToken token) { return reader.GetTypeDefOrRef (token); } public TypeReference ReadTypeSignature () { return ReadTypeSignature ((ElementType)ReadByte ()); } public TypeReference ReadTypeToken () { return GetTypeDefOrRef (ReadTypeTokenSignature ()); } TypeReference ReadTypeSignature (ElementType etype) { switch (etype) { case ElementType.ValueType: { var value_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); value_type.KnownValueType (); return value_type; } case ElementType.Class: return GetTypeDefOrRef (ReadTypeTokenSignature ()); case ElementType.Ptr: return new PointerType (ReadTypeSignature ()); case ElementType.FnPtr: { var fptr = new FunctionPointerType (); ReadMethodSignature (fptr); return fptr; } case ElementType.ByRef: return new ByReferenceType (ReadTypeSignature ()); case ElementType.Pinned: return new PinnedType (ReadTypeSignature ()); case ElementType.SzArray: return new ArrayType (ReadTypeSignature ()); case ElementType.Array: return ReadArrayTypeSignature (); case ElementType.CModOpt: return new OptionalModifierType ( GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); case ElementType.CModReqD: return new RequiredModifierType ( GetTypeDefOrRef (ReadTypeTokenSignature ()), ReadTypeSignature ()); case ElementType.Sentinel: return new SentinelType (ReadTypeSignature ()); case ElementType.Var: return GetGenericParameter (GenericParameterType.Type, ReadCompressedUInt32 ()); case ElementType.MVar: return GetGenericParameter (GenericParameterType.Method, ReadCompressedUInt32 ()); case ElementType.GenericInst: { var is_value_type = ReadByte () == (byte)ElementType.ValueType; var element_type = GetTypeDefOrRef (ReadTypeTokenSignature ()); var arity = ReadCompressedUInt32 (); var generic_instance = new GenericInstanceType (element_type, (int)arity); ReadGenericInstanceSignature (element_type, generic_instance, arity); if (is_value_type) { generic_instance.KnownValueType (); element_type.GetElementType ().KnownValueType (); } return generic_instance; } case ElementType.Object: return TypeSystem.Object; case ElementType.Void: return TypeSystem.Void; case ElementType.TypedByRef: return TypeSystem.TypedReference; case ElementType.I: return TypeSystem.IntPtr; case ElementType.U: return TypeSystem.UIntPtr; default: return GetPrimitiveType (etype); } } public void ReadMethodSignature (IMethodSignature method) { var calling_convention = ReadByte (); const byte has_this = 0x20; const byte explicit_this = 0x40; if ((calling_convention & has_this) != 0) { method.HasThis = true; calling_convention = (byte)(calling_convention & ~has_this); } if ((calling_convention & explicit_this) != 0) { method.ExplicitThis = true; calling_convention = (byte)(calling_convention & ~explicit_this); } method.CallingConvention = (MethodCallingConvention)calling_convention; var generic_context = method as MethodReference; if (generic_context != null && !generic_context.DeclaringType.IsArray) reader.context = generic_context; if ((calling_convention & 0x10) != 0) { var arity = ReadCompressedUInt32 (); if (generic_context != null && !generic_context.IsDefinition) CheckGenericContext (generic_context, (int)arity - 1); } var param_count = ReadCompressedUInt32 (); method.MethodReturnType.ReturnType = ReadTypeSignature (); if (param_count == 0) return; Collection parameters; var method_ref = method as MethodReference; if (method_ref != null) parameters = method_ref.parameters = new ParameterDefinitionCollection (method, (int)param_count); else parameters = method.Parameters; for (int i = 0; i < param_count; i++) parameters.Add (new ParameterDefinition (ReadTypeSignature ())); } public object ReadConstantSignature (ElementType type) { return ReadPrimitiveValue (type); } public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, Collection parameters) { var count = parameters.Count; if (count == 0) return; attribute.arguments = new Collection (count); for (int i = 0; i < count; i++) attribute.arguments.Add ( ReadCustomAttributeFixedArgument (parameters [i].ParameterType)); } CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type) { if (type.IsArray) return ReadCustomAttributeFixedArrayArgument ((ArrayType)type); return ReadCustomAttributeElement (type); } public void ReadCustomAttributeNamedArguments (ushort count, ref Collection fields, ref Collection properties) { for (int i = 0; i < count; i++) { if (!CanReadMore ()) return; ReadCustomAttributeNamedArgument (ref fields, ref properties); } } void ReadCustomAttributeNamedArgument (ref Collection fields, ref Collection properties) { var kind = ReadByte (); var type = ReadCustomAttributeFieldOrPropType (); var name = ReadUTF8String (); Collection container; switch (kind) { case 0x53: container = GetCustomAttributeNamedArgumentCollection (ref fields); break; case 0x54: container = GetCustomAttributeNamedArgumentCollection (ref properties); break; default: throw new NotSupportedException (); } container.Add (new CustomAttributeNamedArgument (name, ReadCustomAttributeFixedArgument (type))); } static Collection GetCustomAttributeNamedArgumentCollection (ref Collection collection) { if (collection != null) return collection; return collection = new Collection (); } CustomAttributeArgument ReadCustomAttributeFixedArrayArgument (ArrayType type) { var length = ReadUInt32 (); if (length == 0xffffffff) return new CustomAttributeArgument (type, null); if (length == 0) return new CustomAttributeArgument (type, Empty.Array); var arguments = new CustomAttributeArgument [length]; var element_type = type.ElementType; for (int i = 0; i < length; i++) arguments [i] = ReadCustomAttributeElement (element_type); return new CustomAttributeArgument (type, arguments); } CustomAttributeArgument ReadCustomAttributeElement (TypeReference type) { if (type.IsArray) return ReadCustomAttributeFixedArrayArgument ((ArrayType)type); return new CustomAttributeArgument ( type, type.etype == ElementType.Object ? ReadCustomAttributeElement (ReadCustomAttributeFieldOrPropType ()) : ReadCustomAttributeElementValue (type)); } object ReadCustomAttributeElementValue (TypeReference type) { var etype = type.etype; switch (etype) { case ElementType.String: return ReadUTF8String (); case ElementType.None: if (type.IsTypeOf ("System", "Type")) return ReadTypeReference (); return ReadCustomAttributeEnum (type); default: return ReadPrimitiveValue (etype); } } object ReadPrimitiveValue (ElementType type) { switch (type) { case ElementType.Boolean: return ReadByte () == 1; case ElementType.I1: return (sbyte)ReadByte (); case ElementType.U1: return ReadByte (); case ElementType.Char: return (char)ReadUInt16 (); case ElementType.I2: return ReadInt16 (); case ElementType.U2: return ReadUInt16 (); case ElementType.I4: return ReadInt32 (); case ElementType.U4: return ReadUInt32 (); case ElementType.I8: return ReadInt64 (); case ElementType.U8: return ReadUInt64 (); case ElementType.R4: return ReadSingle (); case ElementType.R8: return ReadDouble (); default: throw new NotImplementedException (type.ToString ()); } } TypeReference GetPrimitiveType (ElementType etype) { switch (etype) { case ElementType.Boolean: return TypeSystem.Boolean; case ElementType.Char: return TypeSystem.Char; case ElementType.I1: return TypeSystem.SByte; case ElementType.U1: return TypeSystem.Byte; case ElementType.I2: return TypeSystem.Int16; case ElementType.U2: return TypeSystem.UInt16; case ElementType.I4: return TypeSystem.Int32; case ElementType.U4: return TypeSystem.UInt32; case ElementType.I8: return TypeSystem.Int64; case ElementType.U8: return TypeSystem.UInt64; case ElementType.R4: return TypeSystem.Single; case ElementType.R8: return TypeSystem.Double; case ElementType.String: return TypeSystem.String; default: throw new NotImplementedException (etype.ToString ()); } } TypeReference ReadCustomAttributeFieldOrPropType () { var etype = (ElementType)ReadByte (); switch (etype) { case ElementType.Boxed: return TypeSystem.Object; case ElementType.SzArray: return new ArrayType (ReadCustomAttributeFieldOrPropType ()); case ElementType.Enum: return ReadTypeReference (); case ElementType.Type: return TypeSystem.LookupType ("System", "Type"); default: return GetPrimitiveType (etype); } } public TypeReference ReadTypeReference () { return TypeParser.ParseType (reader.module, ReadUTF8String ()); } object ReadCustomAttributeEnum (TypeReference enum_type) { var type = enum_type.CheckedResolve (); if (!type.IsEnum) throw new ArgumentException (); return ReadCustomAttributeElementValue (type.GetEnumUnderlyingType ()); } public SecurityAttribute ReadSecurityAttribute () { var attribute = new SecurityAttribute (ReadTypeReference ()); ReadCompressedUInt32 (); ReadCustomAttributeNamedArguments ( (ushort)ReadCompressedUInt32 (), ref attribute.fields, ref attribute.properties); return attribute; } public MarshalInfo ReadMarshalInfo () { var native = ReadNativeType (); switch (native) { case NativeType.Array: { var array = new ArrayMarshalInfo (); if (CanReadMore ()) array.element_type = ReadNativeType (); if (CanReadMore ()) array.size_parameter_index = (int)ReadCompressedUInt32 (); if (CanReadMore ()) array.size = (int)ReadCompressedUInt32 (); if (CanReadMore ()) array.size_parameter_multiplier = (int)ReadCompressedUInt32 (); return array; } case NativeType.SafeArray: { var array = new SafeArrayMarshalInfo (); if (CanReadMore ()) array.element_type = ReadVariantType (); return array; } case NativeType.FixedArray: { var array = new FixedArrayMarshalInfo (); if (CanReadMore ()) array.size = (int)ReadCompressedUInt32 (); if (CanReadMore ()) array.element_type = ReadNativeType (); return array; } case NativeType.FixedSysString: { var sys_string = new FixedSysStringMarshalInfo (); if (CanReadMore ()) sys_string.size = (int)ReadCompressedUInt32 (); return sys_string; } case NativeType.CustomMarshaler: { var marshaler = new CustomMarshalInfo (); var guid_value = ReadUTF8String (); marshaler.guid = !string.IsNullOrEmpty (guid_value) ? new Guid (guid_value) : Guid.Empty; marshaler.unmanaged_type = ReadUTF8String (); marshaler.managed_type = ReadTypeReference (); marshaler.cookie = ReadUTF8String (); return marshaler; } default: return new MarshalInfo (native); } } NativeType ReadNativeType () { return (NativeType)ReadByte (); } VariantType ReadVariantType () { return (VariantType)ReadByte (); } string ReadUTF8String () { if (buffer [position] == 0xff) { position++; return null; } var length = (int)ReadCompressedUInt32 (); if (length == 0) return string.Empty; if (position + length > buffer.Length) return string.Empty; var @string = Encoding.UTF8.GetString (buffer, position, length); position += length; return @string; } public string ReadDocumentName () { var separator = (char)buffer [position]; position++; var builder = new StringBuilder (); for (int i = 0; CanReadMore (); i++) { if (i > 0 && separator != 0) builder.Append (separator); uint part = ReadCompressedUInt32 (); if (part != 0) builder.Append (reader.ReadUTF8StringBlob (part)); } return builder.ToString (); } public Collection ReadSequencePoints (Document document) { ReadCompressedUInt32 (); // local_sig_token if (document == null) document = reader.GetDocument (ReadCompressedUInt32 ()); var offset = 0; var start_line = 0; var start_column = 0; var first_non_hidden = true; //there's about 5 compressed int32's per sequenec points. we don't know exactly how many //but let's take a conservative guess so we dont end up reallocating the sequence_points collection //as it grows. var bytes_remaining_for_sequencepoints = sig_length - (position - start); var estimated_sequencepoint_amount = (int)bytes_remaining_for_sequencepoints / 5; var sequence_points = new Collection (estimated_sequencepoint_amount); for (var i = 0; CanReadMore (); i++) { var delta_il = (int)ReadCompressedUInt32 (); if (i > 0 && delta_il == 0) { document = reader.GetDocument (ReadCompressedUInt32 ()); continue; } offset += delta_il; var delta_lines = (int)ReadCompressedUInt32 (); var delta_columns = delta_lines == 0 ? (int)ReadCompressedUInt32 () : ReadCompressedInt32 (); if (delta_lines == 0 && delta_columns == 0) { sequence_points.Add (new SequencePoint (offset, document) { StartLine = 0xfeefee, EndLine = 0xfeefee, StartColumn = 0, EndColumn = 0, }); continue; } if (first_non_hidden) { start_line = (int)ReadCompressedUInt32 (); start_column = (int)ReadCompressedUInt32 (); } else { start_line += ReadCompressedInt32 (); start_column += ReadCompressedInt32 (); } sequence_points.Add (new SequencePoint (offset, document) { StartLine = start_line, StartColumn = start_column, EndLine = start_line + delta_lines, EndColumn = start_column + delta_columns, }); first_non_hidden = false; } return sequence_points; } public bool CanReadMore () { return (position - start) < sig_length; } } }