Example #1
0
        private ChecksumAlgorithmType ChecksumAlgorithmForFullPdb()
        {
            string fileName  = Path.GetFileName(this.FileName);
            string extension = Path.GetExtension(fileName);
            string pdbPath   = this.FileName.Replace(fileName, fileName.Replace(extension, ".pdb"));

            if (!File.Exists(pdbPath))
            {
                return(ChecksumAlgorithmType.Unknown);
            }

            using var pdbStream = new FileStream(pdbPath, FileMode.Open, FileAccess.Read);

            var    metadataProvider     = new SymMetadataProvider(this.metadataReader);
            object importer             = SymUnmanagedReaderFactory.CreateSymReaderMetadataImport(metadataProvider);
            ISymUnmanagedReader3 reader = SymUnmanagedReaderFactory.CreateReaderWithMetadataImport <ISymUnmanagedReader3>(pdbStream, importer, SymUnmanagedReaderCreationOptions.UseComRegistry);

            try
            {
                Guid algorithm = Guid.Empty;
                foreach (ISymUnmanagedDocument document in reader.GetDocuments())
                {
                    document.GetChecksumAlgorithmId(ref algorithm);
                    return(algorithm == sha256guid ? ChecksumAlgorithmType.Sha256 : ChecksumAlgorithmType.Sha1);
                }
            }
            finally
            {
                _ = ((ISymUnmanagedDispose)reader).Destroy();
            }

            return(ChecksumAlgorithmType.Unknown);
        }
        private static void ReadCSharpNativeCustomDebugInfo(
            ISymUnmanagedReader3 reader,
            int methodToken,
            int methodVersion,
            IEnumerable <ISymUnmanagedScope> scopes,
            out ImmutableArray <HoistedLocalScopeRecord> hoistedLocalScopeRecords,
            out ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap,
            out ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap)
        {
            hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty;
            dynamicLocalMap          = ImmutableDictionary <int, ImmutableArray <bool> > .Empty;
            dynamicLocalConstantMap  = ImmutableDictionary <string, ImmutableArray <bool> > .Empty;

            byte[] customDebugInfoBytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion);
            if (customDebugInfoBytes == null)
            {
                return;
            }

            var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBytes, CustomDebugInfoKind.StateMachineHoistedLocalScopes);

            if (!customDebugInfoRecord.IsDefault)
            {
                hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord)
                                           .SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.EndOffset - s.StartOffset + 1));
            }

            CustomDebugInfoReader.GetCSharpDynamicLocalInfo(
                customDebugInfoBytes,
                methodToken,
                methodVersion,
                scopes,
                out dynamicLocalMap,
                out dynamicLocalConstantMap);
        }
Example #3
0
 public static byte[] GetCustomDebugInfoBytes(
     ISymUnmanagedReader3 reader,
     MethodDefinitionHandle handle,
     int methodVersion
     )
 {
     return(reader.GetCustomDebugInfo(MetadataTokens.GetToken(handle), methodVersion));
 }
Example #4
0
        public static void Initialize(this ISymUnmanagedReader3 reader, Stream stream, object metadataImporter, string fileName = null, string searchPath = null)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            ThrowExceptionForHR(reader.Initialize(metadataImporter, fileName, searchPath, SymUnmanagedStreamFactory.CreateStream(stream)));
        }
Example #5
0
        public static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(this ISymUnmanagedReader3 symReader, MethodDefinitionHandle handle)
        {
            var cdi = CustomDebugInfoUtilities.GetCustomDebugInfoBytes(symReader, handle, methodVersion: 1);

            if (cdi == null)
            {
                return(EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), default(ImmutableArray <byte>)));
            }

            return(GetEncMethodDebugInfo(cdi));
        }
 /// <summary>
 /// Get the blob of binary custom debug info for a given method.
 /// </summary>
 private static byte[] GetCustomDebugInfoBytes(ISymUnmanagedReader3 reader, int methodToken, int methodVersion)
 {
     try
     {
         return(reader.GetCustomDebugInfo(methodToken, methodVersion));
     }
     catch (ArgumentOutOfRangeException)
     {
         // Sometimes the debugger returns the HRESULT for ArgumentOutOfRangeException, rather than E_FAIL,
         // for methods without custom debug info (https://github.com/dotnet/roslyn/issues/4138).
         return(null);
     }
 }
