private unsafe static void ConvertConstantSignature(BlobBuilder builder, MetadataModel metadataModel, byte[] signature, object value)
        {
            fixed(byte *sigPtr = signature)
            {
                var sigReader = new BlobReader(sigPtr, signature.Length);

                // copy custom modifiers over:
                byte rawTypeCode;

                while (true)
                {
                    rawTypeCode = sigReader.ReadByte();
                    if (rawTypeCode != (int)SignatureTypeCode.OptionalModifier && rawTypeCode != (int)SignatureTypeCode.RequiredModifier)
                    {
                        break;
                    }

                    builder.WriteByte(rawTypeCode);
                    builder.WriteCompressedInteger(sigReader.ReadCompressedInteger());
                }

                switch ((SignatureTypeCode)rawTypeCode)
                {
                case (SignatureTypeCode)SignatureTypeKind.Class:
                case (SignatureTypeCode)SignatureTypeKind.ValueType:
                    int typeRefDefSpec = sigReader.ReadCompressedInteger();

                    if (value is decimal)
                    {
                        // GeneralConstant: VALUETYPE TypeDefOrRefOrSpecEncoded <decimal>
                        builder.WriteByte((byte)SignatureTypeKind.ValueType);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                        builder.WriteDecimal((decimal)value);
                    }
                    else if (value is double d)
                    {
                        // GeneralConstant: VALUETYPE TypeDefOrRefOrSpecEncoded <date-time>
                        builder.WriteByte((byte)SignatureTypeKind.ValueType);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                        builder.WriteDateTime(new DateTime(BitConverter.DoubleToInt64Bits(d)));
                    }
                    else if (value is 0 && rawTypeCode == (byte)SignatureTypeKind.Class)
                    {
                        // GeneralConstant: CLASS TypeDefOrRefOrSpecEncoded
                        builder.WriteByte(rawTypeCode);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                    }
                    else
                    {
                        // EnumConstant ::= EnumTypeCode EnumValue EnumType
                        // EnumTypeCode ::= BOOLEAN | CHAR | I1 | U1 | I2 | U2 | I4 | U4 | I8 | U8
                        // EnumType     ::= TypeDefOrRefOrSpecEncoded

                        var enumTypeCode = AssemblyDisplayNameBuilder.GetConstantTypeCode(value);
                        builder.WriteByte((byte)enumTypeCode);
                        builder.WriteConstant(value);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                    }

                    break;
        private static BlobHandle SerializeModuleImportScope(
            MetadataBuilder metadataBuilder,
            IEnumerable <ImportInfo> csExternAliasImports,
            IEnumerable <ImportInfo> vbProjectLevelImports,
            string vbDefaultNamespace,
            MetadataModel metadataModel)
        {
            // module-level import scope:
            var builder = new BlobBuilder();
            var encoder = new ImportDefinitionEncoder(metadataBuilder, builder);

            if (vbDefaultNamespace != null)
            {
                SerializeModuleDefaultNamespace(metadataBuilder, vbDefaultNamespace);
            }

            foreach (var import in csExternAliasImports)
            {
                SerializeImport(encoder, import, metadataModel);
            }

            foreach (var import in vbProjectLevelImports)
            {
                SerializeImport(encoder, import, metadataModel);
            }

            return(metadataBuilder.GetOrAddBlob(builder));
        }
        private unsafe static BlobHandle SerializeConstantSignature(MetadataBuilder metadataBuilder, MetadataModel metadataModel, byte[] signature, object value)
        {
            var builder = new BlobBuilder();

            ConvertConstantSignature(builder, metadataModel, signature, value);
            return(metadataBuilder.GetOrAddBlob(builder));
        }
        private static void SerializeScope(
            MetadataBuilder metadataBuilder,
            MetadataModel metadataModel,
            MethodDefinitionHandle methodHandle,
            ImportScopeHandle importScopeHandle,
            ISymUnmanagedScope symScope,
            Dictionary <int, DynamicLocalInfo> dynamicSlots,
            Dictionary <string, DynamicLocalInfo> dynamicNames,
            bool vbSemantics,
            ref LocalVariableHandle lastLocalVariableHandle,
            ref LocalConstantHandle lastLocalConstantHandle)
        {
            // VB Windows PDB encode the range as end-inclusive,
            // all Portable PDBs use end-exclusive encoding.
            int start = symScope.GetStartOffset();
            int end   = symScope.GetEndOffset() + (vbSemantics ? 1 : 0);

            metadataBuilder.AddLocalScope(
                method: methodHandle,
                importScope: importScopeHandle,
                variableList: NextHandle(lastLocalVariableHandle),
                constantList: NextHandle(lastLocalConstantHandle),
                startOffset: start,
                length: end - start);

            foreach (var symLocal in symScope.GetLocals())
            {
                int    slot = symLocal.GetSlot();
                string name = symLocal.GetName();

                lastLocalVariableHandle = metadataBuilder.AddLocalVariable(
                    attributes: (LocalVariableAttributes)symLocal.GetAttributes(),
                    index: slot,
                    name: metadataBuilder.GetOrAddString(name));

                DynamicLocalInfo dynamicInfo;
                if (slot > 0 && dynamicSlots.TryGetValue(slot, out dynamicInfo) ||
                    slot == 0 && dynamicNames.TryGetValue(name, out dynamicInfo))
                {
                    metadataBuilder.AddCustomDebugInformation(
                        parent: lastLocalVariableHandle,
                        kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.DynamicLocalVariables),
                        value: SerializeDynamicLocalBlob(metadataBuilder, dynamicInfo));
                }
            }

            foreach (var symConstant in symScope.GetConstants())
            {
                string name  = symConstant.GetName();
                object value = symConstant.GetValue();

                lastLocalConstantHandle = metadataBuilder.AddLocalConstant(
                    name: metadataBuilder.GetOrAddString(name),
                    signature: SerializeConstantSignature(metadataBuilder, metadataModel, symConstant.GetSignature(), value));

                DynamicLocalInfo dynamicInfo;
                if (dynamicNames.TryGetValue(name, out dynamicInfo))
                {
                    metadataBuilder.AddCustomDebugInformation(
                        parent: lastLocalConstantHandle,
                        kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.DynamicLocalVariables),
                        value: SerializeDynamicLocalBlob(metadataBuilder, dynamicInfo));
                }
            }

            int previousChildScopeEnd = start;

            foreach (ISymUnmanagedScope child in symScope.GetChildren())
            {
                int childScopeStart = child.GetStartOffset();
                int childScopeEnd   = child.GetEndOffset();

                // scopes are properly nested:
                if (childScopeStart < previousChildScopeEnd || childScopeEnd > end)
                {
                    // TODO: loc/warning
                    throw new BadImageFormatException($"Invalid scope IL offset range: [{childScopeStart}, {childScopeEnd}), method 0x{MetadataTokens.GetToken(methodHandle):x}.");
                }

                previousChildScopeEnd = childScopeEnd;

                SerializeScope(metadataBuilder, metadataModel, methodHandle, importScopeHandle, child, dynamicSlots, dynamicNames, vbSemantics, ref lastLocalVariableHandle, ref lastLocalConstantHandle);
            }
        }
        private static void SerializeImport(ImportDefinitionEncoder encoder, ImportInfo import, MetadataModel metadataModel)
        {
            var          assemblyRef = default(AssemblyReferenceHandle);
            EntityHandle type;

            switch (import.Kind)
            {
            case ImportTargetKind.Assembly:
                // alias: assembly alias
                // target: assembly name for module-level extern alias definition, or null for file level extern alias import

                if (import.Target == null)
                {
                    // TODO: skip if the alias isn't defined in an ancestor scope?
                    encoder.ImportAssemblyReferenceAlias(import.Alias);
                    break;
                }

                if (!metadataModel.TryResolveAssemblyReference(import.Target, out assemblyRef))
                {
                    // no type from the assembly is used, the AssemblyRef is not present in the metadata
                    break;
                }

                encoder.AliasAssemblyReference(assemblyRef, import.Alias);
                break;

            case ImportTargetKind.Namespace:
                if (import.ExternAlias != null && !metadataModel.TryResolveAssemblyReference(import.ExternAlias, out assemblyRef))
                {
                    // no type from the assembly is used, the AssemblyRef is not present in the metadata
                    break;
                }

                encoder.Namespace(import.Target, import.Alias, assemblyRef);
                break;

            case ImportTargetKind.Type:
                if (!metadataModel.TryResolveType(import.Target, out type))
                {
                    // the type is not used in the source, the metadata is missing a TypeRef.
                    break;
                }

                encoder.Type(type, import.Alias);
                break;

            case ImportTargetKind.NamespaceOrType:
                if (metadataModel.TryResolveType(import.Target, out type))
                {
                    encoder.Type(type, import.Alias);
                }
                else
                {
                    encoder.Namespace(import.Target, import.Alias);
                }

                break;

            case ImportTargetKind.XmlNamespace:
                encoder.XmlNamespace(import.Alias, import.Target);
                break;

            case ImportTargetKind.DefaultNamespace:
                // alraedy handled
                throw ExceptionUtilities.Unreachable;

            case ImportTargetKind.CurrentNamespace:
            case ImportTargetKind.MethodToken:
            case ImportTargetKind.Defunct:
                break;
            }
        }
        private static BlobHandle SerializeImportsBlob(MetadataBuilder metadataBuilder, ImmutableArray <ImportInfo> imports, MetadataModel metadataModel)
        {
            var builder = new BlobBuilder();
            var encoder = new ImportDefinitionEncoder(metadataBuilder, builder);

            foreach (var import in imports)
            {
                SerializeImport(encoder, import, metadataModel);
            }

            return(metadataBuilder.GetOrAddBlob(builder));
        }
        public static void Convert(Stream peStream, Stream sourcePdbStream, Stream targetPdbStream)
        {
            var metadataBuilder = new MetadataBuilder();
            ImmutableArray <int> typeSystemRowCounts;
            var debugEntryPointToken = default(MethodDefinitionHandle);
            var pdbId = default(BlobContentId);

            try
            {
                using (var peReader = new PEReader(peStream))
                {
                    pdbId = ReadPdbId(peReader);

                    var symReader = SymReaderFactory.CreateWindowsPdbReader(sourcePdbStream, peReader);

                    var metadataReader = peReader.GetMetadataReader();
                    var metadataModel  = new MetadataModel(metadataReader);

                    typeSystemRowCounts  = metadataModel.GetRowCounts();
                    debugEntryPointToken = ReadEntryPointHandle(symReader);

                    // documents:
                    var documentIndex = new Dictionary <string, DocumentHandle>(StringComparer.Ordinal);
                    var documents     = symReader.GetDocuments();
                    metadataBuilder.SetCapacity(TableIndex.Document, documents.Length);

                    bool vbSemantics = false;

                    foreach (var document in documents)
                    {
                        string name     = document.GetName();
                        Guid   language = document.GetLanguage();

                        // TODO:
                        // won't work for IL-merged assmemblies
                        vbSemantics |= language == SymReaderHelpers.VisualBasicLanguageGuid;

                        var rid = metadataBuilder.AddDocument(
                            name: metadataBuilder.GetOrAddDocumentName(name),
                            hashAlgorithm: metadataBuilder.GetOrAddGuid(document.GetHashAlgorithm()),
                            hash: metadataBuilder.GetOrAddBlob(document.GetChecksum()),
                            language: metadataBuilder.GetOrAddGuid(language));

                        documentIndex.Add(name, rid);
                    }

                    var lastLocalVariableHandle = default(LocalVariableHandle);
                    var lastLocalConstantHandle = default(LocalConstantHandle);

                    var importStringsByMethod = new Dictionary <int, ImmutableArray <string> >();
                    var importScopesByMethod  = new Dictionary <int, ImportScopeHandle>();

                    // Maps import scope content to import scope handles
                    var importScopeIndex = new Dictionary <ImportScopeInfo, ImportScopeHandle>();
                    var importScopes     = new List <ImportScopeInfo>();

                    // reserve slot for module import scope:
                    importScopes.Add(default(ImportScopeInfo));

                    var externAliasImports   = new List <ImportInfo>();
                    var externAliasStringSet = new HashSet <string>(StringComparer.Ordinal);

                    string vbDefaultNamespace    = null;
                    var    vbProjectLevelImports = new List <ImportInfo>();

                    // first pass:
                    foreach (var methodHandle in metadataReader.MethodDefinitions)
                    {
                        int methodToken = MetadataTokens.GetToken(methodHandle);
                        ImmutableArray <ImmutableArray <ImportInfo> > importGroups;

                        if (vbSemantics)
                        {
                            var importStrings = CustomDebugInfoReader.GetVisualBasicImportStrings(
                                methodToken,
                                symReader,
                                getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr));

                            if (importStrings.IsEmpty)
                            {
                                // no debug info
                                continue;
                            }

                            var vbFileLevelImports = ArrayBuilder <ImportInfo> .GetInstance();

                            foreach (var importString in importStrings)
                            {
                                if (TryParseImportString(importString, out var import, vbSemantics: true))
                                {
                                    if (import.Kind == ImportTargetKind.DefaultNamespace)
                                    {
                                        vbDefaultNamespace = import.Target;
                                    }
                                    else if (import.Scope == VBImportScopeKind.Project)
                                    {
                                        vbProjectLevelImports.Add(import);
                                    }
                                    else
                                    {
                                        vbFileLevelImports.Add(import);
                                    }
                                }
                            }

                            importGroups = ImmutableArray.Create(vbFileLevelImports.ToImmutableAndFree());
                        }
                        else
                        {
                            var importStringGroups = CustomDebugInfoReader.GetCSharpGroupedImportStrings(
                                methodToken,
                                symReader,
                                getMethodCustomDebugInfo: (token, sr) => sr.GetCustomDebugInfo(token, methodVersion: 1),
                                getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr),
                                externAliasStrings: out var localExternAliasStrings);

                            if (importStringGroups.IsDefault)
                            {
                                // no debug info
                                continue;
                            }

                            if (!localExternAliasStrings.IsDefault)
                            {
                                foreach (var externAlias in localExternAliasStrings)
                                {
                                    if (externAliasStringSet.Add(externAlias) &&
                                        TryParseImportString(externAlias, out var import, vbSemantics: false))
                                    {
                                        externAliasImports.Add(import);
                                    }
                                }
                            }

                            importGroups = ImmutableArray.CreateRange(importStringGroups.Select(g => ParseImportStrings(g, vbSemantics: false)));
                        }

                        var importScopeHandle = DefineImportScope(importGroups, importScopeIndex, importScopes);
                        importScopesByMethod.Add(methodToken, importScopeHandle);
                    }

                    // import scopes:
                    metadataBuilder.AddImportScope(
                        parentScope: default(ImportScopeHandle),
                        imports: SerializeModuleImportScope(metadataBuilder, externAliasImports, vbProjectLevelImports, vbDefaultNamespace, metadataModel));

                    for (int i = 1; i < importScopes.Count; i++)
                    {
                        metadataBuilder.AddImportScope(
                            parentScope: importScopes[i].Parent,
                            imports: SerializeImportsBlob(metadataBuilder, importScopes[i].Imports, metadataModel));
                    }

                    var dynamicNames = new Dictionary <string, DynamicLocalInfo>();
                    var dynamicSlots = new Dictionary <int, DynamicLocalInfo>();

                    // methods:
                    metadataBuilder.SetCapacity(TableIndex.MethodDebugInformation, metadataReader.MethodDefinitions.Count);
                    foreach (var methodHandle in metadataReader.MethodDefinitions)
                    {
                        var methodDef   = metadataReader.GetMethodDefinition(methodHandle);
                        int methodToken = MetadataTokens.GetToken(methodHandle);

                        var symMethod = symReader.GetMethod(methodToken);
                        if (symMethod == null)
                        {
                            metadataBuilder.AddMethodDebugInformation(default(DocumentHandle), sequencePoints: default(BlobHandle));
                            continue;
                        }

                        // method debug info:
                        int localSignatureRowId;
                        if (methodDef.RelativeVirtualAddress != 0)
                        {
                            var methodBody = peReader.GetMethodBody(methodDef.RelativeVirtualAddress);
                            localSignatureRowId = methodBody.LocalSignature.IsNil ? 0 : MetadataTokens.GetRowNumber(methodBody.LocalSignature);
                        }
                        else
                        {
                            localSignatureRowId = 0;
                        }

                        var symSequencePoints = symMethod.GetSequencePoints().ToImmutableArray();

                        DocumentHandle singleDocumentHandle;
                        BlobHandle     sequencePointsBlob = SerializeSequencePoints(metadataBuilder, localSignatureRowId, symSequencePoints, documentIndex, out singleDocumentHandle);

                        metadataBuilder.AddMethodDebugInformation(
                            document: singleDocumentHandle,
                            sequencePoints: sequencePointsBlob);

                        // state machine and async info:
                        var symAsyncMethod = symMethod.AsAsyncMethod();
                        if (symAsyncMethod != null)
                        {
                            var kickoffToken = MetadataTokens.Handle(symAsyncMethod.GetKickoffMethod());
                            metadataBuilder.AddStateMachineMethod(
                                moveNextMethod: methodHandle,
                                kickoffMethod: (MethodDefinitionHandle)kickoffToken);

                            metadataBuilder.AddCustomDebugInformation(
                                parent: methodHandle,
                                kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob),
                                value: SerializeAsyncMethodSteppingInfo(metadataBuilder, symAsyncMethod, MetadataTokens.GetRowNumber(methodHandle)));
                        }

                        // custom debug information:
                        var dynamicLocals = default(ImmutableArray <DynamicLocalInfo>);

                        byte[] customDebugInfoBytes = symReader.GetCustomDebugInfo(methodToken, methodVersion: 1);
                        if (customDebugInfoBytes != null)
                        {
                            foreach (var record in CustomDebugInfoReader.GetCustomDebugInfoRecords(customDebugInfoBytes))
                            {
                                switch (record.Kind)
                                {
                                case CustomDebugInfoKind.DynamicLocals:
                                    dynamicLocals = CustomDebugInfoReader.DecodeDynamicLocalsRecord(record.Data);
                                    break;

                                case CustomDebugInfoKind.StateMachineHoistedLocalScopes:
                                    metadataBuilder.AddCustomDebugInformation(
                                        parent: methodHandle,
                                        kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap),
                                        value: SerializeStateMachineHoistedLocalsBlob(metadataBuilder, CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(record.Data)));
                                    break;

                                case CustomDebugInfoKind.EditAndContinueLocalSlotMap:
                                    metadataBuilder.AddCustomDebugInformation(
                                        parent: methodHandle,
                                        kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap),
                                        value: metadataBuilder.GetOrAddBlob(record.Data));
                                    break;

                                case CustomDebugInfoKind.EditAndContinueLambdaMap:
                                    metadataBuilder.AddCustomDebugInformation(
                                        parent: methodHandle,
                                        kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap),
                                        value: metadataBuilder.GetOrAddBlob(record.Data));
                                    break;
                                }
                            }
                        }

                        var rootScope = symMethod.GetRootScope();
                        if (rootScope.GetNamespaces().Length == 0 || rootScope.GetLocals().Length == 0 || rootScope.GetConstants().Length == 0)
                        {
                            dynamicNames.Clear();
                            dynamicSlots.Clear();

                            foreach (var dynamicLocal in dynamicLocals)
                            {
                                if (dynamicLocal.SlotId == 0)
                                {
                                    // All dynamic constants have slot id == 0,
                                    // but a variable can also have slot id == 0
                                    if (!dynamicNames.ContainsKey(dynamicLocal.LocalName))
                                    {
                                        dynamicNames.Add(dynamicLocal.LocalName, dynamicLocal);
                                    }
                                    else
                                    {
                                        // TODO: warning
                                    }
                                }
                                else if (!dynamicSlots.ContainsKey(dynamicLocal.SlotId))
                                {
                                    dynamicSlots.Add(dynamicLocal.SlotId, dynamicLocal);
                                }
                                else
                                {
                                    // TODO: warning
                                }
                            }

                            foreach (ISymUnmanagedScope scope in rootScope.GetChildren())
                            {
                                SerializeScope(
                                    metadataBuilder,
                                    metadataModel,
                                    methodHandle,
                                    importScopesByMethod[methodToken],
                                    scope,
                                    dynamicSlots,
                                    dynamicNames,
                                    vbSemantics,
                                    ref lastLocalVariableHandle,
                                    ref lastLocalConstantHandle);
                            }
                        }
                        else
                        {
                            // TODO: warning:
                            // "Root scope must be empty (method 0x{0:x8})", MetadataTokens.GetToken(methodHandle))
                        }
                    }
                }
            }
            catch (COMException e)
            {
                // TODO: loc
                throw new BadImageFormatException("Invalid PDB format: " + e.Message, e);
            }

            var         serializer  = new PortablePdbBuilder(metadataBuilder, typeSystemRowCounts, debugEntryPointToken, idProvider: _ => pdbId);
            BlobBuilder blobBuilder = new BlobBuilder();

            serializer.Serialize(blobBuilder);
            blobBuilder.WriteContentTo(targetPdbStream);
        }
        public unsafe static void Convert(BlobBuilder builder, MetadataModel metadataModel, byte[] signature, object value)
        {
            fixed(byte *sigPtr = signature)
            {
                var sigReader = new BlobReader(sigPtr, signature.Length);

                // copy custom modifiers over:
                byte rawTypeCode;

                while (true)
                {
                    rawTypeCode = sigReader.ReadByte();
                    if (rawTypeCode != (int)SignatureTypeCode.OptionalModifier && rawTypeCode != (int)SignatureTypeCode.RequiredModifier)
                    {
                        break;
                    }

                    builder.WriteByte(rawTypeCode);
                    builder.WriteCompressedInteger(sigReader.ReadCompressedInteger());
                }

                switch ((SignatureTypeCode)rawTypeCode)
                {
                case (SignatureTypeCode)SignatureTypeKind.Class:
                case (SignatureTypeCode)SignatureTypeKind.ValueType:
                    int typeRefDefSpec = sigReader.ReadCompressedInteger();

                    if (value is decimal)
                    {
                        // GeneralConstant: VALUETYPE TypeDefOrRefOrSpecEncoded <decimal>
                        builder.WriteByte((byte)SignatureTypeKind.ValueType);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                        builder.WriteDecimal((decimal)value);
                    }
                    else if (value is DateTime)
                    {
                        // GeneralConstant: VALUETYPE TypeDefOrRefOrSpecEncoded <date-time>
                        builder.WriteByte((byte)SignatureTypeKind.ValueType);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                        builder.WriteDateTime((DateTime)value);
                    }
                    else if (value == null)
                    {
                        // GeneralConstant: CLASS TypeDefOrRefOrSpecEncoded
                        builder.WriteByte(rawTypeCode);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                    }
                    else
                    {
                        // EnumConstant ::= EnumTypeCode EnumValue EnumType
                        // EnumTypeCode ::= BOOLEAN | CHAR | I1 | U1 | I2 | U2 | I4 | U4 | I8 | U8
                        // EnumType     ::= TypeDefOrRefOrSpecEncoded

                        var enumTypeCode = MetadataHelpers.GetConstantTypeCode(value);
                        builder.WriteByte((byte)enumTypeCode);
                        builder.WriteConstant(value);
                        builder.WriteCompressedInteger(typeRefDefSpec);
                    }

                    break;

                case SignatureTypeCode.Object:
                    // null:
                    Debug.Assert(value == null);
                    builder.WriteByte((byte)SignatureTypeCode.Object);
                    break;

                case SignatureTypeCode.Boolean:
                case SignatureTypeCode.Char:
                case SignatureTypeCode.SByte:
                case SignatureTypeCode.Byte:
                case SignatureTypeCode.Int16:
                case SignatureTypeCode.UInt16:
                case SignatureTypeCode.Int32:
                case SignatureTypeCode.UInt32:
                case SignatureTypeCode.Int64:
                case SignatureTypeCode.UInt64:
                case SignatureTypeCode.Single:
                case SignatureTypeCode.Double:
                case SignatureTypeCode.String:
                    // PrimitiveConstant
                    builder.WriteByte(rawTypeCode);
                    builder.WriteConstant(value);
                    break;

                case SignatureTypeCode.SZArray:
                case SignatureTypeCode.Array:
                case SignatureTypeCode.GenericTypeInstance:
                    Debug.Assert(value == null);

                    // Find an existing TypeSpec in metadata.
                    // If there isn't one we can't represent the constant type in the Portable PDB, use Object.

                    // +1/-1 for the type code we already read.
                    var spec = new byte[sigReader.RemainingBytes + 1];
                    Buffer.BlockCopy(signature, sigReader.Offset - 1, spec, 0, spec.Length);

                    TypeSpecificationHandle typeSpec;
                    if (metadataModel.TryResolveTypeSpecification(spec, out typeSpec))
                    {
                        builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(typeSpec));
                    }
                    else
                    {
                        // TODO: warning - can't translate const type
                        builder.WriteByte((byte)SignatureTypeCode.Object);
                    }

                    break;

                case SignatureTypeCode.GenericMethodParameter:
                case SignatureTypeCode.GenericTypeParameter:
                case SignatureTypeCode.FunctionPointer:
                case SignatureTypeCode.Pointer:
                    // generic parameters, pointers are not valid types for constants:
                    throw new BadImageFormatException();
                }
            }
        }
        internal void Convert(PEReader peReader, MetadataReader pdbReader, PdbWriter <TDocumentWriter> pdbWriter, PdbConversionOptions options)
        {
            if (!SymReaderHelpers.TryReadPdbId(peReader, out var pePdbId, out int peAge))
            {
                throw new InvalidDataException(ConverterResources.SpecifiedPEFileHasNoAssociatedPdb);
            }

            if (!new BlobContentId(pdbReader.DebugMetadataHeader.Id).Equals(pePdbId))
            {
                throw new InvalidDataException(ConverterResources.PdbNotMatchingDebugDirectory);
            }

            string vbDefaultNamespace             = MetadataUtilities.GetVisualBasicDefaultNamespace(pdbReader);
            bool   vbSemantics                    = vbDefaultNamespace != null;
            string vbDefaultNamespaceImportString = string.IsNullOrEmpty(vbDefaultNamespace) ? null : "*" + vbDefaultNamespace;

            var metadataReader = peReader.GetMetadataReader();
            var metadataModel  = new MetadataModel(metadataReader, vbSemantics);

            var documentWriters         = new ArrayBuilder <TDocumentWriter>(pdbReader.Documents.Count);
            var documentNames           = new ArrayBuilder <string>(pdbReader.Documents.Count);
            var symSequencePointBuilder = new SequencePointsBuilder(capacity: 64);
            var declaredExternAliases   = new HashSet <string>();
            var importStringsBuilder    = new List <string>();
            var importGroups            = new List <int>();
            var cdiBuilder          = new BlobBuilder();
            var dynamicLocals       = new List <(string LocalName, byte[] Flags, int Count, int SlotIndex)>();
            var tupleLocals         = new List <(string LocalName, int SlotIndex, int ScopeStart, int ScopeEnd, ImmutableArray <string> Names)>();
            var openScopeEndOffsets = new Stack <int>();

            // state for calculating import string forwarding:
            var lastImportScopeHandle          = default(ImportScopeHandle);
            var vbLastImportScopeNamespace     = default(string);
            var lastImportScopeMethodDefHandle = default(MethodDefinitionHandle);
            var importStringsMap = new Dictionary <ImmutableArray <string>, MethodDefinitionHandle>(SequenceComparer <string> .Instance);

            var aliasedAssemblyRefs = GetAliasedAssemblyRefs(pdbReader);

            foreach (var documentHandle in pdbReader.Documents)
            {
                var document     = pdbReader.GetDocument(documentHandle);
                var languageGuid = pdbReader.GetGuid(document.Language);
                var name         = pdbReader.GetString(document.Name);
                documentNames.Add(name);

                documentWriters.Add(pdbWriter.DefineDocument(
                                        name: name,
                                        language: languageGuid,
                                        type: s_documentTypeText,
                                        vendor: GetLanguageVendorGuid(languageGuid),
                                        algorithmId: pdbReader.GetGuid(document.HashAlgorithm),
                                        checksum: pdbReader.GetBlobBytes(document.Hash)));
            }

            var        localScopeEnumerator = pdbReader.LocalScopes.GetEnumerator();
            LocalScope?currentLocalScope    = NextLocalScope();

            LocalScope?NextLocalScope() =>
            localScopeEnumerator.MoveNext() ? pdbReader.GetLocalScope(localScopeEnumerator.Current) : default(LocalScope?);

            // Handle of the method that is gonna contain list of AssemblyRef aliases.
            // Other methods will forward to it.
            var methodDefHandleWithAssemblyRefAliases = default(MethodDefinitionHandle);

            foreach (var methodDebugInfoHandle in pdbReader.MethodDebugInformation)
            {
                var methodDebugInfo = pdbReader.GetMethodDebugInformation(methodDebugInfoHandle);
                var methodDefHandle = methodDebugInfoHandle.ToDefinitionHandle();
                int methodToken     = MetadataTokens.GetToken(methodDefHandle);
                var methodDef       = metadataReader.GetMethodDefinition(methodDefHandle);
#if DEBUG
                var declaringTypeDef = metadataReader.GetTypeDefinition(methodDef.GetDeclaringType());
                var typeName         = metadataReader.GetString(declaringTypeDef.Name);
                var methodName       = metadataReader.GetString(methodDef.Name);
#endif
                bool methodOpened = false;

                var methodBodyOpt = (methodDef.RelativeVirtualAddress != 0 && (methodDef.ImplAttributes & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.Managed) ?
                                    peReader.GetMethodBody(methodDef.RelativeVirtualAddress) : null;

                var  vbCurrentMethodNamespace = vbSemantics ? GetMethodNamespace(metadataReader, methodDef) : null;
                var  moveNextHandle           = metadataModel.FindStateMachineMoveNextMethod(methodDefHandle, vbSemantics);
                bool isKickOffMethod          = !moveNextHandle.IsNil;

                var forwardImportScopesToMethodDef = default(MethodDefinitionHandle);
                Debug.Assert(dynamicLocals.Count == 0);
                Debug.Assert(tupleLocals.Count == 0);
                Debug.Assert(openScopeEndOffsets.Count == 0);

                void LazyOpenMethod()
                {
                    if (!methodOpened)
                    {
#if DEBUG
                        Debug.WriteLine($"Open Method '{typeName}::{methodName}' {methodToken:X8}");
#endif
                        pdbWriter.OpenMethod(methodToken);
                        methodOpened = true;
                    }
                }

                void CloseOpenScopes(int currentScopeStartOffset)
                {
                    // close all open scopes that end before this scope starts:
                    while (openScopeEndOffsets.Count > 0 && currentScopeStartOffset >= openScopeEndOffsets.Peek())
                    {
                        int scopeEnd = openScopeEndOffsets.Pop();
                        Debug.WriteLine($"Close Scope [.., {scopeEnd})");

                        // Note that the root scope end is not end-inclusive in VB:
                        pdbWriter.CloseScope(AdjustEndScopeOffset(scopeEnd, isEndInclusive: vbSemantics && openScopeEndOffsets.Count > 0));
                    }
                }

                bool isFirstMethodScope = true;
                while (currentLocalScope.HasValue && currentLocalScope.Value.Method == methodDefHandle)
                {
                    // kickoff methods don't have any scopes emitted to Windows PDBs
                    if (methodBodyOpt == null)
                    {
                        ReportDiagnostic(PdbDiagnosticId.MethodAssociatedWithLocalScopeHasNoBody, MetadataTokens.GetToken(localScopeEnumerator.Current));
                    }
                    else if (!isKickOffMethod)
                    {
                        LazyOpenMethod();

                        var localScope = currentLocalScope.Value;
                        CloseOpenScopes(localScope.StartOffset);

                        Debug.WriteLine($"Open Scope [{localScope.StartOffset}, {localScope.EndOffset})");
                        pdbWriter.OpenScope(localScope.StartOffset);
                        openScopeEndOffsets.Push(localScope.EndOffset);

                        if (isFirstMethodScope)
                        {
                            if (lastImportScopeHandle == localScope.ImportScope && vbLastImportScopeNamespace == vbCurrentMethodNamespace)
                            {
                                // forward to a method that has the same imports:
                                forwardImportScopesToMethodDef = lastImportScopeMethodDefHandle;
                            }
                            else
                            {
                                Debug.Assert(importStringsBuilder.Count == 0);
                                Debug.Assert(declaredExternAliases.Count == 0);
                                Debug.Assert(importGroups.Count == 0);

                                AddImportStrings(importStringsBuilder, importGroups, declaredExternAliases, pdbReader, metadataModel, localScope.ImportScope, aliasedAssemblyRefs, vbDefaultNamespaceImportString, vbCurrentMethodNamespace, vbSemantics);
                                var importStrings = importStringsBuilder.ToImmutableArray();
                                importStringsBuilder.Clear();

                                if (importStringsMap.TryGetValue(importStrings, out forwardImportScopesToMethodDef))
                                {
                                    // forward to a method that has the same imports:
                                    lastImportScopeMethodDefHandle = forwardImportScopesToMethodDef;
                                }
                                else
                                {
                                    // attach import strings to the current method:
                                    WriteImports(pdbWriter, importStrings);
                                    lastImportScopeMethodDefHandle  = methodDefHandle;
                                    importStringsMap[importStrings] = methodDefHandle;
                                }

                                lastImportScopeHandle      = localScope.ImportScope;
                                vbLastImportScopeNamespace = vbCurrentMethodNamespace;
                            }

                            if (vbSemantics && !forwardImportScopesToMethodDef.IsNil)
                            {
                                pdbWriter.UsingNamespace("@" + MetadataTokens.GetToken(forwardImportScopesToMethodDef));
                            }

                            // This is the method that's gonna have AssemblyRef aliases attached:
                            if (methodDefHandleWithAssemblyRefAliases.IsNil)
                            {
                                foreach (var(assemblyRefHandle, alias) in aliasedAssemblyRefs)
                                {
                                    var assemblyRef = metadataReader.GetAssemblyReference(assemblyRefHandle);
                                    pdbWriter.UsingNamespace("Z" + alias + " " + AssemblyDisplayNameBuilder.GetAssemblyDisplayName(metadataReader, assemblyRef));
                                }
                            }
                        }

                        foreach (var localVariableHandle in localScope.GetLocalVariables())
                        {
                            var    variable = pdbReader.GetLocalVariable(localVariableHandle);
                            string name     = pdbReader.GetString(variable.Name);

                            if (name.Length > MaxEntityNameLength)
                            {
                                ReportDiagnostic(PdbDiagnosticId.LocalConstantNameTooLong, MetadataTokens.GetToken(localVariableHandle));
                                continue;
                            }

                            if (methodBodyOpt.LocalSignature.IsNil)
                            {
                                ReportDiagnostic(PdbDiagnosticId.MethodContainingLocalVariablesHasNoLocalSignature, methodToken);
                                continue;
                            }

                            // TODO: translate hoisted variable scopes to dummy VB hoisted state machine locals (https://github.com/dotnet/roslyn/issues/8473)

                            pdbWriter.DefineLocalVariable(variable.Index, name, variable.Attributes, MetadataTokens.GetToken(methodBodyOpt.LocalSignature));

                            var dynamicFlags = MetadataUtilities.ReadDynamicCustomDebugInformation(pdbReader, localVariableHandle);
                            if (TryGetDynamicLocal(name, variable.Index, dynamicFlags, out var dynamicLocal))
                            {
                                dynamicLocals.Add(dynamicLocal);
                            }

                            var tupleElementNames = MetadataUtilities.ReadTupleCustomDebugInformation(pdbReader, localVariableHandle);
                            if (!tupleElementNames.IsDefaultOrEmpty)
                            {
                                tupleLocals.Add((name, SlotIndex: variable.Index, ScopeStart: 0, ScopeEnd: 0, Names: tupleElementNames));
                            }
                        }

                        foreach (var localConstantHandle in localScope.GetLocalConstants())
                        {
                            var    constant = pdbReader.GetLocalConstant(localConstantHandle);
                            string name     = pdbReader.GetString(constant.Name);

                            if (name.Length > MaxEntityNameLength)
                            {
                                ReportDiagnostic(PdbDiagnosticId.LocalConstantNameTooLong, MetadataTokens.GetToken(localConstantHandle));
                                continue;
                            }

                            var(value, signature) = PortableConstantSignature.GetConstantValueAndSignature(pdbReader, localConstantHandle, metadataReader.GetQualifiedTypeName);
                            if (!metadataModel.TryGetStandaloneSignatureHandle(signature, out var constantSignatureHandle))
                            {
                                // Signature will be unspecified. At least we store the name and the value.
                                constantSignatureHandle = default(StandaloneSignatureHandle);
                            }

                            pdbWriter.DefineLocalConstant(name, value, MetadataTokens.GetToken(constantSignatureHandle));

                            var dynamicFlags = MetadataUtilities.ReadDynamicCustomDebugInformation(pdbReader, localConstantHandle);
                            if (TryGetDynamicLocal(name, 0, dynamicFlags, out var dynamicLocal))
                            {
                                dynamicLocals.Add(dynamicLocal);
                            }

                            var tupleElementNames = MetadataUtilities.ReadTupleCustomDebugInformation(pdbReader, localConstantHandle);
                            if (!tupleElementNames.IsDefaultOrEmpty)
                            {
                                // Note that the end offset of tuple locals is always end-exclusive, regardless of whether the PDB uses VB semantics or not.
                                tupleLocals.Add((name, SlotIndex: -1, ScopeStart: localScope.StartOffset, ScopeEnd: localScope.EndOffset, Names: tupleElementNames));
                            }
                        }
                    }

                    currentLocalScope  = NextLocalScope();
                    isFirstMethodScope = false;
                }

                bool hasAnyScopes = !isFirstMethodScope;

                CloseOpenScopes(int.MaxValue);
                if (openScopeEndOffsets.Count > 0)
                {
                    ReportDiagnostic(PdbDiagnosticId.LocalScopeRangesNestingIsInvalid, methodToken);
                    openScopeEndOffsets.Clear();
                }

                if (!methodDebugInfo.SequencePointsBlob.IsNil)
                {
                    LazyOpenMethod();
                    WriteSequencePoints(pdbWriter, documentWriters, symSequencePointBuilder, methodDebugInfo.GetSequencePoints(), methodToken);
                }

                // async method data:
                var asyncData = MetadataUtilities.ReadAsyncMethodData(pdbReader, methodDebugInfoHandle);
                if (!asyncData.IsNone)
                {
                    LazyOpenMethod();
                    pdbWriter.SetAsyncInfo(
                        moveNextMethodToken: methodToken,
                        kickoffMethodToken: MetadataTokens.GetToken(asyncData.KickoffMethod),
                        catchHandlerOffset: asyncData.CatchHandlerOffset,
                        yieldOffsets: asyncData.YieldOffsets.ToArray(),
                        resumeOffsets: asyncData.ResumeOffsets.ToArray());
                }

                // custom debug information:
                var cdiEncoder = new CustomDebugInfoEncoder(cdiBuilder);
                if (isKickOffMethod)
                {
                    cdiEncoder.AddStateMachineTypeName(GetIteratorTypeName(metadataReader, moveNextHandle));
                }
                else
                {
                    if (!vbSemantics && hasAnyScopes)
                    {
                        if (forwardImportScopesToMethodDef.IsNil)
                        {
                            // record the number of import strings in each scope:
                            cdiEncoder.AddUsingGroups(importGroups);

                            if (!methodDefHandleWithAssemblyRefAliases.IsNil)
                            {
                                // forward assembly ref aliases to the first method:
                                cdiEncoder.AddForwardModuleInfo(methodDefHandleWithAssemblyRefAliases);
                            }
                        }
                        else
                        {
                            // forward all imports to another method:
                            cdiEncoder.AddForwardMethodInfo(forwardImportScopesToMethodDef);
                        }
                    }

                    var hoistedLocalScopes = GetStateMachineHoistedLocalScopes(pdbReader, methodDefHandle);
                    if (!hoistedLocalScopes.IsDefault)
                    {
                        cdiEncoder.AddStateMachineHoistedLocalScopes(hoistedLocalScopes);
                    }

                    if (dynamicLocals.Count > 0)
                    {
                        cdiEncoder.AddDynamicLocals(dynamicLocals);
                        dynamicLocals.Clear();
                    }

                    if (tupleLocals.Count > 0)
                    {
                        cdiEncoder.AddTupleElementNames(tupleLocals);
                        tupleLocals.Clear();
                    }
                }

                importGroups.Clear();

                // the following blobs map 1:1
                CopyCustomDebugInfoRecord(ref cdiEncoder, pdbReader, methodDefHandle, PortableCustomDebugInfoKinds.EncLocalSlotMap, CustomDebugInfoKind.EditAndContinueLocalSlotMap);
                CopyCustomDebugInfoRecord(ref cdiEncoder, pdbReader, methodDefHandle, PortableCustomDebugInfoKinds.EncLambdaAndClosureMap, CustomDebugInfoKind.EditAndContinueLambdaMap);

                if (cdiEncoder.RecordCount > 0)
                {
                    LazyOpenMethod();
                    pdbWriter.DefineCustomMetadata(cdiEncoder.ToArray());
                }

                cdiBuilder.Clear();

                if (methodOpened && aliasedAssemblyRefs.Length > 0 && !isKickOffMethod && methodDefHandleWithAssemblyRefAliases.IsNil)
                {
                    methodDefHandleWithAssemblyRefAliases = methodDefHandle;
                }

                if (methodOpened)
                {
                    Debug.WriteLine($"Close Method {methodToken:X8}");
                    pdbWriter.CloseMethod();
                }
            }

            if (!pdbReader.DebugMetadataHeader.EntryPoint.IsNil)
            {
                pdbWriter.SetEntryPoint(MetadataTokens.GetToken(pdbReader.DebugMetadataHeader.EntryPoint));
            }

            var sourceLinkHandle = pdbReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition, PortableCustomDebugInfoKinds.SourceLink);
            if (!sourceLinkHandle.IsNil)
            {
                if ((options & PdbConversionOptions.SuppressSourceLinkConversion) == 0)
                {
                    ConvertSourceServerData(pdbReader.GetStringUTF8(sourceLinkHandle), pdbWriter, documentNames);
                }
                else
                {
                    pdbWriter.SetSourceLinkData(pdbReader.GetBlobBytes(sourceLinkHandle));
                }
            }

            SymReaderHelpers.GetWindowsPdbSignature(pdbReader.DebugMetadataHeader.Id, out var guid, out var stamp, out var age);
            pdbWriter.UpdateSignature(guid, stamp, age);
        }
