/// <summary> /// Adds a CodeView entry. /// </summary> /// <param name="pdbPath">Path to the PDB. Shall not be empty.</param> /// <param name="pdbContentId">Unique id of the PDB content.</param> /// <param name="portablePdbVersion">Version of Portable PDB format (e.g. 0x0100 for 1.0), or 0 if the PDB is not portable.</param> /// <exception cref="ArgumentNullException"><paramref name="pdbPath"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="pdbPath"/> contains NUL character.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.</exception> public void AddCodeViewEntry( string pdbPath, BlobContentId pdbContentId, ushort portablePdbVersion) { if (pdbPath == null) { Throw.ArgumentNull(nameof(pdbPath)); } // We allow NUL characters to allow for padding for backward compat purposes. if (pdbPath.Length == 0 || pdbPath.IndexOf('\0') == 0) { Throw.InvalidArgument(SR.ExpectedNonEmptyString, nameof(pdbPath)); } if (portablePdbVersion > 0 && portablePdbVersion < PortablePdbVersions.MinFormatVersion) { Throw.ArgumentOutOfRange(nameof(portablePdbVersion)); } int dataSize = WriteCodeViewData(_dataBuilder, pdbPath, pdbContentId.Guid); AddEntry( type: DebugDirectoryEntryType.CodeView, version: (portablePdbVersion == 0) ? 0 : PortablePdbVersions.DebugDirectoryEntryVersion(portablePdbVersion), stamp: pdbContentId.Stamp, dataSize: dataSize); }
public void Empty() { var b = new DebugDirectoryBuilder(); var id = new BlobContentId(new Guid("3C88E66E-E0B9-4508-9290-11E0DB51A1C5"), 0x12345678); var blob = new BlobBuilder(); b.Serialize(blob, new SectionLocation(0x1000, 0x2000), 0x50); AssertEx.Equal(new byte[0], blob.ToArray()); }
public void AddCodeViewEntry2() { var b = new DebugDirectoryBuilder(); var id = new BlobContentId(new Guid("3C88E66E-E0B9-4508-9290-11E0DB51A1C5"), 0x12345678); b.AddCodeViewEntry("foo.pdb" + new string('\0', 260 - "foo.pdb".Length - 1), id, 0xABCD); var blob = new BlobBuilder(); b.Serialize(blob, new SectionLocation(0x1000, 0x2000), 0x50); var bytes = blob.ToArray(); AssertEx.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00, // Characteristics 0x78, 0x56, 0x34, 0x12, // Stamp 0xCD, 0xAB, 0x4D, 0x50, // Version 0x02, 0x00, 0x00, 0x00, // Type 0x1C, 0x01, 0x00, 0x00, // SizeOfData 0x6C, 0x10, 0x00, 0x00, // AddressOfRawData 0x6C, 0x20, 0x00, 0x00, // PointerToRawData // data (byte)'R', (byte)'S', (byte)'D', (byte)'S', 0x6E, 0xE6, 0x88, 0x3C, 0xB9, 0xE0, 0x08, 0x45, 0x92, 0x90, 0x11, 0xE0, 0xDB, 0x51, 0xA1, 0xC5, // GUID 0x01, 0x00, 0x00, 0x00, // age (byte)'f', (byte)'o', (byte)'o', (byte)'.', (byte)'p', (byte)'d', (byte)'b', 0x00, // path // path padding: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, bytes); using (var pinned = new PinnedBlob(bytes)) { var actual = PEReader.ReadDebugDirectoryEntries(pinned.CreateReader(0, DebugDirectoryEntry.Size)); Assert.Equal(1, actual.Length); Assert.Equal(id.Stamp, actual[0].Stamp); Assert.Equal(0xABCD, actual[0].MajorVersion); Assert.Equal(0x504d, actual[0].MinorVersion); Assert.Equal(DebugDirectoryEntryType.CodeView, actual[0].Type); Assert.Equal(0x0000011c, actual[0].DataSize); Assert.Equal(0x0000106c, actual[0].DataRelativeVirtualAddress); Assert.Equal(0x0000206c, actual[0].DataPointer); } }
public void EmbeddedPortablePdb() { string source = @" using System; class C { public static void Main() { Console.WriteLine(); } } "; var c = CreateCompilationWithMscorlib(Parse(source, "foo.cs"), options: TestOptions.DebugDll); var peBlob = c.EmitToArray(EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.Embedded).WithPdbFilePath(@"a/b/c/d.pdb")); using (var peReader = new PEReader(peBlob)) { var entries = peReader.ReadDebugDirectory(); AssertEx.Equal(new[] { DebugDirectoryEntryType.CodeView, DebugDirectoryEntryType.EmbeddedPortablePdb }, entries.Select(e => e.Type)); var codeView = entries[0]; var embedded = entries[1]; // EmbeddedPortablePdb entry: Assert.Equal(0x0100, embedded.MajorVersion); Assert.Equal(0x0100, embedded.MinorVersion); Assert.Equal(0u, embedded.Stamp); BlobContentId pdbId; using (var embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embedded)) { var mdReader = embeddedMetadataProvider.GetMetadataReader(); AssertEx.Equal(new[] { "foo.cs" }, mdReader.Documents.Select(doc => mdReader.GetString(mdReader.GetDocument(doc).Name))); pdbId = new BlobContentId(mdReader.DebugMetadataHeader.Id); } // CodeView entry: var codeViewData = peReader.ReadCodeViewDebugDirectoryData(codeView); Assert.Equal(0x0100, codeView.MajorVersion); Assert.Equal(0x504D, codeView.MinorVersion); Assert.Equal(pdbId.Stamp, codeView.Stamp); Assert.Equal(pdbId.Guid, codeViewData.Guid); Assert.Equal("d.pdb", codeViewData.Path); } }
public void AddCodeViewEntry( string pdbPath, BlobContentId pdbContentId, ushort portablePdbVersion) { if (pdbPath == null) { Throw.ArgumentNull(nameof(pdbPath)); } int dataSize = WriteCodeViewData(_dataBuilder, pdbPath, pdbContentId.Guid); AddEntry( type: DebugDirectoryEntryType.CodeView, version: (portablePdbVersion == 0) ? 0 : PortablePdbVersions.DebugDirectoryEntryVersion(portablePdbVersion), stamp: pdbContentId.Stamp, dataSize: dataSize); }
public void MultipleEntries() { var b = new DebugDirectoryBuilder(); var id = new BlobContentId(new Guid("3C88E66E-E0B9-4508-9290-11E0DB51A1C5"), 0x12345678); b.AddReproducibleEntry(); b.AddCodeViewEntry("x", id, 0); b.AddReproducibleEntry(); b.AddCodeViewEntry("y", id, 0xABCD); var blob = new BlobBuilder(); b.Serialize(blob, new SectionLocation(0x1000, 0x2000), 0x50); AssertEx.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00, // Characteristics 0x00, 0x00, 0x00, 0x00, // Stamp 0x00, 0x00, 0x00, 0x00, // Version 0x10, 0x00, 0x00, 0x00, // Type 0x00, 0x00, 0x00, 0x00, // SizeOfData 0x00, 0x00, 0x00, 0x00, // AddressOfRawData 0x00, 0x00, 0x00, 0x00, // PointerToRawData 0x00, 0x00, 0x00, 0x00, // Characteristics 0x78, 0x56, 0x34, 0x12, // Stamp 0x00, 0x00, 0x00, 0x00, // Version 0x02, 0x00, 0x00, 0x00, // Type 0x1A, 0x00, 0x00, 0x00, // SizeOfData 0xC0, 0x10, 0x00, 0x00, // AddressOfRawData 0xC0, 0x20, 0x00, 0x00, // PointerToRawData 0x00, 0x00, 0x00, 0x00, // Characteristics 0x00, 0x00, 0x00, 0x00, // Stamp 0x00, 0x00, 0x00, 0x00, // Version 0x10, 0x00, 0x00, 0x00, // Type 0x00, 0x00, 0x00, 0x00, // SizeOfData 0x00, 0x00, 0x00, 0x00, // AddressOfRawData 0x00, 0x00, 0x00, 0x00, // PointerToRawData 0x00, 0x00, 0x00, 0x00, // Characteristics 0x78, 0x56, 0x34, 0x12, // Stamp 0xCD, 0xAB, 0x4D, 0x50, // Version 0x02, 0x00, 0x00, 0x00, // Type 0x1A, 0x00, 0x00, 0x00, // SizeOfData 0xDA, 0x10, 0x00, 0x00, // AddressOfRawData 0xDA, 0x20, 0x00, 0x00, // PointerToRawData // data (byte)'R', (byte)'S', (byte)'D', (byte)'S', 0x6E, 0xE6, 0x88, 0x3C, 0xB9, 0xE0, 0x08, 0x45, 0x92, 0x90, 0x11, 0xE0, 0xDB, 0x51, 0xA1, 0xC5, // GUID 0x01, 0x00, 0x00, 0x00, // age (byte)'x', 0x00, // path // data (byte)'R', (byte)'S', (byte)'D', (byte)'S', 0x6E, 0xE6, 0x88, 0x3C, 0xB9, 0xE0, 0x08, 0x45, 0x92, 0x90, 0x11, 0xE0, 0xDB, 0x51, 0xA1, 0xC5, // GUID 0x01, 0x00, 0x00, 0x00, // age (byte)'y', 0x00, // path }, blob.ToArray()); }
public void TryOpenAssociatedPortablePdb_BadStreamProvider() { var pdbBuilder = new BlobBuilder(); pdbBuilder.WriteBytes(PortablePdbs.DocumentsPdb); var id = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678); var ddBuilder = new DebugDirectoryBuilder(); ddBuilder.AddCodeViewEntry(@"/a/b/a.pdb", id, portablePdbVersion: 0x0100); var peStream = new MemoryStream(TestBuilders.BuildPEWithDebugDirectory(ddBuilder)); using (var reader = new PEReader(peStream)) { MetadataReaderProvider pdbProvider; string pdbPath; // pass-thru: Assert.Throws<ArgumentException>(() => reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new ArgumentException(); }, out pdbProvider, out pdbPath)); Assert.Throws<InvalidOperationException>(() => reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { return new TestStream(canRead: false, canWrite: true, canSeek: true); }, out pdbProvider, out pdbPath)); Assert.Throws<InvalidOperationException>(() => reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { return new TestStream(canRead: true, canWrite: true, canSeek: false); }, out pdbProvider, out pdbPath)); } }
public void TryOpenAssociatedPortablePdb_ExpectedExceptionFromStreamProvider_NoFallback() { var pdbBuilder = new BlobBuilder(); pdbBuilder.WriteBytes(PortablePdbs.DocumentsPdb); var id = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678); var ddBuilder = new DebugDirectoryBuilder(); ddBuilder.AddCodeViewEntry(@"/a/b/a.pdb", id, portablePdbVersion: 0x0100); var peStream = new MemoryStream(TestBuilders.BuildPEWithDebugDirectory(ddBuilder)); using (var reader = new PEReader(peStream)) { MetadataReaderProvider pdbProvider; string pdbPath; Assert.Throws<IOException>(() => reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new IOException(); }, out pdbProvider, out pdbPath)); AssertEx.Throws<BadImageFormatException>(() => reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new BadImageFormatException("Bang!"); }, out pdbProvider, out pdbPath), e => Assert.Equal("Bang!", e.Message)); // file doesn't exist and no embedded => return false Assert.False(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new FileNotFoundException(); }, out pdbProvider, out pdbPath)); } }
public void TryOpenAssociatedPortablePdb_ExpectedExceptionFromStreamProvider_FallbackOnEmbedded_Valid() { var pdbBuilder = new BlobBuilder(); pdbBuilder.WriteBytes(PortablePdbs.DocumentsPdb); var id = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678); var ddBuilder = new DebugDirectoryBuilder(); ddBuilder.AddCodeViewEntry(@"/a/b/a.pdb", id, portablePdbVersion: 0x0100); ddBuilder.AddEmbeddedPortablePdbEntry(pdbBuilder, portablePdbVersion: 0x0100); var peStream = new MemoryStream(TestBuilders.BuildPEWithDebugDirectory(ddBuilder)); using (var reader = new PEReader(peStream)) { MetadataReaderProvider pdbProvider; string pdbPath; Assert.True(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new IOException(); }, out pdbProvider, out pdbPath)); Assert.Null(pdbPath); Assert.Equal(13, pdbProvider.GetMetadataReader().Documents.Count); Assert.True(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new BadImageFormatException(); }, out pdbProvider, out pdbPath)); Assert.Null(pdbPath); Assert.Equal(13, pdbProvider.GetMetadataReader().Documents.Count); Assert.True(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new FileNotFoundException(); }, out pdbProvider, out pdbPath)); Assert.Null(pdbPath); Assert.Equal(13, pdbProvider.GetMetadataReader().Documents.Count); } }
public void TryOpenAssociatedPortablePdb_BadPdbFile_FallbackToEmbedded() { var pdbBuilder = new BlobBuilder(); pdbBuilder.WriteBytes(PortablePdbs.DocumentsPdb); var id = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678); var ddBuilder = new DebugDirectoryBuilder(); ddBuilder.AddCodeViewEntry(@"/a/b/a.pdb", id, portablePdbVersion: 0x0100); ddBuilder.AddEmbeddedPortablePdbEntry(pdbBuilder, portablePdbVersion: 0x0100); var peStream = new MemoryStream(TestBuilders.BuildPEWithDebugDirectory(ddBuilder)); using (var reader = new PEReader(peStream)) { string pathQueried = null; Func<string, Stream> streamProvider = p => { Assert.Null(pathQueried); pathQueried = p; // Bad PDB return new MemoryStream(new byte[] { 0x01 }); }; MetadataReaderProvider pdbProvider; string pdbPath; Assert.True(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), streamProvider, out pdbProvider, out pdbPath)); Assert.Null(pdbPath); Assert.Equal(PathUtilities.CombinePathWithRelativePath("pedir", "a.pdb"), pathQueried); Assert.Equal(13, pdbProvider.GetMetadataReader().Documents.Count); } }
public void TryOpenAssociatedPortablePdb_DuplicateEntries_CodeView() { var id = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678); var ddBuilder = new DebugDirectoryBuilder(); ddBuilder.AddCodeViewEntry(@"/a/b/a.pdb", id, portablePdbVersion: 0); ddBuilder.AddReproducibleEntry(); ddBuilder.AddCodeViewEntry(@"/a/b/c.pdb", id, portablePdbVersion: 0x0100); ddBuilder.AddCodeViewEntry(@"/a/b/d.pdb", id, portablePdbVersion: 0x0100); var peStream = new MemoryStream(TestBuilders.BuildPEWithDebugDirectory(ddBuilder)); using (var reader = new PEReader(peStream)) { string pathQueried = null; Func<string, Stream> streamProvider = p => { Assert.Null(pathQueried); pathQueried = p; return null; }; MetadataReaderProvider pdbProvider; string pdbPath; Assert.False(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), streamProvider, out pdbProvider, out pdbPath)); Assert.Equal(PathUtilities.CombinePathWithRelativePath("pedir", "c.pdb"), pathQueried); } }
public void Serialize(BlobBuilder builder, out BlobContentId contentId) { // Define and serialize sections in two steps. // We need to know about all sections before serializing them. var serializedSections = SerializeSections(); // The positions and sizes of directories are calculated during section serialization. var directories = GetDirectories(); Blob stampFixup; WritePESignature(builder); WriteCoffHeader(builder, serializedSections, out stampFixup); WritePEHeader(builder, directories, serializedSections); WriteSectionHeaders(builder, serializedSections); builder.Align(Header.FileAlignment); foreach (var section in serializedSections) { builder.LinkSuffix(section.Builder); builder.Align(Header.FileAlignment); } contentId = IdProvider(builder.GetBlobs()); // patch timestamp in COFF header: var stampWriter = new BlobWriter(stampFixup); stampWriter.WriteUInt32(contentId.Stamp); Debug.Assert(stampWriter.RemainingBytes == 0); }