Example #7
0
        public static unsafe EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(
            this ISymUnmanagedReader3 symReader,
            MethodDefinitionHandle handle
            )
        {
            const int S_OK = 0;

            if (symReader is ISymUnmanagedReader4 symReader4)
            {
                int hr = symReader4.GetPortableDebugMetadata(out byte *metadata, out int size);
                Marshal.ThrowExceptionForHR(hr);

                if (hr == S_OK)
                {
                    var pdbReader = new MetadataReader(metadata, size);

                    ImmutableArray <byte> GetCdiBytes(Guid kind) =>
                    TryGetCustomDebugInformation(pdbReader, handle, kind, out var info)
                          ? pdbReader.GetBlobContent(info.Value)
                          : default(ImmutableArray <byte>);

                    return(EditAndContinueMethodDebugInformation.Create(
                               compressedSlotMap: GetCdiBytes(
                                   PortableCustomDebugInfoKinds.EncLocalSlotMap
                                   ),
                               compressedLambdaMap: GetCdiBytes(
                                   PortableCustomDebugInfoKinds.EncLambdaAndClosureMap
                                   )
                               ));
                }
            }

            var cdi = CustomDebugInfoUtilities.GetCustomDebugInfoBytes(
                symReader,
                handle,
                methodVersion: 1
                );

            if (cdi == null)
            {
                return(EditAndContinueMethodDebugInformation.Create(
                           default(ImmutableArray <byte>),
                           default(ImmutableArray <byte>)
                           ));
            }

            return(GetEncMethodDebugInfo(cdi));
        }
        private static void ReadCSharpNativeImportsInfo(
            ISymUnmanagedReader3 reader,
            EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProvider,
            int methodToken,
            int methodVersion,
            out ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups,
            out ImmutableArray <ExternAliasRecord> externAliasRecords)
        {
            ImmutableArray <string> externAliasStrings;

            var importStringGroups = CustomDebugInfoReader.GetCSharpGroupedImportStrings(
                methodToken,
                KeyValuePair.Create(reader, methodVersion),
                getMethodCustomDebugInfo: (token, arg) => GetCustomDebugInfoBytes(arg.Key, token, arg.Value),
                getMethodImportStrings: (token, arg) => GetImportStrings(arg.Key, token, arg.Value),
                externAliasStrings: out externAliasStrings);

            Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault);

            ArrayBuilder <ImmutableArray <ImportRecord> > importRecordGroupBuilder = null;
            ArrayBuilder <ExternAliasRecord> externAliasRecordBuilder = null;

            if (!importStringGroups.IsDefault)
            {
                importRecordGroupBuilder = ArrayBuilder <ImmutableArray <ImportRecord> > .GetInstance(importStringGroups.Length);

                foreach (var importStringGroup in importStringGroups)
                {
                    var groupBuilder = ArrayBuilder <ImportRecord> .GetInstance(importStringGroup.Length);

                    foreach (var importString in importStringGroup)
                    {
                        ImportRecord record;
                        if (TryCreateImportRecordFromCSharpImportString(symbolProvider, importString, out record))
                        {
                            groupBuilder.Add(record);
                        }
                        else
                        {
                            Debug.WriteLine($"Failed to parse import string {importString}");
                        }
                    }
                    importRecordGroupBuilder.Add(groupBuilder.ToImmutableAndFree());
                }

                if (!externAliasStrings.IsDefault)
                {
                    externAliasRecordBuilder = ArrayBuilder <ExternAliasRecord> .GetInstance(externAliasStrings.Length);

                    foreach (string externAliasString in externAliasStrings)
                    {
                        string           alias;
                        string           externAlias;
                        string           target;
                        ImportTargetKind kind;
                        if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind))
                        {
                            Debug.WriteLine($"Unable to parse extern alias '{externAliasString}'");
                            continue;
                        }

                        Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?");
                        Debug.Assert(alias != null);       // Name of the extern alias.
                        Debug.Assert(externAlias == null); // Not used.
                        Debug.Assert(target != null);      // Name of the target assembly.

                        AssemblyIdentity targetIdentity;
                        if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity))
                        {
                            Debug.WriteLine($"Unable to parse target of extern alias '{externAliasString}'");
                            continue;
                        }

                        externAliasRecordBuilder.Add(new ExternAliasRecord(alias, targetIdentity));
                    }
                }
            }

            importRecordGroups = importRecordGroupBuilder?.ToImmutableAndFree() ?? ImmutableArray <ImmutableArray <ImportRecord> > .Empty;
            externAliasRecords = externAliasRecordBuilder?.ToImmutableAndFree() ?? ImmutableArray <ExternAliasRecord> .Empty;
        }
        private static ImmutableArray <string> GetImportStrings(int token, Dictionary <int, ImmutableArray <string> > cache, ISymUnmanagedReader3 reader)
        {
            ImmutableArray <string> result;

            if (!cache.TryGetValue(token, out result))
            {
                result = SymReaderHelpers.GetImportStrings(reader, token, methodVersion: 1);
                cache.Add(token, result);
            }

            return(result);
        }
 public static byte[] GetCustomDebugInfoBytes(ISymUnmanagedReader3 reader, MethodDefinitionHandle handle, int methodVersion)
 {
     return reader.GetCustomDebugInfoBytes(MetadataTokens.GetToken(handle), methodVersion);
 }
