예제 #1
0
        /// <summary>
        /// Returns metadata readers for assembly PE file and portable PDB.
        /// </summary>
        /// <param name="assemblyFileName">file name of the assembly</param>
        /// <param name="peReader">PE metadata reader return</param>
        /// <param name="pdbReader">PDB metadata reader return</param>
        /// <returns>true if debugging information is available</returns>
        private static bool GetReaders(string assemblyFileName, out MetadataReader peReader, out MetadataReader pdbReader)
        {
            peReader  = null;
            pdbReader = null;

            if (!File.Exists(assemblyFileName))
            {
                return(false);
            }
            Stream   peStream = File.OpenRead(assemblyFileName);
            PEReader reader   = new PEReader(peStream);
            string   pdbPath  = null;

            foreach (DebugDirectoryEntry entry in reader.ReadDebugDirectory())
            {
                if (entry.Type == DebugDirectoryEntryType.CodeView)
                {
                    CodeViewDebugDirectoryData codeViewData = reader.ReadCodeViewDebugDirectoryData(entry);
                    pdbPath = codeViewData.Path;
                    break;
                }
            }
            if (pdbPath == null)
            {
                return(false);
            }
            if (!File.Exists(pdbPath))
            {
                pdbPath = Path.GetFileName(pdbPath);
                if (!File.Exists(pdbPath))
                {
                    return(false);
                }
            }

            peReader = reader.GetMetadataReader();
            Stream pdbStream = File.OpenRead(pdbPath);
            MetadataReaderProvider provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);

            pdbReader = provider.GetMetadataReader();

            return(true);
        }
예제 #2
0
        private MetadataReader GetMetadataReader(string assemblyPath)
        {
            MetadataReaderProvider provider = null;

            if (!_cache.TryGetValue(assemblyPath, out provider))
            {
                var pdbPath = GetPdbPath(assemblyPath);

                if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath))
                {
                    var pdbStream = File.OpenRead(pdbPath);
                    provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
                }

                _cache[assemblyPath] = provider;
            }

            return(provider?.GetMetadataReader());
        }
예제 #3
0
파일: DebugStore.cs 프로젝트: jteer/runtime
        public unsafe AssemblyInfo(MonoProxy monoProxy, SessionId sessionId, string url, byte[] assembly, byte[] pdb, CancellationToken token)
        {
            this.id             = Interlocked.Increment(ref next_id);
            using var asmStream = new MemoryStream(assembly);
            peReader            = new PEReader(asmStream);
            var entries = peReader.ReadDebugDirectory();

            if (entries.Length > 0)
            {
                var codeView = entries[0];
                CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(codeView);
                PdbAge  = codeViewData.Age;
                PdbGuid = codeViewData.Guid;
                PdbName = codeViewData.Path;
                PdbInformationAvailable = true;
            }
            asmMetadataReader = PEReaderExtensions.GetMetadataReader(peReader);
            var asmDef = asmMetadataReader.GetAssemblyDefinition();

            Name = asmDef.GetAssemblyName().Name + ".dll";
            if (pdb != null)
            {
                var pdbStream = new MemoryStream(pdb);
                try
                {
                    // MetadataReaderProvider.FromPortablePdbStream takes ownership of the stream
                    pdbMetadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader();
                }
                catch (BadImageFormatException)
                {
                    monoProxy.SendLog(sessionId, $"Warning: Unable to read debug information of: {Name} (use DebugType=Portable/Embedded)", token);
                }
            }
            else
            {
                var embeddedPdbEntry = entries.FirstOrDefault(e => e.Type == DebugDirectoryEntryType.EmbeddedPortablePdb);
                if (embeddedPdbEntry.DataSize != 0)
                {
                    pdbMetadataReader = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry).GetMetadataReader();
                }
            }
            Populate();
        }
        public AssemblyDebugParser(Stream?peStream, Stream pdbStream)
        {
            Stream inputStream;

            if (!PdbConverter.IsPortable(pdbStream))
            {
                if (peStream == null)
                {
                    throw new ArgumentNullException(nameof(peStream), "Full PDB's require the PE file to be next to the PDB");
                }
                // Full PDB. convert to ppdb in memory

                _pdbBytes          = pdbStream.ReadAllBytes();
                pdbStream.Position = 0;
                _peBytes           = peStream.ReadAllBytes();
                peStream.Position  = 0;

                _temporaryPdbStream = new MemoryStream();
                PdbConverter.Default.ConvertWindowsToPortable(peStream, pdbStream, _temporaryPdbStream);
                _temporaryPdbStream.Position = 0;
                peStream.Position            = 0;
                inputStream = _temporaryPdbStream;
                _pdbType    = PdbType.Full;
            }
            else
            {
                inputStream        = pdbStream;
                _pdbType           = PdbType.Portable;
                _pdbBytes          = pdbStream.ReadAllBytes();
                pdbStream.Position = 0;
            }



            _readerProvider = MetadataReaderProvider.FromPortablePdbStream(inputStream);
            _reader         = _readerProvider.GetMetadataReader();

            if (peStream != null)
            {
                _peReader    = new PEReader(peStream);
                _ownPeReader = true;
            }
        }
