< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 149
Coverable lines: 149
Total lines: 338
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 36
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using System.Collections.Immutable;
 6using System.Reflection.Metadata;
 7
 8namespace System.Reflection.PortableExecutable
 9{
 10    public sealed partial class DebugDirectoryBuilder
 11    {
 12        private struct Entry
 13        {
 14            public uint Stamp;
 15            public uint Version;
 16            public DebugDirectoryEntryType Type;
 17            public int DataSize;
 18        }
 19
 20        private readonly List<Entry> _entries;
 21        private readonly BlobBuilder _dataBuilder;
 22
 023        public DebugDirectoryBuilder()
 024        {
 025            _entries = new List<Entry>(3);
 026            _dataBuilder = new BlobBuilder();
 027        }
 28
 29        internal void AddEntry(DebugDirectoryEntryType type, uint version, uint stamp, int dataSize)
 030        {
 031            _entries.Add(new Entry()
 032            {
 033                Stamp = stamp,
 034                Version = version,
 035                Type = type,
 036                DataSize = dataSize,
 037            });
 038        }
 39
 40        /// <summary>
 41        /// Adds an entry.
 42        /// </summary>
 43        /// <param name="type">Entry type.</param>
 44        /// <param name="version">Entry version.</param>
 45        /// <param name="stamp">Entry stamp.</param>
 46        public void AddEntry(DebugDirectoryEntryType type, uint version, uint stamp)
 047            => AddEntry(type, version, stamp, dataSize: 0);
 48
 49        /// <summary>
 50        /// Adds an entry.
 51        /// </summary>
 52        /// <typeparam name="TData">Type of data passed to <paramref name="dataSerializer"/>.</typeparam>
 53        /// <param name="type">Entry type.</param>
 54        /// <param name="version">Entry version.</param>
 55        /// <param name="stamp">Entry stamp.</param>
 56        /// <param name="data">Data passed to <paramref name="dataSerializer"/>.</param>
 57        /// <param name="dataSerializer">Serializes data to a <see cref="BlobBuilder"/>.</param>
 58        public void AddEntry<TData>(DebugDirectoryEntryType type, uint version, uint stamp, TData data, Action<BlobBuild
 059        {
 060            if (dataSerializer is null)
 061            {
 062                Throw.ArgumentNull(nameof(dataSerializer));
 63            }
 64
 065            int start = _dataBuilder.Count;
 066            dataSerializer(_dataBuilder, data);
 067            int dataSize = _dataBuilder.Count - start;
 68
 069            AddEntry(type, version, stamp, dataSize);
 070        }
 71
 72        /// <summary>
 73        /// Adds a CodeView entry.
 74        /// </summary>
 75        /// <param name="pdbPath">Path to the PDB. Shall not be empty.</param>
 76        /// <param name="pdbContentId">Unique id of the PDB content.</param>
 77        /// <param name="portablePdbVersion">Version of Portable PDB format (e.g. 0x0100 for 1.0), or 0 if the PDB is no
 78        /// <exception cref="ArgumentNullException"><paramref name="pdbPath"/> is null.</exception>
 79        /// <exception cref="ArgumentException"><paramref name="pdbPath"/> contains NUL character.</exception>
 80        /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.<
 81        public void AddCodeViewEntry(
 82            string pdbPath,
 83            BlobContentId pdbContentId,
 84            ushort portablePdbVersion)
 085        {
 086            AddCodeViewEntry(pdbPath, pdbContentId, portablePdbVersion, age: 1);
 087        }
 88
 89        /// <summary>
 90        /// Adds a CodeView entry.
 91        /// </summary>
 92        /// <param name="pdbPath">Path to the PDB. Shall not be empty.</param>
 93        /// <param name="pdbContentId">Unique id of the PDB content.</param>
 94        /// <param name="portablePdbVersion">Version of Portable PDB format (e.g. 0x0100 for 1.0), or 0 if the PDB is no
 95        /// <param name="age">Age (iteration) of the PDB. Shall be 1 for Portable PDBs.</param>
 96        /// <exception cref="ArgumentNullException"><paramref name="pdbPath"/> is null.</exception>
 97        /// <exception cref="ArgumentException"><paramref name="pdbPath"/> contains NUL character.</exception>
 98        /// <exception cref="ArgumentOutOfRangeException"><paramref name="age"/> is less than 1.</exception>
 99        /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.<
 100        public void AddCodeViewEntry(
 101            string pdbPath,
 102            BlobContentId pdbContentId,
 103            ushort portablePdbVersion,
 104            int age)
 0105        {
 0106            if (pdbPath is null)
 0107            {
 0108                Throw.ArgumentNull(nameof(pdbPath));
 109            }
 110
 0111            if (age < 1)
 0112            {
 0113                Throw.ArgumentOutOfRange(nameof(age));
 114            }
 115
 116            // We allow NUL characters to allow for padding for backward compat purposes.
 0117            if (pdbPath.Length == 0 || pdbPath[0] == '\0')
 0118            {
 0119                Throw.InvalidArgument(SR.ExpectedNonEmptyString, nameof(pdbPath));
 120            }
 121
 0122            if (portablePdbVersion > 0 && portablePdbVersion < PortablePdbVersions.MinFormatVersion)
 0123            {
 0124                Throw.ArgumentOutOfRange(nameof(portablePdbVersion));
 125            }
 126
 0127            int dataSize = WriteCodeViewData(_dataBuilder, pdbPath, pdbContentId.Guid, age);
 128
 0129            AddEntry(
 0130                type: DebugDirectoryEntryType.CodeView,
 0131                version: (portablePdbVersion == 0) ? 0 : PortablePdbVersions.DebugDirectoryEntryVersion(portablePdbVersi
 0132                stamp: pdbContentId.Stamp,
 0133                dataSize);
 0134        }
 135
 136        /// <summary>
 137        /// Adds Reproducible entry.
 138        /// </summary>
 139        public void AddReproducibleEntry()
 0140            => AddEntry(type: DebugDirectoryEntryType.Reproducible, version: 0, stamp: 0);
 141
 142        private static int WriteCodeViewData(BlobBuilder builder, string pdbPath, Guid pdbGuid, int age)
 0143        {
 0144            int start = builder.Count;
 145
 0146            builder.WriteByte((byte)'R');
 0147            builder.WriteByte((byte)'S');
 0148            builder.WriteByte((byte)'D');
 0149            builder.WriteByte((byte)'S');
 150
 151            // PDB id:
 0152            builder.WriteGuid(pdbGuid);
 153
 154            // age
 0155            builder.WriteInt32(age);
 156
 157            // UTF-8 encoded zero-terminated path to PDB
 0158            builder.WriteUTF8(pdbPath, allowUnpairedSurrogates: true);
 0159            builder.WriteByte(0);
 160
 0161            return builder.Count - start;
 0162        }
 163
 164        /// <summary>
 165        /// Adds PDB checksum entry.
 166        /// </summary>
 167        /// <param name="algorithmName">Hash algorithm name (e.g. "SHA256").</param>
 168        /// <param name="checksum">Checksum.</param>
 169        /// <exception cref="ArgumentNullException"><paramref name="algorithmName"/> or <paramref name="checksum"/> is n
 170        /// <exception cref="ArgumentException"><paramref name="algorithmName"/> or <paramref name="checksum"/> is empty
 171        public void AddPdbChecksumEntry(string algorithmName, ImmutableArray<byte> checksum)
 0172        {
 0173            if (algorithmName is null)
 0174            {
 0175                Throw.ArgumentNull(nameof(algorithmName));
 176            }
 177
 0178            if (algorithmName.Length == 0)
 0179            {
 0180                Throw.ArgumentEmptyString(nameof(algorithmName));
 181            }
 182
 0183            if (checksum.IsDefault)
 0184            {
 0185                Throw.ArgumentNull(nameof(checksum));
 186            }
 187
 0188            if (checksum.Length == 0)
 0189            {
 0190                Throw.ArgumentEmptyArray(nameof(checksum));
 191            }
 192
 0193            int dataSize = WritePdbChecksumData(_dataBuilder, algorithmName, checksum);
 194
 0195            AddEntry(
 0196                type: DebugDirectoryEntryType.PdbChecksum,
 0197                version: 0x00000001,
 0198                stamp: 0x00000000,
 0199                dataSize);
 0200        }
 201
 202        private static int WritePdbChecksumData(BlobBuilder builder, string algorithmName, ImmutableArray<byte> checksum
 0203        {
 0204            int start = builder.Count;
 205
 206            // NUL-terminated algorithm name:
 0207            builder.WriteUTF8(algorithmName, allowUnpairedSurrogates: true);
 0208            builder.WriteByte(0);
 209
 210            // checksum:
 0211            builder.WriteBytes(checksum);
 212
 0213            return builder.Count - start;
 0214        }
 215
 0216        internal int TableSize => DebugDirectoryEntry.Size * _entries.Count;
 0217        internal int Size => TableSize + _dataBuilder?.Count ?? 0;
 218
 219        /// <summary>
 220        /// Serialize the Debug Table and Data.
 221        /// </summary>
 222        /// <param name="builder">Builder.</param>
 223        /// <param name="sectionLocation">The containing PE section location.</param>
 224        /// <param name="sectionOffset">Offset of the table within the containing section.</param>
 225        internal void Serialize(BlobBuilder builder, SectionLocation sectionLocation, int sectionOffset)
 0226        {
 0227            int dataOffset = sectionOffset + TableSize;
 0228            foreach (var entry in _entries)
 0229            {
 230                int addressOfRawData;
 231                int pointerToRawData;
 0232                if (entry.DataSize > 0)
 0233                {
 0234                    addressOfRawData = sectionLocation.RelativeVirtualAddress + dataOffset;
 0235                    pointerToRawData = sectionLocation.PointerToRawData + dataOffset;
 0236                }
 237                else
 0238                {
 0239                    addressOfRawData = 0;
 0240                    pointerToRawData = 0;
 0241                }
 242
 0243                builder.WriteUInt32(0); // characteristics, always 0
 0244                builder.WriteUInt32(entry.Stamp);
 0245                builder.WriteUInt32(entry.Version);
 0246                builder.WriteInt32((int)entry.Type);
 0247                builder.WriteInt32(entry.DataSize);
 0248                builder.WriteInt32(addressOfRawData);
 0249                builder.WriteInt32(pointerToRawData);
 250
 0251                dataOffset += entry.DataSize;
 0252            }
 253
 0254            builder.LinkSuffix(_dataBuilder);
 0255        }
 256    }
 257}
 258

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using System.IO;
 6using System.IO.Compression;
 7using System.Reflection.Metadata;
 8
 9namespace System.Reflection.PortableExecutable
 10{
 11    public sealed partial class DebugDirectoryBuilder
 12    {
 13        /// <summary>
 14        /// Adds Embedded Portable PDB entry.
 15        /// </summary>
 16        /// <param name="debugMetadata">Portable PDB metadata builder.</param>
 17        /// <param name="portablePdbVersion">Version of Portable PDB format (e.g. 0x0100 for 1.0).</param>
 18        /// <exception cref="ArgumentNullException"><paramref name="debugMetadata"/> is null.</exception>
 19        /// <exception cref="ArgumentOutOfRangeException"><paramref name="portablePdbVersion"/> is smaller than 0x0100.<
 20        public void AddEmbeddedPortablePdbEntry(BlobBuilder debugMetadata, ushort portablePdbVersion)
 021        {
 022            if (debugMetadata is null)
 023            {
 024                Throw.ArgumentNull(nameof(debugMetadata));
 25            }
 26
 027            if (portablePdbVersion < PortablePdbVersions.MinFormatVersion)
 028            {
 029                Throw.ArgumentOutOfRange(nameof(portablePdbVersion));
 30            }
 31
 032            int dataSize = WriteEmbeddedPortablePdbData(_dataBuilder, debugMetadata);
 33
 034            AddEntry(
 035                type: DebugDirectoryEntryType.EmbeddedPortablePdb,
 036                version: PortablePdbVersions.DebugDirectoryEmbeddedVersion(portablePdbVersion),
 037                stamp: 0,
 038                dataSize);
 039        }
 40
 41        private static int WriteEmbeddedPortablePdbData(BlobBuilder builder, BlobBuilder debugMetadata)
 042        {
 043            int start = builder.Count;
 44
 45            // header (signature, decompressed size):
 046            builder.WriteUInt32(PortablePdbVersions.DebugDirectoryEmbeddedSignature);
 047            builder.WriteInt32(debugMetadata.Count);
 48
 49            // compressed data:
 050            using (var deflate = new DeflateStream(new BlobBuilderStream(builder), CompressionLevel.Optimal, leaveOpen: 
 051            {
 052                debugMetadata.WriteContentTo(deflate);
 053            }
 54
 055            return builder.Count - start;
 056        }
 57
 58        /// <summary>
 59        /// Provides a <see cref="Stream"/> interface to write to a <see cref="BlobBuilder"/>.
 60        /// </summary>
 61        /// <param name="builder">The blob builder to write data to.</param>
 062        private sealed class BlobBuilderStream(BlobBuilder builder) : Stream
 63        {
 064            public override bool CanRead => false;
 065            public override bool CanSeek => false;
 066            public override bool CanWrite => true;
 067            public override long Length => throw new NotSupportedException();
 068            public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedExcep
 069            public override void Flush() { }
 070            public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
 071            public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
 072            public override void SetLength(long value) => throw new NotSupportedException();
 073            public override void Write(byte[] buffer, int offset, int count) => builder.WriteBytes(buffer, offset, count
 74#if NET
 075            public override void Write(ReadOnlySpan<byte> buffer) => builder.WriteBytes(buffer);
 76#endif
 77        }
 78    }
 79}
 80

Methods/Properties

.ctor()
AddEntry(System.Reflection.PortableExecutable.DebugDirectoryEntryType,System.UInt32,System.UInt32,System.Int32)
AddEntry(System.Reflection.PortableExecutable.DebugDirectoryEntryType,System.UInt32,System.UInt32)
AddEntry(System.Reflection.PortableExecutable.DebugDirectoryEntryType,System.UInt32,System.UInt32,TData,System.Action`2<System.Reflection.Metadata.BlobBuilder,TData>)
AddCodeViewEntry(System.String,System.Reflection.Metadata.BlobContentId,System.UInt16)
AddCodeViewEntry(System.String,System.Reflection.Metadata.BlobContentId,System.UInt16,System.Int32)
AddReproducibleEntry()
WriteCodeViewData(System.Reflection.Metadata.BlobBuilder,System.String,System.Guid,System.Int32)
AddPdbChecksumEntry(System.String,System.Collections.Immutable.ImmutableArray`1<System.Byte>)
WritePdbChecksumData(System.Reflection.Metadata.BlobBuilder,System.String,System.Collections.Immutable.ImmutableArray`1<System.Byte>)
TableSize()
Size()
Serialize(System.Reflection.Metadata.BlobBuilder,System.Reflection.PortableExecutable.SectionLocation,System.Int32)
AddEmbeddedPortablePdbEntry(System.Reflection.Metadata.BlobBuilder,System.UInt16)
WriteEmbeddedPortablePdbData(System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.BlobBuilder)
.ctor(System.Reflection.Metadata.BlobBuilder)
CanRead()
CanSeek()
CanWrite()
Length()
Position()
Flush()
Read(System.Byte[],System.Int32,System.Int32)
Seek(System.Int64,System.IO.SeekOrigin)
SetLength(System.Int64)
Write(System.Byte[],System.Int32,System.Int32)
Write(System.ReadOnlySpan`1<System.Byte>)