public void AddEmbeddedPortablePdbEntry_Args()
        {
            var bb = new BlobBuilder();

            var builder = new DebugDirectoryBuilder();
            Assert.Throws<ArgumentNullException>(() => builder.AddEmbeddedPortablePdbEntry(null, 0x0100));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.AddEmbeddedPortablePdbEntry(bb, 0x0000));
            Assert.Throws<ArgumentOutOfRangeException>(() => builder.AddEmbeddedPortablePdbEntry(bb, 0x00ff));
            builder.AddEmbeddedPortablePdbEntry(bb, 0x0100);
            builder.AddEmbeddedPortablePdbEntry(bb, 0xffff);
        }
Example #2
0
        public void AddEmbeddedPortablePdbEntry_Args()
        {
            var bb = new BlobBuilder();

            var builder = new DebugDirectoryBuilder();

            Assert.Throws <ArgumentNullException>(() => builder.AddEmbeddedPortablePdbEntry(null, 0x0100));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.AddEmbeddedPortablePdbEntry(bb, 0x0000));
            Assert.Throws <ArgumentOutOfRangeException>(() => builder.AddEmbeddedPortablePdbEntry(bb, 0x00ff));
            builder.AddEmbeddedPortablePdbEntry(bb, 0x0100);
            builder.AddEmbeddedPortablePdbEntry(bb, 0xffff);
        }
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 void Hello()
        {
            var metadata = new MetadataBuilder(0, 0, 0, 0);

            var location = Assembly.GetExecutingAssembly().Location;
            var pdbPath  = Path.ChangeExtension(location, "pdb");

            using (var fileStream = new FileStream(pdbPath, FileMode.Open))
            {
                var readerProvider =
                    MetadataReaderProvider.FromPortablePdbStream(fileStream, MetadataStreamOptions.Default);

                var reader = readerProvider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections, null);


                var debugDir = new DebugDirectoryBuilder();

                debugDir.AddEmbeddedPortablePdbEntry(null, 0);



                var blob = new BlobBuilder();

                var methodHandle = new MethodDefinitionHandle();

                var pdb = new PortablePdbBuilder(metadata, ImmutableArray <int> .Empty, methodHandle, null);

                var blobContentId = pdb.Serialize(blob);

                blob.ToArray();
            }
        }
Example #5
0
        public void TryOpenAssociatedPortablePdb_DuplicateEntries_Embedded()
        {
            var pdbBuilder1 = new BlobBuilder();

            pdbBuilder1.WriteBytes(PortablePdbs.DocumentsPdb);

            var pdbBuilder2 = new BlobBuilder();

            pdbBuilder2.WriteByte(1);

            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.AddReproducibleEntry();
            ddBuilder.AddEmbeddedPortablePdbEntry(pdbBuilder1, portablePdbVersion: 0x0100);
            ddBuilder.AddEmbeddedPortablePdbEntry(pdbBuilder2, 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.True(reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), streamProvider, out pdbProvider, out pdbPath));
                Assert.Equal(PathUtilities.CombinePathWithRelativePath("pedir", "a.pdb"), pathQueried);
                Assert.Null(pdbPath);

                Assert.Equal(13, pdbProvider.GetMetadataReader().Documents.Count);
            }
        }
