/// <summary> /// Creates a new <see cref="SymbolReader"/> instance /// </summary> /// <param name="pdbContext">PDB context</param> /// <param name="pdbStream">PDB file stream which is now owned by this method</param> /// <returns>A new <see cref="SymbolReader"/> instance or <c>null</c>.</returns> public static SymbolReader Create(PdbReaderContext pdbContext, DataReaderFactory pdbStream) { if (pdbStream == null) { return(null); } try { var debugDir = pdbContext.CodeViewDebugDirectory; if (debugDir == null) { return(null); } if (!pdbContext.TryGetCodeViewData(out var pdbGuid, out uint age)) { return(null); } var pdbReader = new PdbReader(pdbGuid, age); pdbReader.Read(pdbStream.CreateReader()); if (pdbReader.MatchesModule) { return(pdbReader); } return(null); } catch (PdbException) { } catch (IOException) { } finally { pdbStream?.Dispose(); } return(null); }
public static SymbolReader TryCreate(PdbReaderContext pdbContext, DataReaderFactory pdbStream, bool isEmbeddedPortablePdb) { bool disposePdbStream = true; try { if (!pdbContext.HasDebugInfo) { return(null); } if (pdbStream == null) { return(null); } if (pdbStream.Length < 4) { return(null); } if (pdbStream.CreateReader().ReadUInt32() != 0x424A5342) { return(null); } var debugDir = pdbContext.CodeViewDebugDirectory; if (debugDir == null) { return(null); } if (debugDir.MinorVersion != DDW.PortablePdbConstants.PortableCodeViewVersionMagic) { return(null); } bool validFormatVersion = debugDir.MajorVersion == DDW.PortablePdbConstants.FormatVersion; Debug.Assert(validFormatVersion, $"New Portable PDB version: 0x{debugDir.MajorVersion:X4}"); if (!validFormatVersion) { return(null); } if (!pdbContext.TryGetCodeViewData(out var pdbGuid, out uint age)) { return(null); } var reader = new PortablePdbReader(pdbStream, isEmbeddedPortablePdb ? PdbFileKind.EmbeddedPortablePDB : PdbFileKind.PortablePDB); if (!reader.MatchesModule(pdbGuid, debugDir.TimeDateStamp, age)) { return(null); } disposePdbStream = false; return(reader); } catch (IOException) { } finally { if (disposePdbStream) { pdbStream?.Dispose(); } } return(null); }
public static SymbolReader TryCreateEmbeddedPortablePdbReader(PdbReaderContext pdbContext, Metadata metadata) { if (metadata == null) { return(null); } try { if (!pdbContext.HasDebugInfo) { return(null); } var embeddedDir = pdbContext.TryGetDebugDirectoryEntry(ImageDebugType.EmbeddedPortablePdb); if (embeddedDir == null) { return(null); } var reader = pdbContext.CreateReader(embeddedDir.PointerToRawData, embeddedDir.SizeOfData); if (reader.Length < 8) { return(null); } // "MPDB" = 0x4244504D if (reader.ReadUInt32() != 0x4244504D) { return(null); } uint uncompressedSize = reader.ReadUInt32(); // If this fails, see the (hopefully) updated spec: // https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#embedded-portable-pdb-debug-directory-entry-type-17 bool newVersion = (uncompressedSize & 0x80000000) != 0; Debug.Assert(!newVersion); if (newVersion) { return(null); } var decompressedBytes = new byte[uncompressedSize]; using (var deflateStream = new DeflateStream(reader.AsStream(), CompressionMode.Decompress)) { int pos = 0; while (pos < decompressedBytes.Length) { int read = deflateStream.Read(decompressedBytes, pos, decompressedBytes.Length - pos); if (read == 0) { break; } pos += read; } if (pos != decompressedBytes.Length) { return(null); } var stream = ByteArrayDataReaderFactory.Create(decompressedBytes, filename: null); return(TryCreate(pdbContext, stream, isEmbeddedPortablePdb: true)); } } catch (IOException) { } return(null); }
public static SymbolReader TryCreate(PdbReaderContext pdbContext, DataReaderFactory pdbStream, bool isEmbeddedPortablePdb) { bool disposePdbStream = true; try { if (!pdbContext.HasDebugInfo) { return(null); } if (pdbStream is null) { return(null); } if (pdbStream.Length < 4) { return(null); } if (pdbStream.CreateReader().ReadUInt32() != 0x424A5342) { return(null); } var debugDir = pdbContext.CodeViewDebugDirectory; if (debugDir is null) { return(null); } // Don't check that debugDir.MinorVersion == PortablePdbConstants.PortableCodeViewVersionMagic // and debugDir.MajorVersion == PortablePdbConstants.FormatVersion since it could be a converted // WindowsPDB file: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 if (!pdbContext.TryGetCodeViewData(out var pdbGuid, out uint age)) { return(null); } var reader = new PortablePdbReader(pdbStream, isEmbeddedPortablePdb ? PdbFileKind.EmbeddedPortablePDB : PdbFileKind.PortablePDB); if (!reader.MatchesModule(pdbGuid, debugDir.TimeDateStamp, age)) { return(null); } disposePdbStream = false; return(reader); } catch (IOException) { } finally { if (disposePdbStream) { pdbStream?.Dispose(); } } return(null); }
public static SymbolReader Create(PdbReaderContext pdbContext, MD.Metadata metadata, DataReaderFactory pdbStream) { ISymUnmanagedReader unmanagedReader = null; SymbolReaderImpl symReader = null; ReaderMetaDataImport mdImporter = null; DataReaderIStream comPdbStream = null; bool error = true; try { if (pdbStream is null) { return(null); } var debugDir = pdbContext.CodeViewDebugDirectory; if (debugDir is null) { return(null); } if (!pdbContext.TryGetCodeViewData(out var pdbGuid, out uint age)) { return(null); } unmanagedReader = CreateSymUnmanagedReader(pdbContext.Options); if (unmanagedReader is null) { return(null); } mdImporter = new ReaderMetaDataImport(metadata); comPdbStream = new DataReaderIStream(pdbStream); int hr = unmanagedReader.Initialize(mdImporter, null, null, comPdbStream); if (hr < 0) { return(null); } symReader = new SymbolReaderImpl(unmanagedReader, new object[] { pdbStream, mdImporter, comPdbStream }); if (!symReader.MatchesModule(pdbGuid, debugDir.TimeDateStamp, age)) { return(null); } error = false; return(symReader); } catch (IOException) { } catch (InvalidCastException) { } catch (COMException) { } finally { if (error) { pdbStream?.Dispose(); symReader?.Dispose(); mdImporter?.Dispose(); comPdbStream?.Dispose(); (unmanagedReader as ISymUnmanagedDispose)?.Destroy(); } } return(null); }