Example #1
0
        private static void WritePEImage(
            Stream peStream,
            MetadataBuilder metadataBuilder,
            BlobBuilder ilBuilder,
            MethodDefinitionHandle entryPointHandle
            )
        {
            // Create executable with the managed metadata from the specified MetadataBuilder.
            var peHeaderBuilder = new PEHeaderBuilder(
                imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll
                );

            var peBuilder = new ManagedPEBuilder(
                peHeaderBuilder,
                new MetadataRootBuilder(metadataBuilder),
                ilBuilder,
                entryPoint: entryPointHandle,
                flags: CorFlags.ILOnly,
                deterministicIdProvider: content => s_contentId);

            // Write executable into the specified stream.
            var           peBlob    = new BlobBuilder();
            BlobContentId contentId = peBuilder.Serialize(peBlob);

            peBlob.WriteContentTo(peStream);
        }
Example #2
0
        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));
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
        public override IEnumerable <SymbolStoreKey> GetKeys(KeyTypeFlags flags)
        {
            if ((flags & KeyTypeFlags.IdentityKey) != 0)
            {
                SymbolStoreKey key = null;

                try
                {
                    _file.Stream.Position = 0;
                    using (MetadataReaderProvider provider = MetadataReaderProvider.FromPortablePdbStream(_file.Stream, MetadataStreamOptions.LeaveOpen))
                    {
                        MetadataReader reader = provider.GetMetadataReader();
                        var            blob   = new BlobContentId(reader.DebugMetadataHeader.Id);
                        if ((flags & KeyTypeFlags.ForceWindowsPdbs) == 0)
                        {
                            key = GetKey(_file.FileName, blob.Guid);
                        }
                        else
                        {
                            // Force the Windows PDB index
                            key = PDBFileKeyGenerator.GetKey(_file.FileName, blob.Guid, 1);
                        }
                    }
                }
                catch (BadImageFormatException ex)
                {
                    Tracer.Warning("PortablePDBFileKeyGenerator {0}", ex.Message);
                }

                if (key != null)
                {
                    yield return(key);
                }
            }
        }
Example #5
0
        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:
                AssertExtensions.Throws <ArgumentException>(null, () =>
                                                            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));
            }
        }
Example #6
0
        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());
        }
Example #7
0
        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);
        }
        /// <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>
        /// <param name="age">Age (iteration) of the PDB. Shall be 1 for Portable PDBs.</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="age"/> is less than 1.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.</exception>
        internal void AddCodeViewEntry(
            string pdbPath,
            BlobContentId pdbContentId,
            ushort portablePdbVersion,
            int age)
        {
            if (pdbPath == null)
            {
                Throw.ArgumentNull(nameof(pdbPath));
            }

            if (age < 1)
            {
                Throw.ArgumentOutOfRange(nameof(age));
            }

            // 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, age);

            AddEntry(
                type: DebugDirectoryEntryType.CodeView,
                version: (portablePdbVersion == 0) ? 0 : PortablePdbVersions.DebugDirectoryEntryVersion(portablePdbVersion),
                stamp: pdbContentId.Stamp,
                dataSize);
        }
 /// <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)
 {
     AddCodeViewEntry(pdbPath, pdbContentId, portablePdbVersion, age: 1);
 }
Example #10
0
        private bool TryOpenCodeViewPortablePdb(DebugDirectoryEntry codeViewEntry, string peImageDirectory, Func <string, Stream?> pdbFileStreamProvider, out MetadataReaderProvider?provider, out string?pdbPath, ref Exception?errorToReport)
        {
            pdbPath  = null;
            provider = null;

            CodeViewDebugDirectoryData data;

            try
            {
                data = ReadCodeViewDebugDirectoryData(codeViewEntry);
            }
            catch (Exception e) when(e is BadImageFormatException || e is IOException)
            {
                errorToReport = errorToReport ?? e;
                return(false);
            }

            var id = new BlobContentId(data.Guid, codeViewEntry.Stamp);

            // The interpretation os the path in the CodeView needs to be platform agnostic,
            // so that PDBs built on Windows work on Unix-like systems and vice versa.
            // System.IO.Path.GetFileName() on Unix-like systems doesn't treat '\' as a file name separator,
            // so we need a custom implementation. Also avoid throwing an exception if the path contains invalid characters,
            // they might not be invalid on the other platform. It's up to the FS APIs to deal with that when opening the stream.
            string collocatedPdbPath = PathUtilities.CombinePathWithRelativePath(peImageDirectory, PathUtilities.GetFileName(data.Path));

            if (TryOpenPortablePdbFile(collocatedPdbPath, id, pdbFileStreamProvider, out provider, ref errorToReport))
            {
                pdbPath = collocatedPdbPath;
                return(true);
            }

            return(false);
        }
        private static unsafe void ValidatePortablePdbId(MetadataReader pdbReader, uint stampInDebugDirectory, Guid guidInDebugDirectory)
        {
            var expectedId = new BlobContentId(guidInDebugDirectory, stampInDebugDirectory);
            var actualId   = new BlobContentId(pdbReader.DebugMetadataHeader.Id);

            Assert.Equal(expectedId, actualId);
        }