Example #11
0
        public FullPdbReader(Stream pdbStream)
        {
            pdbStream.Position = 0;

            _symReader = CreateNativeSymReader(pdbStream);
        }
Example #12
0
        public FullPdbReader(Stream pdbStream)
        {
            pdbStream.Position = 0;

            _symReader = CreateNativeSymReader(pdbStream);
        }
        /// <summary>
        /// Returns EnC debug information for initial version of the specified method.
        /// </summary>
        /// <exception cref="InvalidDataException">The debug information data is corrupt or can't be retrieved from the debugger.</exception>
        private EditAndContinueMethodDebugInformation GetBaselineEncDebugInfo(MethodDefinitionHandle methodHandle)
        {
            Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);
            if (_pdbReader == null)
            {
                // Unmarshal the symbol reader (being marshalled cross thread from STA -> MTA).
                Debug.Assert(_pdbReaderObjAsStream != IntPtr.Zero);
                object pdbReaderObjMta;

                var exception = Marshal.GetExceptionForHR(NativeMethods.GetObjectForStream(_pdbReaderObjAsStream, out pdbReaderObjMta));
                if (exception != null)
                {
                    // likely a bug in the compiler/debugger
                    FatalError.ReportWithoutCrash(exception); 

                    throw new InvalidDataException(exception.Message, exception);
                }

                _pdbReaderObjAsStream = IntPtr.Zero;
                _pdbReader = (ISymUnmanagedReader3)pdbReaderObjMta;
            }

            int methodToken = MetadataTokens.GetToken(methodHandle);

            byte[] debugInfo;
            try
            {
                debugInfo = _pdbReader.GetCustomDebugInfoBytes(methodToken, methodVersion: 1);
            }
            catch (Exception e) when (FatalError.ReportWithoutCrash(e)) // likely a bug in the compiler/debugger
            {
                throw new InvalidDataException(e.Message, e);
            }

            try
            {
                ImmutableArray<byte> localSlots, lambdaMap;
                if (debugInfo != null)
                {
                    localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLocalSlotMap);
                    lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLambdaMap);
                }
                else
                {
                    localSlots = lambdaMap = default(ImmutableArray<byte>);
                }

                return EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap);
            }
            catch (InvalidOperationException e) when (FatalError.ReportWithoutCrash(e)) // likely a bug in the compiler/debugger
            {
                // TODO: CustomDebugInfoReader should throw InvalidDataException
                throw new InvalidDataException(e.Message, e);
            }
        }
        public unsafe static MethodDebugInfo <TTypeSymbol, TLocalSymbol> ReadMethodDebugInfo(
            ISymUnmanagedReader3 symReader,
            EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProviderOpt, // TODO: only null in DTEE case where we looking for default namesapace
            int methodToken,
            int methodVersion,
            int ilOffset,
            bool isVisualBasicMethod)
        {
            // no symbols
            if (symReader == null)
            {
                return(None);
            }

            var symReader4 = symReader as ISymUnmanagedReader4;

            if (symReader4 != null) // TODO: VB Portable PDBs
            {
                byte *metadata;
                int   size;

                // TODO: version
                int hr = symReader4.GetPortableDebugMetadata(out metadata, out size);
                SymUnmanagedReaderExtensions.ThrowExceptionForHR(hr);

                if (metadata != null)
                {
                    var mdReader = new MetadataReader(metadata, size);
                    try
                    {
                        return(ReadFromPortable(mdReader, methodToken, ilOffset, symbolProviderOpt, isVisualBasicMethod));
                    }
                    catch (BadImageFormatException)
                    {
                        // bad CDI, ignore
                        return(None);
                    }
                }
            }

            var allScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance();

            var containingScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance();

            try
            {
                ImmutableArray <HoistedLocalScopeRecord>        hoistedLocalScopeRecords;
                ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups;
                ImmutableArray <ExternAliasRecord> externAliasRecords;
                ImmutableDictionary <int, ImmutableArray <bool> >    dynamicLocalMap;
                ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap;
                string defaultNamespaceName;

                var symMethod = symReader.GetMethodByVersion(methodToken, methodVersion);
                if (symMethod != null)
                {
                    symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive: isVisualBasicMethod);
                }

                if (isVisualBasicMethod)
                {
                    ReadVisualBasicImportsDebugInfo(
                        symReader,
                        methodToken,
                        methodVersion,
                        out importRecordGroups,
                        out defaultNamespaceName);

                    hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty;
                    externAliasRecords       = ImmutableArray <ExternAliasRecord> .Empty;
                    dynamicLocalMap          = null;
                    dynamicLocalConstantMap  = null;
                }
                else
                {
                    Debug.Assert(symbolProviderOpt != null);

                    ReadCSharpNativeImportsInfo(
                        symReader,
                        symbolProviderOpt,
                        methodToken,
                        methodVersion,
                        out importRecordGroups,
                        out externAliasRecords);

                    ReadCSharpNativeCustomDebugInfo(
                        symReader,
                        methodToken,
                        methodVersion,
                        allScopes,
                        out hoistedLocalScopeRecords,
                        out dynamicLocalMap,
                        out dynamicLocalConstantMap);

                    defaultNamespaceName = "";
                }

                var constantsBuilder = ArrayBuilder <TLocalSymbol> .GetInstance();

                if (symbolProviderOpt != null) // TODO
                {
                    GetConstants(constantsBuilder, symbolProviderOpt, containingScopes, dynamicLocalConstantMap);
                }

                var reuseSpan = GetReuseSpan(allScopes, ilOffset, isVisualBasicMethod);

                return(new MethodDebugInfo <TTypeSymbol, TLocalSymbol>(
                           hoistedLocalScopeRecords,
                           importRecordGroups,
                           externAliasRecords,
                           dynamicLocalMap,
                           defaultNamespaceName,
                           containingScopes.GetLocalNames(),
                           constantsBuilder.ToImmutableAndFree(),
                           reuseSpan));
            }
            catch (InvalidOperationException)
            {
                // bad CDI, ignore
                return(None);
            }
            finally
            {
                allScopes.Free();
                containingScopes.Free();
            }
        }
