private BlobReader GetCustomDebugInformationBlobReader(Guid infoGuid)
        {
            var blobs = from cdiHandle in _metadataReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition)
                        let cdi = _metadataReader.GetCustomDebugInformation(cdiHandle)
                                  where _metadataReader.GetGuid(cdi.Kind) == infoGuid
                                  select _metadataReader.GetBlobReader(cdi.Value);

            if (blobs.Any())
            {
                return(blobs.Single());
            }

            throw new InvalidDataException($"No blob found for {infoGuid}");
        }
Example #2
0
        internal static BlobHandle GetCustomDebugInformation(this MetadataReader reader, EntityHandle parent, Guid kind)
        {
            foreach (var cdiHandle in reader.GetCustomDebugInformation(parent))
            {
                var cdi = reader.GetCustomDebugInformation(cdiHandle);
                if (reader.GetGuid(cdi.Kind) == kind)
                {
                    // return the first record
                    return(cdi.Value);
                }
            }

            return(default(BlobHandle));
        }
        /// <exception cref="BadImageFormatException">Invalid data format.</exception>
        private static ImmutableArray <bool> ReadDynamicCustomDebugInformation(MetadataReader reader, EntityHandle variableOrConstantHandle)
        {
            foreach (var infoHandle in reader.GetCustomDebugInformation(variableOrConstantHandle))
            {
                var info = reader.GetCustomDebugInformation(infoHandle);
                var id   = reader.GetGuid(info.Kind);
                if (id == PortableCustomDebugInfoKinds.DynamicLocalVariables)
                {
                    return(DecodeDynamicFlags(reader.GetBlobReader(info.Value)));
                }
            }

            return(default(ImmutableArray <bool>));
        }
Example #4
0
        /// <summary>
        /// Unpacks all files stored in a PortablePDB meta-data. The key in the dictionary is the location of a source file
        /// on the build machine. The value is the content of the source file itself.
        /// The function will throw an exception if PortablePDB file is not found or anything else went wrong.
        /// </summary>
        /// <param name="pdbFilePath">Path to PortablePDB file to load source files from.</param>
        public static Dictionary <string, CompressedSourceFile> GetEmbeddedFiles(string pdbFilePath)
        {
            Dictionary <string, CompressedSourceFile> embeddedFiles = new Dictionary <string, CompressedSourceFile>();

            using (FileStream stream = File.OpenRead(pdbFilePath))
                using (MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream))
                {
                    MetadataReader metadataReader = metadataReaderProvider.GetMetadataReader();
                    CustomDebugInformationHandleCollection customDebugInformationHandles = metadataReader.CustomDebugInformation;
                    foreach (var customDebugInformationHandle in customDebugInformationHandles)
                    {
                        CustomDebugInformation customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle);
                        if (metadataReader.GetGuid(customDebugInformation.Kind) == EmbeddedSource)
                        {
                            byte[] embeddedSource             = metadataReader.GetBlobBytes(customDebugInformation.Value);
                            Int32  uncompressedSourceFileSize = BitConverter.ToInt32(embeddedSource, 0);
                            if (uncompressedSourceFileSize != 0)
                            {
                                Document document       = metadataReader.GetDocument((DocumentHandle)customDebugInformation.Parent);
                                string   sourceFileName = System.IO.Path.GetFullPath(metadataReader.GetString(document.Name));
                                embeddedFiles.Add(sourceFileName, new CompressedSourceFile(embeddedSource));
                            }
                        }
                    }
                }
            return(embeddedFiles);
        }
Example #5
0
        private byte[]? TryGetEmbeddedTextBytes(DocumentHandle handle)
        {
            var handles = _pdbReader.GetCustomDebugInformation(handle);

            foreach (var cdiHandle in handles)
            {
                var cdi  = _pdbReader.GetCustomDebugInformation(cdiHandle);
                var guid = _pdbReader.GetGuid(cdi.Kind);
                if (guid == PortableCustomDebugInfoKinds.EmbeddedSource)
                {
                    return(_pdbReader.GetBlobBytes(cdi.Value));
                }
            }

            return(null);
        }