Example #6
0
        public void EmbeddedPortablePdb()
        {
            var b = new DebugDirectoryBuilder();

            var pdb = new BlobBuilder();

            pdb.WriteInt64(0x1122334455667788);

            b.AddEmbeddedPortablePdbEntry(pdb, portablePdbVersion: 0x0100);

            var blob = new BlobBuilder();

            b.Serialize(blob, new SectionLocation(0, 0), sectionOffset: 0);
            var bytes = blob.ToImmutableArray();

            AssertEx.Equal(new byte[]
            {
                0x00, 0x00, 0x00, 0x00,                                    // Characteristics
                0x00, 0x00, 0x00, 0x00,                                    // Stamp
                0x00, 0x01, 0x00, 0x01,                                    // Version
                0x11, 0x00, 0x00, 0x00,                                    // Type
                0x12, 0x00, 0x00, 0x00,                                    // SizeOfData
                0x1C, 0x00, 0x00, 0x00,                                    // AddressOfRawData
                0x1C, 0x00, 0x00, 0x00,                                    // PointerToRawData

                0x4D, 0x50, 0x44, 0x42,                                    // signature
                0x08, 0x00, 0x00, 0x00,                                    // uncompressed size
                0xEB, 0x28, 0x4F, 0x0B, 0x75, 0x31, 0x56, 0x12, 0x04, 0x00 // compressed data
            }, bytes);

            using (var pinned = new PinnedBlob(bytes))
            {
                var actual = PEReader.ReadDebugDirectoryEntries(pinned.CreateReader(0, DebugDirectoryEntry.Size));
                Assert.Equal(1, actual.Length);
                Assert.Equal(0u, actual[0].Stamp);
                Assert.Equal(0x0100, actual[0].MajorVersion);
                Assert.Equal(0x0100, actual[0].MinorVersion);
                Assert.Equal(DebugDirectoryEntryType.EmbeddedPortablePdb, actual[0].Type);
                Assert.False(actual[0].IsPortableCodeView);
                Assert.Equal(0x00000012, actual[0].DataSize);
                Assert.Equal(0x0000001c, actual[0].DataRelativeVirtualAddress);
                Assert.Equal(0x0000001c, actual[0].DataPointer);

                var provider = new ByteArrayMemoryProvider(bytes);
                using (var block = provider.GetMemoryBlock(actual[0].DataPointer, actual[0].DataSize))
                {
                    var decoded = PEReader.DecodeEmbeddedPortablePdbDebugDirectoryData(block);
                    AssertEx.Equal(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, decoded);
                }
            }
        }
Example #7
0
        public void TryOpenAssociatedPortablePdb_ExpectedExceptionFromStreamProvider_FallbackOnEmbedded_Invalid()
        {
            var pdbBuilder = new BlobBuilder();

            pdbBuilder.WriteBytes(new byte[] { 0x01 });

            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;

                // reports the first error:
                Assert.Throws <IOException>(() =>
                                            reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new IOException(); }, out pdbProvider, out pdbPath));

                // reports the first error:
                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, fall back to embedded without reporting FileNotFoundExeception
                Assert.Throws <BadImageFormatException>(() =>
                                                        reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new FileNotFoundException(); }, out pdbProvider, out pdbPath));

                Assert.Throws <BadImageFormatException>(() =>
                                                        reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => null, out pdbProvider, out pdbPath));
            }
        }
Example #8
0
        internal static bool WritePeToStream(
            EmitContext context,
            CommonMessageProvider messageProvider,
            Func <Stream> getPeStream,
            Func <Stream> getPortablePdbStreamOpt,
            PdbWriter nativePdbWriterOpt,
            string pdbPathOpt,
            bool metadataOnly,
            bool isDeterministic,
            bool emitTestCoverageData,
            RSAParameters?privateKeyOpt,
            CancellationToken cancellationToken)
        {
            // If PDB writer is given, we have to have PDB path.
            Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null);

            var mdWriter = FullMetadataWriter.Create(context, messageProvider, metadataOnly, isDeterministic,
                                                     emitTestCoverageData, getPortablePdbStreamOpt != null, cancellationToken);

            var properties = context.Module.SerializationProperties;

            nativePdbWriterOpt?.SetMetadataEmitter(mdWriter);

            // Since we are producing a full assembly, we should not have a module version ID
            // imposed ahead-of time. Instead we will compute a deterministic module version ID
            // based on the contents of the generated stream.
            Debug.Assert(properties.PersistentIdentifier == default(Guid));

            var ilBuilder = new BlobBuilder(32 * 1024);
            var mappedFieldDataBuilder = new BlobBuilder();
            var managedResourceBuilder = new BlobBuilder(1024);

            Blob mvidFixup, mvidStringFixup;

            mdWriter.BuildMetadataAndIL(
                nativePdbWriterOpt,
                ilBuilder,
                mappedFieldDataBuilder,
                managedResourceBuilder,
                out mvidFixup,
                out mvidStringFixup);

            MethodDefinitionHandle entryPointHandle;
            MethodDefinitionHandle debugEntryPointHandle;

            mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle);

            if (!debugEntryPointHandle.IsNil)
            {
                nativePdbWriterOpt?.SetEntryPoint(MetadataTokens.GetToken(debugEntryPointHandle));
            }

            if (nativePdbWriterOpt != null)
            {
                if (context.Module.SourceLinkStreamOpt != null)
                {
                    nativePdbWriterOpt.EmbedSourceLink(context.Module.SourceLinkStreamOpt);
                }

                if (mdWriter.Module.OutputKind == OutputKind.WindowsRuntimeMetadata)
                {
                    // Dev12: If compiling to winmdobj, we need to add to PDB source spans of
                    //        all types and members for better error reporting by WinMDExp.
                    nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap());
                }
                else
                {
#if DEBUG
                    // validate that all definitions are writable
                    // if same scenario would happen in an winmdobj project
                    nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap());