Example #12
0
        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, age: 0x1234);
            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);
            }
        }
Example #13
0
        public void TryOpenAssociatedPortablePdb_WindowsSpecificPath()
        {
            var id        = new BlobContentId(Guid.Parse("18091B06-32BB-46C2-9C3B-7C9389A2F6C6"), 0x12345678);
            var ddBuilder = new DebugDirectoryBuilder();

            ddBuilder.AddCodeViewEntry(@"C:def.xyz", 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(Path.Combine("pedir", "def.xyz"), pathQueried);
            }
        }
Example #14
0
        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, 0x99);

            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
                0x99, 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.True(actual[0].IsPortableCodeView);
                Assert.Equal(0x0000011c, actual[0].DataSize);
                Assert.Equal(0x0000106c, actual[0].DataRelativeVirtualAddress);
                Assert.Equal(0x0000206c, actual[0].DataPointer);
            }
        }
Example #15
0
        public void EmbeddedPortablePdb()
        {
            string source = @"
using System;

class C
{
    public static void Main()
    {
        Console.WriteLine();
    }
}
";
            var    c      = CreateCompilation(Parse(source, "goo.cs"), options: TestOptions.DebugDll);

            var peBlob = c.EmitToArray(EmitOptions.Default.
                                       WithDebugInformationFormat(DebugInformationFormat.Embedded).
                                       WithPdbFilePath(@"a/b/c/d.pdb").
                                       WithPdbChecksumAlgorithm(HashAlgorithmName.SHA512));

            using (var peReader = new PEReader(peBlob))
            {
                var entries = peReader.ReadDebugDirectory();

                AssertEx.Equal(new[] { DebugDirectoryEntryType.CodeView, DebugDirectoryExtensions.PdbChecksumEntryType, DebugDirectoryEntryType.EmbeddedPortablePdb }, entries.Select(e => e.Type));

                var codeView = entries[0];
                var checksum = entries[1];
                var embedded = entries[2];

                // 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[] { "goo.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);

                // Checksum entry:
                var checksumData = peReader.ReadPdbChecksumDebugDirectoryData(checksum);
                Assert.Equal("SHA512", checksumData.AlgorithmName);
                Assert.Equal(64, checksumData.Checksum.Length);
            }
        }
Example #16
0
        private string ReadFromProgramDatabaseStream(Stream pdbStream)
        {
            var metadataProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
            var metadataReader   = metadataProvider.GetMetadataReader();
            var id   = new BlobContentId(metadataReader.DebugMetadataHeader.Id);
            var guid = id.Guid.ToString("N");

            return($"{guid}FFFFFFFF".ToUpper());
        }
Example #17
0
        public void EmbeddedPortablePdb_Deterministic()
        {
            string source = @"
using System;

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

            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.Reproducible, DebugDirectoryEntryType.EmbeddedPortablePdb }, entries.Select(e => e.Type));

                var codeView     = entries[0];
                var reproducible = entries[1];
                var embedded     = entries[2];

                // 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);

                // Reproducible entry:
                Assert.Equal(0, reproducible.MajorVersion);
                Assert.Equal(0, reproducible.MinorVersion);
                Assert.Equal(0U, reproducible.Stamp);
                Assert.Equal(0, reproducible.DataSize);
            }
        }
Example #18
0
        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());
        }