Example #15
0
        /// <summary>
        /// Get the import strings for a given method, following forward pointers as necessary.
        /// </summary>
        /// <returns>
        /// For each namespace enclosing the method, a list of import strings, innermost to outermost.
        /// There should always be at least one entry, for the global namespace.
        /// </returns>
        public static ImmutableArray <ImmutableArray <string> > GetCSharpGroupedImportStrings(this ISymUnmanagedReader3 reader, int methodToken, int methodVersion, out ImmutableArray <string> externAliasStrings)
        {
            externAliasStrings = default(ImmutableArray <string>);

            ImmutableArray <short> groupSizes = default(ImmutableArray <short>);
            bool seenForward = false;

RETRY:
            byte[] bytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion);
            if (bytes == null)
            {
                return(default(ImmutableArray <ImmutableArray <string> >));
            }

            foreach (var record in GetCustomDebugInfoRecords(bytes))
            {
                switch (record.Kind)
                {
                case CustomDebugInfoKind.UsingInfo:
                    if (!groupSizes.IsDefault)
                    {
                        throw new InvalidOperationException(string.Format("Expected at most one Using record for method {0}", FormatMethodToken(methodToken)));
                    }

                    groupSizes = DecodeUsingRecord(record.Data);
                    break;

                case CustomDebugInfoKind.ForwardInfo:
                    if (!externAliasStrings.IsDefault)
                    {
                        throw new InvalidOperationException(string.Format("Did not expect both Forward and ForwardToModule records for method {0}", FormatMethodToken(methodToken)));
                    }

                    methodToken = DecodeForwardRecord(record.Data);

                    // Follow at most one forward link (as in FUNCBRECEE::ensureNamespaces).
                    // NOTE: Dev11 may produce chains of forward links (e.g. for System.Collections.Immutable).
                    if (!seenForward)
                    {
                        seenForward = true;
                        goto RETRY;
                    }

                    break;

                case CustomDebugInfoKind.ForwardToModuleInfo:
                    if (!externAliasStrings.IsDefault)
                    {
                        throw new InvalidOperationException(string.Format("Expected at most one ForwardToModule record for method {0}", FormatMethodToken(methodToken)));
                    }

                    int moduleInfoMethodToken = DecodeForwardToModuleRecord(record.Data);
                    ImmutableArray <string> allModuleInfoImportStrings = reader.GetMethodByVersion(moduleInfoMethodToken, methodVersion).GetImportStrings();
                    ArrayBuilder <string>   externAliasBuilder         = ArrayBuilder <string> .GetInstance();

                    foreach (string importString in allModuleInfoImportStrings)
                    {
                        if (IsCSharpExternAliasInfo(importString))
                        {
                            externAliasBuilder.Add(importString);
                        }
                    }

                    externAliasStrings = externAliasBuilder.ToImmutableAndFree();
                    break;
                }
            }

            if (groupSizes.IsDefault)
            {
                // This can happen in malformed PDBs (e.g. chains of forwards).
                return(default(ImmutableArray <ImmutableArray <string> >));
            }

            var method = reader.GetMethodByVersion(methodToken, methodVersion);

            if (method == null)
            {
                return(default(ImmutableArray <ImmutableArray <string> >));
            }

            ImmutableArray <string> importStrings = method.GetImportStrings();
            int numImportStrings = importStrings.Length;

            ArrayBuilder <ImmutableArray <string> > resultBuilder = ArrayBuilder <ImmutableArray <string> > .GetInstance(groupSizes.Length);

            ArrayBuilder <string> groupBuilder = ArrayBuilder <string> .GetInstance();

            int pos = 0;

            foreach (short groupSize in groupSizes)
            {
                for (int i = 0; i < groupSize; i++, pos++)
                {
                    if (pos >= numImportStrings)
                    {
                        throw new InvalidOperationException(string.Format("Group size indicates more imports than there are import strings (method {0}).", FormatMethodToken(methodToken)));
                    }

                    string importString = importStrings[pos];
                    if (IsCSharpExternAliasInfo(importString))
                    {
                        throw new InvalidOperationException(string.Format("Encountered extern alias info before all import strings were consumed (method {0}).", FormatMethodToken(methodToken)));
                    }

                    groupBuilder.Add(importString);
                }

                resultBuilder.Add(groupBuilder.ToImmutable());
                groupBuilder.Clear();
            }

            if (externAliasStrings.IsDefault)
            {
                Debug.Assert(groupBuilder.Count == 0);

                // Extern alias detail strings (prefix "Z") are not included in the group counts.
                for (; pos < numImportStrings; pos++)
                {
                    string importString = importStrings[pos];
                    if (!IsCSharpExternAliasInfo(importString))
                    {
                        throw new InvalidOperationException(string.Format("Expected only extern alias info strings after consuming the indicated number of imports (method {0}).", FormatMethodToken(methodToken)));
                    }

                    groupBuilder.Add(importString);
                }

                externAliasStrings = groupBuilder.ToImmutableAndFree();
            }
            else
            {
                groupBuilder.Free();

                if (pos < numImportStrings)
                {
                    throw new InvalidOperationException(string.Format("Group size indicates fewer imports than there are import strings (method {0}).", FormatMethodToken(methodToken)));
                }
            }

            return(resultBuilder.ToImmutableAndFree());
        }
        public unsafe static MethodDebugInfo <TTypeSymbol, TLocalSymbol> ReadMethodDebugInfo(
            ISymUnmanagedReader3 symReader,
            EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProviderOpt, // TODO: only null in DTEE case where we looking for default namesapace
            int methodToken,
            int methodVersion,
            int ilOffset,
            bool isVisualBasicMethod)
        {
            // no symbols
            if (symReader == null)
            {
                return(None);
            }

            if (symReader is ISymUnmanagedReader5 symReader5)
            {
                int hr = symReader5.GetPortableDebugMetadataByVersion(methodVersion, out byte *metadata, out int size);
                ThrowExceptionForHR(hr);

                if (hr == S_OK)
                {
                    var mdReader = new MetadataReader(metadata, size);
                    try
                    {
                        return(ReadFromPortable(mdReader, methodToken, ilOffset, symbolProviderOpt, isVisualBasicMethod));
                    }
                    catch (BadImageFormatException)
                    {
                        // bad CDI, ignore
                        return(None);
                    }
                }
            }

            var allScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance();

            var containingScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance();

            try
            {
                var symMethod = symReader.GetMethodByVersion(methodToken, methodVersion);
                if (symMethod != null)
                {
                    symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive: isVisualBasicMethod);
                }

                ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups;
                ImmutableArray <ExternAliasRecord> externAliasRecords;
                string defaultNamespaceName;

                if (isVisualBasicMethod)
                {
                    ReadVisualBasicImportsDebugInfo(
                        symReader,
                        methodToken,
                        methodVersion,
                        out importRecordGroups,
                        out defaultNamespaceName);

                    externAliasRecords = ImmutableArray <ExternAliasRecord> .Empty;
                }
                else
                {
                    Debug.Assert(symbolProviderOpt != null);

                    ReadCSharpNativeImportsInfo(
                        symReader,
                        symbolProviderOpt,
                        methodToken,
                        methodVersion,
                        out importRecordGroups,
                        out externAliasRecords);

                    defaultNamespaceName = "";
                }

                // VB should read hoisted scope information from local variables:
                var hoistedLocalScopeRecords = isVisualBasicMethod ?
                                               default(ImmutableArray <HoistedLocalScopeRecord>) :
                                               ImmutableArray <HoistedLocalScopeRecord> .Empty;

                ImmutableDictionary <int, ImmutableArray <bool> >    dynamicLocalMap                    = null;
                ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap            = null;
                ImmutableDictionary <int, ImmutableArray <string> >  tupleLocalMap                      = null;
                ImmutableDictionary <LocalNameAndScope, ImmutableArray <string> > tupleLocalConstantMap = null;

                byte[] customDebugInfo = GetCustomDebugInfoBytes(symReader, methodToken, methodVersion);
                if (customDebugInfo != null)
                {
                    if (!isVisualBasicMethod)
                    {
                        var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.StateMachineHoistedLocalScopes);
                        if (!customDebugInfoRecord.IsDefault)
                        {
                            hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord)
                                                       .SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.Length));
                        }

                        GetCSharpDynamicLocalInfo(
                            customDebugInfo,
                            allScopes,
                            out dynamicLocalMap,
                            out dynamicLocalConstantMap);
                    }

                    GetTupleElementNamesLocalInfo(
                        customDebugInfo,
                        out tupleLocalMap,
                        out tupleLocalConstantMap);
                }

                var constantsBuilder = ArrayBuilder <TLocalSymbol> .GetInstance();

                if (symbolProviderOpt != null) // TODO
                {
                    GetConstants(constantsBuilder, symbolProviderOpt, containingScopes, dynamicLocalConstantMap, tupleLocalConstantMap);
                }

                var reuseSpan = GetReuseSpan(allScopes, ilOffset, isVisualBasicMethod);

                return(new MethodDebugInfo <TTypeSymbol, TLocalSymbol>(
                           hoistedLocalScopeRecords,
                           importRecordGroups,
                           externAliasRecords,
                           dynamicLocalMap,
                           tupleLocalMap,
                           defaultNamespaceName,
                           containingScopes.GetLocalNames(),
                           constantsBuilder.ToImmutableAndFree(),
                           reuseSpan));
            }
            catch (InvalidOperationException)
            {
                // bad CDI, ignore
                return(None);
            }
            finally
            {
                allScopes.Free();
                containingScopes.Free();
            }
        }
        public int StopDebuggingPE()
        {
            try
            {
                log.Write("Exit Debug Mode: project '{0}'", _vsProject.DisplayName);
                Debug.Assert(s_breakStateEnteredProjects.Count == 0);

                // Clear the solution stored while projects were entering break mode. 
                // It should be cleared as soon as all tracked projects enter the break mode 
                // but if the entering break mode fails for some projects we should avoid leaking the solution.
                Debug.Assert(s_breakStateEntrySolution == null);
                s_breakStateEntrySolution = null;

                // EnC service is global (per solution), but the debugger calls this for each project.
                // Avoid ending the debug session if it has already been ended.
                if (_encService.DebuggingSession != null)
                {
                    _encService.OnBeforeDebuggingStateChanged(DebuggingState.Run, DebuggingState.Design);

                    _encService.EndDebuggingSession();
                    LogEncSession();

                    s_encDebuggingSessionInfo = null;
                    s_readOnlyDocumentTracker.Dispose();
                    s_readOnlyDocumentTracker = null;
                }

                if (_metadata != null)
                {
                    _metadata.Dispose();
                    _metadata = null;

                    s_debugStateProjectCount--;
                }
                else
                {
                    // an error might have been reported:
                    var errorId = new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId);
                    _diagnosticProvider.ClearDiagnostics(errorId, _vsProject.Workspace.CurrentSolution, _vsProject.Id, documentIdOpt: null);
                }

                _activeMethods = null;
                _exceptionRegions = null;
                _committedBaseline = null;
                _activeStatementIds = null;
                _projectBeingEmitted = null;

                Debug.Assert((_pdbReaderObjAsStream == IntPtr.Zero) || (_pdbReader == null));

                if (_pdbReader != null)
                {
                    Marshal.ReleaseComObject(_pdbReader);
                    _pdbReader = null;
                }

                // The HResult is ignored by the debugger.
                return VSConstants.S_OK;
            }
            catch (Exception e) when (FatalError.ReportWithoutCrash(e))
            {
                return VSConstants.E_FAIL;
            }
        }
        private EditAndContinueMethodDebugInformation GetBaselineEncDebugInfo(MethodDefinitionHandle methodHandle)
        {
            Debug.Assert(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA);

            if (_pdbReader == null)
            {
                // Unmarshal the symbol reader (being marshalled cross thread from STA -> MTA).
                Debug.Assert(_pdbReaderObjAsStream != IntPtr.Zero);
                object pdbReaderObjMta;
                int hr = NativeMethods.GetObjectForStream(_pdbReaderObjAsStream, out pdbReaderObjMta);
                _pdbReaderObjAsStream = IntPtr.Zero;
                if (hr != VSConstants.S_OK)
                {
                    log.Write("Error unmarshaling object from stream.");
                    return default(EditAndContinueMethodDebugInformation);
                }
                _pdbReader = (ISymUnmanagedReader3)pdbReaderObjMta;
            }

            int methodToken = MetadataTokens.GetToken(methodHandle);
            byte[] debugInfo = _pdbReader.GetCustomDebugInfoBytes(methodToken, methodVersion: 1);
            if (debugInfo != null)
            {
                try
                {
                    var localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLocalSlotMap);
                    var lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLambdaMap);
                    return EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap);
                }
                catch (Exception e) when (e is InvalidOperationException || e is InvalidDataException)
                {
                    log.Write($"Error reading CDI of method 0x{methodToken:X8}: {e.Message}");
                }
            }

            return default(EditAndContinueMethodDebugInformation);
        }