예제 #5
0
        public bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
        {
            firstNotFoundDocument = "";
            using (var moduleStream = _fileSystem.OpenRead(module))
                using (var peReader = new PEReader(moduleStream))
                {
                    foreach (var entry in peReader.ReadDebugDirectory())
                    {
                        if (entry.Type == DebugDirectoryEntryType.CodeView)
                        {
                            var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
                            using Stream pdbStream = _fileSystem.OpenRead(_sourceRootTranslator.ResolveFilePath(codeViewData.Path));
                            using MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
                            MetadataReader metadataReader = null;
                            try
                            {
                                metadataReader = metadataReaderProvider.GetMetadataReader();
                            }
                            catch (BadImageFormatException)
                            {
                                _logger.LogWarning($"{nameof(BadImageFormatException)} during MetadataReaderProvider.FromPortablePdbStream in InstrumentationHelper.PortablePdbHasLocalSource, unable to check if module has got local source.");
                                return(true);
                            }
                            foreach (DocumentHandle docHandle in metadataReader.Documents)
                            {
                                Document document = metadataReader.GetDocument(docHandle);
                                string   docName  = _sourceRootTranslator.ResolveFilePath(metadataReader.GetString(document.Name));

                                // We verify all docs and return false if not all are present in local
                                // We could have false negative if doc is not a source
                                // Btw check for all possible extension could be weak approach
                                if (!_fileSystem.Exists(docName))
                                {
                                    firstNotFoundDocument = docName;
                                    return(false);
                                }
                            }
                        }
                    }
                }

            return(true);
        }
        private static void VerifyPortablePdb(Stream pdbStream, string expectedMetadata, string message)
        {
            using (var provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream, MetadataStreamOptions.LeaveOpen))
            {
                var mdReader = provider.GetMetadataReader();
                var writer   = new StringWriter();
                var mdv      = new MetadataVisualizer(mdReader, writer, MetadataVisualizerOptions.NoHeapReferences);

                mdv.WriteDocument();
                mdv.WriteMethodDebugInformation();
                mdv.WriteLocalScope();
                mdv.WriteLocalVariable();
                mdv.WriteLocalConstant();
                mdv.WriteImportScope();
                mdv.WriteCustomDebugInformation();

                AssertEx.AssertLinesEqual(expectedMetadata, writer.ToString(), message);
            }
        }
예제 #7
0
        private static OpenedReader TryOpenReaderForInMemoryPdb(Stream pdbStream)
        {
            Debug.Assert(pdbStream != null);

            byte[] buffer = new byte[sizeof(uint)];
            if (pdbStream.Read(buffer, 0, sizeof(uint)) != sizeof(uint))
            {
                return(null);
            }
            uint signature = BitConverter.ToUInt32(buffer, 0);

            // quick check to avoid throwing exceptions below in common cases:
            const uint ManagedMetadataSignature = 0x424A5342;

            if (signature != ManagedMetadataSignature)
            {
                // not a Portable PDB
                return(null);
            }

            OpenedReader           result   = null;
            MetadataReaderProvider provider = null;

            try
            {
                pdbStream.Position = 0;
                provider           = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
                result             = new OpenedReader(provider, provider.GetMetadataReader());
            }
            catch (Exception e) when(e is BadImageFormatException || e is IOException)
            {
                return(null);
            }
            finally
            {
                if (result == null)
                {
                    provider?.Dispose();
                }
            }

            return(result);
        }