Example #6
0
 public static ImmutableArray <byte> GetSourceLinkBlob(this MetadataReader reader)
 {
     return((from handle in reader.CustomDebugInformation
             let cdi = reader.GetCustomDebugInformation(handle)
                       where reader.GetGuid(cdi.Kind) == PortableCustomDebugInfoKinds.SourceLink
                       select reader.GetBlobContent(cdi.Value)).Single());
 }
Example #7
0
        private static bool TryMapPortablePdb(Module module, out MetadataReaderProvider metadataReaderProvider)
        {
            metadataReaderProvider = null;
            MetadataReader rd = null;

            try
            {
                metadataReaderProvider = GetMetadataReaderProvider(module);
                rd = metadataReaderProvider?.GetMetadataReader();
            }
            catch (BadImageFormatException ex) when(ex.Message == "Invalid COR20 header signature.")
            {
                TraceSourceLink("no portable PDB found: " + module.FullyQualifiedName);
                // todo figure out a better way to detect if PDB is portable or classic
                // https://github.com/dotnet/corefx/blob/06b1365d9881ed26a921490d7edd2d4e4de35565/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs#L185
            }
            if (rd == null)
            {
                metadataReaderProvider?.Dispose();
                metadataReaderProvider = null;
                return(false);
            }

            TraceSourceLink("found portable PDB for: " + module.FullyQualifiedName);

            // https://github.com/dotnet/symreader-portable/blob/d27c08d6015c4716ced790e34233c0219773ab10/src/Microsoft.DiaSymReader.PortablePdb/Utilities/MetadataUtilities.cs
            var sourceLinkHandles = rd
                                    .GetCustomDebugInformation(EntityHandle.ModuleDefinition)
                                    .Where(r => !r.IsNil)
                                    .Select(rd.GetCustomDebugInformation)
                                    .Where(cdi => !cdi.Value.IsNil && rd.GetGuid(cdi.Kind) == SourceLinkId)
                                    .ToList();

            if (sourceLinkHandles.Count == 0)
            {
                metadataReaderProvider?.Dispose();
                metadataReaderProvider = null;
                return(false);
            }
            var sourceLinkHandle = sourceLinkHandles.First();
            var sourceLink       = SourceLink.Deserialize(rd.GetBlobBytes(sourceLinkHandle.Value));

            var hinstance = (long)Marshal.GetHINSTANCE(module);

            foreach (var dh in rd.Documents)
            {
                if (dh.IsNil)
                {
                    continue;
                }
                var doc = rd.GetDocument(dh);

                var file = rd.GetString(doc.Name);
                SourceMappedPaths[Tuple.Create(hinstance, file)] = sourceLink.GetUrl(file);
            }

            return(true);
        }
        /// <exception cref="BadImageFormatException">Invalid data format.</exception>
        private static void ReadMethodCustomDebugInformation(
            MetadataReader reader,
            MethodDefinitionHandle methodHandle,
            out ImmutableArray <HoistedLocalScopeRecord> hoistedLocalScopes,
            out string defaultNamespace)
        {
            hoistedLocalScopes = ImmutableArray <HoistedLocalScopeRecord> .Empty;

            foreach (var infoHandle in reader.GetCustomDebugInformation(methodHandle))
            {
                var info = reader.GetCustomDebugInformation(infoHandle);
                var id   = reader.GetGuid(info.Kind);
                if (id == PortableCustomDebugInfoKinds.StateMachineHoistedLocalScopes)
                {
                    // only single CDIof this kind is allowed on a method:
                    if (!hoistedLocalScopes.IsEmpty)
                    {
                        throw new BadImageFormatException();
                    }

                    hoistedLocalScopes = DecodeHoistedLocalScopes(reader.GetBlobReader(info.Value));
                }
            }

            // TODO: consider looking this up once per module (not for every method)
            defaultNamespace = null;
            foreach (var infoHandle in reader.GetCustomDebugInformation(EntityHandle.ModuleDefinition))
            {
                var info = reader.GetCustomDebugInformation(infoHandle);
                var id   = reader.GetGuid(info.Kind);
                if (id == PortableCustomDebugInfoKinds.DefaultNamespace)
                {
                    // only single CDI of this kind is allowed on the module:
                    if (defaultNamespace != null)
                    {
                        throw new BadImageFormatException();
                    }

                    var valueReader = reader.GetBlobReader(info.Value);
                    defaultNamespace = valueReader.ReadUTF8(valueReader.Length);
                }
            }

            defaultNamespace = defaultNamespace ?? "";
        }
 public CustomDebugInformationEntry(PEFile module, MetadataReader metadata, bool isEmbedded, CustomDebugInformationHandle handle)
 {
     this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.CustomDebugInformation)
                   + metadata.GetTableRowSize(TableIndex.CustomDebugInformation) * (MetadataTokens.GetRowNumber(handle) - 1);
     this.module    = module;
     this.metadata  = metadata;
     this.handle    = handle;
     this.debugInfo = metadata.GetCustomDebugInformation(handle);
 }
