Search code examples
c#.netpdb-files

How to read details of a PDB file in C#


I wanted to read details like the document URLs (=the paths of the documents) from a PDB-file (in my specific case a Windows PDB and not a portable PDB), but couldn't find an easy and straight forward example.


Solution

  • After some research I came up with the following, and I just want to share it, as some post like that would have been what I was looking for in the first place:

    1. Add a package reference to Microsoft.DiaSymReader.Native
    2. Create a helper class like the following. At the moment this is just reading and returning the document paths, but of course we could also extract several other details as well.

    Important:

    • Unsafe code must be allowed in the project for this to work.
    • Also note that these are the steps for Windows PDBs (not portable PDBs).
        /// <summary>
        /// Helper class to get specific contents of a PDB file.
        /// </summary>
        public static class PdbReader
        {
            /// <summary>
            /// Gets all paths of all documents from the given PDB.
            /// </summary>
            public static IReadOnlyCollection<string> GetAllDocumentPathsFromPdb(string path)
            {
                using var stream = new FileStream(path, FileMode.Open);
                var metadataProvider = new SymReaderMetadataProvider();
                var reader = SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(stream, metadataProvider);
                var result = reader.GetDocuments();
    
                return GetDocumentPaths(result).ToList();
            }
    
            private static IEnumerable<string> GetDocumentPaths(IEnumerable<ISymUnmanagedDocument> result)
            {
                foreach (var document in result)
                {
                    var url = new char[256];
                    document.GetUrl(url.Length, out var count, url);
                    yield return new string(url, 0, count-1);
                }
            }
    
            /// <summary>
            /// Dummy implementation which is doing nothing.
            /// At the moment we just need it to pass *any* implementation of <see cref="ISymReaderMetadataProvider"/>
            /// to <see cref="SymUnmanagedReaderFactory.CreateReader{T}"/>.
            /// </summary>
            private class SymReaderMetadataProvider : ISymReaderMetadataProvider
            {
                public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length)
                {
                    throw new NotImplementedException();
                }
    
                public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespaceName, out string typeName, out TypeAttributes attributes)
                {
                    throw new NotImplementedException();
                }
    
                public bool TryGetTypeReferenceInfo(int typeReferenceToken, out string namespaceName, out string typeName)
                {
                    throw new NotImplementedException();
                }
            }
        }
    

    Credits: The biggest help was this file. Thanks Kirill Osenkov!