예제 #8
0
        private async Task <PortablePdb> ExtractPortablePdbAsync(
            PackageArchiveReader symbolPackage,
            string pdbPath,
            CancellationToken cancellationToken)
        {
            // TODO: Validate that the PDB has a corresponding DLL
            // See: https://github.com/NuGet/NuGet.Jobs/blob/master/src/Validation.Symbols/SymbolsValidatorService.cs#L170
            Stream      pdbStream = null;
            PortablePdb result    = null;

            try
            {
                using (var rawPdbStream = await symbolPackage.GetStreamAsync(pdbPath, cancellationToken))
                {
                    pdbStream = await rawPdbStream.AsTemporaryFileStreamAsync();

                    string signature;
                    using (var pdbReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream, MetadataStreamOptions.LeaveOpen))
                    {
                        var reader = pdbReaderProvider.GetMetadataReader();
                        var id     = new BlobContentId(reader.DebugMetadataHeader.Id);

                        signature = id.Guid.ToString("N").ToUpperInvariant();
                    }

                    var fileName = Path.GetFileName(pdbPath).ToLowerInvariant();
                    var key      = $"{signature}ffffffff";

                    pdbStream.Position = 0;
                    result             = new PortablePdb(fileName, key, pdbStream);
                }
            }
            finally
            {
                if (result == null)
                {
                    pdbStream?.Dispose();
                }
            }

            return(result);
        }
        /// <summary>
        /// Returns the portable PDB reader for the assembly path
        /// </summary>
        /// <param name="assembly">Managed Assembly to be used as a cache key</param>
        /// <param name="assemblyPath">
        /// File path of the assembly or null if the module is dynamic (generated by Reflection.Emit).
        /// </param>
        /// <param name="loadedPeAddress">
        /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit).
        /// Dynamic modules have their PDBs (if any) generated to an in-memory stream
        /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>).
        /// </param>
        /// <param name="loadedPeSize">loaded PE image size</param>
        /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param>
        /// <param name="inMemoryPdbSize">in memory PDB size</param>
        /// <returns>reader</returns>
        /// <remarks>
        /// Accounts for unloadable and dynamic types by keying the cache on the managed Assembly. The
        /// underlying ConditionalWeakTable doesn't keep the assembly alive, so cached types will be
        /// correctly invalidated when the Assembly is unloaded by the GC.
        /// </remarks>
        private unsafe MetadataReader TryGetReader(Assembly assembly, string assemblyPath, IntPtr loadedPeAddress, int loadedPeSize, IntPtr inMemoryPdbAddress, int inMemoryPdbSize)
        {
            if ((loadedPeAddress == IntPtr.Zero || assemblyPath == null) && inMemoryPdbAddress == IntPtr.Zero)
            {
                // Dynamic or in-memory module without symbols (they would be in-memory if they were available).
                return(null);
            }

            // The ConditionalWeakTable's GetValue + callback will atomically create the cache entry for us
            // so we are protected from multiple threads racing to get/create the same MetadataReaderProvider
            MetadataReaderProvider provider = _metadataCache.GetValue(assembly, (assembly) =>
            {
                return((inMemoryPdbAddress != IntPtr.Zero) ?
                       TryOpenReaderForInMemoryPdb(inMemoryPdbAddress, inMemoryPdbSize) :
                       TryOpenReaderFromAssemblyFile(assemblyPath, loadedPeAddress, loadedPeSize));
            });

            // The reader has already been open, so this doesn't throw.
            return(provider?.GetMetadataReader());
        }
예제 #10
0
        public string GetSourceLinkBlob()
        {
            using (var provider = MetadataReaderProvider.FromPortablePdbStream(GetStream())) {
                var pdbReader = provider.GetMetadataReader();

                var jsonBlob =
                    pdbReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition)
                    .Select(cdiHandle => pdbReader.GetCustomDebugInformation(cdiHandle))
                    .Where(cdi => pdbReader.GetGuid(cdi.Kind) == SourceLinkGuid)
                    .Select(cdi => pdbReader.GetBlobBytes(cdi.Value))
                    .FirstOrDefault();

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

                return(System.Text.Encoding.UTF8.GetString(jsonBlob));
            }
        }
예제 #11
0
        public void EmbeddedSource()
        {
            string source = @"
using System;

class C
{
    public static void Main()
    {
        Console.WriteLine();
    }
}
";
            var    tree   = Parse(source, "f:/build/foo.cs");
            var    c      = CreateCompilationWithMscorlib(tree, options: TestOptions.DebugDll);

            var pdbStream = new MemoryStream();

            c.EmitToArray(
                EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.PortablePdb),
                pdbStream: pdbStream,
                embeddedTexts: new[] { EmbeddedText.FromSource(tree.FilePath, tree.GetText()) });
            pdbStream.Position = 0;

            using (var provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream))
            {
                var pdbReader = provider.GetMetadataReader();

                var embeddedSource =
                    (from documentHandle in pdbReader.Documents
                     let document = pdbReader.GetDocument(documentHandle)
                                    select new
                {
                    FilePath = pdbReader.GetString(document.Name),
                    Text = pdbReader.GetEmbeddedSource(documentHandle)
                }).Single();

                Assert.Equal(embeddedSource.FilePath, "f:/build/foo.cs");
                Assert.Equal(source, embeddedSource.Text.ToString());
            }
        }
