Ejemplo n.º 1
0
        private ValueTuple <Dictionary <string, AssemblyReferenceHandle>, string[]> BuildAssemblyRefMap()
        {
            var assemblyRefsByName = new Dictionary <string, AssemblyReferenceHandle>(StringComparer.OrdinalIgnoreCase);
            var assemblyNames      = new string[Reader.AssemblyReferences.Count];

            foreach (var handle in Reader.AssemblyReferences)
            {
                var displayName = MetadataHelpers.GetAssemblyDisplayName(Reader, Reader.GetAssemblyReference(handle));

                assemblyNames[MetadataTokens.GetRowNumber(handle)] = displayName;
                assemblyRefsByName.Add(displayName, handle);
            }

            return(ValueTuple.Create(assemblyRefsByName, assemblyNames));
        }
        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);
                    }
        }