Example #10
0
        private SourceText?TryGetEmbeddedSourceText(DocumentHandle handle)
        {
            var handles = _pdbReader.GetCustomDebugInformation(handle);

            foreach (var cdiHandle in handles)
            {
                var cdi  = _pdbReader.GetCustomDebugInformation(cdiHandle);
                var guid = _pdbReader.GetGuid(cdi.Kind);
                if (guid == PortableCustomDebugInfoKinds.EmbeddedSource)
                {
                    var blob = _pdbReader.GetBlobBytes(cdi.Value);
                    if (blob is not null)
                    {
                        var uncompressedSize = BitConverter.ToInt32(blob, 0);
                        var stream           = new MemoryStream(blob, sizeof(int), blob.Length - sizeof(int));

                        if (uncompressedSize != 0)
                        {
                            var decompressed = new MemoryStream(uncompressedSize);

                            using (var deflater = new DeflateStream(stream, CompressionMode.Decompress))
                            {
                                deflater.CopyTo(decompressed);
                            }

                            if (decompressed.Length != uncompressedSize)
                            {
                                return(null);
                            }

                            stream = decompressed;
                        }

                        using (stream)
                        {
                            return(EncodedStringText.Create(stream));
                        }
                    }
                }
            }

            return(null);
        }
Example #11
0
        private bool AddTypeDocumentsInCustomDebugInformation(TypeDefinitionHandle typeHandle, MetadataReader pdbReader, List <DocumentHandle> docList)
        {
            foreach (var handle in pdbReader.GetCustomDebugInformation(typeHandle))
            {
                var typeId = pdbReader.GetCustomDebugInformation(handle).Parent;

                if (((TypeDefinitionHandle)typeId).Equals(typeHandle))
                {
                    var blob   = pdbReader.GetCustomDebugInformation(handle).Value;
                    var reader = pdbReader.GetBlobReader(blob);
                    while (reader.RemainingBytes > 0)
                    {
                        docList.Add(MetadataTokens.DocumentHandle(reader.ReadCompressedInteger()));
                    }
                    return(true);
                }
            }
            return(false);
        }
        private IReadOnlyList <SourceLinkMap> GetSourceLinkInformation()
        {
            var sl = (from cdi in _reader.CustomDebugInformation
                      let cd = _reader.GetCustomDebugInformation(cdi)
                               let kind = _reader.GetGuid(cd.Kind)
                                          where kind == SourceLinkGuid
                                          let bl = _reader.GetBlobBytes(cd.Value)
                                                   select Encoding.UTF8.GetString(bl))
                     .FirstOrDefault();

            if (sl != null)
            {
                try
                {
                    /* Some tools, like GitLink generate incorrectly escaped JSON:
                     *
                     * {
                     * "documents": {
                     *  "C:\projects\cefsharp\*": "https://raw.github.com/CefSharp/CefSharp/4f88ad11416e93dde4b52216800efd42ba3b9c8a/*"
                     * }
                     * }
                     *
                     * Catch the exception and try to fix the key
                     */
                    JObject?jobj = null;
                    try
                    {
                        jobj = JObject.Parse(sl);
                    }
                    catch (JsonReaderException e) when(e.Path == "documents")
                    {
                        sl   = sl.Replace(@"\", @"\\");
                        jobj = JObject.Parse(sl);
                    }

                    var docs = (JObject)jobj["documents"];

                    var slis = (from prop in docs.Properties()
                                select new SourceLinkMap
                    {
                        Base = prop.Name.Replace(@"\", @"/"),             // use forward slashes for the url,
                        Location = prop.Value.Value <string>()
                    })
                               .ToList();

                    return(slis);
                }
                catch (JsonReaderException jse)
                {
                    throw new InvalidDataException("SourceLink data could not be parsed", jse);
                }
            }

            return(Array.Empty <SourceLinkMap>());
        }
Example #13
0
        private static void AddDocumentsFromTypeDefinitionDocuments(TypeDefinitionHandle typeDefHandle, MetadataReader pdbReader, HashSet <DocumentHandle> docList)
        {
            var handles = pdbReader.GetCustomDebugInformation(typeDefHandle);

            foreach (var cdiHandle in handles)
            {
                var cdi  = pdbReader.GetCustomDebugInformation(cdiHandle);
                var guid = pdbReader.GetGuid(cdi.Kind);
                if (guid == PortableCustomDebugInfoKinds.TypeDefinitionDocuments)
                {
                    if (((TypeDefinitionHandle)cdi.Parent).Equals(typeDefHandle))
                    {
                        var reader = pdbReader.GetBlobReader(cdi.Value);
                        while (reader.RemainingBytes > 0)
                        {
                            docList.Add(MetadataTokens.DocumentHandle(reader.ReadCompressedInteger()));
                        }
                    }
                }
            }
        }
Example #14
0
        private static bool TryGetCustomDebugInformation(MetadataReader reader, EntityHandle handle, Guid kind, out CustomDebugInformation customDebugInfo)
        {
            bool foundAny = false;

            customDebugInfo = default(CustomDebugInformation);
            foreach (var infoHandle in reader.GetCustomDebugInformation(handle))
            {
                var info = reader.GetCustomDebugInformation(infoHandle);
                var id   = reader.GetGuid(info.Kind);
                if (id == kind)
                {
                    if (foundAny)
                    {
                        throw new BadImageFormatException();
                    }
                    customDebugInfo = info;
                    foundAny        = true;
                }
            }
            return(foundAny);
        }
Example #15
0
        private string?TryGetSourceLinkUrl(DocumentHandle handle)
        {
            var document = _pdbReader.GetDocument(handle);

            if (document.Name.IsNil)
            {
                return(null);
            }

            var documentName = _pdbReader.GetString(document.Name);

            if (documentName is null)
            {
                return(null);
            }

            foreach (var cdiHandle in _pdbReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition))
            {
                var cdi = _pdbReader.GetCustomDebugInformation(cdiHandle);
                if (_pdbReader.GetGuid(cdi.Kind) == PortableCustomDebugInfoKinds.SourceLink && !cdi.Value.IsNil)
                {
                    var blobReader     = _pdbReader.GetBlobReader(cdi.Value);
                    var sourceLinkJson = blobReader.ReadUTF8(blobReader.Length);

                    var map = SourceLinkMap.Parse(sourceLinkJson);

                    if (map.TryGetUri(documentName, out var uri))
                    {
                        return(uri);
                    }
                }
            }

            return(null);
        }
        private byte[]? GetSourceLinkBytes()
        {
            if (_reader == null)
            {
                return(null);
            }
            var blobh = default(BlobHandle);

            foreach (var cdih in _reader.GetCustomDebugInformation(EntityHandle.ModuleDefinition))
            {
                var cdi = _reader.GetCustomDebugInformation(cdih);
                if (_reader.GetGuid(cdi.Kind) == SourceLinkId)
                {
                    blobh = cdi.Value;
                }
            }
            if (blobh.IsNil)
            {
                return(Array.Empty <byte>());
            }
            return(_reader.GetBlobBytes(blobh));
        }
Example #17
0
        public static SourceText GetEmbeddedSource(this MetadataReader reader, DocumentHandle document)
        {
            byte[] bytes = (from handle in reader.GetCustomDebugInformation(document)
                            let cdi = reader.GetCustomDebugInformation(handle)
                                      where reader.GetGuid(cdi.Kind) == PortableCustomDebugInfoKinds.EmbeddedSource
                                      select reader.GetBlobBytes(cdi.Value)).SingleOrDefault();

            if (bytes == null)
            {
                return(null);
            }

            int uncompressedSize = BitConverter.ToInt32(bytes, 0);
            var stream           = new MemoryStream(bytes, sizeof(int), bytes.Length - sizeof(int));

            if (uncompressedSize != 0)
            {
                var decompressed = new MemoryStream(uncompressedSize);

                using (var deflater = new DeflateStream(stream, CompressionMode.Decompress))
                {
                    deflater.CopyTo(decompressed);
                }

                if (decompressed.Length != uncompressedSize)
                {
                    throw new InvalidDataException();
                }

                stream = decompressed;
            }

            using (stream)
            {
                return(EncodedStringText.Create(stream));
            }
        }
        private bool HasSourceLinkDebugInformation(MetadataReader pdbReader)
        {
            foreach (var customDebugInfoHandle in pdbReader.CustomDebugInformation)
            {
                var customDebugInfo = pdbReader.GetCustomDebugInformation(customDebugInfoHandle);
                if (pdbReader.GetGuid(customDebugInfo.Kind) == SourceLinkCustomDebugInfoGuid)
                {
                    // var sourceLinkContent = pdbReader.GetBlobBytes(customDebugInfo.Value);
                    // var sourceLinkText = System.Text.Encoding.UTF8.GetString(sourceLinkContent);
                    return(true);
                }
            }

            return(false);
        }
Example #19
0
        public static bool HasSourceLink(this MetadataReader reader)
        {
            foreach (var customDebugInfoHandle in reader.CustomDebugInformation)
            {
                var customDebugInfo = reader.GetCustomDebugInformation(customDebugInfoHandle);
                if (reader.GetGuid(customDebugInfo.Kind) == SourceLinkMagic)
                {
                    //var sourceLinkContent = pdbReader.GetBlobBytes(customDebugInfo.Value);
                    //var sourceLinkText = System.Text.Encoding.UTF8.GetString(sourceLinkContent);

                    //Console.WriteLine("Sourcelink: " + sourceLinkText);
                    return(true);
                }
            }

            return(false);
        }
Example #20
0
        /// <summary>
        /// Returns SourceLink information, that is the source link information as described at https://github.com/dotnet/designs/blob/master/accepted/diagnostics/source-link.md#source-link-json-schema
        /// stored in PortablePDB.
        /// The function will throw an exception if PortablePDB file is not found or anything else went wrong.
        /// </summary>
        /// <param name="pdbFilePath">Path to PortablePDB file </param>
        public static SourceLinkInfo GetSourceLinkInfo(string pdbFilePath)
        {
            using (FileStream stream = File.OpenRead(pdbFilePath))
            {
                using (MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream))
                {
                    MetadataReader metadataReader = metadataReaderProvider.GetMetadataReader();
                    CustomDebugInformationHandleCollection customDebugInformationHandles = metadataReader.CustomDebugInformation;
                    foreach (var customDebugInformationHandle in customDebugInformationHandles)
                    {
                        CustomDebugInformation customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle);

                        if (metadataReader.GetGuid(customDebugInformation.Kind) == SourceLink)
                        {
                            string jsonString = Encoding.UTF8.GetString(metadataReader.GetBlobBytes(customDebugInformation.Value));
                            return(Newtonsoft.Json.JsonConvert.DeserializeObject <SourceLinkInfo>(jsonString));
                        }
                    }
                }
            }
            return(null);
        }