#endif
                }

                nativePdbWriterOpt.WriteRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments);
            }

            Stream peStream = getPeStream();
            if (peStream == null)
            {
                return(false);
            }

            BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default;

            // the writer shall not be used after this point for writing:
            nativePdbWriterOpt = null;

            ushort portablePdbVersion  = 0;
            var    metadataRootBuilder = mdWriter.GetRootBuilder();

            var peHeaderBuilder = new PEHeaderBuilder(
                machine: properties.Machine,
                sectionAlignment: properties.SectionAlignment,
                fileAlignment: properties.FileAlignment,
                imageBase: properties.BaseAddress,
                majorLinkerVersion: properties.LinkerMajorVersion,
                minorLinkerVersion: properties.LinkerMinorVersion,
                majorOperatingSystemVersion: 4,
                minorOperatingSystemVersion: 0,
                majorImageVersion: 0,
                minorImageVersion: 0,
                majorSubsystemVersion: properties.MajorSubsystemVersion,
                minorSubsystemVersion: properties.MinorSubsystemVersion,
                subsystem: properties.Subsystem,
                dllCharacteristics: properties.DllCharacteristics,
                imageCharacteristics: properties.ImageCharacteristics,
                sizeOfStackReserve: properties.SizeOfStackReserve,
                sizeOfStackCommit: properties.SizeOfStackCommit,
                sizeOfHeapReserve: properties.SizeOfHeapReserve,
                sizeOfHeapCommit: properties.SizeOfHeapCommit);

            // TODO: replace SHA1 with non-crypto alg: https://github.com/dotnet/roslyn/issues/24737
            var peIdProvider = isDeterministic ?
                               new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeHash(HashAlgorithmName.SHA1, content))) :
                               null;

            // We need to calculate the PDB checksum, so we may as well use the calculated hash for PDB ID regardless of whether deterministic build is requested.
            var portablePdbContentHash = default(ImmutableArray <byte>);

            BlobBuilder portablePdbToEmbed = null;
            if (mdWriter.EmitPortableDebugMetadata)
            {
                mdWriter.AddRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments);

                // The algorithm must be specified for deterministic builds (checked earlier).
                Debug.Assert(!isDeterministic || context.Module.PdbChecksumAlgorithm.Name != null);

                var portablePdbIdProvider = (context.Module.PdbChecksumAlgorithm.Name != null) ?
                                            new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(portablePdbContentHash = CryptographicHashProvider.ComputeHash(context.Module.PdbChecksumAlgorithm, content))) :
                                            null;

                var portablePdbBlob    = new BlobBuilder();
                var portablePdbBuilder = mdWriter.GetPortablePdbBuilder(metadataRootBuilder.Sizes.RowCounts, debugEntryPointHandle, portablePdbIdProvider);
                pdbContentId       = portablePdbBuilder.Serialize(portablePdbBlob);
                portablePdbVersion = portablePdbBuilder.FormatVersion;

                if (getPortablePdbStreamOpt == null)
                {
                    // embed to debug directory:
                    portablePdbToEmbed = portablePdbBlob;
                }
                else
                {
                    // write to Portable PDB stream:
                    Stream portablePdbStream = getPortablePdbStreamOpt();
                    if (portablePdbStream != null)
                    {
                        try
                        {
                            portablePdbBlob.WriteContentTo(portablePdbStream);
                        }
                        catch (Exception e) when(!(e is OperationCanceledException))
                        {
                            throw new SymUnmanagedWriterException(e.Message, e);
                        }
                    }
                }
            }

            DebugDirectoryBuilder debugDirectoryBuilder;
            if (pdbPathOpt != null || isDeterministic || portablePdbToEmbed != null)
            {
                debugDirectoryBuilder = new DebugDirectoryBuilder();
                if (pdbPathOpt != null)
                {
                    string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt);
                    debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion);

                    if (!portablePdbContentHash.IsDefault)
                    {
                        // Emit PDB Checksum entry for Portable and Embedded PDBs. The checksum is not as useful when the PDB is embedded,
                        // however it allows the client to efficiently validate a standalone Portable PDB that
                        // has been extracted from Embedded PDB and placed next to the PE file.
                        debugDirectoryBuilder.AddPdbChecksumEntry(context.Module.PdbChecksumAlgorithm.Name, portablePdbContentHash);
                    }
                }

                if (isDeterministic)
                {
                    debugDirectoryBuilder.AddReproducibleEntry();
                }

                if (portablePdbToEmbed != null)
                {
                    debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbToEmbed, portablePdbVersion);
                }
            }
            else
            {
                debugDirectoryBuilder = null;
            }

            var strongNameProvider = context.Module.CommonCompilation.Options.StrongNameProvider;
            var corFlags           = properties.CorFlags;

            var peBuilder = new ExtendedPEBuilder(
                peHeaderBuilder,
                metadataRootBuilder,
                ilBuilder,
                mappedFieldDataBuilder,
                managedResourceBuilder,
                CreateNativeResourceSectionSerializer(context.Module),
                debugDirectoryBuilder,
                CalculateStrongNameSignatureSize(context.Module, privateKeyOpt),
                entryPointHandle,
                corFlags,
                peIdProvider,
                metadataOnly && !context.IncludePrivateMembers);

            var peBlob      = new BlobBuilder();
            var peContentId = peBuilder.Serialize(peBlob, out Blob mvidSectionFixup);

            PatchModuleVersionIds(mvidFixup, mvidSectionFixup, mvidStringFixup, peContentId.Guid);

            if (privateKeyOpt != null && corFlags.HasFlag(CorFlags.StrongNameSigned))
            {
                Debug.Assert(strongNameProvider.Capability == SigningCapability.SignsPeBuilder);
                strongNameProvider.SignPeBuilder(peBuilder, peBlob, privateKeyOpt.Value);
            }

            try
            {
                peBlob.WriteContentTo(peStream);
            }
            catch (Exception e) when(!(e is OperationCanceledException))
            {
                throw new PeWritingException(e);
            }

            return(true);
        }
        public void EmbeddedPortablePdb()
        {
            var b = new DebugDirectoryBuilder();

            var pdb = new BlobBuilder();
            pdb.WriteInt64(0x1122334455667788);

            b.AddEmbeddedPortablePdbEntry(pdb, portablePdbVersion: 0x0100);

            var blob = new BlobBuilder();
            b.Serialize(blob, new SectionLocation(0, 0), sectionOffset: 0);
            var bytes = blob.ToImmutableArray();

            AssertEx.Equal(new byte[]
            {
                0x00, 0x00, 0x00, 0x00, // Characteristics
                0x00, 0x00, 0x00, 0x00, // Stamp
                0x00, 0x01, 0x00, 0x01, // Version
                0x11, 0x00, 0x00, 0x00, // Type
                0x12, 0x00, 0x00, 0x00, // SizeOfData
                0x1C, 0x00, 0x00, 0x00, // AddressOfRawData
                0x1C, 0x00, 0x00, 0x00, // PointerToRawData

                0x4D, 0x50, 0x44, 0x42, // signature
                0x08, 0x00, 0x00, 0x00, // uncompressed size
                0xEB, 0x28, 0x4F, 0x0B, 0x75, 0x31, 0x56, 0x12, 0x04, 0x00 // compressed data
            }, bytes);

            using (var pinned = new PinnedBlob(bytes))
            {
                var actual = PEReader.ReadDebugDirectoryEntries(pinned.CreateReader(0, DebugDirectoryEntry.Size));
                Assert.Equal(1, actual.Length);
                Assert.Equal(0u, actual[0].Stamp);
                Assert.Equal(0x0100, actual[0].MajorVersion);
                Assert.Equal(0x0100, actual[0].MinorVersion);
                Assert.Equal(DebugDirectoryEntryType.EmbeddedPortablePdb, actual[0].Type);
                Assert.Equal(0x00000012, actual[0].DataSize);
                Assert.Equal(0x0000001c, actual[0].DataRelativeVirtualAddress);
                Assert.Equal(0x0000001c, actual[0].DataPointer);

                var provider = new ByteArrayMemoryProvider(bytes);
                using (var block = provider.GetMemoryBlock(actual[0].DataPointer, actual[0].DataSize))
                {
                    var decoded = PEReader.DecodeEmbeddedPortablePdbDebugDirectoryData(block);
                    AssertEx.Equal(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, decoded);
                }
            }
        }