예제 #12
0
        public void SourceLink()
        {
            string source         = @"
using System;

class C
{
    public static void Main()
    {
        Console.WriteLine();
    }
}
";
            var    sourceLinkBlob = Encoding.UTF8.GetBytes(@"
{
  ""documents"": {
     ""f:/build/*"" : ""https://raw.githubusercontent.com/my-org/my-project/1111111111111111111111111111111111111111/*""
  }
}
");

            var c = CreateCompilation(Parse(source, "f:/build/goo.cs"), options: TestOptions.DebugDll);

            var pdbStream = new MemoryStream();

            c.EmitToArray(EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.PortablePdb), pdbStream: pdbStream, sourceLinkStream: new MemoryStream(sourceLinkBlob));
            pdbStream.Position = 0;

            using (var provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream))
            {
                var pdbReader = provider.GetMetadataReader();

                var actualBlob =
                    (from cdiHandle in pdbReader.GetCustomDebugInformation(EntityHandle.ModuleDefinition)
                     let cdi = pdbReader.GetCustomDebugInformation(cdiHandle)
                               where pdbReader.GetGuid(cdi.Kind) == PortableCustomDebugInfoKinds.SourceLink
                               select pdbReader.GetBlobBytes(cdi.Value)).Single();

                AssertEx.Equal(sourceLinkBlob, actualBlob);
            }
        }
예제 #13
0
        /// <summary>
        /// Constructs new assembly debug information.
        /// </summary>
        /// <param name="assembly">The referenced assembly.</param>
        /// <param name="pdbStream">The associated PDB stream.</param>
        internal AssemblyDebugInformation(Assembly assembly, Stream pdbStream)
        {
            Assembly = assembly;
            Modules  = ImmutableArray.Create(assembly.GetModules());

            using (var metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream, MetadataStreamOptions.PrefetchMetadata))
                MetadataReader = metadataReaderProvider.GetMetadataReader();

            var methodDebugInformationEnumerator = MetadataReader.MethodDebugInformation.GetEnumerator();

            while (methodDebugInformationEnumerator.MoveNext())
            {
                var methodDebugRef         = methodDebugInformationEnumerator.Current;
                var methodDefinitionHandle = methodDebugRef.ToDefinitionHandle();
                var metadataToken          = MetadataTokens.GetToken(methodDefinitionHandle);
                if (TryResolveMethod(metadataToken, out MethodBase method))
                {
                    debugInformation.Add(method, new MethodDebugInformation(this, method, methodDebugRef));
                }
            }
        }
예제 #14
0
        /// <summary>
        /// The method takes ownership of the <paramref name="provider"/> upon entry and disposes it in case of a failure to construct the reader.
        /// </summary>
        internal PortablePdbReader(MetadataReaderProvider provider, LazyMetadataImport metadataImport)
        {
            Debug.Assert(metadataImport != null);
            Debug.Assert(provider != null);

            try
            {
                _metadataReader = provider.GetMetadataReader();
            }
            finally
            {
                // dispose the provider on error:
                if (_metadataReader == null)
                {
                    provider.Dispose();
                }
            }

            _metadataReaderProvider = provider;
            _lazyMetadataImport     = metadataImport;
        }
예제 #15
0
 internal string [] TupleElementNamesPrivate(MethodMirror method, int localVariableIndex)
 {
     using (var metadataReader = MetadataReaderProvider.FromPortablePdbStream(GetStream())) {
         var reader       = metadataReader.GetMetadataReader();
         var methodHandle = MetadataTokens.MethodDefinitionHandle(method.MetadataToken);
         var localScopes  = reader.GetLocalScopes(methodHandle);
         // localVariableIndex is not really il_index, but sequential index when fetching locals
         // hence use Skip(index) instead of Index matching.
         var localVar         = localScopes.Select(s => reader.GetLocalScope(s)).SelectMany(s => s.GetLocalVariables()).Skip(localVariableIndex).First();
         var customDebugInfos = reader.GetCustomDebugInformation(localVar);
         foreach (var item in customDebugInfos)
         {
             var debugInfo = reader.GetCustomDebugInformation(item);
             if (reader.GetGuid(debugInfo.Kind) == TupleElementNames)
             {
                 return(DecodeTupleElementNames(reader.GetBlobReader(debugInfo.Value)));
             }
         }
     }
     return(null);
 }
예제 #16
0
        /// <summary>
        /// Opens metadata section of the assembly file produced by the compiler.
        /// </summary>
        /// <param name="prefetch">
        /// True to prefetch all metadata from the assembly and close the underlying stream on return,
        /// otherwise keeps the underlying stream open until the returned <see cref="MetadataReaderProvider"/> is disposed.
        /// </param>
        /// <returns>
        /// Instance of <see cref="MetadataReaderProvider"/>, which owns the opened metadata and must be disposed once the caller is done reading the data,
        /// or null if the assembly is not available.
        /// </returns>
        /// <exception cref="BadImageFormatException">Invalid format of the assembly data.</exception>
        /// <exception cref="InvalidOperationException">The stream returned by <see cref="OpenAssemblyStreamChecked"/> does not support read and seek operations.</exception>
        /// <exception cref="Exception">Error while reading assembly data.</exception>
        public virtual MetadataReaderProvider OpenAssemblyMetadata(bool prefetch)
        {
            var peStream = OpenAssemblyStreamChecked();

            if (peStream != null)
            {
                PEHeaders peHeaders;
                using (var peReader = new PEReader(peStream, PEStreamOptions.LeaveOpen))
                {
                    peHeaders = peReader.PEHeaders;
                }

                peStream.Position = peHeaders.MetadataStartOffset;
                return(MetadataReaderProvider.FromMetadataStream(
                           peStream,
                           prefetch ? MetadataStreamOptions.PrefetchMetadata : MetadataStreamOptions.Default,
                           size: peHeaders.MetadataSize));
            }

            return(null);
        }
예제 #17
0
        /// <summary>
        /// This gets format for the VSTS symbol server indexed files. This format is
        /// based off of the PDB name and the signature present in the PDB
        /// </summary>
        /// <param name="pdbFullPath">Path to the PDB file</param>
        /// <returns>The indexed format of PDB file for the VSTS symbol server</returns>
        public static string GetIndex(string pdbFullPath)
        {
            if (pdbFullPath == null)
            {
                throw new ArgumentNullException(nameof(pdbFullPath));
            }

            var indexingPath = string.Empty;

            using (var stream = File.OpenRead(pdbFullPath))
                using (var pdbReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream, MetadataStreamOptions.LeaveOpen))
                {
                    var pdbReader    = pdbReaderProvider.GetMetadataReader();
                    var pdbSignature = new BlobContentId(pdbReader.DebugMetadataHeader.Id).Guid;
                    var pdbFileName  = Path.GetFileName(pdbFullPath).ToLowerInvariant();
                    var pdbAge       = "FFFFFFFF";
                    indexingPath = $"{pdbFileName}/{pdbSignature.ToString("N")}{pdbAge}/{pdbFileName}";
                }

            return(indexingPath);
        }
예제 #18
0
        private static MetadataReaderProvider GetMetadataReaderProvider(Module module)
        {
            // TODO can the PEReader be pointed at a memory location instead of reading from disk?
            var dllFileContent = File.ReadAllBytes(module.FullyQualifiedName).ToImmutableArray();
            var reader         = new PEReader(dllFileContent);

            TraceSourceLink("probing for embedded symbols: " + module.FullyQualifiedName);
            if (!reader.HasMetadata)
            {
                return(null);
            }

            // https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs
            var embeddedPdb = reader.ReadDebugDirectory().FirstOrDefault(x => x.Type == DebugDirectoryEntryType.EmbeddedPortablePdb);

            if (!embeddedPdb.Equals(default(DebugDirectoryEntry)))
            {
                TraceSourceLink("found embedded symbols: " + module.FullyQualifiedName);
                return(reader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdb));
            }

            var sbFile = new StringBuilder(1024);
            var sbPath = new StringBuilder(1024);

            if (SymGetSymbolFile(ProcessHandle, null, module.FullyQualifiedName, SymbolFileType.sfPdb, sbFile, sbFile.Capacity, sbPath, sbPath.Capacity))
            {
                // todo determine if pdb is not portable early
                // https://github.com/tmat/corefx/blob/f808e59c3ef93e141b019d661a4443a0e19c7442/src/System.Diagnostics.StackTrace/src/System/Diagnostics/StackTraceSymbols.CoreCLR.cs#L164
                TraceSourceLink("probing for portable PDB symbols: " + sbFile);
                var pdbFileContent = File.ReadAllBytes(sbFile.ToString()).ToImmutableArray();
                return(MetadataReaderProvider.FromPortablePdbImage(pdbFileContent));
            }
            else
            {
                TraceSourceLink("probing for portable PDB symbols failed: " + Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
            }

            return(null);
        }
예제 #19
0
        /// <summary>
        /// The method takes ownership of the <paramref name="provider"/> upon entry and disposes it in case of a failure to construct the reader.
        /// </summary>
        internal PortablePdbReader(MetadataReaderProvider provider, int version, int previousDocumentCount)
        {
            Debug.Assert(provider != null);
            Debug.Assert(version >= 1);

            try
            {
                _metadataReader = provider.GetMetadataReader();
            }
            finally
            {
                // dispose the provider on error:
                if (_metadataReader == null)
                {
                    provider.Dispose();
                }
            }

            _metadataReaderProvider = provider;
            Version = version;
            PreviousDocumentCount = previousDocumentCount;
        }
예제 #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);
        }
예제 #21
0
        public void GetOrAddDocumentName2()
        {
            var mdBuilder = new MetadataBuilder();

            mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));

            var n1  = mdBuilder.GetOrAddDocumentName("");
            var n2  = mdBuilder.GetOrAddDocumentName("/a/b/c");
            var n3  = mdBuilder.GetOrAddDocumentName(@"\a\b\cc");
            var n4  = mdBuilder.GetOrAddDocumentName(@"/a/b\c");
            var n5  = mdBuilder.GetOrAddDocumentName(@"/\a/\b\\//c");
            var n6  = mdBuilder.GetOrAddDocumentName(@"a/");
            var n7  = mdBuilder.GetOrAddDocumentName(@"/");
            var n8  = mdBuilder.GetOrAddDocumentName(@"\\");
            var n9  = mdBuilder.GetOrAddDocumentName("\ud800"); // unpaired surrogate
            var n10 = mdBuilder.GetOrAddDocumentName("\0");

            var root        = new MetadataRootBuilder(mdBuilder);
            var rootBuilder = new BlobBuilder();

            root.Serialize(rootBuilder, 0, 0);
            var mdImage = rootBuilder.ToImmutableArray();

            using (var provider = MetadataReaderProvider.FromMetadataImage(mdImage))
            {
                var mdReader = provider.GetMetadataReader();
                Assert.Equal("", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n1))));
                Assert.Equal("/a/b/c", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n2))));
                Assert.Equal(@"\a\b\cc", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n3))));
                Assert.Equal(@"/a/b\c", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n4))));
                Assert.Equal(@"/\a/\b\\//c", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n5))));
                Assert.Equal(@"a/", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n6))));
                Assert.Equal(@"/", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n7))));
                Assert.Equal(@"\\", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n8))));
                Assert.Equal("\uFFFd\uFFFd", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n9))));
                Assert.Equal("\0", mdReader.GetString(MetadataTokens.DocumentNameBlobHandle(MetadataTokens.GetHeapOffset(n10))));
            }
        }
예제 #22
0
        public static Guid TryReadPdbGuid(string pdbFilePath)
        {
            try
            {
                using (var stream = File.OpenRead(pdbFilePath))
                {
                    if (stream.Length < 1024)
                    {
                        return(Guid.Empty);
                    }

                    if (stream.ReadByte() != 'B' ||
                        stream.ReadByte() != 'S' ||
                        stream.ReadByte() != 'J' ||
                        stream.ReadByte() != 'B')
                    {
                        // not a portable Pdb
                        return(Guid.Empty);
                    }

                    stream.Position = 0;

                    using (var provider = MetadataReaderProvider.FromPortablePdbStream(stream))
                    {
                        var metadataReader = provider.GetMetadataReader();
                        var id             = metadataReader.DebugMetadataHeader.Id;
                        var guid           = new Guid(id.Take(16).ToArray());
                        var stamp          = id.Skip(16).ToArray();
                        Log("Portable Pdb Guid: " + guid.ToString("D"));
                        return(guid);
                    }
                }
            }
            catch (Exception)
            {
                return(Guid.Empty);
            }
        }
        private static void VerifyMatchingSignatures(Stream portablePdbStream, Stream windowsPdbStream)
        {
            Guid guid;
            uint stamp;
            int  age;

            using (var provider = MetadataReaderProvider.FromPortablePdbStream(portablePdbStream, MetadataStreamOptions.LeaveOpen))
            {
                SymReaderHelpers.GetWindowsPdbSignature(provider.GetMetadataReader().DebugMetadataHeader !.Id, out guid, out stamp, out age);
            }

            var symReader = SymReaderHelpers.CreateWindowsPdbReader(windowsPdbStream);

            try
            {
                Marshal.ThrowExceptionForHR(symReader.MatchesModule(guid, stamp, age, out bool result));
                Assert.True(result);
            }
            finally
            {
                ((ISymUnmanagedDispose)symReader).Destroy();
            }
        }
예제 #24
0
        public string GetSrcSrvStream()
        {
            using (var stream = File.Open(this.pdbPath, FileMode.Open, FileAccess.Read))
            {
                using (var metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(stream))
                {
                    var metadataReader = metadataReaderProvider.GetMetadataReader();
                    var customDebugInformationHandleCollection = metadataReader.CustomDebugInformation;

                    foreach (var customDebugInformationHandle in customDebugInformationHandleCollection)
                    {
                        var customDebugInformation = metadataReader.GetCustomDebugInformation(customDebugInformationHandle);

                        if (metadataReader.GetGuid(customDebugInformation.Kind) == SourceLink)
                        {
                            return(Encoding.UTF8.GetString(metadataReader.GetBlobBytes(customDebugInformation.Value)));
                        }
                    }
                }
            }

            return(null);
        }
예제 #25
0
        public void CustomPdbId()
        {
            // Generate a PDB for an assembly using a randomly-generated ID, then validate that the PDB uses the specified ID
            (string peFileName, string pdbFileName) = CompileTestCase(nameof(CustomPdbId));

            var moduleDefinition = new PEFile(peFileName);
            var resolver         = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
            var decompiler       = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
            var expectedPdbId    = new BlobContentId(Guid.NewGuid(), (uint)Random.Shared.Next());

            using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, nameof(CustomPdbId) + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                pdbStream.SetLength(0);
                PortablePdbWriter.WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream, noLogo: true, pdbId: expectedPdbId);

                pdbStream.Position = 0;
                var metadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader();
                var generatedPdbId = new BlobContentId(metadataReader.DebugMetadataHeader.Id);

                Assert.AreEqual(expectedPdbId.Guid, generatedPdbId.Guid);
                Assert.AreEqual(expectedPdbId.Stamp, generatedPdbId.Stamp);
            }
        }
예제 #26
0
 public DebugReaderProvider(string path, Stream stream)
 {
     Path        = path;
     this.stream = stream;
     if (path.EndsWith(".dll"))
     {
         var reader = new PEReader(stream);
         if (reader.HasMetadata)
         {
             // https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs
             var debugDirectoryEntries = reader.ReadDebugDirectory();
             var embeddedPdb           = debugDirectoryEntries.Where(dde => dde.Type == DebugDirectoryEntryType.EmbeddedPortablePdb).FirstOrDefault();
             if (!embeddedPdb.Equals(default(DebugDirectoryEntry)))
             {
                 provider = reader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdb);
             }
         }
     }
     else
     {
         provider = MetadataReaderProvider.FromPortablePdbStream(stream);
     }
 }
예제 #27
0
        public bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
        {
            firstNotFoundDocument = "";
            using (var moduleStream = _fileSystem.OpenRead(module))
                using (var peReader = new PEReader(moduleStream))
                {
                    foreach (var entry in peReader.ReadDebugDirectory())
                    {
                        if (entry.Type == DebugDirectoryEntryType.CodeView)
                        {
                            var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
                            using Stream pdbStream = _fileSystem.OpenRead(_sourceRootTranslator.ResolveFilePath(codeViewData.Path));
                            using MetadataReaderProvider metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
                            MetadataReader metadataReader = null;
                            try
                            {
                                metadataReader = metadataReaderProvider.GetMetadataReader();
                            }
                            catch (BadImageFormatException)
                            {
                                _logger.LogWarning($"{nameof(BadImageFormatException)} during MetadataReaderProvider.FromPortablePdbStream in InstrumentationHelper.PortablePdbHasLocalSource, unable to check if module has got local source.");
                                return(true);
                            }

                            var matchingResult = MatchDocumentsWithSources(metadataReader);

                            if (!matchingResult.allDocumentsMatch)
                            {
                                firstNotFoundDocument = matchingResult.notFoundDocument;
                                return(false);
                            }
                        }
                    }
                }

            return(true);
        }
예제 #28
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();
        }
        public bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
        {
            firstNotFoundDocument = "";
            using (Stream moduleStream = _fileSystem.OpenRead(module))
                using (var peReader = new PEReader(moduleStream))
                {
                    foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
                    {
                        if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
                        {
                            using (MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry))
                            {
                                MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
                                foreach (DocumentHandle docHandle in metadataReader.Documents)
                                {
                                    Document document = metadataReader.GetDocument(docHandle);
                                    string   docName  = _sourceRootTranslator.ResolveFilePath(metadataReader.GetString(document.Name));

                                    // We verify all docs and return false if not all are present in local
                                    // We could have false negative if doc is not a source
                                    // Btw check for all possible extension could be weak approach
                                    // We exlude from the check the autogenerated source file(i.e. source generators)
                                    if (!_fileSystem.Exists(docName) && !docName.EndsWith(".g.cs"))
                                    {
                                        firstNotFoundDocument = docName;
                                        return(false);
                                    }
                                }
                            }
                        }
                    }
                }

            // If we don't have EmbeddedPortablePdb entry return true, for instance empty dll
            // We should call this method only on embedded pdb module
            return(true);
        }
예제 #30
0
        private unsafe void TestGetMetadataReader(MetadataReaderProvider provider)
        {
            var decoder = new TestMetadataStringDecoder(Encoding.UTF8, (a, b) => "str");

            var reader1 = provider.GetMetadataReader(MetadataReaderOptions.None, decoder);

            Assert.Equal("str", reader1.MetadataVersion);
            Assert.Same(reader1.UTF8Decoder, decoder);
            Assert.Equal(reader1.Options, MetadataReaderOptions.None);

            var reader2 = provider.GetMetadataReader(MetadataReaderOptions.None, decoder);

            Assert.Same(reader1, reader2);

            var reader3 = provider.GetMetadataReader(MetadataReaderOptions.None);

            Assert.NotSame(reader2, reader3);
            Assert.Equal("v9.9.9.9", reader3.MetadataVersion);
            Assert.Same(reader3.UTF8Decoder, MetadataStringDecoder.DefaultUTF8);
            Assert.Equal(reader3.Options, MetadataReaderOptions.None);

            var reader4 = provider.GetMetadataReader(MetadataReaderOptions.None);

            Assert.Same(reader3, reader4);

            var reader5 = provider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections);

            Assert.NotSame(reader4, reader5);
            Assert.Equal("v9.9.9.9", reader5.MetadataVersion);
            Assert.Same(reader5.UTF8Decoder, MetadataStringDecoder.DefaultUTF8);
            Assert.Equal(reader5.Options, MetadataReaderOptions.ApplyWindowsRuntimeProjections);

            provider.Dispose();
            Assert.Throws <ObjectDisposedException>(() => provider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections));
            Assert.Throws <ObjectDisposedException>(() => provider.GetMetadataReader());
        }
        private unsafe void TestGetMetadataReader(MetadataReaderProvider provider)
        {
            var decoder = new TestMetadataStringDecoder(Encoding.UTF8, (a, b) => "str");

            var reader1 = provider.GetMetadataReader(MetadataReaderOptions.None, decoder);
            Assert.Equal("str", reader1.MetadataVersion);
            Assert.Same(reader1.Utf8Decoder, decoder);
            Assert.Equal(reader1.Options, MetadataReaderOptions.None);

            var reader2 = provider.GetMetadataReader(MetadataReaderOptions.None, decoder);
            Assert.Same(reader1, reader2);

            var reader3 = provider.GetMetadataReader(MetadataReaderOptions.None);
            Assert.NotSame(reader2, reader3);
            Assert.Equal("v9.9.9.9", reader3.MetadataVersion);
            Assert.Same(reader3.Utf8Decoder, MetadataStringDecoder.DefaultUTF8);
            Assert.Equal(reader3.Options, MetadataReaderOptions.None);

            var reader4 = provider.GetMetadataReader(MetadataReaderOptions.None);
            Assert.Same(reader3, reader4);

            var reader5 = provider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections);
            Assert.NotSame(reader4, reader5);
            Assert.Equal("v9.9.9.9", reader5.MetadataVersion);
            Assert.Same(reader5.Utf8Decoder, MetadataStringDecoder.DefaultUTF8);
            Assert.Equal(reader5.Options, MetadataReaderOptions.ApplyWindowsRuntimeProjections);

            provider.Dispose();
            Assert.Throws<ObjectDisposedException>(() => provider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections));
            Assert.Throws<ObjectDisposedException>(() => provider.GetMetadataReader());
        }