Example #19
0
 public StandaloneDebugMetadataSerializer(
     MetadataBuilder builder,
     ImmutableArray <int> typeSystemRowCounts,
     MethodDefinitionHandle entryPoint,
     bool isMinimalDelta,
     Func <IEnumerable <Blob>, BlobContentId> deterministicIdProvider = null)
     : base(builder, CreateSizes(builder, typeSystemRowCounts, isMinimalDelta, isStandaloneDebugMetadata: true), DebugMetadataVersionString)
 {
     _entryPoint = entryPoint;
     IdProvider  = deterministicIdProvider ?? BlobContentId.GetTimeBasedProvider();
 }
Example #20
0
        internal bool MatchesModule(Guid guid, uint stamp, int age)
        {
            if (age != 1)
            {
                return(false);
            }

            var id = new BlobContentId(MetadataReader.DebugMetadataHeader.Id);

            return(id.Guid == guid && id.Stamp == stamp);
        }
Example #21
0
        protected PEBuilder(PEHeaderBuilder header, Func <IEnumerable <Blob>, BlobContentId>?deterministicIdProvider)
        {
            if (header is null)
            {
                Throw.ArgumentNull(nameof(header));
            }

            IdProvider      = deterministicIdProvider ?? BlobContentId.GetTimeBasedProvider();
            IsDeterministic = deterministicIdProvider != null;
            Header          = header;
            _lazySections   = new Lazy <ImmutableArray <Section> >(CreateSections);
        }
Example #22
0
        private bool TryOpenPortablePdbFile(string path, BlobContentId id, Func <string, Stream?> pdbFileStreamProvider, out MetadataReaderProvider?provider, ref Exception?errorToReport)
        {
            provider = null;
            MetadataReaderProvider?candidate = null;

            try
            {
                Stream?pdbStream;

                try
                {
                    pdbStream = pdbFileStreamProvider(path);
                }
                catch (FileNotFoundException)
                {
                    // Not an unexpected IO exception, continue witout reporting the error.
                    pdbStream = null;
                }

                if (pdbStream == null)
                {
                    return(false);
                }

                if (!pdbStream.CanRead || !pdbStream.CanSeek)
                {
                    throw new InvalidOperationException(SR.StreamMustSupportReadAndSeek);
                }

                candidate = MetadataReaderProvider.FromPortablePdbStream(pdbStream);

                // Validate that the PDB matches the assembly version
                if (new BlobContentId(candidate.GetMetadataReader().DebugMetadataHeader !.Id) != id)
                {
                    return(false);
                }

                provider = candidate;
                return(true);
            }
            catch (Exception e) when(e is BadImageFormatException || e is IOException)
            {
                errorToReport = errorToReport ?? e;
                return(false);
            }
            finally
            {
                if (provider == null)
                {
                    candidate?.Dispose();
                }
            }
        }
Example #23
0
        public void SerializeMetadata(BlobBuilder builder, out BlobContentId contentId)
        {
            SerializeMetadataImpl(builder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0);

            contentId = IdProvider(builder.GetBlobs());

            // fill in the id:
            var idWriter = new BlobWriter(_pdbIdBlob);

            idWriter.WriteGuid(contentId.Guid);
            idWriter.WriteUInt32(contentId.Stamp);
            Debug.Assert(idWriter.RemainingBytes == 0);
        }
        public void Ctor()
        {
            var id1 = new BlobContentId(default(Guid), 1);
            Assert.Equal(default(Guid), id1.Guid);
            Assert.Equal(1u, id1.Stamp);
            Assert.False(id1.IsDefault);

            var id2 = new BlobContentId(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), 0x12345678);
            Assert.Equal(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), id2.Guid);
            Assert.Equal(0x12345678u, id2.Stamp);
            Assert.False(id2.IsDefault);

            Assert.True(default(BlobContentId).IsDefault);
        }
Example #25
0
        public void Ctor()
        {
            var id1 = new BlobContentId(default(Guid), 1);

            Assert.Equal(default(Guid), id1.Guid);
            Assert.Equal(1u, id1.Stamp);
            Assert.False(id1.IsDefault);

            var id2 = new BlobContentId(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), 0x12345678);

            Assert.Equal(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), id2.Guid);
            Assert.Equal(0x12345678u, id2.Stamp);
            Assert.False(id2.IsDefault);

            Assert.True(default(BlobContentId).IsDefault);
        }