Example #21
0
        static void Main(string[] args)
        {
            string pdbPath = GetPdbPath("SourceLink.pdb");

            using (var stream = File.OpenRead(pdbPath))
            {
                using (var pdbStream = MetadataReaderProvider.FromPortablePdbStream(stream))
                {
                    MethodDebugInformationHandle methodDebugHandle = GetHandle("SourceLink.BubbleSort, SourceLink");
                    MetadataReader metadataReader = pdbStream.GetMetadataReader();

                    foreach (var localVariableHandle in GetLocalVariableHandles(metadataReader, methodDebugHandle).SelectMany(_ => _))
                    {
                        var localVariable = metadataReader.GetLocalVariable(localVariableHandle);
                        var name          = metadataReader.GetString(localVariable.Name);
                        Console.WriteLine("Local variable " + name);
                    }

                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();

                    foreach (var debugInfoHandle in metadataReader.CustomDebugInformation)
                    {
                        CustomDebugInformation debugInfo = metadataReader.GetCustomDebugInformation(debugInfoHandle);
                        var guid = metadataReader.GetGuid(debugInfo.Kind);
                        if (guid == new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A"))
                        {
                            var reader = metadataReader.GetBlobReader(debugInfo.Value);
                            Console.WriteLine(reader.ReadUTF8(reader.RemainingBytes));
                        }
                    }
                }
            }

            Console.ReadLine();
        }
        private IReadOnlyList <SourceLinkMap> GetSourceLinkInformation()
        {
            var sl = (from cdi in _reader.CustomDebugInformation
                      let cd = _reader.GetCustomDebugInformation(cdi)
                               let kind = _reader.GetGuid(cd.Kind)
                                          where kind == SourceLinkGuid
                                          let bl = _reader.GetBlobBytes(cd.Value)
                                                   select Encoding.UTF8.GetString(bl))
                     .FirstOrDefault();

            if (sl != null)
            {
                try
                {
                    var jobj = JObject.Parse(sl);
                    var docs = (JObject)jobj["documents"];


                    var slis = (from prop in docs.Properties()
                                select new SourceLinkMap
                    {
                        Base = prop.Name,
                        Location = prop.Value.Value <string>()
                    })
                               .ToList();

                    return(slis);
                }
                catch (JsonReaderException jse)
                {
                    throw new InvalidDataException("SourceLink data could not be parsed", jse);
                }
            }

            return(Array.Empty <SourceLinkMap>());
        }
Example #23
0
        private IReadOnlyList <SourceLinkMap> GetSourceLinkInformation()
        {
            var sl = (from cdi in _reader.CustomDebugInformation
                      let cd = _reader.GetCustomDebugInformation(cdi)
                               let kind = _reader.GetGuid(cd.Kind)
                                          where kind == SourceLinkGuid
                                          let bl = _reader.GetBlobBytes(cd.Value)
                                                   select Encoding.UTF8.GetString(bl))
                     .FirstOrDefault();

            var jobj = JObject.Parse(sl);
            var docs = (JObject)jobj["documents"];


            var slis = (from prop in docs.Properties()
                        select new SourceLinkMap
            {
                Base = prop.Name,
                Location = prop.Value.Value <string>()
            })
                       .ToList();

            return(slis);
        }
Example #24
0
 void ReadCustomDebugInformations(MethodDebugInformation info)
 {
     info.method.custom_infos = debug_reader.GetCustomDebugInformation(info.method);
 }
Example #25
0
 public static CustomDebugInformationHandleCollection GetCustomDebugInformation(this EntityHandle handle, MetadataReader reader) => reader.GetCustomDebugInformation(handle);
Example #26
0
        public string GetSourceLinkContent(string link)
        {
            if (_sourceLinkContents.ContainsKey(link))
            {
                return(_sourceLinkContents[link]);
            }

            var documentHandle = SourceLinks[link];

            string content = null;

            foreach (var cdih in MetadataReader.GetCustomDebugInformation(documentHandle))
            {
                var cdi = MetadataReader.GetCustomDebugInformation(cdih);

                if (MetadataReader.GetGuid(cdi.Kind) == Guid.Parse("0E8A571B-6926-466E-B4AD-8AB04611F5FE"))
                {
                    // embedded content
                    var bytes = MetadataReader.GetBlobBytes(cdi.Value);

                    // decompress content
                    int uncompressedSize = BitConverter.ToInt32(bytes, 0);

                    using (var stream = new MemoryStream(bytes, sizeof(int), bytes.Length - sizeof(int)))
                    {
                        if (uncompressedSize != 0)
                        {
                            using (var decompressed = new MemoryStream(uncompressedSize))
                            {
                                using (var deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
                                {
                                    deflateStream.CopyTo(decompressed);
                                }

                                using (var streamReader = new StreamReader(decompressed))
                                {
                                    decompressed.Position = 0;
                                    content = streamReader.ReadToEnd();
                                }
                            }
                        }
                        else
                        {
                            using (var streamReader = new StreamReader(stream))
                            {
                                stream.Position = 0;
                                content         = streamReader.ReadToEnd();
                            }
                        }
                    }
                }
            }

            if (content == null)
            {
                // from external link
                if (File.Exists(link))
                {
                    content = File.ReadAllText(link);
                }
            }

            _sourceLinkContents[link] = content;

            return(content);
        }
        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);
        }