Example #10
0
        public static bool WritePeToStream(
            EmitContext context,
            CommonMessageProvider messageProvider,
            Func <Stream> getPeStream,
            Func <Stream> getPortablePdbStreamOpt,
            PdbWriter nativePdbWriterOpt,
            string pdbPathOpt,
            bool allowMissingMethodBodies,
            bool isDeterministic,
            CancellationToken cancellationToken)
        {
            // If PDB writer is given, we have to have PDB path.
            Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null);

            var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken);

            var properties = context.Module.SerializationProperties;

            nativePdbWriterOpt?.SetMetadataEmitter(mdWriter);

            // Since we are producing a full assembly, we should not have a module version ID
            // imposed ahead-of time. Instead we will compute a deterministic module version ID
            // based on the contents of the generated stream.
            Debug.Assert(properties.PersistentIdentifier == default(Guid));

            var ilBuilder = new BlobBuilder(32 * 1024);
            var mappedFieldDataBuilder = new BlobBuilder();
            var managedResourceBuilder = new BlobBuilder(1024);

            Blob mvidFixup, mvidStringFixup;

            mdWriter.BuildMetadataAndIL(
                nativePdbWriterOpt,
                ilBuilder,
                mappedFieldDataBuilder,
                managedResourceBuilder,
                out mvidFixup,
                out mvidStringFixup);

            MethodDefinitionHandle entryPointHandle;
            MethodDefinitionHandle debugEntryPointHandle;

            mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle);

            if (!debugEntryPointHandle.IsNil)
            {
                nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle));
            }

            if (nativePdbWriterOpt != null)
            {
                if (context.Module.SourceLinkStreamOpt != null)
                {
                    nativePdbWriterOpt.EmbedSourceLink(context.Module.SourceLinkStreamOpt);
                }

                if (mdWriter.Module.OutputKind == OutputKind.WindowsRuntimeMetadata)
                {
                    // Dev12: If compiling to winmdobj, we need to add to PDB source spans of
                    //        all types and members for better error reporting by WinMDExp.
                    nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap());
                }
                else
                {
#if DEBUG
                    // validate that all definitions are writable
                    // if same scenario would happen in an winmdobj project
                    nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap());