Example #26
0
        //
        // Symbols
        //

        private PdbSymbolReader OpenAssociatedSymbolFile(string peFilePath, PEReader peReader)
        {
            string        pdbFileName  = null;
            BlobContentId pdbContentId = default;

            foreach (DebugDirectoryEntry debugEntry in peReader.ReadDebugDirectory())
            {
                if (debugEntry.Type != DebugDirectoryEntryType.CodeView)
                {
                    continue;
                }

                CodeViewDebugDirectoryData debugDirectoryData = peReader.ReadCodeViewDebugDirectoryData(debugEntry);

                string candidatePath = debugDirectoryData.Path;
                if (!Path.IsPathRooted(candidatePath) || !File.Exists(candidatePath))
                {
                    // Also check next to the PE file
                    candidatePath = Path.Combine(Path.GetDirectoryName(peFilePath), Path.GetFileName(candidatePath));
                    if (!File.Exists(candidatePath))
                    {
                        continue;
                    }
                }

                pdbFileName  = candidatePath;
                pdbContentId = new BlobContentId(debugDirectoryData.Guid, debugEntry.Stamp);
                break;
            }

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

            // Try to open the symbol file as portable pdb first
            PdbSymbolReader reader = PortablePdbSymbolReader.TryOpen(pdbFileName, GetMetadataStringDecoder(), pdbContentId);

            if (reader == null)
            {
                // Fallback to the diasymreader for non-portable pdbs
                reader = UnmanagedPdbSymbolReader.TryOpenSymbolReaderForMetadataFile(peFilePath, Path.GetDirectoryName(pdbFileName));
            }

            return(reader);
        }
Example #27
0
        public static bool TryReadPdbId(PEReader peReader, out BlobContentId id, out int age)
        {
            var codeViewEntry = peReader.ReadDebugDirectory().FirstOrDefault(entry => entry.Type == DebugDirectoryEntryType.CodeView);

            if (codeViewEntry.DataSize == 0)
            {
                id  = default(BlobContentId);
                age = 0;
                return(false);
            }

            var codeViewData = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry);

            id  = new BlobContentId(codeViewData.Guid, codeViewEntry.Stamp);
            age = codeViewData.Age;
            return(true);
        }
Example #28
0
        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,
                stamp: pdbContentId.Stamp,
                version: (portablePdbVersion == 0) ? 0 : ('P' << 24 | 'M' << 16 | (uint)portablePdbVersion),
                dataSize: dataSize);
        }
Example #29
0
        public void Ctor()
        {
            var id1 = new BlobContentId(default(Guid), 1);
            Assert.Equal(default(Guid), id1.Guid);
            Assert.Equal(1u, id1.Stamp);
            Assert.False(id1.IsDefault);

            var id2 = new BlobContentId(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), 0x12345678);
            Assert.Equal(new Guid("D6D61CDE-5BAF-4E77-ADDD-3B80F4020BF2"), id2.Guid);
            Assert.Equal(0x12345678u, id2.Stamp);
            Assert.False(id2.IsDefault);

            var id3 = new BlobContentId(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14 });
            Assert.Equal(new Guid("04030201-0605-0807-090a-0b0c0d0e0f10"), id3.Guid);
            Assert.Equal(0x14131211u, id3.Stamp);
            Assert.False(id3.IsDefault);

            Assert.True(default(BlobContentId).IsDefault);
        }
Example #30
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);
        }
Example #31
0
        public static PdbSymbolReader TryOpen(string pdbFilename, MetadataStringDecoder stringDecoder, BlobContentId expectedContentId)
        {
            MemoryMappedViewAccessor mappedViewAccessor;
            MetadataReader           reader = TryOpenMetadataFile(pdbFilename, stringDecoder, out mappedViewAccessor);

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

            var foundContentId = new BlobContentId(reader.DebugMetadataHeader.Id);

            if (foundContentId != expectedContentId)
            {
                mappedViewAccessor.Dispose();
                return(null);
            }

            return(new PortablePdbSymbolReader(reader, mappedViewAccessor));
        }
Example #32
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);
        }