Beispiel #10
0
 public SerializedTypeNameSignatureDecoder(MetadataModel model, bool useAssemblyQualification, char nestedNameSeparator)
 {
     _model = model;
     _useAssemblyQualification = useAssemblyQualification;
     _nestedNameSeparator      = nestedNameSeparator;
 }
        public static void Convert(Stream peStream, Stream sourcePdbStream, Stream targetPdbStream)
        {
            using (var peReader = new PEReader(peStream))
                using (var pdbReaderProvider = MetadataReaderProvider.FromPortablePdbStream(sourcePdbStream))
                    using (var pdbWriter = new PdbWriter(peReader.GetMetadataReader()))
                    {
                        var metadataReader = peReader.GetMetadataReader();
                        var metadataModel  = new MetadataModel(metadataReader);

                        var pdbReader = pdbReaderProvider.GetMetadataReader();

                        var documentWriters         = new ArrayBuilder <ISymUnmanagedDocumentWriter>(pdbReader.Documents.Count);
                        var symSequencePointBuilder = new SequencePointsBuilder(capacity: 64);
                        var declaredExternAliases   = new HashSet <string>();
                        var importStringsBuilder    = new List <string>();
                        var importCountsPerScope    = new List <int>();
                        var cdiBuilder    = new BlobBuilder();
                        var dynamicLocals = new List <(string LocalName, byte[] Flags, int Count, int SlotIndex)>();

                        // state for calculating import string forwarding:
                        var lastImportScopeHandle          = default(ImportScopeHandle);
                        var lastImportScopeMethodDefHandle = default(MethodDefinitionHandle);
                        var importStringsMap = new Dictionary <ImmutableArray <string>, MethodDefinitionHandle>();

                        var aliasedAssemblyRefs = GetAliasedAssemblyRefs(pdbReader);
                        var kickOffMethodToMoveNextMethodMap = GetStateMachineMethodMap(pdbReader);

                        string vbDefaultNamespace             = MetadataUtilities.GetVisualBasicDefaultNamespace(metadataReader);
                        bool   vbSemantics                    = vbDefaultNamespace != null;
                        string vbDefaultNamespaceImportString = vbSemantics ? "*" + vbDefaultNamespace : null;

                        foreach (var documentHandle in pdbReader.Documents)
                        {
                            var document     = pdbReader.GetDocument(documentHandle);
                            var languageGuid = pdbReader.GetGuid(document.Language);

                            documentWriters.Add(pdbWriter.DefineDocument(
                                                    name: pdbReader.GetString(document.Name),
                                                    language: languageGuid,
                                                    type: s_documentTypeText,
                                                    vendor: GetLanguageVendorGuid(languageGuid),
                                                    algorithmId: pdbReader.GetGuid(document.HashAlgorithm),
                                                    checksum: pdbReader.GetBlobBytes(document.Hash)));
                        }

                        var        localScopeEnumerator = pdbReader.LocalScopes.GetEnumerator();
                        LocalScope currentLocalScope    = NextLocalScope();

                        LocalScope NextLocalScope() =>
                        localScopeEnumerator.MoveNext() ? pdbReader.GetLocalScope(localScopeEnumerator.Current) : default(LocalScope);

                        var firstMethodDefHandle = default(MethodDefinitionHandle);
                        foreach (var methodDebugInfoHandle in pdbReader.MethodDebugInformation)
                        {
                            var methodDebugInfo = pdbReader.GetMethodDebugInformation(methodDebugInfoHandle);
                            var methodDefHandle = methodDebugInfoHandle.ToDefinitionHandle();
                            int methodToken     = MetadataTokens.GetToken(methodDefHandle);
                            var methodDef       = metadataReader.GetMethodDefinition(methodDefHandle);

                            // methods without debug info:
                            if (methodDebugInfo.Document.IsNil && methodDebugInfo.SequencePointsBlob.IsNil)
                            {
                                continue;
                            }

                            // methods without method body don't currently have any debug information:
                            if (methodDef.RelativeVirtualAddress == 0)
                            {
                                continue;
                            }

                            var methodBody = peReader.GetMethodBody(methodDef.RelativeVirtualAddress);

                            pdbWriter.OpenMethod(methodToken);

                            var forwardImportScopesToMethodDef = default(MethodDefinitionHandle);
                            Debug.Assert(dynamicLocals.Count == 0);

                            bool isFirstMethodScope = true;
                            while (currentLocalScope.Method == methodDefHandle)
                            {
                                if (isFirstMethodScope)
                                {
                                    if (lastImportScopeHandle == currentLocalScope.ImportScope)
                                    {
                                        // forward to a method that has the same imports:
                                        forwardImportScopesToMethodDef = lastImportScopeMethodDefHandle;
                                    }
                                    else
                                    {
                                        Debug.Assert(importStringsBuilder.Count == 0);
                                        Debug.Assert(declaredExternAliases.Count == 0);
                                        Debug.Assert(importCountsPerScope.Count == 0);

                                        AddImportStrings(importStringsBuilder, importCountsPerScope, declaredExternAliases, pdbReader, metadataModel, currentLocalScope.ImportScope, aliasedAssemblyRefs, vbDefaultNamespaceImportString);
                                        var importStrings = importStringsBuilder.ToImmutableArray();
                                        importStringsBuilder.Clear();

                                        if (importStringsMap.TryGetValue(importStrings, out forwardImportScopesToMethodDef))
                                        {
                                            // forward to a method that has the same imports:
                                            lastImportScopeMethodDefHandle = forwardImportScopesToMethodDef;
                                        }
                                        else
                                        {
                                            // attach import strings to the current method:
                                            WriteImports(pdbWriter, importStrings);
                                            lastImportScopeMethodDefHandle = methodDefHandle;
                                        }

                                        lastImportScopeHandle = currentLocalScope.ImportScope;
                                    }

                                    if (vbSemantics && !forwardImportScopesToMethodDef.IsNil)
                                    {
                                        pdbWriter.UsingNamespace("@" + MetadataTokens.GetToken(forwardImportScopesToMethodDef));
                                    }
                                }
                                else
                                {
                                    pdbWriter.OpenScope(currentLocalScope.StartOffset);
                                }

                                foreach (var localConstantHandle in currentLocalScope.GetLocalConstants())
                                {
                                    var    constant = pdbReader.GetLocalConstant(localConstantHandle);
                                    string name     = pdbReader.GetString(constant.Name);

                                    if (name.Length > MaxEntityNameLength)
                                    {
                                        // TODO: report warning
                                        continue;
                                    }

                                    var(value, signature) = PortableConstantSignature.GetConstantValueAndSignature(pdbReader, localConstantHandle, pdbWriter.MetadataImport);
                                    if (!metadataModel.TryGetStandaloneSignatureHandle(signature, out var constantSignatureHandle))
                                    {
                                        // TODO: report warning

                                        // TODO:
                                        // Currently the EEs require signature to match exactly the type of the value.
                                        // We could relax that and use the type of the value regardless of the signature for primitive types.
                                        // Then we could use any signature here.
                                        continue;
                                    }

                                    pdbWriter.DefineLocalConstant(name, value, MetadataTokens.GetToken(constantSignatureHandle));

                                    var dynamicFlags = MetadataUtilities.ReadDynamicCustomDebugInformation(pdbReader, localConstantHandle);
                                    if (TryGetDynamicLocal(name, 0, dynamicFlags, out var dynamicLocal))
                                    {
                                        dynamicLocals.Add(dynamicLocal);
                                    }
                                }

                                foreach (var localVariableHandle in currentLocalScope.GetLocalVariables())
                                {
                                    var    variable = pdbReader.GetLocalVariable(localVariableHandle);
                                    string name     = pdbReader.GetString(variable.Name);

                                    if (name.Length > MaxEntityNameLength)
                                    {
                                        // TODO: report warning
                                        continue;
                                    }

                                    int localSignatureToken = methodBody.LocalSignature.IsNil ? 0 : MetadataTokens.GetToken(methodBody.LocalSignature);
                                    pdbWriter.DefineLocalVariable(variable.Index, name, variable.Attributes, localSignatureToken);

                                    var dynamicFlags = MetadataUtilities.ReadDynamicCustomDebugInformation(pdbReader, localVariableHandle);
                                    if (TryGetDynamicLocal(name, variable.Index, dynamicFlags, out var dynamicLocal))
                                    {
                                        dynamicLocals.Add(dynamicLocal);
                                    }
                                }

                                if (!isFirstMethodScope)
                                {
                                    pdbWriter.CloseScope(currentLocalScope.EndOffset - (vbSemantics ? 1 : 0));
                                }

                                currentLocalScope  = NextLocalScope();
                                isFirstMethodScope = false;
                            }

                            WriteSequencePoints(pdbWriter, documentWriters, symSequencePointBuilder, methodDebugInfo.GetSequencePoints());

                            // async method data:
                            var asyncData = MetadataUtilities.ReadAsyncMethodData(pdbReader, methodDebugInfoHandle);
                            if (!asyncData.IsNone)
                            {
                                pdbWriter.SetAsyncInfo(
                                    moveNextMethodToken: methodToken,
                                    kickoffMethodToken: MetadataTokens.GetToken(asyncData.KickoffMethod),
                                    catchHandlerOffset: asyncData.CatchHandlerOffset,
                                    yieldOffsets: asyncData.YieldOffsets,
                                    resumeOffsets: asyncData.ResumeOffsets);
                            }

                            // custom debug information:
                            var cdiEncoder = new CustomDebugInfoEncoder(cdiBuilder);
                            if (kickOffMethodToMoveNextMethodMap.TryGetValue(methodDefHandle, out var moveNextHandle))
                            {
                                cdiEncoder.AddReferenceToIteratorClass(GetIteratorTypeName(metadataReader, moveNextHandle));
                            }
                            else
                            {
                                if (!vbSemantics)
                                {
                                    if (forwardImportScopesToMethodDef.IsNil)
                                    {
                                        // record the number of import strings in each scope:
                                        cdiEncoder.AddUsingInfo(importCountsPerScope);

                                        if (!firstMethodDefHandle.IsNil)
                                        {
                                            // forward assembly ref aliases to the first method:
                                            cdiEncoder.AddReferenceToMethodWithModuleInfo(firstMethodDefHandle);
                                        }
                                    }
                                    else
                                    {
                                        // forward all imports to another method:
                                        cdiEncoder.AddReferenceToPreviousMethodWithUsingInfo(forwardImportScopesToMethodDef);
                                    }
                                }

                                var hoistedLocalScopes = GetStateMachineHoistedLocalScopes(pdbReader, methodDefHandle);
                                if (!hoistedLocalScopes.IsDefault)
                                {
                                    cdiEncoder.AddStateMachineLocalScopes(hoistedLocalScopes);
                                }
                            }

                            if (dynamicLocals.Count > 0)
                            {
                                cdiEncoder.AddDynamicLocals(dynamicLocals);
                                dynamicLocals.Clear();
                            }

                            // the following blobs map 1:1
                            CopyCustomDebugInfoRecord(ref cdiEncoder, pdbReader, methodDefHandle, PortableCustomDebugInfoKinds.TupleElementNames, CustomDebugInfoKind.TupleElementNames);
                            CopyCustomDebugInfoRecord(ref cdiEncoder, pdbReader, methodDefHandle, PortableCustomDebugInfoKinds.EncLocalSlotMap, CustomDebugInfoKind.EditAndContinueLocalSlotMap);
                            CopyCustomDebugInfoRecord(ref cdiEncoder, pdbReader, methodDefHandle, PortableCustomDebugInfoKinds.EncLambdaAndClosureMap, CustomDebugInfoKind.EditAndContinueLambdaMap);

                            cdiBuilder.Clear();

                            if (firstMethodDefHandle.IsNil)
                            {
                                firstMethodDefHandle = methodDefHandle;

                                foreach (var(assemblyRefHandle, alias) in aliasedAssemblyRefs)
                                {
                                    var assemblyRef = metadataReader.GetAssemblyReference(assemblyRefHandle);
                                    pdbWriter.UsingNamespace("Z" + alias + " " + MetadataHelpers.GetAssemblyDisplayName(metadataReader, assemblyRef));
                                }
                            }

                            pdbWriter.CloseMethod(methodBody.GetILReader().Length);
                        }

                        pdbWriter.WriteTo(targetPdbStream);
                    }
        }