public Task <DocumentDebugInfoReader?> GetDocumentDebugInfoReaderAsync(string dllPath, CancellationToken cancellationToken) { var dllStream = IOUtilities.PerformIO(() => File.OpenRead(dllPath)); if (dllStream is null) { return(Task.FromResult <DocumentDebugInfoReader?>(null)); } Stream?pdbStream = null; DocumentDebugInfoReader?result = null; var peReader = new PEReader(dllStream); try { if (peReader.TryOpenAssociatedPortablePdb(dllPath, pdbPath => File.OpenRead(pdbPath), out var pdbReaderProvider, out _)) { Contract.ThrowIfNull(pdbReaderProvider); result = new DocumentDebugInfoReader(peReader, pdbReaderProvider); } // TODO: Otherwise call the debugger to find the PDB from a symbol server etc. if (result is null) { // Debugger needs: // - PDB MVID // - PDB Age // - PDB TimeStamp // - PDB Path // - DLL Path // // Most of this info comes from the CodeView Debug Directory from the dll } } catch (BadImageFormatException) { // If the PDB is corrupt in some way we can just ignore it, and let the system fall through to another provider // TODO: Log this to the output window: https://github.com/dotnet/roslyn/issues/57352 result = null; } finally { // If we're returning a result then it will own the disposal of the reader, but if not // then we need to do it ourselves. if (result is null) { pdbStream?.Dispose(); peReader.Dispose(); } } return(Task.FromResult <DocumentDebugInfoReader?>(result)); }
public async Task <DocumentDebugInfoReader?> GetDocumentDebugInfoReaderAsync(string dllPath, TelemetryMessage telemetry, CancellationToken cancellationToken) { var dllStream = IOUtilities.PerformIO(() => File.OpenRead(dllPath)); if (dllStream is null) { return(null); } Stream?pdbStream = null; DocumentDebugInfoReader?result = null; var peReader = new PEReader(dllStream); try { // Try to load the pdb file from disk, or embedded if (peReader.TryOpenAssociatedPortablePdb(dllPath, pdbPath => File.OpenRead(pdbPath), out var pdbReaderProvider, out var pdbFilePath)) { Contract.ThrowIfNull(pdbReaderProvider); if (pdbFilePath is null) { telemetry.SetPdbSource("embedded"); _logger?.Log(FeaturesResources.Found_embedded_PDB_file); } else { telemetry.SetPdbSource("ondisk"); _logger?.Log(FeaturesResources.Found_PDB_file_at_0, pdbFilePath); } result = new DocumentDebugInfoReader(peReader, pdbReaderProvider); } if (result is null) { if (_sourceLinkService is null) { _logger?.Log(FeaturesResources.Could_not_find_PDB_on_disk_or_embedded); } else { var delay = Task.Delay(SymbolLocatorTimeout, cancellationToken); // Call the debugger to find the PDB from a symbol server etc. var pdbResultTask = _sourceLinkService.GetPdbFilePathAsync(dllPath, peReader, cancellationToken); var winner = await Task.WhenAny(pdbResultTask, delay).ConfigureAwait(false); if (winner == pdbResultTask) { var pdbResult = await pdbResultTask.ConfigureAwait(false); if (pdbResult is not null) { pdbStream = IOUtilities.PerformIO(() => File.OpenRead(pdbResult.PdbFilePath)); if (pdbStream is not null) { var readerProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); telemetry.SetPdbSource("symbolserver"); result = new DocumentDebugInfoReader(peReader, readerProvider); _logger?.Log(FeaturesResources.Found_PDB_on_symbol_server); } else { _logger?.Log(FeaturesResources.Found_PDB_on_symbol_server_but_could_not_read_file); } } else { _logger?.Log(FeaturesResources.Could_not_find_PDB_on_disk_or_embedded_or_server); } } else { telemetry.SetPdbSource("timeout"); _logger?.Log(FeaturesResources.Timeout_symbol_server); } } } } catch (BadImageFormatException ex) { // If the PDB is corrupt in some way we can just ignore it, and let the system fall through to another provider _logger?.Log(FeaturesResources.Error_reading_PDB_0, ex.Message); result = null; } finally { // If we're returning a result then it will own the disposal of the reader, but if not // then we need to do it ourselves. if (result is null) { pdbStream?.Dispose(); peReader.Dispose(); } } return(result); }
public async Task <DocumentDebugInfoReader?> GetDocumentDebugInfoReaderAsync(string dllPath, IPdbSourceDocumentLogger?logger, CancellationToken cancellationToken) { var dllStream = IOUtilities.PerformIO(() => File.OpenRead(dllPath)); if (dllStream is null) { return(null); } Stream?pdbStream = null; DocumentDebugInfoReader?result = null; var peReader = new PEReader(dllStream); try { // Try to load the pdb file from disk, or embedded if (peReader.TryOpenAssociatedPortablePdb(dllPath, pdbPath => File.OpenRead(pdbPath), out var pdbReaderProvider, out _)) { Contract.ThrowIfNull(pdbReaderProvider); result = new DocumentDebugInfoReader(peReader, pdbReaderProvider); } // Otherwise call the debugger to find the PDB from a symbol server etc. if (result is null && _sourceLinkService is not null) { var delay = Task.Delay(SymbolLocatorTimeout, cancellationToken); var pdbResultTask = _sourceLinkService.GetPdbFilePathAsync(dllPath, peReader, logger, cancellationToken); var winner = await Task.WhenAny(pdbResultTask, delay).ConfigureAwait(false); if (winner == pdbResultTask) { var pdbResult = await pdbResultTask.ConfigureAwait(false); // TODO: Support windows PDBs: https://github.com/dotnet/roslyn/issues/55834 // TODO: Log results from pdbResult.Log: https://github.com/dotnet/roslyn/issues/57352 if (pdbResult is not null && pdbResult.IsPortablePdb) { pdbStream = IOUtilities.PerformIO(() => File.OpenRead(pdbResult.PdbFilePath)); if (pdbStream is not null) { var readerProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); result = new DocumentDebugInfoReader(peReader, readerProvider); } } } else { // TODO: Log the timeout: https://github.com/dotnet/roslyn/issues/57352 } } } catch (BadImageFormatException) { // If the PDB is corrupt in some way we can just ignore it, and let the system fall through to another provider // TODO: Log this to the output window: https://github.com/dotnet/roslyn/issues/57352 result = null; } finally { // If we're returning a result then it will own the disposal of the reader, but if not // then we need to do it ourselves. if (result is null) { pdbStream?.Dispose(); peReader.Dispose(); } } return(result); }