#endif
                }

                // embedded text not currently supported for native PDB and we should have validated that
                Debug.Assert(!mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments.Any());
            }

            Stream peStream = getPeStream();
            if (peStream == null)
            {
                return(false);
            }

            BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(BlobContentId);

            // the writer shall not be used after this point for writing:
            nativePdbWriterOpt = null;

            ushort portablePdbVersion  = 0;
            var    metadataRootBuilder = mdWriter.GetRootBuilder();

            var peHeaderBuilder = new PEHeaderBuilder(
                machine: properties.Machine,
                sectionAlignment: properties.SectionAlignment,
                fileAlignment: properties.FileAlignment,
                imageBase: properties.BaseAddress,
                majorLinkerVersion: properties.LinkerMajorVersion,
                minorLinkerVersion: properties.LinkerMinorVersion,
                majorOperatingSystemVersion: 4,
                minorOperatingSystemVersion: 0,
                majorImageVersion: 0,
                minorImageVersion: 0,
                majorSubsystemVersion: properties.MajorSubsystemVersion,
                minorSubsystemVersion: properties.MinorSubsystemVersion,
                subsystem: properties.Subsystem,
                dllCharacteristics: properties.DllCharacteristics,
                imageCharacteristics: properties.ImageCharacteristics,
                sizeOfStackReserve: properties.SizeOfStackReserve,
                sizeOfStackCommit: properties.SizeOfStackCommit,
                sizeOfHeapReserve: properties.SizeOfHeapReserve,
                sizeOfHeapCommit: properties.SizeOfHeapCommit);

            var deterministicIdProvider = isDeterministic ?
                                          new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) :
                                          null;

            BlobBuilder portablePdbToEmbed = null;
            if (mdWriter.EmitStandaloneDebugMetadata)
            {
                mdWriter.AddRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments);

                var portablePdbBlob    = new BlobBuilder();
                var portablePdbBuilder = mdWriter.GetPortablePdbBuilder(metadataRootBuilder.Sizes.RowCounts, debugEntryPointHandle, deterministicIdProvider);
                pdbContentId       = portablePdbBuilder.Serialize(portablePdbBlob);
                portablePdbVersion = portablePdbBuilder.FormatVersion;

                if (getPortablePdbStreamOpt == null)
                {
                    // embed to debug directory:
                    portablePdbToEmbed = portablePdbBlob;
                }
                else
                {
                    // write to Portable PDB stream:
                    Stream portablePdbStream = getPortablePdbStreamOpt();
                    if (portablePdbStream != null)
                    {
                        portablePdbBlob.WriteContentTo(portablePdbStream);
                    }
                }
            }

            DebugDirectoryBuilder debugDirectoryBuilder;
            if (pdbPathOpt != null || isDeterministic || portablePdbToEmbed != null)
            {
                debugDirectoryBuilder = new DebugDirectoryBuilder();
                if (pdbPathOpt != null)
                {
                    string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt);
                    debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion);
                }

                if (isDeterministic)
                {
                    debugDirectoryBuilder.AddReproducibleEntry();
                }

                if (portablePdbToEmbed != null)
                {
                    debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbToEmbed, portablePdbVersion);
                }
            }
            else
            {
                debugDirectoryBuilder = null;
            }

            var peBuilder = new ManagedPEBuilder(
                peHeaderBuilder,
                metadataRootBuilder,
                ilBuilder,
                mappedFieldDataBuilder,
                managedResourceBuilder,
                CreateNativeResourceSectionSerializer(context.Module),
                debugDirectoryBuilder,
                CalculateStrongNameSignatureSize(context.Module),
                entryPointHandle,
                properties.CorFlags,
                deterministicIdProvider);

            var peBlob      = new BlobBuilder();
            var peContentId = peBuilder.Serialize(peBlob);

            PatchModuleVersionIds(mvidFixup, mvidStringFixup, peContentId.Guid);

            try
            {
                peBlob.WriteContentTo(peStream);
            }
            catch (Exception e) when(!(e is OperationCanceledException))
            {
                throw new PeWritingException(e);
            }

            return(true);
        }
Example #11
0
        public void TryOpenAssociatedPortablePdb_ExpectedExceptionFromStreamProvider_FallbackOnEmbedded_Invalid()
        {
            var pdbBuilder = new BlobBuilder();
            pdbBuilder.WriteBytes(new byte[] { 0x01 });

            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;

                // reports the first error:
                Assert.Throws<IOException>(() => 
                    reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new IOException(); }, out pdbProvider, out pdbPath));

                // reports the first error:
                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, fall back to embedded without reporting FileNotFoundExeception
                Assert.Throws<BadImageFormatException>(() =>
                    reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => { throw new FileNotFoundException(); }, out pdbProvider, out pdbPath));

                Assert.Throws<BadImageFormatException>(() =>
                    reader.TryOpenAssociatedPortablePdb(Path.Combine("pedir", "file.exe"), _ => null, out pdbProvider, out pdbPath));
            }
        }
Example #12
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 #13
0
        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);
            }
        }