Example #28
0
 void ReadModule()
 {
     module.custom_infos = debug_reader.GetCustomDebugInformation(module);
 }
Example #29
0
        /// <summary>
        /// Helper method to return all async methods stepping information.
        /// </summary>
        /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
        /// <param name="asyncInfo">array with all async methods stepping information</param>
        /// <param name="asyncInfoCount">entry's count in asyncInfo</param>
        internal static void GetAsyncMethodsSteppingInfo(IntPtr symbolReaderHandle, out IntPtr asyncInfo, out int asyncInfoCount)
        {
            Debug.Assert(symbolReaderHandle != IntPtr.Zero);

            asyncInfo      = IntPtr.Zero;
            asyncInfoCount = 0;
            var list = new List <AsyncAwaitInfoBlock>();

            GCHandle       gch    = GCHandle.FromIntPtr(symbolReaderHandle);
            MetadataReader reader = ((OpenedReader)gch.Target).Reader;

            // Guid is taken from Roslyn source code:
            // https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs#L13
            Guid asyncMethodSteppingInformationBlob = new Guid("54FD2AC5-E925-401A-9C2A-F94F171072F8");

            foreach (MethodDebugInformationHandle methodDebugInformationHandle in reader.MethodDebugInformation)
            {
                var entityHandle = MetadataTokens.EntityHandle(MetadataTokens.GetToken(methodDebugInformationHandle.ToDefinitionHandle()));

                foreach (var cdiHandle in reader.GetCustomDebugInformation(entityHandle))
                {
                    var cdi = reader.GetCustomDebugInformation(cdiHandle);

                    if (reader.GetGuid(cdi.Kind) == asyncMethodSteppingInformationBlob)
                    {
                        // Format of this blob is taken from Roslyn source code:
                        // https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs#L575

                        var blobReader         = reader.GetBlobReader(cdi.Value);
                        var catchHandlerOffset = blobReader.ReadUInt32();

                        while (blobReader.Offset < blobReader.Length)
                        {
                            list.Add(new AsyncAwaitInfoBlock()
                            {
                                catch_handler_offset = catchHandlerOffset,
                                yield_offset         = blobReader.ReadUInt32(),
                                resume_offset        = blobReader.ReadUInt32(),
                                // explicit conversion from int into uint here, see:
                                // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.metadata.blobreader.readcompressedinteger
                                token = (uint)blobReader.ReadCompressedInteger()
                            });
                        }
                    }
                }
            }

            if (list.Count == 0)
            {
                return;
            }

            var    structSize = Marshal.SizeOf <AsyncAwaitInfoBlock>();
            IntPtr allInfo    = Marshal.AllocCoTaskMem(list.Count * structSize);
            var    currentPtr = allInfo;

            foreach (var p in list)
            {
                Marshal.StructureToPtr(p, currentPtr, false);
                currentPtr = (IntPtr)(currentPtr.ToInt64() + structSize);
            }

            asyncInfo      = allInfo;
            asyncInfoCount = list.Count;
        }